root/tags/gdal_1_3_2/gcore/gdal_misc.cpp

Revision 9299, 80.3 kB (checked in by fwarmerdam, 3 years ago)

added --locale switch to force a locale

  • 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:  Free standing functions for GDAL.
6  * Author:   Frank Warmerdam, warmerdam@pobox.com
7  *
8  ******************************************************************************
9  * Copyright (c) 1999, 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.78  2006/03/03 19:43:44  fwarmerdam
32  * added --locale switch to force a locale
33  *
34  * Revision 1.77  2006/03/02 11:33:31  dron
35  * Unused variable in GDALFindAssociatedAuxFile() removed.
36  *
37  * Revision 1.76  2006/01/23 15:23:45  fwarmerdam
38  * Modified GDALTermProgress to output "." on 2.5% intervals except
39  * integral ones.
40  *
41  * Revision 1.75  2005/12/06 21:51:01  fwarmerdam
42  * before calling GDALOpen on a .aux file, verify it is HFA
43  *
44  * Revision 1.74  2005/10/07 13:31:26  dron
45  * Allow pixel width/height to be zero when rotation is present
46  * (GDALReadWorldFile).
47  *
48  * Revision 1.73  2005/09/26 15:52:03  fwarmerdam
49  * centralized .aux opening logic
50  *
51  * Revision 1.72  2005/09/11 21:07:54  fwarmerdam
52  * Changed worldfile reading to use large file API.
53  *
54  * Revision 1.71  2005/09/11 19:16:31  fwarmerdam
55  * Use CPLString for safer string manipulation.
56  *
57  * Revision 1.70  2005/07/15 13:28:00  fwarmerdam
58  * Fixed another big raster int overflow problem in GDALGetRasterSampleOverview
59  *
60  * Revision 1.69  2005/07/13 17:21:10  fwarmerdam
61  * Avoiding 32bit overflow in GDALGetRasterSampleOverview().
62  *
63  * Revision 1.68  2005/07/08 18:59:54  fwarmerdam
64  * Don't use thread local storage for GDALTermProgress() last complete, or
65  * the GDALVersionInfo() static buffer.
66  *
67  * Revision 1.67  2005/05/23 06:44:31  fwarmerdam
68  * Updated for locking of block refs
69  *
70  * Revision 1.66  2005/04/04 15:24:48  fwarmerdam
71  * Most C entry points now CPL_STDCALL
72  *
73  * Revision 1.65  2005/03/21 16:12:08  fwarmerdam
74  * Trimmed log.
75  *
76  * Revision 1.64  2005/03/21 16:11:32  fwarmerdam
77  * Added special case for simple 4 corners, non-rotated case in
78  * GDALGCPsToGeoTransform().
79  *
80  * Revision 1.63  2005/02/10 04:30:29  fwarmerdam
81  * added support for YCbCr color space
82  *
83  * Revision 1.62  2004/11/23 19:54:07  fwarmerdam
84  * Fixed initialization bug in szDerivedExtension in GDALReadWorldFile().
85  *
86  * Revision 1.61  2004/10/26 15:59:06  fwarmerdam
87  * Added rw+ for formats with Create().
88  *
89  * Revision 1.60  2004/08/09 14:40:41  warmerda
90  * return name for GDT_Unknown
91  *
92  * Revision 1.59  2004/05/28 16:05:25  warmerda
93  * add default ext handling and docs for  GDALReadWorldFile
94  *
95  * Revision 1.58  2004/05/25 16:58:59  warmerda
96  * Try to return an error if we don't find GCPs in TAB file.
97  *
98  * Revision 1.57  2004/04/21 15:48:47  warmerda
99  * Reimplement GDALGetGeoTransformFromGCPs to do best fit - Eric Donges
100  *
101  * Revision 1.56  2004/04/02 18:42:48  warmerda
102  * Added rw/ro flag in --formats list.
103  *
104  * Revision 1.55  2004/04/02 18:01:35  warmerda
105  * Finished docs for commandline processor function.
106  *
107  * Revision 1.54  2004/04/02 17:58:29  warmerda
108  * added --optfile support in general commandline processor
109  *
110  * Revision 1.53  2004/04/02 17:32:40  warmerda
111  * added GDALGeneralCmdLineProcessor()
112  *
113  * Revision 1.52  2004/02/25 09:03:15  dron
114  * Added GDALPackedDMSToDec() and GDALDecToPackedDMS() functions.
115  *
116  * Revision 1.51  2004/02/18 14:59:55  dron
117  * Properly determine pixel offset in last tiles in GDALGetRandomRasterSample().
118  *
119  * Revision 1.50  2004/01/18 16:43:37  dron
120  * Added GDALGetDataTypeByName() function.
121  */
122
123 #include "gdal_priv.h"
124 #include "cpl_string.h"
125 #include "cpl_minixml.h"
126 #include <ctype.h>
127 #include <string>
128
129 CPL_CVSID("$Id$");
130
131 #include "ogr_spatialref.h"
132
133 #ifdef HAVE_MITAB
134 // from mitab component.
135 OGRSpatialReference * MITABCoordSys2SpatialRef( const char * pszCoordSys );
136 #endif
137
138 /************************************************************************/
139 /*                           __pure_virtual()                           */
140 /*                                                                      */
141 /*      The following is a gross hack to remove the last remaining      */
142 /*      dependency on the GNU C++ standard library.                     */
143 /************************************************************************/
144
145 #ifdef __GNUC__
146
147 extern "C"
148 void __pure_virtual()
149
150 {
151 }
152
153 #endif
154
155 /************************************************************************/
156 /*                         GDALDataTypeUnion()                          */
157 /************************************************************************/
158
159 /**
160  * Return the smallest data type that can fully express both input data
161  * types.
162  *
163  * @param eType1
164  * @param eType2
165  *
166  * @return a data type able to express eType1 and eType2.
167  */
168
169 GDALDataType CPL_STDCALL
170 GDALDataTypeUnion( GDALDataType eType1, GDALDataType eType2 )
171
172 {
173     int         bFloating, bComplex, nBits, bSigned;
174
175     bComplex = GDALDataTypeIsComplex(eType1) | GDALDataTypeIsComplex(eType2);
176    
177     switch( eType1 )
178     {
179       case GDT_Byte:
180         nBits = 8;
181         bSigned = FALSE;
182         bFloating = FALSE;
183         break;
184        
185       case GDT_Int16:
186       case GDT_CInt16:
187         nBits = 16;
188         bSigned = TRUE;
189         bFloating = FALSE;
190         break;
191        
192       case GDT_UInt16:
193         nBits = 16;
194         bSigned = FALSE;
195         bFloating = FALSE;
196         break;
197        
198       case GDT_Int32:
199       case GDT_CInt32:
200         nBits = 32;
201         bSigned = TRUE;
202         bFloating = FALSE;
203         break;
204        
205       case GDT_UInt32:
206         nBits = 32;
207         bSigned = FALSE;
208         bFloating = FALSE;
209         break;
210
211       case GDT_Float32:
212       case GDT_CFloat32:
213         nBits = 32;
214         bSigned = TRUE;
215         bFloating = TRUE;
216         break;
217
218       case GDT_Float64:
219       case GDT_CFloat64:
220         nBits = 64;
221         bSigned = TRUE;
222         bFloating = TRUE;
223         break;
224
225       default:
226         CPLAssert( FALSE );
227         return GDT_Unknown;
228     }
229
230     switch( eType2 )
231     {
232       case GDT_Byte:
233         break;
234        
235       case GDT_Int16:
236         nBits = MAX(nBits,16);
237         bSigned = TRUE;
238         break;
239        
240       case GDT_UInt16:
241         nBits = MAX(nBits,16);
242         break;
243        
244       case GDT_Int32:
245       case GDT_CInt32:
246         nBits = MAX(nBits,32);
247         bSigned = TRUE;
248         break;
249        
250       case GDT_UInt32:
251         nBits = MAX(nBits,32);
252         break;
253
254       case GDT_Float32:
255       case GDT_CFloat32:
256         nBits = MAX(nBits,32);
257         bSigned = TRUE;
258         bFloating = TRUE;
259         break;
260
261       case GDT_Float64:
262       case GDT_CFloat64:
263         nBits = MAX(nBits,64);
264         bSigned = TRUE;
265         bFloating = TRUE;
266         break;
267
268       default:
269         CPLAssert( FALSE );
270         return GDT_Unknown;
271     }
272
273     if( nBits == 8 )
274         return GDT_Byte;
275     else if( nBits == 16 && bComplex )
276         return GDT_CInt16;
277     else if( nBits == 16 && bSigned )
278         return GDT_Int16;
279     else if( nBits == 16 && !bSigned )
280         return GDT_UInt16;
281     else if( nBits == 32 && bFloating && bComplex )
282         return GDT_CFloat32;
283     else if( nBits == 32 && bFloating )
284         return GDT_Float32;
285     else if( nBits == 32 && bComplex )
286         return GDT_CInt32;
287     else if( nBits == 32 && bSigned )
288         return GDT_Int32;
289     else if( nBits == 32 && !bSigned )
290         return GDT_UInt32;
291     else if( nBits == 64 && bComplex )
292         return GDT_CFloat64;
293     else
294         return GDT_Float64;
295 }
296
297
298 /************************************************************************/
299 /*                        GDALGetDataTypeSize()                         */
300 /************************************************************************/
301
302 /**
303  * Get data type size in bits.
304  *
305  * Returns the size of a a GDT_* type in bits, <b>not bytes</b>!
306  *
307  * @param data type, such as GDT_Byte.
308  * @return the number of bits or zero if it is not recognised.
309  */
310
311 int CPL_STDCALL GDALGetDataTypeSize( GDALDataType eDataType )
312
313 {
314     switch( eDataType )
315     {
316       case GDT_Byte:
317         return 8;
318
319       case GDT_UInt16:
320       case GDT_Int16:
321         return 16;
322
323       case GDT_UInt32:
324       case GDT_Int32:
325       case GDT_Float32:
326       case GDT_CInt16:
327         return 32;
328
329       case GDT_Float64:
330       case GDT_CInt32:
331       case GDT_CFloat32:
332         return 64;
333
334       case GDT_CFloat64:
335         return 128;
336
337       default:
338         CPLAssert( FALSE );
339         return 0;
340     }
341 }
342
343 /************************************************************************/
344 /*                       GDALDataTypeIsComplex()                        */
345 /************************************************************************/
346
347 /**
348  * Is data type complex?
349  *
350  * @return TRUE if the passed type is complex (one of GDT_CInt16, GDT_CInt32,
351  * GDT_CFloat32 or GDT_CFloat64), that is it consists of a real and imaginary
352  * component.
353  */
354
355 int CPL_STDCALL GDALDataTypeIsComplex( GDALDataType eDataType )
356
357 {
358     switch( eDataType )
359     {
360       case GDT_CInt16:
361       case GDT_CInt32:
362       case GDT_CFloat32:
363       case GDT_CFloat64:
364         return TRUE;
365
366       default:
367         return FALSE;
368     }
369 }
370
371 /************************************************************************/
372 /*                        GDALGetDataTypeName()                         */
373 /************************************************************************/
374
375 /**
376  * Get name of data type.
377  *
378  * Returns a symbolic name for the data type.  This is essentially the
379  * the enumerated item name with the GDT_ prefix removed.  So GDT_Byte returns
380  * "Byte".  The returned strings are static strings and should not be modified
381  * or freed by the application.  These strings are useful for reporting
382  * datatypes in debug statements, errors and other user output.
383  *
384  * @param eDataType type to get name of.
385  * @return string corresponding to type.
386  */
387
388 const char * CPL_STDCALL GDALGetDataTypeName( GDALDataType eDataType )
389
390 {
391     switch( eDataType )
392     {
393       case GDT_Unknown:
394         return "Unknown";
395
396       case GDT_Byte:
397         return "Byte";
398
399       case GDT_UInt16:
400         return "UInt16";
401
402       case GDT_Int16:
403         return "Int16";
404
405       case GDT_UInt32:
406         return "UInt32";
407        
408       case GDT_Int32:
409         return "Int32";
410        
411       case GDT_Float32:
412         return "Float32";
413
414       case GDT_Float64:
415         return "Float64";
416
417       case GDT_CInt16:
418         return "CInt16";
419
420       case GDT_CInt32:
421         return "CInt32";
422
423       case GDT_CFloat32:
424         return "CFloat32";
425
426       case GDT_CFloat64:
427         return "CFloat64";
428
429       default:
430         return NULL;
431     }
432 }
433
434 /************************************************************************/
435 /*                        GDALGetDataTypeByName()                       */
436 /************************************************************************/
437
438 /**
439  * Get data type by symbolic name.
440  *
441  * Returns a data type corresponding to the given symbolic name. This
442  * function is opposite to the GDALGetDataTypeName().
443  *
444  * @param pszName string containing the symbolic name of the type.
445  *
446  * @return GDAL data type.
447  */
448
449 GDALDataType CPL_STDCALL GDALGetDataTypeByName( const char *pszName )
450
451 {
452     int iType;
453    
454     for( iType = 1; iType < GDT_TypeCount; iType++ )
455     {
456         if( GDALGetDataTypeName((GDALDataType)iType) != NULL
457             && EQUAL(GDALGetDataTypeName((GDALDataType)iType), pszName) )
458         {
459             return (GDALDataType)iType;
460         }
461     }
462
463     return GDT_Unknown;
464 }
465
466 /************************************************************************/
467 /*                  GDALGetPaletteInterpretationName()                  */
468 /************************************************************************/
469
470 const char *GDALGetPaletteInterpretationName( GDALPaletteInterp eInterp )
471
472 {
473     switch( eInterp )
474     {
475       case GPI_Gray:
476         return "Gray";
477
478       case GPI_RGB:
479         return "RGB";
480        
481       case GPI_CMYK:
482         return "CMYK";
483
484       case GPI_HLS:
485         return "HLS";
486        
487       default:
488         return "Unknown";
489     }
490 }
491
492 /************************************************************************/
493 /*                   GDALGetColorInterpretationName()                   */
494 /************************************************************************/
495
496 const char *GDALGetColorInterpretationName( GDALColorInterp eInterp )
497
498 {
499     switch( eInterp )
500     {
501       case GCI_Undefined:
502         return "Undefined";
503
504       case GCI_GrayIndex:
505         return "Gray";
506
507       case GCI_PaletteIndex:
508         return "Palette";
509
510       case GCI_RedBand:
511         return "Red";
512
513       case GCI_GreenBand:
514         return "Green";
515
516       case GCI_BlueBand:
517         return "Blue";
518
519       case GCI_AlphaBand:
520         return "Alpha";
521
522       case GCI_HueBand:
523         return "Hue";
524
525       case GCI_SaturationBand:
526         return "Saturation";
527
528       case GCI_LightnessBand:
529         return "Lightness";
530
531       case GCI_CyanBand:
532         return "Cyan";
533
534       case GCI_MagentaBand:
535         return "Magenta";
536
537       case GCI_YellowBand:
538         return "Yellow";
539
540       case GCI_BlackBand:
541         return "Black";
542        
543       case GCI_YCbCr_YBand:
544         return "YCbCr_Y";
545        
546       case GCI_YCbCr_CbBand:
547         return "YCbCr_Cb";
548        
549       case GCI_YCbCr_CrBand:
550         return "YCbCr_Cr";
551        
552       default:
553         return "Unknown";
554     }
555 }
556
557 /************************************************************************/
558 /*                      GDALComputeRasterMinMax()                       */
559 /************************************************************************/
560
561 /**
562  * Compute the min/max values for a band.
563  *
564  * If approximate is OK, then the band's GetMinimum()/GetMaximum() will
565  * be trusted.  If it doesn't work, a subsample of blocks will be read to
566  * get an approximate min/max.  If the band has a nodata value it will
567  * be excluded from the minimum and maximum.
568  *
569  * If bApprox is FALSE, then all pixels will be read and used to compute
570  * an exact range.
571  *
572  * @param hBand the band to copmute the range for.
573  * @param bApproxOK TRUE if an approximate (faster) answer is OK, otherwise
574  * FALSE.
575  * @param adfMinMax the array in which the minimum (adfMinMax[0]) and the
576  * maximum (adfMinMax[1]) are returned.
577  */
578
579 void CPL_STDCALL
580 GDALComputeRasterMinMax( GDALRasterBandH hBand, int bApproxOK,
581                          double adfMinMax[2] )
582
583 {
584     double       dfMin=0.0, dfMax=0.0;
585     GDALRasterBand *poBand;
586
587 /* -------------------------------------------------------------------- */
588 /*      Does the driver already know the min/max?                       */
589 /* -------------------------------------------------------------------- */
590     if( bApproxOK )
591     {
592         int          bSuccessMin, bSuccessMax;
593
594         dfMin = GDALGetRasterMinimum( hBand, &bSuccessMin );
595         dfMax = GDALGetRasterMaximum( hBand, &bSuccessMax );
596
597         if( bSuccessMin && bSuccessMax )
598         {
599             adfMinMax[0] = dfMin;
600             adfMinMax[1] = dfMax;
601             return;
602         }
603     }
604    
605 /* -------------------------------------------------------------------- */
606 /*      If we have overview bands, use them for min/max.                */
607 /* -------------------------------------------------------------------- */
608     if( bApproxOK )
609         poBand = (GDALRasterBand *) GDALGetRasterSampleOverview( hBand, 2500 );
610     else
611         poBand = (GDALRasterBand *) hBand;
612    
613 /* -------------------------------------------------------------------- */
614 /*      Figure out the ratio of blocks we will read to get an           */
615 /*      approximate value.                                              */
616 /* -------------------------------------------------------------------- */
617     int         nBlockXSize, nBlockYSize;
618     int         nBlocksPerRow, nBlocksPerColumn;
619     int         nSampleRate;
620     int         bGotNoDataValue, bFirstValue = TRUE;
621     double      dfNoDataValue;
622
623     dfNoDataValue = poBand->GetNoDataValue( &bGotNoDataValue );
624
625     poBand->GetBlockSize( &nBlockXSize, &nBlockYSize );
626     nBlocksPerRow = (poBand->GetXSize() + nBlockXSize - 1) / nBlockXSize;
627     nBlocksPerColumn = (poBand->GetYSize() + nBlockYSize - 1) / nBlockYSize;
628
629     if( bApproxOK )
630         nSampleRate =
631             (int) MAX(1,sqrt((double) nBlocksPerRow * nBlocksPerColumn));
632     else
633         nSampleRate = 1;
634    
635     for( int iSampleBlock = 0;
636          iSampleBlock < nBlocksPerRow * nBlocksPerColumn;
637          iSampleBlock += nSampleRate )
638     {
639         double dfValue = 0.0;
640         int  iXBlock, iYBlock, nXCheck, nYCheck;
641         GDALRasterBlock *poBlock;
642
643         iYBlock = iSampleBlock / nBlocksPerRow;
644         iXBlock = iSampleBlock - nBlocksPerRow * iYBlock;
645        
646         poBlock = poBand->GetLockedBlockRef( iXBlock, iYBlock );
647         if( poBlock == NULL )
648             continue;
649        
650         if( (iXBlock+1) * nBlockXSize > poBand->GetXSize() )
651             nXCheck = poBand->GetXSize() - iXBlock * nBlockXSize;
652         else
653             nXCheck = nBlockXSize;
654
655         if( (iYBlock+1) * nBlockYSize > poBand->GetYSize() )
656             nYCheck = poBand->GetYSize() - iYBlock * nBlockYSize;
657         else
658             nYCheck = nBlockYSize;
659
660         /* this isn't the fastest way to do this, but is easier for now */
661         for( int iY = 0; iY < nYCheck; iY++ )
662         {
663             for( int iX = 0; iX < nXCheck; iX++ )
664             {
665                 int    iOffset = iX + iY * nBlockXSize;
666
667                 switch( poBlock->GetDataType() )
668                 {
669                   case GDT_Byte:
670                     dfValue = ((GByte *) poBlock->GetDataRef())[iOffset];
671                     break;
672                   case GDT_UInt16:
673                     dfValue = ((GUInt16 *) poBlock->GetDataRef())[iOffset];
674                     break;
675                   case GDT_Int16:
676                     dfValue = ((GInt16 *) poBlock->GetDataRef())[iOffset];
677                     break;
678                   case GDT_UInt32:
679                     dfValue = ((GUInt32 *) poBlock->GetDataRef())[iOffset];
680                     break;
681                   case GDT_Int32:
682                     dfValue = ((GInt32 *) poBlock->GetDataRef())[iOffset];
683                     break;
684                   case GDT_Float32:
685                     dfValue = ((float *) poBlock->GetDataRef())[iOffset];
686                     break;
687                   case GDT_Float64:
688                     dfValue = ((double *) poBlock->GetDataRef())[iOffset];
689                     break;
690                   case GDT_CInt16:
691                     dfValue = ((GInt16 *) poBlock->GetDataRef())[iOffset*2];
692                     break;
693                   case GDT_CInt32:
694                     dfValue = ((GInt32 *) poBlock->GetDataRef())[iOffset*2];
695                     break;
696                   case GDT_CFloat32:
697                     dfValue = ((float *) poBlock->GetDataRef())[iOffset*2];
698                     break;
699                   case GDT_CFloat64:
700                     dfValue = ((double *) poBlock->GetDataRef())[iOffset*2];
701                     break;
702                   default:
703                     CPLAssert( FALSE );
704                 }
705                
706                 if( bGotNoDataValue && dfValue == dfNoDataValue )
707                     continue;
708
709                 if( bFirstValue )
710                 {
711                     dfMin = dfMax = dfValue;
712                     bFirstValue = FALSE;
713                 }
714                 else
715                 {
716                     dfMin = MIN(dfMin,dfValue);
717                     dfMax = MAX(dfMax,dfValue);
718                 }
719             }
720         }
721
722         poBlock->DropLock();
723     }
724
725     adfMinMax[0] = dfMin;
726     adfMinMax[1] = dfMax;
727 }
728
729 /************************************************************************/
730 /*                         GDALDummyProgress()                          */
731 /************************************************************************/
732
733 /**
734  * Stub progress function.
735  *
736  * This is a stub (does nothing) implementation of the GDALProgressFunc()
737  * semantics.  It is primarily useful for passing to functions that take
738  * a GDALProgressFunc() argument but for which the application does not want
739  * to use one of the other progress functions that actually do something.
740  */
741
742 int CPL_STDCALL GDALDummyProgress( double, const char *, void * )
743
744 {
745     return TRUE;
746 }
747
748 /************************************************************************/
749 /*                         GDALScaledProgress()                         */
750 /************************************************************************/
751 typedef struct {
752     GDALProgressFunc pfnProgress;
753     void *pData;
754     double dfMin;
755     double dfMax;
756 } GDALScaledProgressInfo;
757
758 /**
759  * Scaled progress transformer.
760  *
761  * This is the progress function that should be passed along with the
762  * callback data returned by GDALCreateScaledProgress().
763  */
764
765 int CPL_STDCALL GDALScaledProgress( double dfComplete, const char *pszMessage,
766                                     void *pData )
767
768 {
769     GDALScaledProgressInfo *psInfo = (GDALScaledProgressInfo *) pData;
770
771     return psInfo->pfnProgress( dfComplete * (psInfo->dfMax - psInfo->dfMin)
772                                 + psInfo->dfMin,
773                                 pszMessage, psInfo->pData );
774 }
775
776 /************************************************************************/
777 /*                      GDALCreateScaledProgress()                      */
778 /************************************************************************/
779
780 /**
781  * Create scaled progress transformer.
782  *
783  * Sometimes when an operations wants to report progress it actually
784  * invokes several subprocesses which also take GDALProgressFunc()s,
785  * and it is desirable to map the progress of each sub operation into
786  * a portion of 0.0 to 1.0 progress of the overall process.  The scaled
787  * progress function can be used for this.
788  *
789  * For each subsection a scaled progress function is created and
790  * instead of passing the overall progress func down to the sub functions,
791  * the GDALScaledProgress() function is passed instead.
792  *
793  * @param dfMin the value to which 0.0 in the sub operation is mapped.
794  * @param dfMax the value to which 1.0 is the sub operation is mapped.
795  * @param pfnProgress the overall progress function.
796  * @param dData the overall progress function callback data.
797  *
798  * @return pointer to pass as pProgressArg to sub functions.  Should be freed
799  * with GDALDestroyScaledProgress().
800  *
801  * Example:
802  *
803  * \code
804  *   int MyOperation( ..., GDALProgressFunc pfnProgress, void *pProgressData );
805  *
806  *   {
807  *       void *pScaledProgress;
808  *
809  *       pScaledProgress = GDALCreateScaledProgress( 0.0, 0.5, pfnProgress,
810  *                                                   pProgressData );
811  *       GDALDoLongSlowOperation( ..., GDALScaledProgressFunc, pProgressData );
812  *       GDALDestroyScaledProgress( pScaledProgress );
813  *
814  *       pScaledProgress = GDALCreateScaledProgress( 0.5, 1.0, pfnProgress,
815  *                                                   pProgressData );
816  *       GDALDoAnotherOperation( ..., GDALScaledProgressFunc, pProgressData );
817  *       GDALDestroyScaledProgress( pScaledProgress );
818  *
819  *       return ...;
820  *   }
821  * \endcode
822  */
823
824 void * CPL_STDCALL GDALCreateScaledProgress( double dfMin, double dfMax,
825                                 GDALProgressFunc pfnProgress,
826                                 void * pData )
827
828 {
829     GDALScaledProgressInfo *psInfo;
830
831     psInfo = (GDALScaledProgressInfo *)
832         CPLCalloc(sizeof(GDALScaledProgressInfo),1);
833
834     if( ABS(dfMin-dfMax) < 0.0000001 )
835         dfMax = dfMin + 0.01;
836
837     psInfo->pData = pData;
838     psInfo->pfnProgress = pfnProgress;
839     psInfo->dfMin = dfMin;
840     psInfo->dfMax = dfMax;
841
842     return (void *) psInfo;
843 }
844
845 /************************************************************************/
846 /*                     GDALDestroyScaledProgress()                      */
847 /************************************************************************/
848
849 /**
850  * Cleanup scaled progress handle.
851  *
852  * This function cleans up the data associated with a scaled progress function
853  * as returned by GADLCreateScaledProgress().
854  *
855  * @param pData scaled progress handle returned by GDALCreateScaledProgress().
856  */
857
858 void CPL_STDCALL GDALDestroyScaledProgress( void * pData )
859
860 {
861     CPLFree( pData );
862 }
863
864 /************************************************************************/
865 /*                          GDALTermProgress()                          */
866 /************************************************************************/
867
868 /**
869  * Simple progress report to terminal.
870  *
871  * This progress reporter prints simple progress report to the
872  * terminal window.  The progress report generally looks something like
873  * this:
874
875 \verbatim
876 0...10...20...30...40...50...60...70...80...90...100 - done.
877 \endverbatim
878
879  * Every 2.5% of progress another number or period is emitted.  Note that
880  * GDALTermProgress() uses internal static data to keep track of the last
881  * percentage reported and will get confused if two terminal based progress
882  * reportings are active at the same time.
883  *
884  * The GDALTermProgress() function maintains an internal memory of the
885  * last percentage complete reported in a static variable, and this makes
886  * it unsuitable to have multiple GDALTermProgress()'s active eithin a
887  * single thread or across multiple threads.
888  *
889  * @param dfComplete completion ratio from 0.0 to 1.0.
890  * @param pszMessage optional message.
891  * @param pProgressArg ignored callback data argument.
892  *
893  * @return Always returns TRUE indicating the process should continue.
894  */
895
896 int CPL_STDCALL GDALTermProgress( double dfComplete, const char *pszMessage,
897                       void * pProgressArg )
898
899 {
900     static double dfLastComplete = -1.0;
901
902     (void) pProgressArg;
903
904     if( dfLastComplete > dfComplete )
905     {