root/tags/gdal_1_3_2/gcore/gdal_rat.cpp

Revision 9157, 44.1 kB (checked in by fwarmerdam, 3 years ago)

Avoid large amounts of linked list walking adding rows when
serializing RAT.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1 /******************************************************************************
2  * $Id$
3  *
4  * Project:  GDAL Core
5  * Purpose:  Implementation of GDALRasterAttributeTable and related classes.
6  * Author:   Frank Warmerdam, warmerdam@pobox.com
7  *
8  ******************************************************************************
9  * Copyright (c) 2005, Frank Warmerdam
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  * $Log$
31  * Revision 1.7  2006/02/13 17:22:54  fwarmerdam
32  * Avoid large amounts of linked list walking adding rows when
33  * serializing RAT.
34  *
35  * Revision 1.6  2005/11/01 22:16:36  fwarmerdam
36  * fix comments (bug 985)
37  *
38  * Revision 1.5  2005/09/29 00:50:36  fwarmerdam
39  * Added doc note.
40  *
41  * Revision 1.4  2005/09/28 21:29:30  fwarmerdam
42  * added RAT documentation
43  *
44  * Revision 1.3  2005/09/27 22:12:44  fwarmerdam
45  * fixed bug creating string columns
46  *
47  * Revision 1.2  2005/09/27 14:05:47  fwarmerdam
48  * fixed various C wrappers returning void
49  *
50  * Revision 1.1  2005/09/24 19:00:53  fwarmerdam
51  * New
52  *
53  */
54
55 #include "gdal_priv.h"
56 #include "gdal_rat.h"
57
58 CPL_CVSID("$Id$");
59
60 /**
61  * \class GDALRasterAttributeTable
62  *
63  * The GDALRasterAttributeTable (or RAT) class is used to encapsulate a table
64  * used to provide attribute information about pixel values.  Each row
65  * in the table applies to a range of pixel values (or a single value in
66  * some cases), and might have attributes such as the histogram count for
67  * that range, the color pixels of that range should be drawn names of classes
68  * or any other generic information.
69  *
70  * Raster attribute tables can be used to represent histograms, color tables,
71  * and classification information. 
72  *
73  * Each column in a raster attribute table has a name, a type (integer,
74  * floating point or string), and a GDALRATFieldUsage.  The usage distinguishes
75  * columns with particular understood purposes (such as color, histogram
76  * count, name) and columns that have specific purposes not understood by
77  * the library (long label, suitability_for_growing_wheat, etc). 
78  *
79  * In the general case each row as a column indicating the minimum pixel
80  * values falling into that category, and a column indicating the maximum
81  * pixel value.  These are indicated with usage values of GFU_Min, and
82  * GFU_Max.  In other cases where each row is a discrete pixel value, one
83  * column of usage GFU_MinMax can be used. 
84  *
85  * In other cases all the categories are of equal size and regularly spaced
86  * and the categorization information can be determine just by knowing the
87  * value at which the categories start, and the size of a category.  This
88  * is called "Linear Binning" and the information is kept specially on
89  * the raster attribute table as a whole.
90  *
91  * RATs are normally associated with GDALRasterBands and be be queried
92  * using the GDALRasterBand::GetDefaultRAT() method. 
93  */
94
95 /************************************************************************/
96 /*                      GDALRasterAttributeTable()                      */
97 /*                                                                      */
98 /*      Simple initialization constructor.                              */
99 /************************************************************************/
100
101 //! Construct empty table.
102
103 GDALRasterAttributeTable::GDALRasterAttributeTable()
104
105 {
106     nMinCol = -1;
107     nMaxCol = -1;
108     bLinearBinning = FALSE;
109     dfRow0Min = -0.5;
110     dfBinSize = 1.0;
111     nRowCount = 0;
112 }
113
114 /************************************************************************/
115 /*                   GDALCreateRasterAttributeTable()                   */
116 /************************************************************************/
117
118 GDALRasterAttributeTableH CPL_STDCALL GDALCreateRasterAttributeTable()
119
120 {
121     return (GDALRasterAttributeTableH) (new GDALRasterAttributeTable());
122 }
123
124 /************************************************************************/
125 /*                      GDALRasterAttributeTable()                      */
126 /************************************************************************/
127
128 //! Copy constructor.
129
130 GDALRasterAttributeTable::GDALRasterAttributeTable(
131     const GDALRasterAttributeTable &oOther )
132
133 {
134     // We have tried to be careful to allow wholesale assignment
135     *this = oOther;
136 }
137
138 /************************************************************************/
139 /*                     ~GDALRasterAttributeTable()                      */
140 /*                                                                      */
141 /*      All magic done by magic by the container destructors.           */
142 /************************************************************************/
143
144 GDALRasterAttributeTable::~GDALRasterAttributeTable()
145
146 {
147 }
148
149 /************************************************************************/
150 /*                  GDALDestroyRasterAttributeTable()                   */
151 /************************************************************************/
152
153 void CPL_STDCALL
154 GDALDestroyRasterAttributeTable( GDALRasterAttributeTableH hRAT )
155
156 {
157     if( hRAT != NULL )
158         delete (GDALRasterAttributeTable *) hRAT;
159 }
160
161 /************************************************************************/
162 /*                           GetColumnCount()                           */
163 /************************************************************************/
164
165 /**
166  * \brief Fetch table column count.
167  *
168  * This method is the same as the C function GDALRATGetColumnCount().
169  *
170  * @return the number of columns.
171  */
172
173 int GDALRasterAttributeTable::GetColumnCount() const
174
175 {
176     return aoFields.size();
177 }
178
179 /************************************************************************/
180 /*                       GDALRATGetColumnCount()                        */
181 /************************************************************************/
182
183 int CPL_STDCALL GDALRATGetColumnCount( GDALRasterAttributeTableH hRAT )
184
185 {
186     return ((GDALRasterAttributeTable *) hRAT)->GetColumnCount();
187 }
188
189 /************************************************************************/
190 /*                            GetNameOfCol()                            */
191 /************************************************************************/
192
193 /**
194  * \brief Fetch name of indicated column.
195  *
196  * This method is the same as the C function GDALRATGetNameOfCol(), except
197  * that the C function returns "const char *".
198  *
199  * @param iCol the column index (zero based).
200  *
201  * @return the column name or an empty string for invalid column numbers.
202  */
203
204 CPLString GDALRasterAttributeTable::GetNameOfCol( int iCol ) const
205
206 {
207     if( iCol < 0 || iCol >= (int) aoFields.size() )
208         return "";
209
210     else
211         return aoFields[iCol].sName;
212 }
213
214 /************************************************************************/
215 /*                        GDALRATGetNameOfCol()                         */
216 /************************************************************************/
217
218 const char *CPL_STDCALL GDALRATGetNameOfCol( GDALRasterAttributeTableH hRAT,
219                                              int iCol )
220
221 {
222     // we don't just wrap the normal operator because we don't want to
223     // return a temporary string, we want to return a pointer to the
224     // internal column name.
225
226     GDALRasterAttributeTable *poRAT = (GDALRasterAttributeTable *) hRAT;
227
228     if( iCol < 0 || iCol >= (int) poRAT->aoFields.size() )
229         return "";
230
231     else
232         return poRAT->aoFields[iCol].sName.c_str();
233 }
234
235 /************************************************************************/
236 /*                           GetUsageOfCol()                            */
237 /************************************************************************/
238
239 /**
240  * \brief Fetch column usage value.
241  *
242  * This method is the same as the C function GDALRATGetUsageOfCol().
243  *
244  * @param iCol the column index (zero based).
245  *
246  * @return the column usage, or GFU_Generic for improper column numbers.
247  */
248
249 GDALRATFieldUsage GDALRasterAttributeTable::GetUsageOfCol( int iCol ) const
250
251 {
252     if( iCol < 0 || iCol >= (int) aoFields.size() )
253         return GFU_Generic;
254
255     else
256         return aoFields[iCol].eUsage;
257 }
258
259 /************************************************************************/
260 /*                        GDALRATGetUsageOfCol()                        */
261 /************************************************************************/
262
263 GDALRATFieldUsage CPL_STDCALL
264 GDALRATGetUsageOfCol( GDALRasterAttributeTableH hRAT, int iCol )
265
266 {
267     return ((GDALRasterAttributeTable *) hRAT)->GetUsageOfCol( iCol );
268 }
269
270 /************************************************************************/
271 /*                            GetTypeOfCol()                            */
272 /************************************************************************/
273
274 /**
275  * \brief Fetch color type.
276  *
277  * This method is the same as the C function GDALRATGetTypeOfCol().
278  *
279  * @param iCol the column index (zero based).
280  *
281  * @return color type or GFT_Integer if the column index is illegal.
282  */
283
284 GDALRATFieldType GDALRasterAttributeTable::GetTypeOfCol( int iCol ) const
285
286 {
287     if( iCol < 0 || iCol >= (int) aoFields.size() )
288         return GFT_Integer;
289
290     else
291         return aoFields[iCol].eType;
292 }
293
294 /************************************************************************/
295 /*                        GDALRATGetTypeOfCol()                         */
296 /************************************************************************/
297
298 GDALRATFieldType CPL_STDCALL
299 GDALRATGetTypeOfCol( GDALRasterAttributeTableH hRAT, int iCol )
300
301 {
302     return ((GDALRasterAttributeTable *) hRAT)->GetTypeOfCol( iCol );
303 }
304
305 /************************************************************************/
306 /*                           GetColOfUsage()                            */
307 /************************************************************************/
308
309 /**
310  * \brief Fetch column index for given usage.
311  *
312  * Returns the index of the first column of the requested usage type, or -1
313  * if no match is found.
314  *
315  * This method is the same as the C function GDALRATGetUsageOfCol().
316  *
317  * @param eUsage usage type to search for.
318  *
319  * @return column index, or -1 on failure.
320  */
321
322 int GDALRasterAttributeTable::GetColOfUsage( GDALRATFieldUsage eUsage ) const
323
324 {
325     unsigned int i;
326
327     for( i = 0; i < aoFields.size(); i++ )
328     {
329         if( aoFields[i].eUsage == eUsage )
330             return i;
331     }
332
333     return -1;
334 }
335
336 /************************************************************************/
337 /*                        GDALRATGetColOfUsage()                        */
338 /************************************************************************/
339
340 int CPL_STDCALL
341 GDALRATGetColOfUsage( GDALRasterAttributeTableH hRAT,
342                       GDALRATFieldUsage eUsage )
343
344 {
345     return ((GDALRasterAttributeTable *) hRAT)->GetColOfUsage( eUsage );
346 }
347
348 /************************************************************************/
349 /*                            GetRowCount()                             */
350 /************************************************************************/
351
352 /**
353  * \brief Fetch row count.
354  *
355  * This method is the same as the C function GDALRATGetRowCount().
356  *
357  * @return the number of rows.
358  */
359
360 int GDALRasterAttributeTable::GetRowCount() const
361
362 {
363     return (int) nRowCount;
364 }
365
366 /************************************************************************/
367 /*                        GDALRATGetUsageOfCol()                        */
368 /************************************************************************/
369
370 int CPL_STDCALL
371 GDALRATGetRowCount( GDALRasterAttributeTableH hRAT )
372
373 {
374     return ((GDALRasterAttributeTable *) hRAT)->GetRowCount();
375 }
376
377 /************************************************************************/
378 /*                          GetValueAsString()                          */
379 /************************************************************************/
380
381 /**
382  * \brief Fetch field value as a string.
383  *
384  * The value of the requested column in the requested row is returned
385  * as a string.  If the field is numeric, it is formatted as a string
386  * using default rules, so some precision may be lost.
387  *
388  * This method is the same as the C function GDALRATGetValueAsString(),
389  * except it returns a "const char *" result.
390  *
391  * @param iRow row to fetch (zero based).
392  * @param iField column to fetch (zero based).
393  *
394  * @return field value
395  */
396
397 CPLString
398 GDALRasterAttributeTable::GetValueAsString( int iRow, int iField ) const
399
400 {
401     if( iField < 0 || iField >= (int) aoFields.size() )
402     {
403         CPLError( CE_Failure, CPLE_AppDefined,
404                   "iField (%d) out of range.", iField );
405
406         return "";
407     }
408
409     if( iRow < 0 || iRow >= nRowCount )
410     {
411         CPLError( CE_Failure, CPLE_AppDefined,
412                   "iRow (%d) out of range.", iRow );
413
414         return "";
415     }
416
417     switch( aoFields[iField].eType )
418     {
419       case GFT_Integer:
420       {
421           char szValue[100];
422           sprintf( szValue, "%d", aoFields[iField].anValues[iRow] );
423           return szValue;
424       }
425
426       case GFT_Real:
427       {
428           char szValue[100];
429           sprintf( szValue, "%.16g", aoFields[iField].adfValues[iRow] );
430           return szValue;
431       }
432
433       case GFT_String:
434       {
435           return aoFields[iField].aosValues[iRow];
436       }
437     }
438
439     return "";
440 }
441
442 /************************************************************************/
443 /*                      GDALRATGetValueAsString()                       */
444 /************************************************************************/
445
446 const char * CPL_STDCALL
447 GDALRATGetValueAsString( GDALRasterAttributeTableH hRAT, int iRow, int iField )
448
449 {
450     GDALRasterAttributeTable *poRAT = (GDALRasterAttributeTable *) hRAT;
451
452     poRAT->osWorkingResult = poRAT->GetValueAsString( iRow, iField );
453    
454     return poRAT->osWorkingResult.c_str();
455 }
456
457 /************************************************************************/
458 /*                           GetValueAsInt()                            */
459 /************************************************************************/
460
461 /**
462  * \brief Fetch field value as a integer.
463  *
464  * The value of the requested column in the requested row is returned
465  * as an integer.  Non-integer fields will be converted to integer with
466  * the possibility of data loss.
467  *
468  * This method is the same as the C function GDALRATGetValueAsInt().
469  *
470  * @param iRow row to fetch (zero based).
471  * @param iField column to fetch (zero based).
472  *
473  * @return field value
474  */
475
476 int 
477 GDALRasterAttributeTable::GetValueAsInt( int iRow, int iField ) const
478
479 {
480     if( iField < 0 || iField >= (int) aoFields.size() )
481     {
482         CPLError( CE_Failure, CPLE_AppDefined,
483                   "iField (%d) out of range.", iField );
484
485         return 0;
486     }
487
488     if( iRow < 0 || iRow >= nRowCount )
489     {
490         CPLError( CE_Failure, CPLE_AppDefined,
491                   "iRow (%d) out of range.", iRow );
492
493         return 0;
494     }
495
496     switch( aoFields[iField].eType )
497     {
498       case GFT_Integer:
499         return aoFields[iField].anValues[iRow];
500
501       case GFT_Real:
502         return (int)  aoFields[iField].adfValues[iRow];
503
504       case GFT_String:
505         return atoi( aoFields[iField].aosValues[iRow].c_str() );
506     }
507
508     return 0;
509 }
510
511 /************************************************************************/
512 /*                        GDALRATGetValueAsInt()                        */
513 /************************************************************************/
514
515 int CPL_STDCALL
516 GDALRATGetValueAsInt( GDALRasterAttributeTableH hRAT, int iRow, int iField )
517
518 {
519     return ((GDALRasterAttributeTable *) hRAT)->GetValueAsInt( iRow, iField );
520 }
521
522 /************************************************************************/
523 /*                          GetValueAsDouble()                          */
524 /************************************************************************/
525
526 /**
527  * \brief Fetch field value as a double.
528  *
529  * The value of the requested column in the requested row is returned
530  * as a double.   Non double fields will be converted to double with
531  * the possibility of data loss.
532  *
533  * This method is the same as the C function GDALRATGetValueAsDouble().
534  *
535  * @param iRow row to fetch (zero based).
536  * @param iField column to fetch (zero based).
537  *
538  * @return field value
539  */
540
541 double
542 GDALRasterAttributeTable::GetValueAsDouble( int iRow, int iField ) const
543
544 {
545     if( iField < 0 || iField >= (int) aoFields.size() )
546     {
547         CPLError( CE_Failure, CPLE_AppDefined,
548                   "iField (%d) out of range.", iField );
549
550         return 0;
551     }
552
553     if( iRow < 0 || iRow >= nRowCount )
554     {
555         CPLError( CE_Failure, CPLE_AppDefined,
556                   "iRow (%d) out of range.", iRow );
557
558         return 0;
559     }
560
561     switch( aoFields[iField].eType )
562     {
563       case GFT_Integer:
564         return aoFields[iField].anValues[iRow];
565
566       case GFT_Real:
567         return aoFields[iField].adfValues[iRow];
568
569       case GFT_String:
570         return atof( aoFields[iField].aosValues[iRow].c_str() );
571     }
572
573     return 0;
574 }
575
576 /************************************************************************/
577 /*                      GDALRATGetValueAsDouble()                       */
578 /************************************************************************/
579
580 double CPL_STDCALL
581 GDALRATGetValueAsDouble( GDALRasterAttributeTableH hRAT, int iRow, int iField )
582
583 {
584     return ((GDALRasterAttributeTable *) hRAT)->GetValueAsDouble(iRow,iField);
585 }
586
587 /************************************************************************/
588 /*                            SetRowCount()                             */
589 /************************************************************************/
590
591 /**
592  * \brief Set row count.
593  *
594  * Resizes the table to include the indicated number of rows.  Newly created
595  * rows will be initialized to their default values - "" for strings,
596  * and zero for numeric fields.
597  *
598  * This method is the same as the C function GDALRATSetRowCount().
599  *
600  * @param nNewCount the new number of rows.
601  */
602
603 void GDALRasterAttributeTable::SetRowCount( int nNewCount )
604
605 {
606     if( nNewCount == nRowCount )
607         return;
608
609     unsigned int iField;
610     for( iField = 0; iField < aoFields.size(); iField++ )
611     {
612         switch( aoFields[iField].eType )
613         {
614           case GFT_Integer:
615             aoFields[iField].anValues.resize( nNewCount );
616             break;
617
618           case GFT_Real:
619             aoFields[iField].adfValues.resize( nNewCount );
620             break;
621
622           case GFT_String:
623             aoFields[iField].aosValues.resize( nNewCount );
624             break;
625         }
626     }
627
628     nRowCount = nNewCount;
629 }
630
631 /************************************************************************/
632 /*                         GDALRATSetRowCount()                         */
633 /************************************************************************/
634
635 void CPL_STDCALL
636 GDALRATSetRowCount( GDALRasterAttributeTableH hRAT, int nNewCount )
637
638 {
639     ((GDALRasterAttributeTable *) hRAT)->SetRowCount( nNewCount );
640 }
641
642 /************************************************************************/
643 /*                              SetValue()                              */
644 /************************************************************************/
645
646 /**
647  * \brief Set field value from string.
648  *
649  * The indicated field (column) on the indicated row is set from the
650  * passed value.  The value will be automatically converted for other field
651  * types, with a possible loss of precision.
652  *
653  * This method is the same as the C function GDALRATSetValueAsString().
654  *
655  * @param iRow row to fetch (zero based).
656  * @param iField column to fetch (zero based).
657  * @param pszValue the value to assign.
658  */
659
660 void GDALRasterAttributeTable::SetValue( int iRow, int iField,
661                                          const char *pszValue )
662
663 {
664     if( iField < 0 || iField >= (int) aoFields.size() )
665     {
666         CPLError( CE_Failure, CPLE_AppDefined,
667                   "iField (%d) out of range.", iField );
668
669         return;
670     }
671
672     if( iRow == nRowCount )
673         SetRowCount( nRowCount+1 );
674    
675     if( iRow < 0 || iRow >= nRowCount )
676     {
677         CPLError( CE_Failure, CPLE_AppDefined,
678                   "iRow (%d) out of range.", iRow );
679
680         return;
681     }
682
683     switch( aoFields[iField].eType )
684     {
685       case GFT_Integer:
686         aoFields[iField].anValues[iRow] = atoi(pszValue);
687         break;
688        
689       case GFT_Real:
690         aoFields[iField].adfValues[iRow] = atof(pszValue);
691         break;
692        
693       case GFT_String:
694         aoFields[iField].aosValues[iRow] = pszValue;
695         break;
696     }
697 }
698
699 /************************************************************************/
700 /*                      GDALRATSetValueAsString()                       */
701 /************************************************************************/
702
703 void CPL_STDCALL
704 GDALRATSetValueAsString( GDALRasterAttributeTableH hRAT, int iRow, int iField,
705                          const char *pszValue )
706
707 {
708     ((GDALRasterAttributeTable *) hRAT)->SetValue( iRow, iField, pszValue );
709 }
710
711 /************************************************************************/
712 /*                              SetValue()                              */
713 /************************************************************************/
714
715 /**
716  * \brief Set field value from integer.
717  *
718  * The indicated field (column) on the indicated row is set from the
719  * passed value.  The value will be automatically converted for other field
720  * types, with a possible loss of precision.
721  *
722  * This method is the same as the C function GDALRATSetValueAsInteger().
723  *
724  * @param iRow row to fetch (zero based).
725  * @param iField column to fetch (zero based).
726  * @param nValue the value to assign.
727  */
728
729 void GDALRasterAttributeTable::SetValue( int iRow, int iField,
730                                          int nValue )
731
732 {
733     if( iField < 0 || iField >= (int) aoFields.size() )
734     {
735         CPLError( CE_Failure, CPLE_AppDefined,
736                   "iField (%d) out of range.", iField );
737
738         return;
739     }
740
741     if( iRow == nRowCount )
742         SetRowCount( nRowCount+1 );
743    
744     if( iRow < 0 || iRow >= nRowCount )
745     {
746         CPLError( CE_Failure, CPLE_AppDefined,
747                   "iRow (%d) out of range.", iRow );
748
749         return;
750     }
751
752     switch( aoFields[iField].eType )
753     {
754       case GFT_Integer:
755         aoFields[iField].anValues[iRow] = nValue;
756         break;
757        
758       case GFT_Real:
759         aoFields[iField].adfValues[iRow] = nValue;
760         break;
761        
762       case GFT_String:
763       {
764           char szValue[100];
765
766           sprintf( szValue, "%d", nValue );
767           aoFields[iField].aosValues[iRow] = szValue;
768       }
769       break;
770     }
771 }
772
773 /************************************************************************/
774 /*                        GDALRATSetValueAsInt()                        */
775 /************************************************************************/
776
777 void CPL_STDCALL
778 GDALRATSetValueAsInt( GDALRasterAttributeTableH hRAT, int iRow, int iField,
779                       int nValue )
780
781 {
782     ((GDALRasterAttributeTable *) hRAT)->SetValue( iRow, iField, nValue);
783 }
784
785 /************************************************************************/
786 /*                              SetValue()                              */
787 /************************************************************************/
788
789 /**
790  * \brief Set field value from double.
791  *
792  * The indicated field (column) on the indicated row is set from the
793  * passed value.  The value will be automatically converted for other field
794  * types, with a possible loss of precision.
795  *
796  * This method is the same as the C function GDALRATSetValueAsDouble().
797  *
798  * @param iRow row to fetch (zero based).
799  * @param iField column to fetch (zero based).
800  * @param dfValue the value to assign.
801  */
802
803 void GDALRasterAttributeTable::SetValue( int iRow, int iField,
804                                          double dfValue )
805
806 {
807     if( iField < 0 || iField >= (int) aoFields.size() )
808     {
809         CPLError( CE_Failure, CPLE_AppDefined,
810                   "iField (%d) out of range.", iField );
811
812         return;
813     }
814
815     if( iRow == nRowCount )
816         SetRowCount( nRowCount+1 );
817    
818     if( iRow < 0 || iRow >= nRowCount )
819     {
820         CPLError( CE_Failure, CPLE_AppDefined,
821                   "iRow (%d) out of range.", iRow );
822
823         return;
824     }
825
826     switch( aoFields[iField].eType )
827     {
828       case GFT_Integer:
829         aoFields[iField].anValues[iRow] = (int) dfValue;
830         break;
831        
832       case GFT_Real:
833         aoFields[iField].adfValues[iRow] = dfValue;
834         break;
835        
836       case GFT_String:
837       {
838           char szValue[100];
839
840           sprintf( szValue, "%.15g", dfValue );
841           aoFields[iField].aosValues[iRow] = szValue;
842       }
843       break;
844     }
845 }
846
847 /************************************************************************/
848 /*                      GDALRATSetValueAsDouble()                       */
849 /************************************************************************/
850
851 void CPL_STDCALL
852 GDALRATSetValueAsDouble( GDALRasterAttributeTableH hRAT, int iRow, int iField,
853                          double dfValue )
854
855 {
856     ((GDALRasterAttributeTable *) hRAT)->SetValue( iRow, iField, dfValue );
857 }
858
859 /************************************************************************/
860 /*                           GetRowOfValue()                            */
861 /************************************************************************/
862
863 /**
864  * \brief Get row for pixel value.
865  *
866  * Given a raw pixel value, the raster attribute table is scanned to
867  * determine which row in the table applies to the pixel value.  The
868  * row index is returned.
869  *
870  * This method is the same as the C function GDALRATGetRowOfValue().
871  *
872  * @param dfValue the pixel value.
873  *
874  * @return the row index or -1 if no row is appropriate.
875  */
876
877 int GDALRasterAttributeTable::GetRowOfValue( double dfValue ) const
878
879 {
880 /* -------------------------------------------------------------------- */
881 /*      Handle case of regular binning.                                 */
882 /* -------------------------------------------------------------------- */
883     if( bLinearBinning )
884     {
885         int iBin = (int) floor((dfValue - dfRow0Min) / dfBinSize);
886         if( iBin < 0 || iBin >= nRowCount )
887             return -1;
888         else
889             return iBin;
890     }
891
892 /* -------------------------------------------------------------------- */
893 /*      Do we have any information?                                     */
894 /* -------------------------------------------------------------------- */
895     const GDALRasterAttributeField *poMin, *poMax;
896
897     if( nMinCol == -1 && nMaxCol == -1 )
898         return -1;
899
900     if( nMinCol != -1 )
901         poMin = &(aoFields[nMinCol]);
902     else
903         poMin = NULL;
904    
905     if( nMaxCol != -1 )
906         poMax = &(aoFields[nMaxCol]);
907     else
908         poMax = NULL;
909    
910 /* -------------------------------------------------------------------- */
911 /*      Search through rows for match.                                  */
912 /* -------------------------------------------------------------------- */
913     int   iRow;
914
915     for( iRow = 0; iRow < nRowCount; iRow++ )
916     {
917         if( poMin != NULL )
918         {
919             if( poMin->eType == GFT_Integer )
920             {
921                 while( iRow < nRowCount && dfValue < poMin->anValues[iRow] )
922                     iRow++;
923             }
924             else if( poMin->eType == GFT_Real )
925             {
926                 while( iRow < nRowCount && dfValue < poMin->adfValues[iRow] )
927                     iRow++;
928             }
929
930             if( iRow == nRowCount )
931                 break;
932         }
933
934         if( poMax != NULL )
935         {
936             if( (poMax->eType == GFT_Integer
937                  && dfValue > poMax->anValues[iRow] )
938                 || (poMax->eType == GFT_Real
939                     && dfValue > poMax->adfValues[iRow] ) )
940                 continue;
941         }
942
943         return iRow;
944     }
945
946     return -1;