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