1 : /******************************************************************************
2 : * $Id$
3 : *
4 : * Project: CPL - Common Portability Library
5 : * Author: Frank Warmerdam, warmerdam@pobox.com
6 : * Purpose: Progress function implementations.
7 : *
8 : ******************************************************************************
9 : * Copyright (c) 2013, 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 : #include "cpl_progress.h"
31 : #include "cpl_conv.h"
32 :
33 : CPL_CVSID("$Id: gdal_misc.cpp 25494 2013-01-13 12:55:17Z etourigny $");
34 :
35 : /************************************************************************/
36 : /* GDALDummyProgress() */
37 : /************************************************************************/
38 :
39 : /**
40 : * \brief Stub progress function.
41 : *
42 : * This is a stub (does nothing) implementation of the GDALProgressFunc()
43 : * semantics. It is primarily useful for passing to functions that take
44 : * a GDALProgressFunc() argument but for which the application does not want
45 : * to use one of the other progress functions that actually do something.
46 : */
47 :
48 104530 : int CPL_STDCALL GDALDummyProgress( double dfComplete, const char *pszMessage,
49 : void *pData )
50 :
51 : {
52 104530 : return TRUE;
53 : }
54 :
55 : /************************************************************************/
56 : /* GDALScaledProgress() */
57 : /************************************************************************/
58 : typedef struct {
59 : GDALProgressFunc pfnProgress;
60 : void *pData;
61 : double dfMin;
62 : double dfMax;
63 : } GDALScaledProgressInfo;
64 :
65 : /**
66 : * \brief Scaled progress transformer.
67 : *
68 : * This is the progress function that should be passed along with the
69 : * callback data returned by GDALCreateScaledProgress().
70 : */
71 :
72 35331 : int CPL_STDCALL GDALScaledProgress( double dfComplete, const char *pszMessage,
73 : void *pData )
74 :
75 : {
76 35331 : GDALScaledProgressInfo *psInfo = (GDALScaledProgressInfo *) pData;
77 :
78 : return psInfo->pfnProgress( dfComplete * (psInfo->dfMax - psInfo->dfMin)
79 : + psInfo->dfMin,
80 35331 : pszMessage, psInfo->pData );
81 : }
82 :
83 : /************************************************************************/
84 : /* GDALCreateScaledProgress() */
85 : /************************************************************************/
86 :
87 : /**
88 : * \brief Create scaled progress transformer.
89 : *
90 : * Sometimes when an operations wants to report progress it actually
91 : * invokes several subprocesses which also take GDALProgressFunc()s,
92 : * and it is desirable to map the progress of each sub operation into
93 : * a portion of 0.0 to 1.0 progress of the overall process. The scaled
94 : * progress function can be used for this.
95 : *
96 : * For each subsection a scaled progress function is created and
97 : * instead of passing the overall progress func down to the sub functions,
98 : * the GDALScaledProgress() function is passed instead.
99 : *
100 : * @param dfMin the value to which 0.0 in the sub operation is mapped.
101 : * @param dfMax the value to which 1.0 is the sub operation is mapped.
102 : * @param pfnProgress the overall progress function.
103 : * @param pData the overall progress function callback data.
104 : *
105 : * @return pointer to pass as pProgressArg to sub functions. Should be freed
106 : * with GDALDestroyScaledProgress().
107 : *
108 : * Example:
109 : *
110 : * \code
111 : * int MyOperation( ..., GDALProgressFunc pfnProgress, void *pProgressData );
112 : *
113 : * {
114 : * void *pScaledProgress;
115 : *
116 : * pScaledProgress = GDALCreateScaledProgress( 0.0, 0.5, pfnProgress,
117 : * pProgressData );
118 : * GDALDoLongSlowOperation( ..., GDALScaledProgress, pScaledProgress );
119 : * GDALDestroyScaledProgress( pScaledProgress );
120 : *
121 : * pScaledProgress = GDALCreateScaledProgress( 0.5, 1.0, pfnProgress,
122 : * pProgressData );
123 : * GDALDoAnotherOperation( ..., GDALScaledProgress, pScaledProgress );
124 : * GDALDestroyScaledProgress( pScaledProgress );
125 : *
126 : * return ...;
127 : * }
128 : * \endcode
129 : */
130 :
131 803 : void * CPL_STDCALL GDALCreateScaledProgress( double dfMin, double dfMax,
132 : GDALProgressFunc pfnProgress,
133 : void * pData )
134 :
135 : {
136 : GDALScaledProgressInfo *psInfo;
137 :
138 : psInfo = (GDALScaledProgressInfo *)
139 803 : CPLCalloc(sizeof(GDALScaledProgressInfo),1);
140 :
141 803 : if( ABS(dfMin-dfMax) < 0.0000001 )
142 0 : dfMax = dfMin + 0.01;
143 :
144 803 : psInfo->pData = pData;
145 803 : psInfo->pfnProgress = pfnProgress;
146 803 : psInfo->dfMin = dfMin;
147 803 : psInfo->dfMax = dfMax;
148 :
149 803 : return (void *) psInfo;
150 : }
151 :
152 : /************************************************************************/
153 : /* GDALDestroyScaledProgress() */
154 : /************************************************************************/
155 :
156 : /**
157 : * \brief Cleanup scaled progress handle.
158 : *
159 : * This function cleans up the data associated with a scaled progress function
160 : * as returned by GADLCreateScaledProgress().
161 : *
162 : * @param pData scaled progress handle returned by GDALCreateScaledProgress().
163 : */
164 :
165 803 : void CPL_STDCALL GDALDestroyScaledProgress( void * pData )
166 :
167 : {
168 803 : CPLFree( pData );
169 803 : }
170 :
171 : /************************************************************************/
172 : /* GDALTermProgress() */
173 : /************************************************************************/
174 :
175 : /**
176 : * \brief Simple progress report to terminal.
177 : *
178 : * This progress reporter prints simple progress report to the
179 : * terminal window. The progress report generally looks something like
180 : * this:
181 :
182 : \verbatim
183 : 0...10...20...30...40...50...60...70...80...90...100 - done.
184 : \endverbatim
185 :
186 : * Every 2.5% of progress another number or period is emitted. Note that
187 : * GDALTermProgress() uses internal static data to keep track of the last
188 : * percentage reported and will get confused if two terminal based progress
189 : * reportings are active at the same time.
190 : *
191 : * The GDALTermProgress() function maintains an internal memory of the
192 : * last percentage complete reported in a static variable, and this makes
193 : * it unsuitable to have multiple GDALTermProgress()'s active eithin a
194 : * single thread or across multiple threads.
195 : *
196 : * @param dfComplete completion ratio from 0.0 to 1.0.
197 : * @param pszMessage optional message.
198 : * @param pProgressArg ignored callback data argument.
199 : *
200 : * @return Always returns TRUE indicating the process should continue.
201 : */
202 :
203 37075 : int CPL_STDCALL GDALTermProgress( double dfComplete, const char *pszMessage,
204 : void * pProgressArg )
205 :
206 : {
207 : static int nLastTick = -1;
208 37075 : int nThisTick = (int) (dfComplete * 40.0);
209 :
210 : (void) pProgressArg;
211 :
212 37075 : nThisTick = MIN(40,MAX(0,nThisTick));
213 :
214 : // Have we started a new progress run?
215 37075 : if( nThisTick < nLastTick && nLastTick >= 39 )
216 15 : nLastTick = -1;
217 :
218 37075 : if( nThisTick <= nLastTick )
219 32537 : return TRUE;
220 :
221 26095 : while( nThisTick > nLastTick )
222 : {
223 17019 : nLastTick++;
224 17019 : if( nLastTick % 4 == 0 )
225 4600 : fprintf( stdout, "%d", (nLastTick / 4) * 10 );
226 : else
227 12419 : fprintf( stdout, "." );
228 : }
229 :
230 4538 : if( nThisTick == 40 )
231 413 : fprintf( stdout, " - done.\n" );
232 : else
233 4125 : fflush( stdout );
234 :
235 4538 : return TRUE;
236 : }
|