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