Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: CPL - Common Portability Library
4 : * Author: Frank Warmerdam, warmerdam@pobox.com
5 : * Purpose: Progress function implementations.
6 : *
7 : ******************************************************************************
8 : * Copyright (c) 2013, Frank Warmerdam
9 : *
10 : * Permission is hereby granted, free of charge, to any person obtaining a
11 : * copy of this software and associated documentation files (the "Software"),
12 : * to deal in the Software without restriction, including without limitation
13 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
14 : * and/or sell copies of the Software, and to permit persons to whom the
15 : * Software is furnished to do so, subject to the following conditions:
16 : *
17 : * The above copyright notice and this permission notice shall be included
18 : * in all copies or substantial portions of the Software.
19 : *
20 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
21 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
23 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
25 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
26 : * DEALINGS IN THE SOFTWARE.
27 : ****************************************************************************/
28 :
29 : #include "cpl_progress.h"
30 :
31 : #include <cmath>
32 : #include <cstdio>
33 :
34 : #include <algorithm>
35 :
36 : #include "cpl_conv.h"
37 :
38 : /************************************************************************/
39 : /* GDALDummyProgress() */
40 : /************************************************************************/
41 :
42 : /**
43 : * \brief Stub progress function.
44 : *
45 : * This is a stub (does nothing) implementation of the GDALProgressFunc()
46 : * semantics. It is primarily useful for passing to functions that take
47 : * a GDALProgressFunc() argument but for which the application does not want
48 : * to use one of the other progress functions that actually do something.
49 : */
50 :
51 413881 : int CPL_STDCALL GDALDummyProgress(double /* dfComplete */,
52 : const char * /* pszMessage */,
53 : void * /* pData */)
54 : {
55 413881 : return TRUE;
56 : }
57 :
58 : /************************************************************************/
59 : /* GDALScaledProgress() */
60 : /************************************************************************/
61 : typedef struct
62 : {
63 : GDALProgressFunc pfnProgress;
64 : void *pData;
65 : double dfMin;
66 : double dfMax;
67 : } GDALScaledProgressInfo;
68 :
69 : /**
70 : * \brief Scaled progress transformer.
71 : *
72 : * This is the progress function that should be passed along with the
73 : * callback data returned by GDALCreateScaledProgress().
74 : */
75 :
76 292301 : int CPL_STDCALL GDALScaledProgress(double dfComplete, const char *pszMessage,
77 : void *pData)
78 :
79 : {
80 292301 : GDALScaledProgressInfo *psInfo =
81 : reinterpret_cast<GDALScaledProgressInfo *>(pData);
82 :
83 : // Optimization if GDALCreateScaledProgress() provided with
84 : // GDALDummyProgress.
85 292301 : if (psInfo == nullptr)
86 234439 : return TRUE;
87 :
88 115724 : return psInfo->pfnProgress(dfComplete * (psInfo->dfMax - psInfo->dfMin) +
89 57862 : psInfo->dfMin,
90 57862 : pszMessage, psInfo->pData);
91 : }
92 :
93 : /************************************************************************/
94 : /* GDALCreateScaledProgress() */
95 : /************************************************************************/
96 :
97 : /**
98 : * \brief Create scaled progress transformer.
99 : *
100 : * Sometimes when an operations wants to report progress it actually
101 : * invokes several subprocesses which also take GDALProgressFunc()s,
102 : * and it is desirable to map the progress of each sub operation into
103 : * a portion of 0.0 to 1.0 progress of the overall process. The scaled
104 : * progress function can be used for this.
105 : *
106 : * For each subsection a scaled progress function is created and
107 : * instead of passing the overall progress func down to the sub functions,
108 : * the GDALScaledProgress() function is passed instead.
109 : *
110 : * @param dfMin the value to which 0.0 in the sub operation is mapped.
111 : * @param dfMax the value to which 1.0 is the sub operation is mapped.
112 : * @param pfnProgress the overall progress function.
113 : * @param pData the overall progress function callback data.
114 : *
115 : * @return pointer to pass as pProgressArg to sub functions. Should be freed
116 : * with GDALDestroyScaledProgress().
117 : *
118 : * Example:
119 : *
120 : * \code
121 : * int MyOperation( ..., GDALProgressFunc pfnProgress, void *pProgressData );
122 : *
123 : * {
124 : * void *pScaledProgress;
125 : *
126 : * pScaledProgress = GDALCreateScaledProgress( 0.0, 0.5, pfnProgress,
127 : * pProgressData );
128 : * GDALDoLongSlowOperation( ..., GDALScaledProgress, pScaledProgress );
129 : * GDALDestroyScaledProgress( pScaledProgress );
130 : *
131 : * pScaledProgress = GDALCreateScaledProgress( 0.5, 1.0, pfnProgress,
132 : * pProgressData );
133 : * GDALDoAnotherOperation( ..., GDALScaledProgress, pScaledProgress );
134 : * GDALDestroyScaledProgress( pScaledProgress );
135 : *
136 : * return ...;
137 : * }
138 : * \endcode
139 : */
140 :
141 491362 : void *CPL_STDCALL GDALCreateScaledProgress(double dfMin, double dfMax,
142 : GDALProgressFunc pfnProgress,
143 : void *pData)
144 :
145 : {
146 491362 : if (pfnProgress == nullptr || pfnProgress == GDALDummyProgress)
147 487630 : return nullptr;
148 :
149 : GDALScaledProgressInfo *psInfo = static_cast<GDALScaledProgressInfo *>(
150 3732 : CPLCalloc(sizeof(GDALScaledProgressInfo), 1));
151 :
152 3732 : if (std::abs(dfMin - dfMax) < 0.0000001)
153 163 : dfMax = dfMin + 0.01;
154 :
155 3732 : psInfo->pData = pData;
156 3732 : psInfo->pfnProgress = pfnProgress;
157 3732 : psInfo->dfMin = dfMin;
158 3732 : psInfo->dfMax = dfMax;
159 :
160 3732 : return static_cast<void *>(psInfo);
161 : }
162 :
163 : /************************************************************************/
164 : /* GDALDestroyScaledProgress() */
165 : /************************************************************************/
166 :
167 : /**
168 : * \brief Cleanup scaled progress handle.
169 : *
170 : * This function cleans up the data associated with a scaled progress function
171 : * as returned by GADLCreateScaledProgress().
172 : *
173 : * @param pData scaled progress handle returned by GDALCreateScaledProgress().
174 : */
175 :
176 491288 : void CPL_STDCALL GDALDestroyScaledProgress(void *pData)
177 :
178 : {
179 491288 : CPLFree(pData);
180 491287 : }
181 :
182 : /************************************************************************/
183 : /* GDALTermProgress() */
184 : /************************************************************************/
185 :
186 : /**
187 : * \fn GDALTermProgress(double, const char*, void*)
188 : * \brief Simple progress report to terminal.
189 : *
190 : * This progress reporter prints simple progress report to the
191 : * terminal window. The progress report generally looks something like
192 : * this:
193 :
194 : \verbatim
195 : 0...10...20...30...40...50...60...70...80...90...100 - done.
196 : \endverbatim
197 :
198 : * Every 2.5% of progress another number or period is emitted. Note that
199 : * GDALTermProgress() uses internal static data to keep track of the last
200 : * percentage reported and will get confused if two terminal based progress
201 : * reportings are active at the same time.
202 : *
203 : * The GDALTermProgress() function maintains an internal memory of the
204 : * last percentage complete reported in a static variable, and this makes
205 : * it unsuitable to have multiple GDALTermProgress()'s active either in a
206 : * single thread or across multiple threads.
207 : *
208 : * @param dfComplete completion ratio from 0.0 to 1.0.
209 : * @param pszMessage optional message.
210 : * @param pProgressArg ignored callback data argument.
211 : *
212 : * @return Always returns TRUE indicating the process should continue.
213 : */
214 :
215 22789 : int CPL_STDCALL GDALTermProgress(double dfComplete,
216 : CPL_UNUSED const char *pszMessage,
217 : CPL_UNUSED void *pProgressArg)
218 : {
219 : const int nThisTick =
220 22789 : std::min(40, std::max(0, static_cast<int>(dfComplete * 40.0)));
221 :
222 : // Have we started a new progress run?
223 : static int nLastTick = -1;
224 22789 : if (nThisTick < nLastTick && nLastTick >= 39)
225 18 : nLastTick = -1;
226 :
227 22789 : if (nThisTick <= nLastTick)
228 16782 : return TRUE;
229 :
230 21192 : while (nThisTick > nLastTick)
231 : {
232 15185 : ++nLastTick;
233 15185 : if (nLastTick % 4 == 0)
234 4113 : fprintf(stdout, "%d", (nLastTick / 4) * 10);
235 : else
236 11072 : fprintf(stdout, ".");
237 : }
238 :
239 6007 : if (nThisTick == 40)
240 368 : fprintf(stdout, " - done.\n");
241 : else
242 5639 : fflush(stdout);
243 :
244 6007 : return TRUE;
245 : }
|