Coverage Report

Created: 2025-08-28 06:57

/src/gdal/gcore/gdal_rat.cpp
Line
Count
Source (jump to first uncovered line)
1
/******************************************************************************
2
 *
3
 * Project:  GDAL Core
4
 * Purpose:  Implementation of GDALRasterAttributeTable and related classes.
5
 * Author:   Frank Warmerdam, warmerdam@pobox.com
6
 *
7
 ******************************************************************************
8
 * Copyright (c) 2005, Frank Warmerdam
9
 * Copyright (c) 2009, Even Rouault <even dot rouault at spatialys.com>
10
 *
11
 * SPDX-License-Identifier: MIT
12
 ****************************************************************************/
13
14
#include "cpl_port.h"
15
#include "gdal.h"
16
#include "gdal_priv.h"
17
#include "gdal_rat.h"
18
19
#include <cmath>
20
#include <cstddef>
21
#include <cstdlib>
22
23
#include <algorithm>
24
#include <vector>
25
26
#include "cpl_conv.h"
27
#include "cpl_error.h"
28
#include "cpl_string.h"
29
#include "cpl_vsi.h"
30
31
#ifdef __clang__
32
#pragma clang diagnostic push
33
#pragma clang diagnostic ignored "-Wunknown-pragmas"
34
#pragma clang diagnostic ignored "-Wdocumentation"
35
#pragma clang diagnostic ignored "-Wold-style-cast"
36
#endif
37
#include "json.h"
38
#ifdef __clang__
39
#pragma clang diagnostic pop
40
#endif
41
#include "ogrlibjsonutils.h"
42
43
/**
44
 * \class GDALRasterAttributeTable
45
 *
46
 * The GDALRasterAttributeTable (or RAT) class is used to encapsulate a table
47
 * used to provide attribute information about pixel values.  Each row
48
 * in the table applies to a range of pixel values (or a single value in
49
 * some cases), and might have attributes such as the histogram count for
50
 * that range, the color pixels of that range should be drawn names of classes
51
 * or any other generic information.
52
 *
53
 * Raster attribute tables can be used to represent histograms, color tables,
54
 * and classification information.
55
 *
56
 * Each column in a raster attribute table has a name, a type (integer,
57
 * floating point or string), and a GDALRATFieldUsage.  The usage distinguishes
58
 * columns with particular understood purposes (such as color, histogram
59
 * count, name) and columns that have specific purposes not understood by
60
 * the library (long label, suitability_for_growing_wheat, etc).
61
 *
62
 * In the general case each row has a column indicating the minimum pixel
63
 * values falling into that category, and a column indicating the maximum
64
 * pixel value.  These are indicated with usage values of GFU_Min, and
65
 * GFU_Max.  In other cases where each row is a discrete pixel value, one
66
 * column of usage GFU_MinMax can be used.
67
 *
68
 * In other cases all the categories are of equal size and regularly spaced
69
 * and the categorization information can be determined just by knowing the
70
 * value at which the categories start, and the size of a category.  This
71
 * is called "Linear Binning" and the information is kept specially on
72
 * the raster attribute table as a whole.
73
 *
74
 * RATs are normally associated with GDALRasterBands and can be queried
75
 * using the GDALRasterBand::GetDefaultRAT() method.
76
 */
77
78
/************************************************************************/
79
/*                  ~GDALRasterAttributeTable()                         */
80
/*                                                                      */
81
/*                      Virtual Destructor                              */
82
/************************************************************************/
83
84
0
GDALRasterAttributeTable::~GDALRasterAttributeTable() = default;
85
86
/************************************************************************/
87
/*                              ValuesIO()                              */
88
/*                                                                      */
89
/*                      Default Implementations                         */
90
/************************************************************************/
91
92
/**
93
 * \brief Read or Write a block of doubles to/from the Attribute Table.
94
 *
95
 * This method is the same as the C function GDALRATValuesIOAsDouble().
96
 *
97
 * @param eRWFlag Either GF_Read or GF_Write
98
 * @param iField column of the Attribute Table
99
 * @param iStartRow start row to start reading/writing (zero based)
100
 * @param iLength number of rows to read or write
101
 * @param pdfData pointer to array of doubles to read/write. Should be at least
102
 *   iLength long.
103
 *
104
 * @return CE_None or CE_Failure if iStartRow + iLength greater than number of
105
 *   rows in table.
106
 */
107
108
CPLErr GDALRasterAttributeTable::ValuesIO(GDALRWFlag eRWFlag, int iField,
109
                                          int iStartRow, int iLength,
110
                                          double *pdfData)
111
0
{
112
0
    if ((iStartRow + iLength) > GetRowCount())
113
0
    {
114
0
        return CE_Failure;
115
0
    }
116
117
0
    CPLErr eErr = CE_None;
118
0
    if (eRWFlag == GF_Read)
119
0
    {
120
0
        for (int iIndex = iStartRow; iIndex < (iStartRow + iLength); iIndex++)
121
0
        {
122
0
            pdfData[iIndex - iStartRow] = GetValueAsDouble(iIndex, iField);
123
0
        }
124
0
    }
125
0
    else
126
0
    {
127
0
        for (int iIndex = iStartRow;
128
0
             eErr == CE_None && iIndex < (iStartRow + iLength); iIndex++)
129
0
        {
130
0
            eErr = SetValue(iIndex, iField, pdfData[iIndex - iStartRow]);
131
0
        }
132
0
    }
133
0
    return eErr;
134
0
}
135
136
/************************************************************************/
137
/*                       GDALRATValuesIOAsDouble()                      */
138
/************************************************************************/
139
140
/**
141
 * \brief Read or Write a block of doubles to/from the Attribute Table.
142
 *
143
 * This function is the same as the C++ method
144
 * GDALRasterAttributeTable::ValuesIO()
145
 */
146
CPLErr CPL_STDCALL GDALRATValuesIOAsDouble(GDALRasterAttributeTableH hRAT,
147
                                           GDALRWFlag eRWFlag, int iField,
148
                                           int iStartRow, int iLength,
149
                                           double *pdfData)
150
151
0
{
152
0
    VALIDATE_POINTER1(hRAT, "GDALRATValuesIOAsDouble", CE_Failure);
153
154
0
    return GDALRasterAttributeTable::FromHandle(hRAT)->ValuesIO(
155
0
        eRWFlag, iField, iStartRow, iLength, pdfData);
156
0
}
157
158
/**
159
 * \brief Read or Write a block of integers to/from the Attribute Table.
160
 *
161
 * This method is the same as the C function GDALRATValuesIOAsInteger().
162
 *
163
 * @param eRWFlag Either GF_Read or GF_Write
164
 * @param iField column of the Attribute Table
165
 * @param iStartRow start row to start reading/writing (zero based)
166
 * @param iLength number of rows to read or write
167
 * @param pnData pointer to array of ints to read/write. Should be at least
168
 *     iLength long.
169
 *
170
 * @return CE_None or CE_Failure if iStartRow + iLength greater than number of
171
 *     rows in table.
172
 */
173
174
CPLErr GDALRasterAttributeTable::ValuesIO(GDALRWFlag eRWFlag, int iField,
175
                                          int iStartRow, int iLength,
176
                                          int *pnData)
177
0
{
178
0
    if ((iStartRow + iLength) > GetRowCount())
179
0
    {
180
0
        return CE_Failure;
181
0
    }
182
183
0
    CPLErr eErr = CE_None;
184
0
    if (eRWFlag == GF_Read)
185
0
    {
186
0
        for (int iIndex = iStartRow; iIndex < (iStartRow + iLength); iIndex++)
187
0
        {
188
0
            pnData[iIndex - iStartRow] = GetValueAsInt(iIndex, iField);
189
0
        }
190
0
    }
191
0
    else
192
0
    {
193
0
        for (int iIndex = iStartRow;
194
0
             eErr == CE_None && iIndex < (iStartRow + iLength); iIndex++)
195
0
        {
196
0
            eErr = SetValue(iIndex, iField, pnData[iIndex - iStartRow]);
197
0
        }
198
0
    }
199
0
    return eErr;
200
0
}
201
202
/************************************************************************/
203
/*                       GDALRATValuesIOAsInteger()                     */
204
/************************************************************************/
205
206
/**
207
 * \brief Read or Write a block of ints to/from the Attribute Table.
208
 *
209
 * This function is the same as the C++ method
210
 * GDALRasterAttributeTable::ValuesIO()
211
 */
212
CPLErr CPL_STDCALL GDALRATValuesIOAsInteger(GDALRasterAttributeTableH hRAT,
213
                                            GDALRWFlag eRWFlag, int iField,
214
                                            int iStartRow, int iLength,
215
                                            int *pnData)
216
217
0
{
218
0
    VALIDATE_POINTER1(hRAT, "GDALRATValuesIOAsInteger", CE_Failure);
219
220
0
    return GDALRasterAttributeTable::FromHandle(hRAT)->ValuesIO(
221
0
        eRWFlag, iField, iStartRow, iLength, pnData);
222
0
}
223
224
/**
225
 * \brief Read or Write a block of strings to/from the Attribute Table.
226
 *
227
 * This method is the same as the C function GDALRATValuesIOAsString().
228
 * When reading, papszStrList must be already allocated to the correct size.
229
 * The caller is expected to call CPLFree on each read string.
230
 *
231
 * @param eRWFlag Either GF_Read or GF_Write
232
 * @param iField column of the Attribute Table
233
 * @param iStartRow start row to start reading/writing (zero based)
234
 * @param iLength number of rows to read or write
235
 * @param papszStrList pointer to array of strings to read/write. Should be at
236
 *   least iLength long.
237
 *
238
 * @return CE_None or CE_Failure if iStartRow + iLength greater than number of
239
 *   rows in table.
240
 */
241
242
CPLErr GDALRasterAttributeTable::ValuesIO(GDALRWFlag eRWFlag, int iField,
243
                                          int iStartRow, int iLength,
244
                                          char **papszStrList)
245
0
{
246
0
    if ((iStartRow + iLength) > GetRowCount())
247
0
    {
248
0
        return CE_Failure;
249
0
    }
250
251
0
    CPLErr eErr = CE_None;
252
0
    if (eRWFlag == GF_Read)
253
0
    {
254
0
        for (int iIndex = iStartRow; iIndex < (iStartRow + iLength); iIndex++)
255
0
        {
256
0
            papszStrList[iIndex - iStartRow] =
257
0
                VSIStrdup(GetValueAsString(iIndex, iField));
258
0
        }
259
0
    }
260
0
    else
261
0
    {
262
0
        for (int iIndex = iStartRow;
263
0
             eErr == CE_None && iIndex < (iStartRow + iLength); iIndex++)
264
0
        {
265
0
            eErr = SetValue(iIndex, iField, papszStrList[iIndex - iStartRow]);
266
0
        }
267
0
    }
268
0
    return eErr;
269
0
}
270
271
/************************************************************************/
272
/*                       GDALRATValuesIOAsString()                      */
273
/************************************************************************/
274
275
/**
276
 * \brief Read or Write a block of strings to/from the Attribute Table.
277
 *
278
 * This function is the same as the C++ method
279
 * GDALRasterAttributeTable::ValuesIO()
280
 */
281
CPLErr CPL_STDCALL GDALRATValuesIOAsString(GDALRasterAttributeTableH hRAT,
282
                                           GDALRWFlag eRWFlag, int iField,
283
                                           int iStartRow, int iLength,
284
                                           char **papszStrList)
285
286
0
{
287
0
    VALIDATE_POINTER1(hRAT, "GDALRATValuesIOAsString", CE_Failure);
288
289
0
    return GDALRasterAttributeTable::FromHandle(hRAT)->ValuesIO(
290
0
        eRWFlag, iField, iStartRow, iLength, papszStrList);
291
0
}
292
293
/************************************************************************/
294
/*                            SetRowCount()                             */
295
/************************************************************************/
296
297
/**
298
 * \brief Set row count.
299
 *
300
 * Resizes the table to include the indicated number of rows.  Newly created
301
 * rows will be initialized to their default values - "" for strings,
302
 * and zero for numeric fields.
303
 *
304
 * This method is the same as the C function GDALRATSetRowCount().
305
 *
306
 * @param nNewCount the new number of rows.
307
 */
308
309
void GDALRasterAttributeTable::SetRowCount(CPL_UNUSED int nNewCount)
310
0
{
311
0
}
312
313
/************************************************************************/
314
/*                         GDALRATSetRowCount()                         */
315
/************************************************************************/
316
317
/**
318
 * \brief Set row count.
319
 *
320
 * This function is the same as the C++ method
321
 * GDALRasterAttributeTable::SetRowCount()
322
 *
323
 * @param hRAT RAT handle.
324
 * @param nNewCount the new number of rows.
325
 */
326
void CPL_STDCALL GDALRATSetRowCount(GDALRasterAttributeTableH hRAT,
327
                                    int nNewCount)
328
329
0
{
330
0
    VALIDATE_POINTER0(hRAT, "GDALRATSetRowCount");
331
332
0
    GDALRasterAttributeTable::FromHandle(hRAT)->SetRowCount(nNewCount);
333
0
}
334
335
/************************************************************************/
336
/*                           GetRowOfValue()                            */
337
/************************************************************************/
338
339
/**
340
 * \fn GDALRasterAttributeTable::GetRowOfValue(double) const
341
 * \brief Get row for pixel value.
342
 *
343
 * Given a raw pixel value, the raster attribute table is scanned to
344
 * determine which row in the table applies to the pixel value.  The
345
 * row index is returned.
346
 *
347
 * This method is the same as the C function GDALRATGetRowOfValue().
348
 *
349
 * @param dfValue the pixel value.
350
 *
351
 * @return the row index or -1 if no row is appropriate.
352
 */
353
354
/**/
355
/**/
356
357
int GDALRasterAttributeTable::GetRowOfValue(double /* dfValue */) const
358
0
{
359
0
    return -1;
360
0
}
361
362
/************************************************************************/
363
/*                        GDALRATGetRowOfValue()                        */
364
/************************************************************************/
365
366
/**
367
 * \brief Get row for pixel value.
368
 *
369
 * This function is the same as the C++ method
370
 * GDALRasterAttributeTable::GetRowOfValue()
371
 */
372
int CPL_STDCALL GDALRATGetRowOfValue(GDALRasterAttributeTableH hRAT,
373
                                     double dfValue)
374
375
0
{
376
0
    VALIDATE_POINTER1(hRAT, "GDALRATGetRowOfValue", 0);
377
378
0
    return GDALRasterAttributeTable::FromHandle(hRAT)->GetRowOfValue(dfValue);
379
0
}
380
381
/************************************************************************/
382
/*                           GetRowOfValue()                            */
383
/************************************************************************/
384
385
/**
386
 * \brief Get row for pixel value.
387
 *
388
 * Given a raw pixel value, the raster attribute table is scanned to
389
 * determine which row in the table applies to the pixel value.  The
390
 * row index is returned.
391
 *
392
 * Int arg for now just converted to double.  Perhaps we will
393
 * handle this in a special way some day?
394
 *
395
 * This method is the same as the C function GDALRATGetRowOfValue().
396
 *
397
 * @param nValue the pixel value.
398
 *
399
 * @return the row index or -1 if no row is appropriate.
400
 */
401
402
int GDALRasterAttributeTable::GetRowOfValue(int nValue) const
403
404
0
{
405
0
    return GetRowOfValue(static_cast<double>(nValue));
406
0
}
407
408
/************************************************************************/
409
/*                            CreateColumn()                            */
410
/************************************************************************/
411
412
/**
413
 * \fn GDALRasterAttributeTable::CreateColumn(const char*, GDALRATFieldType,
414
 * GDALRATFieldUsage) \brief Create new column.
415
 *
416
 * If the table already has rows, all row values for the new column will
417
 * be initialized to the default value ("", or zero).  The new column is
418
 * always created as the last column, and will be column (field)
419
 * "GetColumnCount()-1" after CreateColumn() has completed successfully.
420
 *
421
 * This method is the same as the C function GDALRATCreateColumn().
422
 *
423
 * @param pszFieldName the name of the field to create.
424
 * @param eFieldType the field type (integer, double or string).
425
 * @param eFieldUsage the field usage, GFU_Generic if not known.
426
 *
427
 * @return CE_None on success or CE_Failure if something goes wrong.
428
 */
429
430
/**/
431
/**/
432
433
CPLErr
434
GDALRasterAttributeTable::CreateColumn(const char * /* pszFieldName */,
435
                                       GDALRATFieldType /* eFieldType */,
436
                                       GDALRATFieldUsage /* eFieldUsage */)
437
0
{
438
0
    return CE_Failure;
439
0
}
440
441
/************************************************************************/
442
/*                        GDALRATCreateColumn()                         */
443
/************************************************************************/
444
445
/**
446
 * \brief Create new column.
447
 *
448
 * This function is the same as the C++ method
449
 * GDALRasterAttributeTable::CreateColumn()
450
 */
451
CPLErr CPL_STDCALL GDALRATCreateColumn(GDALRasterAttributeTableH hRAT,
452
                                       const char *pszFieldName,
453
                                       GDALRATFieldType eFieldType,
454
                                       GDALRATFieldUsage eFieldUsage)
455
456
0
{
457
0
    VALIDATE_POINTER1(hRAT, "GDALRATCreateColumn", CE_Failure);
458
459
0
    return GDALRasterAttributeTable::FromHandle(hRAT)->CreateColumn(
460
0
        pszFieldName, eFieldType, eFieldUsage);
461
0
}
462
463
/************************************************************************/
464
/*                          SetLinearBinning()                          */
465
/************************************************************************/
466
467
/**
468
 * \brief Set linear binning information.
469
 *
470
 * For RATs with equal sized categories (in pixel value space) that are
471
 * evenly spaced, this method may be used to associate the linear binning
472
 * information with the table.
473
 *
474
 * This method is the same as the C function GDALRATSetLinearBinning().
475
 *
476
 * @param dfRow0MinIn the lower bound (pixel value) of the first category.
477
 * @param dfBinSizeIn the width of each category (in pixel value units).
478
 *
479
 * @return CE_None on success or CE_Failure on failure.
480
 */
481
482
CPLErr GDALRasterAttributeTable::SetLinearBinning(CPL_UNUSED double dfRow0MinIn,
483
                                                  CPL_UNUSED double dfBinSizeIn)
484
0
{
485
0
    return CE_Failure;
486
0
}
487
488
/************************************************************************/
489
/*                      GDALRATSetLinearBinning()                       */
490
/************************************************************************/
491
492
/**
493
 * \brief Set linear binning information.
494
 *
495
 * This function is the same as the C++ method
496
 * GDALRasterAttributeTable::SetLinearBinning()
497
 */
498
CPLErr CPL_STDCALL GDALRATSetLinearBinning(GDALRasterAttributeTableH hRAT,
499
                                           double dfRow0Min, double dfBinSize)
500
501
0
{
502
0
    VALIDATE_POINTER1(hRAT, "GDALRATSetLinearBinning", CE_Failure);
503
504
0
    return GDALRasterAttributeTable::FromHandle(hRAT)->SetLinearBinning(
505
0
        dfRow0Min, dfBinSize);
506
0
}
507
508
/************************************************************************/
509
/*                          GetLinearBinning()                          */
510
/************************************************************************/
511
512
/**
513
 * \brief Get linear binning information.
514
 *
515
 * Returns linear binning information if any is associated with the RAT.
516
 *
517
 * This method is the same as the C function GDALRATGetLinearBinning().
518
 *
519
 * @param pdfRow0Min (out) the lower bound (pixel value) of the first category.
520
 * @param pdfBinSize (out) the width of each category (in pixel value units).
521
 *
522
 * @return TRUE if linear binning information exists or FALSE if there is none.
523
 */
524
525
int GDALRasterAttributeTable::GetLinearBinning(
526
    CPL_UNUSED double *pdfRow0Min, CPL_UNUSED double *pdfBinSize) const
527
0
{
528
0
    return false;
529
0
}
530
531
/************************************************************************/
532
/*                      GDALRATGetLinearBinning()                       */
533
/************************************************************************/
534
535
/**
536
 * \brief Get linear binning information.
537
 *
538
 * This function is the same as the C++ method
539
 * GDALRasterAttributeTable::GetLinearBinning()
540
 */
541
int CPL_STDCALL GDALRATGetLinearBinning(GDALRasterAttributeTableH hRAT,
542
                                        double *pdfRow0Min, double *pdfBinSize)
543
544
0
{
545
0
    VALIDATE_POINTER1(hRAT, "GDALRATGetLinearBinning", 0);
546
547
0
    return GDALRasterAttributeTable::FromHandle(hRAT)->GetLinearBinning(
548
0
        pdfRow0Min, pdfBinSize);
549
0
}
550
551
/************************************************************************/
552
/*                        GDALRATGetTableType()                         */
553
/************************************************************************/
554
555
/**
556
 * \brief Get Rat Table Type
557
 *
558
 * @since GDAL 2.4
559
 *
560
 * This function is the same as the C++ method
561
 * GDALRasterAttributeTable::GetTableType()
562
 */
563
GDALRATTableType CPL_STDCALL GDALRATGetTableType(GDALRasterAttributeTableH hRAT)
564
0
{
565
0
    VALIDATE_POINTER1(hRAT, "GDALRATGetTableType", GRTT_THEMATIC);
566
567
0
    return GDALDefaultRasterAttributeTable::FromHandle(hRAT)->GetTableType();
568
0
}
569
570
/************************************************************************/
571
/*                        GDALRATSetTableType()                         */
572
/************************************************************************/
573
574
/**
575
 * \brief Set RAT Table Type
576
 *
577
 * @since GDAL 2.4
578
 *
579
 * This function is the same as the C++ method
580
 * GDALRasterAttributeTable::SetTableType()
581
 */
582
CPLErr CPL_STDCALL GDALRATSetTableType(GDALRasterAttributeTableH hRAT,
583
                                       const GDALRATTableType eInTableType)
584
585
0
{
586
0
    VALIDATE_POINTER1(hRAT, "GDALRATSetTableType", CE_Failure);
587
588
0
    return GDALDefaultRasterAttributeTable::FromHandle(hRAT)->SetTableType(
589
0
        eInTableType);
590
0
}
591
592
/************************************************************************/
593
/*                             Serialize()                              */
594
/************************************************************************/
595
596
/** Serialize as a XML tree.
597
 * @return XML tree.
598
 */
599
CPLXMLNode *GDALRasterAttributeTable::Serialize() const
600
601
0
{
602
0
    if ((GetColumnCount() == 0) && (GetRowCount() == 0))
603
0
        return nullptr;
604
605
0
    CPLXMLNode *psTree =
606
0
        CPLCreateXMLNode(nullptr, CXT_Element, "GDALRasterAttributeTable");
607
608
    /* -------------------------------------------------------------------- */
609
    /*      Add attributes with regular binning info if appropriate.        */
610
    /* -------------------------------------------------------------------- */
611
0
    char szValue[128] = {'\0'};
612
0
    double dfRow0Min = 0.0;
613
0
    double dfBinSize = 0.0;
614
615
0
    if (GetLinearBinning(&dfRow0Min, &dfBinSize))
616
0
    {
617
0
        CPLsnprintf(szValue, sizeof(szValue), "%.16g", dfRow0Min);
618
0
        CPLCreateXMLNode(CPLCreateXMLNode(psTree, CXT_Attribute, "Row0Min"),
619
0
                         CXT_Text, szValue);
620
621
0
        CPLsnprintf(szValue, sizeof(szValue), "%.16g", dfBinSize);
622
0
        CPLCreateXMLNode(CPLCreateXMLNode(psTree, CXT_Attribute, "BinSize"),
623
0
                         CXT_Text, szValue);
624
0
    }
625
626
    /* -------------------------------------------------------------------- */
627
    /*      Store table type                                                */
628
    /* -------------------------------------------------------------------- */
629
0
    const GDALRATTableType tableType = GetTableType();
630
0
    if (tableType == GRTT_ATHEMATIC)
631
0
    {
632
0
        CPLsnprintf(szValue, sizeof(szValue), "athematic");
633
0
    }
634
0
    else
635
0
    {
636
0
        CPLsnprintf(szValue, sizeof(szValue), "thematic");
637
0
    }
638
0
    CPLCreateXMLNode(CPLCreateXMLNode(psTree, CXT_Attribute, "tableType"),
639
0
                     CXT_Text, szValue);
640
641
    /* -------------------------------------------------------------------- */
642
    /*      Define each column.                                             */
643
    /* -------------------------------------------------------------------- */
644
0
    const int iColCount = GetColumnCount();
645
646
0
    for (int iCol = 0; iCol < iColCount; iCol++)
647
0
    {
648
0
        CPLXMLNode *psCol = CPLCreateXMLNode(psTree, CXT_Element, "FieldDefn");
649
650
0
        snprintf(szValue, sizeof(szValue), "%d", iCol);
651
0
        CPLCreateXMLNode(CPLCreateXMLNode(psCol, CXT_Attribute, "index"),
652
0
                         CXT_Text, szValue);
653
654
0
        CPLCreateXMLElementAndValue(psCol, "Name", GetNameOfCol(iCol));
655
656
0
        snprintf(szValue, sizeof(szValue), "%d",
657
0
                 static_cast<int>(GetTypeOfCol(iCol)));
658
0
        CPLXMLNode *psType =
659
0
            CPLCreateXMLElementAndValue(psCol, "Type", szValue);
660
0
        const char *pszTypeStr = "String";
661
0
        switch (GetTypeOfCol(iCol))
662
0
        {
663
0
            case GFT_Integer:
664
0
                pszTypeStr = "Integer";
665
0
                break;
666
0
            case GFT_Real:
667
0
                pszTypeStr = "Real";
668
0
                break;
669
0
            case GFT_String:
670
0
                break;
671
0
        }
672
0
        CPLAddXMLAttributeAndValue(psType, "typeAsString", pszTypeStr);
673
674
0
        snprintf(szValue, sizeof(szValue), "%d",
675
0
                 static_cast<int>(GetUsageOfCol(iCol)));
676
0
        CPLXMLNode *psUsage =
677
0
            CPLCreateXMLElementAndValue(psCol, "Usage", szValue);
678
0
        const char *pszUsageStr = "";
679
680
0
#define USAGE_STR(x)                                                           \
681
0
    case GFU_##x:                                                              \
682
0
        pszUsageStr = #x;                                                      \
683
0
        break
684
0
        switch (GetUsageOfCol(iCol))
685
0
        {
686
0
            USAGE_STR(Generic);
687
0
            USAGE_STR(PixelCount);
688
0
            USAGE_STR(Name);
689
0
            USAGE_STR(Min);
690
0
            USAGE_STR(Max);
691
0
            USAGE_STR(MinMax);
692
0
            USAGE_STR(Red);
693
0
            USAGE_STR(Green);
694
0
            USAGE_STR(Blue);
695
0
            USAGE_STR(Alpha);
696
0
            USAGE_STR(RedMin);
697
0
            USAGE_STR(GreenMin);
698
0
            USAGE_STR(BlueMin);
699
0
            USAGE_STR(AlphaMin);
700
0
            USAGE_STR(RedMax);
701
0
            USAGE_STR(GreenMax);
702
0
            USAGE_STR(BlueMax);
703
0
            USAGE_STR(AlphaMax);
704
0
            case GFU_MaxCount:
705
0
                break;
706
0
        }
707
0
#undef USAGE_STR
708
0
        CPLAddXMLAttributeAndValue(psUsage, "usageAsString", pszUsageStr);
709
0
    }
710
711
    /* -------------------------------------------------------------------- */
712
    /*      Write out each row.                                             */
713
    /* -------------------------------------------------------------------- */
714
0
    const int iRowCount = GetRowCount();
715
0
    CPLXMLNode *psTail = nullptr;
716
0
    CPLXMLNode *psRow = nullptr;
717
718
0
    for (int iRow = 0; iRow < iRowCount; iRow++)
719
0
    {
720
0
        psRow = CPLCreateXMLNode(nullptr, CXT_Element, "Row");
721
0
        if (psTail == nullptr)
722
0
            CPLAddXMLChild(psTree, psRow);
723
0
        else
724
0
            psTail->psNext = psRow;
725
0
        psTail = psRow;
726
727
0
        snprintf(szValue, sizeof(szValue), "%d", iRow);
728
0
        CPLCreateXMLNode(CPLCreateXMLNode(psRow, CXT_Attribute, "index"),
729
0
                         CXT_Text, szValue);
730
731
0
        for (int iCol = 0; iCol < iColCount; iCol++)
732
0
        {
733
0
            const char *pszValue = szValue;
734
735
0
            if (GetTypeOfCol(iCol) == GFT_Integer)
736
0
                snprintf(szValue, sizeof(szValue), "%d",
737
0
                         GetValueAsInt(iRow, iCol));
738
0
            else if (GetTypeOfCol(iCol) == GFT_Real)
739
0
                CPLsnprintf(szValue, sizeof(szValue), "%.16g",
740
0
                            GetValueAsDouble(iRow, iCol));
741
0
            else
742
0
                pszValue = GetValueAsString(iRow, iCol);
743
744
0
            CPLCreateXMLElementAndValue(psRow, "F", pszValue);
745
0
        }
746
0
    }
747
748
0
    return psTree;
749
0
}
750
751
/************************************************************************/
752
/*                             SerializeJSON()                           */
753
/************************************************************************/
754
755
/** Serialize as a JSON object.
756
 * @return JSON object (of type json_object*)
757
 */
758
void *GDALRasterAttributeTable::SerializeJSON() const
759
760
0
{
761
0
    json_object *poRAT = json_object_new_object();
762
763
0
    if ((GetColumnCount() == 0) && (GetRowCount() == 0))
764
0
        return poRAT;
765
766
    /* -------------------------------------------------------------------- */
767
    /*      Add attributes with regular binning info if appropriate.        */
768
    /* -------------------------------------------------------------------- */
769
0
    double dfRow0Min = 0.0;
770
0
    double dfBinSize = 0.0;
771
0
    json_object *poRow0Min = nullptr;
772
0
    json_object *poBinSize = nullptr;
773
0
    json_object *poTableType = nullptr;
774
775
0
    if (GetLinearBinning(&dfRow0Min, &dfBinSize))
776
0
    {
777
0
        poRow0Min = json_object_new_double_with_precision(dfRow0Min, 16);
778
0
        json_object_object_add(poRAT, "row0Min", poRow0Min);
779
780
0
        poBinSize = json_object_new_double_with_precision(dfBinSize, 16);
781
0
        json_object_object_add(poRAT, "binSize", poBinSize);
782
0
    }
783
784
    /* -------------------------------------------------------------------- */
785
    /*      Table Type                                                      */
786
    /* -------------------------------------------------------------------- */
787
0
    const GDALRATTableType tableType = GetTableType();
788
0
    if (tableType == GRTT_ATHEMATIC)
789
0
    {
790
0
        poTableType = json_object_new_string("athematic");
791
0
    }
792
0
    else
793
0
    {
794
0
        poTableType = json_object_new_string("thematic");
795
0
    }
796
0
    json_object_object_add(poRAT, "tableType", poTableType);
797
798
    /* -------------------------------------------------------------------- */
799
    /*      Define each column.                                             */
800
    /* -------------------------------------------------------------------- */
801
0
    const int iColCount = GetColumnCount();
802
0
    json_object *poFieldDefnArray = json_object_new_array();
803
804
0
    for (int iCol = 0; iCol < iColCount; iCol++)
805
0
    {
806
0
        json_object *const poFieldDefn = json_object_new_object();
807
808
0
        json_object *const poColumnIndex = json_object_new_int(iCol);
809
0
        json_object_object_add(poFieldDefn, "index", poColumnIndex);
810
811
0
        json_object *const poName = json_object_new_string(GetNameOfCol(iCol));
812
0
        json_object_object_add(poFieldDefn, "name", poName);
813
814
0
        json_object *const poType =
815
0
            json_object_new_int(static_cast<int>(GetTypeOfCol(iCol)));
816
0
        json_object_object_add(poFieldDefn, "type", poType);
817
818
0
        json_object *const poUsage =
819
0
            json_object_new_int(static_cast<int>(GetUsageOfCol(iCol)));
820
0
        json_object_object_add(poFieldDefn, "usage", poUsage);
821
822
0
        json_object_array_add(poFieldDefnArray, poFieldDefn);
823
0
    }
824
825
0
    json_object_object_add(poRAT, "fieldDefn", poFieldDefnArray);
826
827
    /* -------------------------------------------------------------------- */
828
    /*      Write out each row.                                             */
829
    /* -------------------------------------------------------------------- */
830
0
    const int iRowCount = GetRowCount();
831
0
    json_object *poRowArray = json_object_new_array();
832
833
0
    for (int iRow = 0; iRow < iRowCount; iRow++)
834
0
    {
835
0
        json_object *const poRow = json_object_new_object();
836
837
0
        json_object *const poRowIndex = json_object_new_int(iRow);
838
0
        json_object_object_add(poRow, "index", poRowIndex);
839
840
0
        json_object *const poFArray = json_object_new_array();
841
842
0
        for (int iCol = 0; iCol < iColCount; iCol++)
843
0
        {
844
0
            json_object *poF = nullptr;
845
0
            if (GetTypeOfCol(iCol) == GFT_Integer)
846
0
                poF = json_object_new_int(GetValueAsInt(iRow, iCol));
847
0
            else if (GetTypeOfCol(iCol) == GFT_Real)
848
0
                poF = json_object_new_double_with_precision(
849
0
                    GetValueAsDouble(iRow, iCol), 16);
850
0
            else
851
0
                poF = json_object_new_string(GetValueAsString(iRow, iCol));
852
853
0
            json_object_array_add(poFArray, poF);
854
0
        }
855
0
        json_object_object_add(poRow, "f", poFArray);
856
0
        json_object_array_add(poRowArray, poRow);
857
0
    }
858
0
    json_object_object_add(poRAT, "row", poRowArray);
859
860
0
    return poRAT;
861
0
}
862
863
/************************************************************************/
864
/*                              XMLInit()                               */
865
/************************************************************************/
866
867
/** Deserialize from XML.
868
 * @param psTree XML tree
869
 * @return error code.
870
 */
871
CPLErr GDALRasterAttributeTable::XMLInit(const CPLXMLNode *psTree,
872
                                         const char * /*pszVRTPath*/)
873
874
0
{
875
0
    CPLAssert(GetRowCount() == 0 && GetColumnCount() == 0);
876
877
    /* -------------------------------------------------------------------- */
878
    /*      Linear binning.                                                 */
879
    /* -------------------------------------------------------------------- */
880
0
    if (CPLGetXMLValue(psTree, "Row0Min", nullptr) &&
881
0
        CPLGetXMLValue(psTree, "BinSize", nullptr))
882
0
    {
883
0
        SetLinearBinning(CPLAtof(CPLGetXMLValue(psTree, "Row0Min", "")),
884
0
                         CPLAtof(CPLGetXMLValue(psTree, "BinSize", "")));
885
0
    }
886
887
    /* -------------------------------------------------------------------- */
888
    /*      Table Type                                                      */
889
    /* -------------------------------------------------------------------- */
890
0
    if (CPLGetXMLValue(psTree, "tableType", nullptr))
891
0
    {
892
0
        const char *pszValue = CPLGetXMLValue(psTree, "tableType", "thematic");
893
0
        if (EQUAL(pszValue, "athematic"))
894
0
        {
895
0
            SetTableType(GRTT_ATHEMATIC);
896
0
        }
897
0
        else
898
0
        {
899
0
            SetTableType(GRTT_THEMATIC);
900
0
        }
901
0
    }
902
903
    /* -------------------------------------------------------------------- */
904
    /*      Column definitions                                              */
905
    /* -------------------------------------------------------------------- */
906
907
0
    for (CPLXMLNode *psChild = psTree->psChild; psChild != nullptr;
908
0
         psChild = psChild->psNext)
909
0
    {
910
0
        if (psChild->eType == CXT_Element &&
911
0
            EQUAL(psChild->pszValue, "FieldDefn"))
912
0
        {
913
0
            CreateColumn(CPLGetXMLValue(psChild, "Name", ""),
914
0
                         static_cast<GDALRATFieldType>(
915
0
                             atoi(CPLGetXMLValue(psChild, "Type", "1"))),
916
0
                         static_cast<GDALRATFieldUsage>(
917
0
                             atoi(CPLGetXMLValue(psChild, "Usage", "0"))));
918
0
        }
919
0
    }
920
921
    /* -------------------------------------------------------------------- */
922
    /*      Row data.                                                       */
923
    /* -------------------------------------------------------------------- */
924
0
    for (const CPLXMLNode *psChild = psTree->psChild; psChild != nullptr;
925
0
         psChild = psChild->psNext)
926
0
    {
927
0
        if (psChild->eType == CXT_Element && EQUAL(psChild->pszValue, "Row"))
928
0
        {
929
0
            const int iRow = atoi(CPLGetXMLValue(psChild, "index", "0"));
930
0
            int iField = 0;
931
932
0
            for (CPLXMLNode *psF = psChild->psChild; psF != nullptr;
933
0
                 psF = psF->psNext)
934
0
            {
935
0
                if (psF->eType != CXT_Element || !EQUAL(psF->pszValue, "F"))
936
0
                    continue;
937
938
0
                if (psF->psChild != nullptr && psF->psChild->eType == CXT_Text)
939
0
                    SetValue(iRow, iField++, psF->psChild->pszValue);
940
0
                else
941
0
                    SetValue(iRow, iField++, "");
942
0
            }
943
0
        }
944
0
    }
945
946
0
    return CE_None;
947
0
}
948
949
/************************************************************************/
950
/*                      InitializeFromColorTable()                      */
951
/************************************************************************/
952
953
/**
954
 * \brief Initialize from color table.
955
 *
956
 * This method will setup a whole raster attribute table based on the
957
 * contents of the passed color table.  The Value (GFU_MinMax),
958
 * Red (GFU_Red), Green (GFU_Green), Blue (GFU_Blue), and Alpha (GFU_Alpha)
959
 * fields are created, and a row is set for each entry in the color table.
960
 *
961
 * The raster attribute table must be empty before calling
962
 * InitializeFromColorTable().
963
 *
964
 * The Value fields are set based on the implicit assumption with color
965
 * tables that entry 0 applies to pixel value 0, 1 to 1, etc.
966
 *
967
 * This method is the same as the C function GDALRATInitializeFromColorTable().
968
 *
969
 * @param poTable the color table to copy from.
970
 *
971
 * @return CE_None on success or CE_Failure if something goes wrong.
972
 */
973
974
CPLErr GDALRasterAttributeTable::InitializeFromColorTable(
975
    const GDALColorTable *poTable)
976
977
0
{
978
0
    if (GetRowCount() > 0 || GetColumnCount() > 0)
979
0
    {
980
0
        CPLError(CE_Failure, CPLE_AppDefined,
981
0
                 "Raster Attribute Table not empty in "
982
0
                 "InitializeFromColorTable()");
983
0
        return CE_Failure;
984
0
    }
985
986
0
    SetLinearBinning(0.0, 1.0);
987
0
    CreateColumn("Value", GFT_Integer, GFU_MinMax);
988
0
    CreateColumn("Red", GFT_Integer, GFU_Red);
989
0
    CreateColumn("Green", GFT_Integer, GFU_Green);
990
0
    CreateColumn("Blue", GFT_Integer, GFU_Blue);
991
0
    CreateColumn("Alpha", GFT_Integer, GFU_Alpha);
992
993
0
    SetRowCount(poTable->GetColorEntryCount());
994
995
0
    for (int iRow = 0; iRow < poTable->GetColorEntryCount(); iRow++)
996
0
    {
997
0
        GDALColorEntry sEntry;
998
999
0
        poTable->GetColorEntryAsRGB(iRow, &sEntry);
1000
1001
0
        SetValue(iRow, 0, iRow);
1002
0
        SetValue(iRow, 1, sEntry.c1);
1003
0
        SetValue(iRow, 2, sEntry.c2);
1004
0
        SetValue(iRow, 3, sEntry.c3);
1005
0
        SetValue(iRow, 4, sEntry.c4);
1006
0
    }
1007
1008
0
    return CE_None;
1009
0
}
1010
1011
/************************************************************************/
1012
/*                  GDALRATInitializeFromColorTable()                   */
1013
/************************************************************************/
1014
1015
/**
1016
 * \brief Initialize from color table.
1017
 *
1018
 * This function is the same as the C++ method
1019
 * GDALRasterAttributeTable::InitializeFromColorTable()
1020
 */
1021
CPLErr CPL_STDCALL GDALRATInitializeFromColorTable(
1022
    GDALRasterAttributeTableH hRAT, GDALColorTableH hCT)
1023
1024
0
{
1025
0
    VALIDATE_POINTER1(hRAT, "GDALRATInitializeFromColorTable", CE_Failure);
1026
1027
0
    return GDALRasterAttributeTable::FromHandle(hRAT)->InitializeFromColorTable(
1028
0
        GDALColorTable::FromHandle(hCT));
1029
0
}
1030
1031
/************************************************************************/
1032
/*                       TranslateToColorTable()                        */
1033
/************************************************************************/
1034
1035
/**
1036
 * \brief Translate to a color table.
1037
 *
1038
 * This method will attempt to create a corresponding GDALColorTable from
1039
 * this raster attribute table.
1040
 *
1041
 * This method is the same as the C function GDALRATTranslateToColorTable().
1042
 *
1043
 * @param nEntryCount The number of entries to produce (0 to nEntryCount-1),
1044
 * or -1 to auto-determine the number of entries.
1045
 *
1046
 * @return the generated color table or NULL on failure.
1047
 */
1048
1049
GDALColorTable *GDALRasterAttributeTable::TranslateToColorTable(int nEntryCount)
1050
1051
0
{
1052
    /* -------------------------------------------------------------------- */
1053
    /*      Establish which fields are red, green, blue and alpha.          */
1054
    /* -------------------------------------------------------------------- */
1055
0
    const int iRed = GetColOfUsage(GFU_Red);
1056
0
    const int iGreen = GetColOfUsage(GFU_Green);
1057
0
    const int iBlue = GetColOfUsage(GFU_Blue);
1058
1059
0
    if (iRed == -1 || iGreen == -1 || iBlue == -1)
1060
0
        return nullptr;
1061
1062
0
    const int iAlpha = GetColOfUsage(GFU_Alpha);
1063
1064
    /* -------------------------------------------------------------------- */
1065
    /*      If we aren't given an explicit number of values to scan for,    */
1066
    /*      search for the maximum "max" value.                             */
1067
    /* -------------------------------------------------------------------- */
1068
0
    if (nEntryCount == -1)
1069
0
    {
1070
0
        int iMaxCol = GetColOfUsage(GFU_Max);
1071
0
        if (iMaxCol == -1)
1072
0
            iMaxCol = GetColOfUsage(GFU_MinMax);
1073
1074
0
        if (iMaxCol == -1 || GetRowCount() == 0)
1075
0
            return nullptr;
1076
1077
0
        for (int iRow = 0; iRow < GetRowCount(); iRow++)
1078
0
        {
1079
0
            nEntryCount = std::max(
1080
0
                nEntryCount, std::min(65535, GetValueAsInt(iRow, iMaxCol)) + 1);
1081
0
        }
1082
1083
0
        if (nEntryCount < 0)
1084
0
            return nullptr;
1085
1086
        // Restrict our number of entries to something vaguely sensible.
1087
0
        nEntryCount = std::min(65535, nEntryCount);
1088
0
    }
1089
1090
    /* -------------------------------------------------------------------- */
1091
    /*      Assign values to color table.                                   */
1092
    /* -------------------------------------------------------------------- */
1093
0
    GDALColorTable *poCT = new GDALColorTable();
1094
1095
0
    for (int iEntry = 0; iEntry < nEntryCount; iEntry++)
1096
0
    {
1097
0
        GDALColorEntry sColor = {0, 0, 0, 0};
1098
0
        const int iRow = GetRowOfValue(iEntry);
1099
1100
0
        if (iRow != -1)
1101
0
        {
1102
0
            sColor.c1 = static_cast<short>(GetValueAsInt(iRow, iRed));
1103
0
            sColor.c2 = static_cast<short>(GetValueAsInt(iRow, iGreen));
1104
0
            sColor.c3 = static_cast<short>(GetValueAsInt(iRow, iBlue));
1105
0
            if (iAlpha == -1)
1106
0
                sColor.c4 = 255;
1107
0
            else
1108
0
                sColor.c4 = static_cast<short>(GetValueAsInt(iRow, iAlpha));
1109
0
        }
1110
1111
0
        poCT->SetColorEntry(iEntry, &sColor);
1112
0
    }
1113
1114
0
    return poCT;
1115
0
}
1116
1117
/************************************************************************/
1118
/*                  GDALRATInitializeFromColorTable()                   */
1119
/************************************************************************/
1120
1121
/**
1122
 * \brief Translate to a color table.
1123
 *
1124
 * This function is the same as the C++ method
1125
 * GDALRasterAttributeTable::TranslateToColorTable()
1126
 */
1127
GDALColorTableH CPL_STDCALL
1128
GDALRATTranslateToColorTable(GDALRasterAttributeTableH hRAT, int nEntryCount)
1129
1130
0
{
1131
0
    VALIDATE_POINTER1(hRAT, "GDALRATTranslateToColorTable", nullptr);
1132
1133
0
    return GDALRasterAttributeTable::FromHandle(hRAT)->TranslateToColorTable(
1134
0
        nEntryCount);
1135
0
}
1136
1137
/************************************************************************/
1138
/*                            DumpReadable()                            */
1139
/************************************************************************/
1140
1141
/**
1142
 * \brief Dump RAT in readable form.
1143
 *
1144
 * Currently the readable form is the XML encoding ... only barely
1145
 * readable.
1146
 *
1147
 * This method is the same as the C function GDALRATDumpReadable().
1148
 *
1149
 * @param fp file to dump to or NULL for stdout.
1150
 */
1151
1152
void GDALRasterAttributeTable::DumpReadable(FILE *fp)
1153
1154
0
{
1155
0
    CPLXMLNode *psTree = Serialize();
1156
0
    char *const pszXMLText = CPLSerializeXMLTree(psTree);
1157
1158
0
    CPLDestroyXMLNode(psTree);
1159
1160
0
    if (fp == nullptr)
1161
0
        fp = stdout;
1162
1163
0
    fprintf(fp, "%s\n", pszXMLText);
1164
1165
0
    CPLFree(pszXMLText);
1166
0
}
1167
1168
/************************************************************************/
1169
/*                        GDALRATDumpReadable()                         */
1170
/************************************************************************/
1171
1172
/**
1173
 * \brief Dump RAT in readable form.
1174
 *
1175
 * This function is the same as the C++ method
1176
 * GDALRasterAttributeTable::DumpReadable()
1177
 */
1178
void CPL_STDCALL GDALRATDumpReadable(GDALRasterAttributeTableH hRAT, FILE *fp)
1179
1180
0
{
1181
0
    VALIDATE_POINTER0(hRAT, "GDALRATDumpReadable");
1182
1183
0
    GDALRasterAttributeTable::FromHandle(hRAT)->DumpReadable(fp);
1184
0
}
1185
1186
/* \class GDALDefaultRasterAttributeTable
1187
 *
1188
 * An implementation of GDALRasterAttributeTable that keeps
1189
 * all data in memory. This is the same as the implementation
1190
 * of GDALRasterAttributeTable in GDAL <= 1.10.
1191
 */
1192
1193
/************************************************************************/
1194
/*                  GDALDefaultRasterAttributeTable()                   */
1195
/*                                                                      */
1196
/*      Simple initialization constructor.                              */
1197
/************************************************************************/
1198
1199
//! Construct empty table.
1200
1201
0
GDALDefaultRasterAttributeTable::GDALDefaultRasterAttributeTable() = default;
1202
1203
/************************************************************************/
1204
/*                   GDALCreateRasterAttributeTable()                   */
1205
/************************************************************************/
1206
1207
/**
1208
 * \brief Construct empty table.
1209
 *
1210
 * This function is the same as the C++ method
1211
 * GDALDefaultRasterAttributeTable::GDALDefaultRasterAttributeTable()
1212
 */
1213
GDALRasterAttributeTableH CPL_STDCALL GDALCreateRasterAttributeTable()
1214
1215
0
{
1216
0
    return new GDALDefaultRasterAttributeTable();
1217
0
}
1218
1219
/************************************************************************/
1220
/*                 ~GDALDefaultRasterAttributeTable()                   */
1221
/*                                                                      */
1222
/*      All magic done by magic by the container destructors.           */
1223
/************************************************************************/
1224
1225
0
GDALDefaultRasterAttributeTable::~GDALDefaultRasterAttributeTable() = default;
1226
1227
/************************************************************************/
1228
/*                  GDALDestroyRasterAttributeTable()                   */
1229
/************************************************************************/
1230
1231
/**
1232
 * \brief Destroys a RAT.
1233
 *
1234
 * This function is the same as the C++ method
1235
 * GDALRasterAttributeTable::~GDALRasterAttributeTable()
1236
 */
1237
void CPL_STDCALL GDALDestroyRasterAttributeTable(GDALRasterAttributeTableH hRAT)
1238
1239
0
{
1240
0
    if (hRAT != nullptr)
1241
0
        delete GDALRasterAttributeTable::FromHandle(hRAT);
1242
0
}
1243
1244
/************************************************************************/
1245
/*                           AnalyseColumns()                           */
1246
/*                                                                      */
1247
/*      Internal method to work out which column to use for various     */
1248
/*      tasks.                                                          */
1249
/************************************************************************/
1250
1251
void GDALDefaultRasterAttributeTable::AnalyseColumns()
1252
1253
0
{
1254
0
    bColumnsAnalysed = true;
1255
1256
0
    nMinCol = GetColOfUsage(GFU_Min);
1257
0
    if (nMinCol == -1)
1258
0
        nMinCol = GetColOfUsage(GFU_MinMax);
1259
1260
0
    nMaxCol = GetColOfUsage(GFU_Max);
1261
0
    if (nMaxCol == -1)
1262
0
        nMaxCol = GetColOfUsage(GFU_MinMax);
1263
0
}
1264
1265
/************************************************************************/
1266
/*                           GetColumnCount()                           */
1267
/************************************************************************/
1268
1269
int GDALDefaultRasterAttributeTable::GetColumnCount() const
1270
1271
0
{
1272
0
    return static_cast<int>(aoFields.size());
1273
0
}
1274
1275
/************************************************************************/
1276
/*                       GDALRATGetColumnCount()                        */
1277
/************************************************************************/
1278
1279
/**
1280
 * \brief Fetch table column count.
1281
 *
1282
 * This function is the same as the C++ method
1283
 * GDALRasterAttributeTable::GetColumnCount()
1284
 */
1285
int CPL_STDCALL GDALRATGetColumnCount(GDALRasterAttributeTableH hRAT)
1286
1287
0
{
1288
0
    VALIDATE_POINTER1(hRAT, "GDALRATGetColumnCount", 0);
1289
1290
0
    return GDALRasterAttributeTable::FromHandle(hRAT)->GetColumnCount();
1291
0
}
1292
1293
/************************************************************************/
1294
/*                            GetNameOfCol()                            */
1295
/************************************************************************/
1296
1297
/** \brief Fetch name of indicated column.
1298
 * @param iCol column index.
1299
 * @return name.
1300
 */
1301
const char *GDALDefaultRasterAttributeTable::GetNameOfCol(int iCol) const
1302
1303
0
{
1304
0
    if (iCol < 0 || iCol >= static_cast<int>(aoFields.size()))
1305
0
        return "";
1306
1307
0
    return aoFields[iCol].sName;
1308
0
}
1309
1310
/************************************************************************/
1311
/*                        GDALRATGetNameOfCol()                         */
1312
/************************************************************************/
1313
1314
/**
1315
 * \brief Fetch name of indicated column.
1316
 *
1317
 * This function is the same as the C++ method
1318
 * GDALRasterAttributeTable::GetNameOfCol()
1319
 * @param hRAT RAT handle.
1320
 * @param iCol column index.
1321
 * @return name.
1322
 */
1323
const char *CPL_STDCALL GDALRATGetNameOfCol(GDALRasterAttributeTableH hRAT,
1324
                                            int iCol)
1325
1326
0
{
1327
0
    VALIDATE_POINTER1(hRAT, "GDALRATGetNameOfCol", nullptr);
1328
1329
0
    return GDALRasterAttributeTable::FromHandle(hRAT)->GetNameOfCol(iCol);
1330
0
}
1331
1332
/************************************************************************/
1333
/*                           GetUsageOfCol()                            */
1334
/************************************************************************/
1335
1336
/**
1337
 * \brief Fetch column usage value.
1338
 *
1339
 * @param iCol column index.
1340
 * @return usage.
1341
 */
1342
GDALRATFieldUsage GDALDefaultRasterAttributeTable::GetUsageOfCol(int iCol) const
1343
1344
0
{
1345
0
    if (iCol < 0 || iCol >= static_cast<int>(aoFields.size()))
1346
0
        return GFU_Generic;
1347
1348
0
    return aoFields[iCol].eUsage;
1349
0
}
1350
1351
/************************************************************************/
1352
/*                        GDALRATGetUsageOfCol()                        */
1353
/************************************************************************/
1354
1355
/**
1356
 * \brief Fetch column usage value.
1357
 *
1358
 * This function is the same as the C++ method
1359
 * GDALRasterAttributeTable::GetUsageOfCol()
1360
 * @param hRAT RAT handle.
1361
 * @param iCol column index.
1362
 * @return usage.
1363
 */
1364
GDALRATFieldUsage CPL_STDCALL
1365
GDALRATGetUsageOfCol(GDALRasterAttributeTableH hRAT, int iCol)
1366
1367
0
{
1368
0
    VALIDATE_POINTER1(hRAT, "GDALRATGetUsageOfCol", GFU_Generic);
1369
1370
0
    return GDALRasterAttributeTable::FromHandle(hRAT)->GetUsageOfCol(iCol);
1371
0
}
1372
1373
/************************************************************************/
1374
/*                            GetTypeOfCol()                            */
1375
/************************************************************************/
1376
1377
/**
1378
 * \brief Fetch column type.
1379
 *
1380
 * @param iCol column index.
1381
 * @return type.
1382
 */
1383
GDALRATFieldType GDALDefaultRasterAttributeTable::GetTypeOfCol(int iCol) const
1384
1385
0
{
1386
0
    if (iCol < 0 || iCol >= static_cast<int>(aoFields.size()))
1387
0
        return GFT_Integer;
1388
1389
0
    return aoFields[iCol].eType;
1390
0
}
1391
1392
/************************************************************************/
1393
/*                        GDALRATGetTypeOfCol()                         */
1394
/************************************************************************/
1395
1396
/**
1397
 * \brief Fetch column type.
1398
 *
1399
 * This function is the same as the C++ method
1400
 * GDALRasterAttributeTable::GetTypeOfCol()
1401
 * @param hRAT RAT handle.
1402
 * @param iCol column index.
1403
 * @return type.
1404
 */
1405
GDALRATFieldType CPL_STDCALL GDALRATGetTypeOfCol(GDALRasterAttributeTableH hRAT,
1406
                                                 int iCol)
1407
1408
0
{
1409
0
    VALIDATE_POINTER1(hRAT, "GDALRATGetTypeOfCol", GFT_Integer);
1410
1411
0
    return GDALRasterAttributeTable::FromHandle(hRAT)->GetTypeOfCol(iCol);
1412
0
}
1413
1414
/************************************************************************/
1415
/*                           GetColOfUsage()                            */
1416
/************************************************************************/
1417
1418
/** Return the index of the column that corresponds to the passed usage.
1419
 * @param eUsage usage.
1420
 * @return column index, or -1 in case of error.
1421
 */
1422
int GDALDefaultRasterAttributeTable::GetColOfUsage(
1423
    GDALRATFieldUsage eUsage) const
1424
1425
0
{
1426
0
    for (unsigned int i = 0; i < aoFields.size(); i++)
1427
0
    {
1428
0
        if (aoFields[i].eUsage == eUsage)
1429
0
            return i;
1430
0
    }
1431
1432
0
    return -1;
1433
0
}
1434
1435
/************************************************************************/
1436
/*                        GDALRATGetColOfUsage()                        */
1437
/************************************************************************/
1438
1439
/**
1440
 * \brief Fetch column index for given usage.
1441
 *
1442
 * This function is the same as the C++ method
1443
 * GDALRasterAttributeTable::GetColOfUsage()
1444
 */
1445
int CPL_STDCALL GDALRATGetColOfUsage(GDALRasterAttributeTableH hRAT,
1446
                                     GDALRATFieldUsage eUsage)
1447
1448
0
{
1449
0
    VALIDATE_POINTER1(hRAT, "GDALRATGetColOfUsage", 0);
1450
1451
0
    return GDALRasterAttributeTable::FromHandle(hRAT)->GetColOfUsage(eUsage);
1452
0
}
1453
1454
/************************************************************************/
1455
/*                            GetRowCount()                             */
1456
/************************************************************************/
1457
1458
int GDALDefaultRasterAttributeTable::GetRowCount() const
1459
1460
0
{
1461
0
    return static_cast<int>(nRowCount);
1462
0
}
1463
1464
/************************************************************************/
1465
/*                        GDALRATGetUsageOfCol()                        */
1466
/************************************************************************/
1467
/**
1468
 * \brief Fetch row count.
1469
 *
1470
 * This function is the same as the C++ method
1471
 * GDALRasterAttributeTable::GetRowCount()
1472
 */
1473
int CPL_STDCALL GDALRATGetRowCount(GDALRasterAttributeTableH hRAT)
1474
1475
0
{
1476
0
    VALIDATE_POINTER1(hRAT, "GDALRATGetRowCount", 0);
1477
1478
0
    return GDALRasterAttributeTable::FromHandle(hRAT)->GetRowCount();
1479
0
}
1480
1481
/************************************************************************/
1482
/*                          GetValueAsString()                          */
1483
/************************************************************************/
1484
1485
const char *GDALDefaultRasterAttributeTable::GetValueAsString(int iRow,
1486
                                                              int iField) const
1487
1488
0
{
1489
0
    if (iField < 0 || iField >= static_cast<int>(aoFields.size()))
1490
0
    {
1491
0
        CPLError(CE_Failure, CPLE_AppDefined, "iField (%d) out of range.",
1492
0
                 iField);
1493
1494
0
        return "";
1495
0
    }
1496
1497
0
    if (iRow < 0 || iRow >= nRowCount)
1498
0
    {
1499
0
        CPLError(CE_Failure, CPLE_AppDefined, "iRow (%d) out of range.", iRow);
1500
1501
0
        return "";
1502
0
    }
1503
1504
0
    switch (aoFields[iField].eType)
1505
0
    {
1506
0
        case GFT_Integer:
1507
0
        {
1508
0
            const_cast<GDALDefaultRasterAttributeTable *>(this)
1509
0
                ->osWorkingResult.Printf("%d", aoFields[iField].anValues[iRow]);
1510
0
            return osWorkingResult;
1511
0
        }
1512
1513
0
        case GFT_Real:
1514
0
        {
1515
0
            const_cast<GDALDefaultRasterAttributeTable *>(this)
1516
0
                ->osWorkingResult.Printf("%.16g",
1517
0
                                         aoFields[iField].adfValues[iRow]);
1518
0
            return osWorkingResult;
1519
0
        }
1520
1521
0
        case GFT_String:
1522
0
        {
1523
0
            return aoFields[iField].aosValues[iRow];
1524
0
        }
1525
0
    }
1526
1527
0
    return "";
1528
0
}
1529
1530
/************************************************************************/
1531
/*                      GDALRATGetValueAsString()                       */
1532
/************************************************************************/
1533
/**
1534
 * \brief Fetch field value as a string.
1535
 *
1536
 * This function is the same as the C++ method
1537
 * GDALRasterAttributeTable::GetValueAsString()
1538
 */
1539
const char *CPL_STDCALL GDALRATGetValueAsString(GDALRasterAttributeTableH hRAT,
1540
                                                int iRow, int iField)
1541
1542
0
{
1543
0
    VALIDATE_POINTER1(hRAT, "GDALRATGetValueAsString", nullptr);
1544
1545
0
    return GDALRasterAttributeTable::FromHandle(hRAT)->GetValueAsString(iRow,
1546
0
                                                                        iField);
1547
0
}
1548
1549
/************************************************************************/
1550
/*                           GetValueAsInt()                            */
1551
/************************************************************************/
1552
1553
int GDALDefaultRasterAttributeTable::GetValueAsInt(int iRow, int iField) const
1554
1555
0
{
1556
0
    if (iField < 0 || iField >= static_cast<int>(aoFields.size()))
1557
0
    {
1558
0
        CPLError(CE_Failure, CPLE_AppDefined, "iField (%d) out of range.",
1559
0
                 iField);
1560
1561
0
        return 0;
1562
0
    }
1563
1564
0
    if (iRow < 0 || iRow >= nRowCount)
1565
0
    {
1566
0
        CPLError(CE_Failure, CPLE_AppDefined, "iRow (%d) out of range.", iRow);
1567
1568
0
        return 0;
1569
0
    }
1570
1571
0
    switch (aoFields[iField].eType)
1572
0
    {
1573
0
        case GFT_Integer:
1574
0
            return aoFields[iField].anValues[iRow];
1575
1576
0
        case GFT_Real:
1577
0
            return static_cast<int>(aoFields[iField].adfValues[iRow]);
1578
1579
0
        case GFT_String:
1580
0
            return atoi(aoFields[iField].aosValues[iRow].c_str());
1581
0
    }
1582
1583
0
    return 0;
1584
0
}
1585
1586
/************************************************************************/
1587
/*                        GDALRATGetValueAsInt()                        */
1588
/************************************************************************/
1589
1590
/**
1591
 * \brief Fetch field value as a integer.
1592
 *
1593
 * This function is the same as the C++ method
1594
 * GDALRasterAttributeTable::GetValueAsInt()
1595
 */
1596
int CPL_STDCALL GDALRATGetValueAsInt(GDALRasterAttributeTableH hRAT, int iRow,
1597
                                     int iField)
1598
1599
0
{
1600
0
    VALIDATE_POINTER1(hRAT, "GDALRATGetValueAsInt", 0);
1601
1602
0
    return GDALRasterAttributeTable::FromHandle(hRAT)->GetValueAsInt(iRow,
1603
0
                                                                     iField);
1604
0
}
1605
1606
/************************************************************************/
1607
/*                          GetValueAsDouble()                          */
1608
/************************************************************************/
1609
1610
double GDALDefaultRasterAttributeTable::GetValueAsDouble(int iRow,
1611
                                                         int iField) const
1612
1613
0
{
1614
0
    if (iField < 0 || iField >= static_cast<int>(aoFields.size()))
1615
0
    {
1616
0
        CPLError(CE_Failure, CPLE_AppDefined, "iField (%d) out of range.",
1617
0
                 iField);
1618
1619
0
        return 0;
1620
0
    }
1621
1622
0
    if (iRow < 0 || iRow >= nRowCount)
1623
0
    {
1624
0
        CPLError(CE_Failure, CPLE_AppDefined, "iRow (%d) out of range.", iRow);
1625
1626
0
        return 0;
1627
0
    }
1628
1629
0
    switch (aoFields[iField].eType)
1630
0
    {
1631
0
        case GFT_Integer:
1632
0
            return aoFields[iField].anValues[iRow];
1633
1634
0
        case GFT_Real:
1635
0
            return aoFields[iField].adfValues[iRow];
1636
1637
0
        case GFT_String:
1638
0
            return CPLAtof(aoFields[iField].aosValues[iRow].c_str());
1639
0
    }
1640
1641
0
    return 0;
1642
0
}
1643
1644
/************************************************************************/
1645
/*                      GDALRATGetValueAsDouble()                       */
1646
/************************************************************************/
1647
1648
/**
1649
 * \brief Fetch field value as a double.
1650
 *
1651
 * This function is the same as the C++ method
1652
 * GDALRasterAttributeTable::GetValueAsDouble()
1653
 */
1654
double CPL_STDCALL GDALRATGetValueAsDouble(GDALRasterAttributeTableH hRAT,
1655
                                           int iRow, int iField)
1656
1657
0
{
1658
0
    VALIDATE_POINTER1(hRAT, "GDALRATGetValueAsDouble", 0);
1659
1660
0
    return GDALRasterAttributeTable::FromHandle(hRAT)->GetValueAsDouble(iRow,
1661
0
                                                                        iField);
1662
0
}
1663
1664
/************************************************************************/
1665
/*                            SetRowCount()                             */
1666
/************************************************************************/
1667
1668
/** Set row count.
1669
 * @param nNewCount new count.
1670
 */
1671
void GDALDefaultRasterAttributeTable::SetRowCount(int nNewCount)
1672
1673
0
{
1674
0
    if (nNewCount == nRowCount)
1675
0
        return;
1676
1677
0
    for (auto &oField : aoFields)
1678
0
    {
1679
0
        switch (oField.eType)
1680
0
        {
1681
0
            case GFT_Integer:
1682
0
                oField.anValues.resize(nNewCount);
1683
0
                break;
1684
1685
0
            case GFT_Real:
1686
0
                oField.adfValues.resize(nNewCount);
1687
0
                break;
1688
1689
0
            case GFT_String:
1690
0
                oField.aosValues.resize(nNewCount);
1691
0
                break;
1692
0
        }
1693
0
    }
1694
1695
0
    nRowCount = nNewCount;
1696
0
}
1697
1698
/************************************************************************/
1699
/*                              SetValue()                              */
1700
/************************************************************************/
1701
1702
/** Set value
1703
 * @param iRow row index.
1704
 * @param iField field index.
1705
 * @param pszValue value.
1706
 */
1707
CPLErr GDALDefaultRasterAttributeTable::SetValue(int iRow, int iField,
1708
                                                 const char *pszValue)
1709
1710
0
{
1711
0
    if (iField < 0 || iField >= static_cast<int>(aoFields.size()))
1712
0
    {
1713
0
        CPLError(CE_Failure, CPLE_AppDefined, "iField (%d) out of range.",
1714
0
                 iField);
1715
1716
0
        return CE_Failure;
1717
0
    }
1718
1719
0
    if (iRow == nRowCount)
1720
0
        SetRowCount(nRowCount + 1);
1721
1722
0
    if (iRow < 0 || iRow >= nRowCount)
1723
0
    {
1724
0
        CPLError(CE_Failure, CPLE_AppDefined, "iRow (%d) out of range.", iRow);
1725
1726
0
        return CE_Failure;
1727
0
    }
1728
1729
0
    switch (aoFields[iField].eType)
1730
0
    {
1731
0
        case GFT_Integer:
1732
0
            aoFields[iField].anValues[iRow] = atoi(pszValue);
1733
0
            break;
1734
1735
0
        case GFT_Real:
1736
0
            aoFields[iField].adfValues[iRow] = CPLAtof(pszValue);
1737
0
            break;
1738
1739
0
        case GFT_String:
1740
0
            aoFields[iField].aosValues[iRow] = pszValue;
1741
0
            break;
1742
0
    }
1743
1744
0
    return CE_None;
1745
0
}
1746
1747
/************************************************************************/
1748
/*                      GDALRATSetValueAsString()                       */
1749
/************************************************************************/
1750
1751
/**
1752
 * \brief Set field value from string.
1753
 *
1754
 * This function is the same as the C++ method
1755
 * GDALRasterAttributeTable::SetValue()
1756
 * @param hRAT RAT handle.
1757
 * @param iRow row index.
1758
 * @param iField field index.
1759
 * @param pszValue value.
1760
 */
1761
void CPL_STDCALL GDALRATSetValueAsString(GDALRasterAttributeTableH hRAT,
1762
                                         int iRow, int iField,
1763
                                         const char *pszValue)
1764
1765
0
{
1766
0
    VALIDATE_POINTER0(hRAT, "GDALRATSetValueAsString");
1767
1768
0
    GDALRasterAttributeTable::FromHandle(hRAT)->SetValue(iRow, iField,
1769
0
                                                         pszValue);
1770
0
}
1771
1772
/************************************************************************/
1773
/*                              SetValue()                              */
1774
/************************************************************************/
1775
1776
CPLErr GDALDefaultRasterAttributeTable::SetValue(int iRow, int iField,
1777
                                                 int nValue)
1778
1779
0
{
1780
0
    if (iField < 0 || iField >= static_cast<int>(aoFields.size()))
1781
0
    {
1782
0
        CPLError(CE_Failure, CPLE_AppDefined, "iField (%d) out of range.",
1783
0
                 iField);
1784
1785
0
        return CE_Failure;
1786
0
    }
1787
1788
0
    if (iRow == nRowCount)
1789
0
        SetRowCount(nRowCount + 1);
1790
1791
0
    if (iRow < 0 || iRow >= nRowCount)
1792
0
    {
1793
0
        CPLError(CE_Failure, CPLE_AppDefined, "iRow (%d) out of range.", iRow);
1794
1795
0
        return CE_Failure;
1796
0
    }
1797
1798
0
    switch (aoFields[iField].eType)
1799
0
    {
1800
0
        case GFT_Integer:
1801
0
            aoFields[iField].anValues[iRow] = nValue;
1802
0
            break;
1803
1804
0
        case GFT_Real:
1805
0
            aoFields[iField].adfValues[iRow] = nValue;
1806
0
            break;
1807
1808
0
        case GFT_String:
1809
0
        {
1810
0
            char szValue[100];
1811
1812
0
            snprintf(szValue, sizeof(szValue), "%d", nValue);
1813
0
            aoFields[iField].aosValues[iRow] = szValue;
1814
0
        }
1815
0
        break;
1816
0
    }
1817
1818
0
    return CE_None;
1819
0
}
1820
1821
/************************************************************************/
1822
/*                        GDALRATSetValueAsInt()                        */
1823
/************************************************************************/
1824
1825
/**
1826
 * \brief Set field value from integer.
1827
 *
1828
 * This function is the same as the C++ method
1829
 * GDALRasterAttributeTable::SetValue()
1830
 */
1831
void CPL_STDCALL GDALRATSetValueAsInt(GDALRasterAttributeTableH hRAT, int iRow,
1832
                                      int iField, int nValue)
1833
1834
0
{
1835
0
    VALIDATE_POINTER0(hRAT, "GDALRATSetValueAsInt");
1836
1837
0
    GDALRasterAttributeTable::FromHandle(hRAT)->SetValue(iRow, iField, nValue);
1838
0
}
1839
1840
/************************************************************************/
1841
/*                              SetValue()                              */
1842
/************************************************************************/
1843
1844
CPLErr GDALDefaultRasterAttributeTable::SetValue(int iRow, int iField,
1845
                                                 double dfValue)
1846
1847
0
{
1848
0
    if (iField < 0 || iField >= static_cast<int>(aoFields.size()))
1849
0
    {
1850
0
        CPLError(CE_Failure, CPLE_AppDefined, "iField (%d) out of range.",
1851
0
                 iField);
1852
1853
0
        return CE_Failure;
1854
0
    }
1855
1856
0
    if (iRow == nRowCount)
1857
0
        SetRowCount(nRowCount + 1);
1858
1859
0
    if (iRow < 0 || iRow >= nRowCount)
1860
0
    {
1861
0
        CPLError(CE_Failure, CPLE_AppDefined, "iRow (%d) out of range.", iRow);
1862
1863
0
        return CE_Failure;
1864
0
    }
1865
1866
0
    switch (aoFields[iField].eType)
1867
0
    {
1868
0
        case GFT_Integer:
1869
0
            aoFields[iField].anValues[iRow] = static_cast<int>(dfValue);
1870
0
            break;
1871
1872
0
        case GFT_Real:
1873
0
            aoFields[iField].adfValues[iRow] = dfValue;
1874
0
            break;
1875
1876
0
        case GFT_String:
1877
0
        {
1878
0
            char szValue[100] = {'\0'};
1879
1880
0
            CPLsnprintf(szValue, sizeof(szValue), "%.15g", dfValue);
1881
0
            aoFields[iField].aosValues[iRow] = szValue;
1882
0
        }
1883
0
        break;
1884
0
    }
1885
1886
0
    return CE_None;
1887
0
}
1888
1889
/************************************************************************/
1890
/*                      GDALRATSetValueAsDouble()                       */
1891
/************************************************************************/
1892
1893
/**
1894
 * \brief Set field value from double.
1895
 *
1896
 * This function is the same as the C++ method
1897
 * GDALRasterAttributeTable::SetValue()
1898
 */
1899
void CPL_STDCALL GDALRATSetValueAsDouble(GDALRasterAttributeTableH hRAT,
1900
                                         int iRow, int iField, double dfValue)
1901
1902
0
{
1903
0
    VALIDATE_POINTER0(hRAT, "GDALRATSetValueAsDouble");
1904
1905
0
    GDALRasterAttributeTable::FromHandle(hRAT)->SetValue(iRow, iField, dfValue);
1906
0
}
1907
1908
/************************************************************************/
1909
/*                       ChangesAreWrittenToFile()                      */
1910
/************************************************************************/
1911
1912
int GDALDefaultRasterAttributeTable::ChangesAreWrittenToFile()
1913
0
{
1914
    // GDALRasterBand.SetDefaultRAT needs to be called on instances of
1915
    // GDALDefaultRasterAttributeTable since changes are just in-memory
1916
0
    return false;
1917
0
}
1918
1919
/************************************************************************/
1920
/*                   GDALRATChangesAreWrittenToFile()                   */
1921
/************************************************************************/
1922
1923
/**
1924
 * \brief Determine whether changes made to this RAT are reflected directly in
1925
 * the dataset
1926
 *
1927
 * This function is the same as the C++ method
1928
 * GDALRasterAttributeTable::ChangesAreWrittenToFile()
1929
 */
1930
int CPL_STDCALL GDALRATChangesAreWrittenToFile(GDALRasterAttributeTableH hRAT)
1931
0
{
1932
0
    VALIDATE_POINTER1(hRAT, "GDALRATChangesAreWrittenToFile", false);
1933
1934
0
    return GDALRasterAttributeTable::FromHandle(hRAT)
1935
0
        ->ChangesAreWrittenToFile();
1936
0
}
1937
1938
/************************************************************************/
1939
/*                           GetRowOfValue()                            */
1940
/************************************************************************/
1941
1942
int GDALDefaultRasterAttributeTable::GetRowOfValue(double dfValue) const
1943
1944
0
{
1945
    /* -------------------------------------------------------------------- */
1946
    /*      Handle case of regular binning.                                 */
1947
    /* -------------------------------------------------------------------- */
1948
0
    if (bLinearBinning)
1949
0
    {
1950
0
        const int iBin =
1951
0
            static_cast<int>(floor((dfValue - dfRow0Min) / dfBinSize));
1952
0
        if (iBin < 0 || iBin >= nRowCount)
1953
0
            return -1;
1954
1955
0
        return iBin;
1956
0
    }
1957
1958
    /* -------------------------------------------------------------------- */
1959
    /*      Do we have any information?                                     */
1960
    /* -------------------------------------------------------------------- */
1961
0
    if (!bColumnsAnalysed)
1962
0
        const_cast<GDALDefaultRasterAttributeTable *>(this)->AnalyseColumns();
1963
1964
0
    if (nMinCol == -1 && nMaxCol == -1)
1965
0
        return -1;
1966
1967
0
    const GDALRasterAttributeField *poMin = nullptr;
1968
0
    if (nMinCol != -1)
1969
0
        poMin = &(aoFields[nMinCol]);
1970
0
    else
1971
0
        poMin = nullptr;
1972
1973
0
    const GDALRasterAttributeField *poMax = nullptr;
1974
0
    if (nMaxCol != -1)
1975
0
        poMax = &(aoFields[nMaxCol]);
1976
0
    else
1977
0
        poMax = nullptr;
1978
1979
    /* -------------------------------------------------------------------- */
1980
    /*      Search through rows for match.                                  */
1981
    /* -------------------------------------------------------------------- */
1982
0
    for (int iRow = 0; iRow < nRowCount; iRow++)
1983
0
    {
1984
0
        if (poMin != nullptr)
1985
0
        {
1986
0
            if (poMin->eType == GFT_Integer)
1987
0
            {
1988
0
                while (iRow < nRowCount && dfValue < poMin->anValues[iRow])
1989
0
                    iRow++;
1990
0
            }
1991
0
            else if (poMin->eType == GFT_Real)
1992
0
            {
1993
0
                while (iRow < nRowCount && dfValue < poMin->adfValues[iRow])
1994
0
                    iRow++;
1995
0
            }
1996
1997
0
            if (iRow == nRowCount)
1998
0
                break;
1999
0
        }
2000
2001
0
        if (poMax != nullptr)
2002
0
        {
2003
0
            if ((poMax->eType == GFT_Integer &&
2004
0
                 dfValue > poMax->anValues[iRow]) ||
2005
0
                (poMax->eType == GFT_Real && dfValue > poMax->adfValues[iRow]))
2006
0
                continue;
2007
0
        }
2008
2009
0
        return iRow;
2010
0
    }
2011
2012
0
    return -1;
2013
0
}
2014
2015
/************************************************************************/
2016
/*                           GetRowOfValue()                            */
2017
/*                                                                      */
2018
/*      Int arg for now just converted to double.  Perhaps we will      */
2019
/*      handle this in a special way some day?                          */
2020
/************************************************************************/
2021
2022
int GDALDefaultRasterAttributeTable::GetRowOfValue(int nValue) const
2023
2024
0
{
2025
0
    return GetRowOfValue(static_cast<double>(nValue));
2026
0
}
2027
2028
/************************************************************************/
2029
/*                          SetLinearBinning()                          */
2030
/************************************************************************/
2031
2032
CPLErr GDALDefaultRasterAttributeTable::SetLinearBinning(double dfRow0MinIn,
2033
                                                         double dfBinSizeIn)
2034
2035
0
{
2036
0
    bLinearBinning = true;
2037
0
    dfRow0Min = dfRow0MinIn;
2038
0
    dfBinSize = dfBinSizeIn;
2039
2040
0
    return CE_None;
2041
0
}
2042
2043
/************************************************************************/
2044
/*                          GetLinearBinning()                          */
2045
/************************************************************************/
2046
2047
int GDALDefaultRasterAttributeTable::GetLinearBinning(double *pdfRow0Min,
2048
                                                      double *pdfBinSize) const
2049
2050
0
{
2051
0
    if (!bLinearBinning)
2052
0
        return false;
2053
2054
0
    *pdfRow0Min = dfRow0Min;
2055
0
    *pdfBinSize = dfBinSize;
2056
2057
0
    return true;
2058
0
}
2059
2060
/************************************************************************/
2061
/*                          GetTableType()                              */
2062
/************************************************************************/
2063
2064
/**
2065
 * \brief Get RAT Table Type
2066
 *
2067
 * Returns whether table type is thematic or athematic
2068
 *
2069
 * This method is the same as the C function GDALRATGetTableType().
2070
 *
2071
 * @since GDAL 2.4
2072
 *
2073
 * @return GRTT_THEMATIC or GRTT_ATHEMATIC
2074
 */
2075
2076
GDALRATTableType GDALDefaultRasterAttributeTable::GetTableType() const
2077
0
{
2078
0
    return eTableType;
2079
0
}
2080
2081
/************************************************************************/
2082
/*                          SetTableType()                              */
2083
/************************************************************************/
2084
2085
/**
2086
 * \brief Set RAT Table Type
2087
 *
2088
 * Set whether table type is thematic or athematic
2089
 *
2090
 * This method is the same as the C function GDALRATSetTableType().
2091
 *
2092
 * @param eInTableType the new RAT table type (GRTT_THEMATIC or GRTT_ATHEMATIC)
2093
 *
2094
 * @since GDAL 2.4
2095
 *
2096
 * @return CE_None on success or CE_Failure on failure.
2097
 */
2098
2099
CPLErr GDALDefaultRasterAttributeTable::SetTableType(
2100
    const GDALRATTableType eInTableType)
2101
0
{
2102
0
    eTableType = eInTableType;
2103
0
    return CE_None;
2104
0
}
2105
2106
/************************************************************************/
2107
/*                            CreateColumn()                            */
2108
/************************************************************************/
2109
2110
CPLErr
2111
GDALDefaultRasterAttributeTable::CreateColumn(const char *pszFieldName,
2112
                                              GDALRATFieldType eFieldType,
2113
                                              GDALRATFieldUsage eFieldUsage)
2114
2115
0
{
2116
0
    const size_t iNewField = aoFields.size();
2117
2118
0
    aoFields.resize(iNewField + 1);
2119
2120
0
    aoFields[iNewField].sName = pszFieldName;
2121
2122
    // color columns should be int 0..255
2123
0
    if ((eFieldUsage == GFU_Red) || (eFieldUsage == GFU_Green) ||
2124
0
        (eFieldUsage == GFU_Blue) || (eFieldUsage == GFU_Alpha))
2125
0
    {
2126
0
        eFieldType = GFT_Integer;
2127
0
    }
2128
0
    aoFields[iNewField].eType = eFieldType;
2129
0
    aoFields[iNewField].eUsage = eFieldUsage;
2130
2131
0
    if (eFieldType == GFT_Integer)
2132
0
        aoFields[iNewField].anValues.resize(nRowCount);
2133
0
    else if (eFieldType == GFT_Real)
2134
0
        aoFields[iNewField].adfValues.resize(nRowCount);
2135
0
    else if (eFieldType == GFT_String)
2136
0
        aoFields[iNewField].aosValues.resize(nRowCount);
2137
2138
0
    return CE_None;
2139
0
}
2140
2141
/************************************************************************/
2142
/*                            RemoveStatistics()                        */
2143
/************************************************************************/
2144
2145
/**
2146
 * \brief Remove Statistics from RAT
2147
 *
2148
 * Remove statistics (such as histogram) from the RAT. This is important
2149
 * if these have been invalidated, for example by cropping the image.
2150
 *
2151
 * This method is the same as the C function GDALRATRemoveStatistics().
2152
 *
2153
 * @since GDAL 2.4
2154
 */
2155
2156
void GDALDefaultRasterAttributeTable::RemoveStatistics()
2157
2158
0
{
2159
    // since we are storing the fields in a vector it will generally
2160
    // be faster to create a new vector and replace the old one
2161
    // rather than actually erasing columns.
2162
0
    std::vector<GDALRasterAttributeField> aoNewFields;
2163
0
    for (const auto &field : aoFields)
2164
0
    {
2165
0
        switch (field.eUsage)
2166
0
        {
2167
0
            case GFU_PixelCount:
2168
0
            case GFU_Min:
2169
0
            case GFU_Max:
2170
0
            case GFU_RedMin:
2171
0
            case GFU_GreenMin:
2172
0
            case GFU_BlueMin:
2173
0
            case GFU_AlphaMin:
2174
0
            case GFU_RedMax:
2175
0
            case GFU_GreenMax:
2176
0
            case GFU_BlueMax:
2177
0
            case GFU_AlphaMax:
2178
0
            {
2179
0
                break;
2180
0
            }
2181
2182
0
            default:
2183
0
                if (field.sName != "Histogram")
2184
0
                {
2185
0
                    aoNewFields.push_back(field);
2186
0
                }
2187
0
        }
2188
0
    }
2189
0
    aoFields = std::move(aoNewFields);
2190
0
}
2191
2192
/************************************************************************/
2193
/*                               Clone()                                */
2194
/************************************************************************/
2195
2196
GDALDefaultRasterAttributeTable *GDALDefaultRasterAttributeTable::Clone() const
2197
2198
0
{
2199
0
    return new GDALDefaultRasterAttributeTable(*this);
2200
0
}
2201
2202
/************************************************************************/
2203
/*                            GDALRATClone()                            */
2204
/************************************************************************/
2205
2206
/**
2207
 * \brief Copy Raster Attribute Table
2208
 *
2209
 * This function is the same as the C++ method GDALRasterAttributeTable::Clone()
2210
 */
2211
GDALRasterAttributeTableH CPL_STDCALL
2212
GDALRATClone(const GDALRasterAttributeTableH hRAT)
2213
2214
0
{
2215
0
    VALIDATE_POINTER1(hRAT, "GDALRATClone", nullptr);
2216
2217
0
    return GDALRasterAttributeTable::FromHandle(hRAT)->Clone();
2218
0
}
2219
2220
/************************************************************************/
2221
/*                            GDALRATSerializeJSON()                    */
2222
/************************************************************************/
2223
2224
/**
2225
 * \brief Serialize Raster Attribute Table in Json format
2226
 *
2227
 * This function is the same as the C++ method
2228
 * GDALRasterAttributeTable::SerializeJSON()
2229
 */
2230
void *CPL_STDCALL GDALRATSerializeJSON(GDALRasterAttributeTableH hRAT)
2231
2232
0
{
2233
0
    VALIDATE_POINTER1(hRAT, "GDALRATSerializeJSON", nullptr);
2234
2235
0
    return GDALRasterAttributeTable::FromHandle(hRAT)->SerializeJSON();
2236
0
}
2237
2238
/************************************************************************/
2239
/*                        GDALRATRemoveStatistics()                     */
2240
/************************************************************************/
2241
2242
/**
2243
 * \brief Remove Statistics from RAT
2244
 *
2245
 * This function is the same as the C++ method
2246
 * GDALRasterAttributeTable::RemoveStatistics()
2247
 *
2248
 * @since GDAL 2.4
2249
 */
2250
void CPL_STDCALL GDALRATRemoveStatistics(GDALRasterAttributeTableH hRAT)
2251
2252
0
{
2253
0
    VALIDATE_POINTER0(hRAT, "GDALRATRemoveStatistics");
2254
2255
0
    GDALRasterAttributeTable::FromHandle(hRAT)->RemoveStatistics();
2256
0
}