Coverage Report

Created: 2025-06-13 06:29

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