1 /*=========================================================================
2  *
3  *  Copyright Insight Software Consortium
4  *
5  *  Licensed under the Apache License, Version 2.0 (the "License");
6  *  you may not use this file except in compliance with the License.
7  *  You may obtain a copy of the License at
8  *
9  *         http://www.apache.org/licenses/LICENSE-2.0.txt
10  *
11  *  Unless required by applicable law or agreed to in writing, software
12  *  distributed under the License is distributed on an "AS IS" BASIS,
13  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  *  See the License for the specific language governing permissions and
15  *  limitations under the License.
16  *
17  *=========================================================================*/
18 #ifndef itkProgressAccumulator_h
19 #define itkProgressAccumulator_h
20 
21 #include "itkCommand.h"
22 #include "itkProcessObject.h"
23 #include <vector>
24 
25 namespace itk
26 {
27 /**
28  * \class ProgressAccumulator
29  * \brief Facilitates progress reporting for filters that wrap around
30  *        multiple other filters.
31  *
32  * This object allows a mini-pipeline filters to easily keep track of the
33  * progress performed by the internal filters.
34  * See DiscreteGaussianImageFilter.hxx for an implementation example.
35  *
36  * \sa DiscreteGaussianImageFilter
37  *
38  * \ingroup ITKCommon
39  */
40 class ITKCommon_EXPORT ProgressAccumulator:public Object
41 {
42 public:
43   /** Standard class type aliases. */
44   using Self = ProgressAccumulator;
45   using Superclass = Object;
46   using Pointer = SmartPointer< Self >;
47   using ConstPointer = SmartPointer< const Self >;
48 
49   /** Typedef for inputting filters */
50   using GenericFilterType = ProcessObject;
51   using GenericFilterPointer = GenericFilterType::Pointer;
52 
53   /** Standard New method. */
54   itkNewMacro(Self);
55 
56   /** Runtime information support. */
57   itkTypeMacro(ProgressAccumulator, Object);
58 
59   /** Get the total progress accumulated by this object */
60   itkGetConstMacro(AccumulatedProgress, float);
61 
62   /** Set the mini-pipeline filter */
63   itkSetObjectMacro(MiniPipelineFilter, ProcessObject);
64 
65   /** Set the mini-pipeline filter */
66   itkGetModifiableObjectMacro(MiniPipelineFilter, ProcessObject);
67 
68   /**
69    * Register a filter with the progress accumulator and specify the
70    * fraction of the overall progress associated with this filter.
71    * The sum of the weights for all filters that are registered should
72    * be 1.
73    * However, if streaming is used, the weight should be divided by the
74    * number of streams because each stream will reset the filter
75    * after capturing its progress.
76    * For example, if the desired weight of a filter is 0.4, but it is
77    * streamed into 4 streams, the weight should be 0.1.
78    * The ProgressAccumulator will then ensure that each of the 4 runs
79    * of this filter will add 0.1 to the filter's progress.
80    */
81   void RegisterInternalFilter(GenericFilterType *filter, float weight);
82 
83   /**
84    * Unregister all filters that have been registered with this object
85    */
86   void UnregisterAllFilters();
87 
88   /**
89    * \deprecated
90    * Reset the progress accumulator.  This method should not be necessary
91    * because this functionality is already present in the filter
92    * constructor.
93    */
94 #if ! defined ( ITK_LEGACY_REMOVE )
95   void ResetProgress();
96 #endif
97 
98   /**
99    * \deprecated
100    * Reset the filter progress but keep the accumulated progress.
101    * This method is deprecated because the ProgressAccumulator
102    * now internally checks if a filter has been restarted and updates
103    * the accumulated progress automatically.
104    * This method also used to have the unfortunate side effect of forcing
105    * filters to rerun even if their parameters and input had not changed.
106    * This is because it called SetProgress(0) on the filters, which
107    * triggered a ModifiedTime and thus caused the filters to rerun.
108    * To avoid this behavior, the implementation of this method is now empty.
109    */
110 #if ! defined ( ITK_LEGACY_REMOVE )
111   void ResetFilterProgressAndKeepAccumulatedProgress();
112 #endif
113 
114 protected:
115   ProgressAccumulator();
116   ~ProgressAccumulator() override;
117   void PrintSelf(std::ostream & s, Indent indent) const override;
118 
119 private:
120   /**  Command for observing progress of pipeline filters */
121   using CommandType = MemberCommand< Self >;
122   using CommandPointer = CommandType::Pointer;
123 
124   /** Structure associated with each filter in the pipeline */
125   struct FilterRecord {
126     // Pointer to the filter
127     GenericFilterPointer Filter;
128 
129     // The weight of the filter in total progress of the mini-pipeline
130     float Weight;
131 
132     // The tags for adding/removing observers to mini-pipeline filter
133     unsigned long ProgressObserverTag;
134     unsigned long StartObserverTag;
135   };
136 
137   /** A callback function that is called by the progressing filters */
138   void ReportProgress(Object *object, const EventObject & event);
139 
140   /** The client mini-pipeline filter */
141   GenericFilterPointer m_MiniPipelineFilter;
142 
143   /** An array of record structures */
144   using FilterRecordVector = std::vector< struct FilterRecord >;
145 
146   /** The total accumulated progress */
147   float m_AccumulatedProgress;
148 
149   /** The total accumulated progress for multiple runs of the mini-pipeline */
150   float m_BaseAccumulatedProgress;
151 
152   /**
153    * A list of progress proportions of the different filters in the
154    * pipeline
155    */
156   FilterRecordVector m_FilterRecord;
157 
158   /** The callback command */
159   CommandPointer m_CallbackCommand;
160 };
161 } // End namespace itk
162 
163 #endif // itkProgressAccumulator_h_
164