/*========================================================================= * * Copyright NumFOCUS * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0.txt * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * *=========================================================================*/ /*========================================================================= * * Portions of this file are subject to the VTK Toolkit Version 3 copyright. * * Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen * * For complete copyright, license and disclaimer of warranty information * please refer to the NOTICE file at the top of the ITK source tree. * *=========================================================================*/ #ifndef itkProcessObject_h #define itkProcessObject_h #include "itkDataObject.h" #include "itkObjectFactory.h" #include "itkNumericTraits.h" #include "itkThreadSupport.h" #include "itkIntTypes.h" #include #include #include #include #include namespace itk { class MultiThreaderBase; /** \class ProcessObject * \brief The base class for all process objects (source, * filters, mappers) in the Insight data processing pipeline. * * ProcessObject is an abstract object that specifies behavior and * interface of network process objects (sources, filters, * mappers). Source objects are creators of visualization data; * filters input, process, and output image data; and mappers * transform data into another form (like transforming coordinates or * writing data to a file). * * A major role of ProcessObject is to define the inputs and outputs * of a filter. More than one input and/or output may exist for a given * filter. Some classes (e.g., source objects or mapper objects) will * not use inputs (the source) or outputs (mappers). In this case, the * inputs or outputs is just ignored. * * VOCABULARY: * - named entry - an entry indexed by a DataObjectIdentifierType or string. * - index entry - an entry indexed by an integer, which also always has a * string identifier. * - define an input/output - adds a named entry or a indexed entry. * - required input - a precondition that the inputs is set before updating. * - set the value - set the value of an input or output, and * automatically define the entry if it does not exist. * * \note * - The Primary Input is always defined internally, and is handled as * a special case for many methods. * - Some inputs can be defined as required. Either explicitly by * name or the older ITKv3 style where a certain number of index * inputs are required. * * The inputs and outputs are referenced by name and optionally by an * integer index. The \b Primary input and the \b Primary output play * a special role: they drive the pipeline. * * In addition to the reference by name, it is possible to access the * inputs and outputs with an index. The index by default is mapped * internally to a name with '_' followed by the index number. This * default name can be changed with the AddRequiredInputName * method. The indexed input or output 0 is mapped to the Primary * input or output. The name of the Primary input or output defaults * to "Primary", but this can be changed with SetPrimaryInputName and * SetPrimaryOutputName. * * For complicated filters which have optional, or varied required * inputs, named input access is preferred. However, indexed input * access provides constant time access to input and output * DataObjects, and so are more efficient. A name can also be * associated with an indexed input. Neither type of input or output * should be accessed in a tight loop. * * ProcessObject invokes the following events: * Command::StartEvent, Command::EndEvent * These are convenience events you can use for any purpose * (e.g., debugging info, highlighting/notifying user interface, etc.) * See Command and LightObject for information on using AddObserver. * * Another event Command::ProgressEvent can be observed. Some filters invoke * this event periodically during their execution (with the progress, * parameter, the fraction of work done). The use is similar to that of * StartEvent and EndEvent. Filters may also check their * AbortGenerateData flag to determine whether to prematurely end their * execution. * * An important feature of subclasses of ProcessObject is that it is * possible to control the memory-management model (i.e., retain * output versus delete output data). The ReleaseDataFlag enables the * deletion of the output data once the downstream process object * finishes processing the data (please see text). The * ReleaseDataBeforeUpdateFlag enables the deletion of the * ProcessObject's output data from a previous update if that output * data is slated to be regenerated by the pipeline process. Setting * this flag can control peak memory usage during a subsequent * pipeline update. For a ProcessObject, the ReleaseDataFlag defaults * to false and the ReleaseDataBeforeUpdateFlag defaults to true. * Some subclasses of ProcessObject, for example ImageSource, use a * default setting of false for the ReleaseDataBeforeUpdateFlag. * * Subclasses of ProcessObject may override 4 of the methods of this class * to control how a given filter may interact with the pipeline (dataflow). * These methods are: GenerateOutputInformation(), * EnlargeOutputRequestedRegion(), GenerateInputRequestedRegion(), and * GenerateOutputRequestedRegion(). By overriding these methods, a filter * can deviate from the base assumptions of the pipeline execution model. * * \ingroup ITKSystemObjects * \ingroup DataProcessing * * \ingroup ITKCommon */ class ITKCommon_EXPORT ProcessObject : public Object { public: ITK_DISALLOW_COPY_AND_MOVE(ProcessObject); /** Standard class type aliases. */ using Self = ProcessObject; using Superclass = Object; using Pointer = SmartPointer; using ConstPointer = SmartPointer; /** \see LightObject::GetNameOfClass() */ itkOverrideGetNameOfClassMacro(ProcessObject); /** Smart Pointer type to a DataObject. */ using DataObjectPointer = DataObject::Pointer; /** STL array of const pointer to the data objects */ // using ConstDataObjectPointerArray = std::vector< const DataObject * >; /** STL array of pointer to the data objects */ using DataObjectPointerArray = std::vector; using DataObjectIdentifierType = DataObject::DataObjectIdentifierType; /** STL array of data object names */ using NameArray = std::vector; //** Type of general multi-threader interface */ using MultiThreaderType = MultiThreaderBase; /** \brief Return an array with the names of the inputs defined. * * The names are ordered lexicographically, and match the order of the * data object produced by GetInputs(). */ NameArray GetInputNames() const; /** Return an array with the names of the required inputs. */ NameArray GetRequiredInputNames() const; /** \brief Return an array of DataObjects with the defined named inputs. * * The order of the inputs matches the order of the input names produced * by GetInputNames(). */ DataObjectPointerArray GetInputs(); /** Return true if the input with this name is defined */ bool HasInput(const DataObjectIdentifierType & key) const; using DataObjectPointerArraySizeType = DataObjectPointerArray::size_type; /** \brief Get the size of the input container. * * If the Primary input is nullptr it is not counted. This is * not the number of inputs that have valid DataObject's * assigned. Use GetNumberOfValidRequiredInputs() to determine how * many inputs are non-null. * * \sa GetNumberOfValidRequiredInputs * \sa GetNumberOfIndexedInputs */ DataObjectPointerArraySizeType GetNumberOfInputs() const; /** \brief Get the size of the output container. */ DataObjectPointerArraySizeType GetNumberOfOutputs() const; /** \brief Return an array with the defined names of the outputs. * * The names are ordered lexicographically, and match the order of the * data object produced by GetOutputs() */ NameArray GetOutputNames() const; /** \brief Return an array with the defined named outputs. * * The order of the outputs match the order of the input names produced * by GetOutputNames(). */ DataObjectPointerArray GetOutputs(); /** \brief Return true if the output with this name is defined. */ bool HasOutput(const DataObjectIdentifierType & key) const; /** \brief Return an array with all the indexed inputs. */ DataObjectPointerArray GetIndexedInputs(); /** \brief Get the number of defined Indexed inputs. * * This is merely the size of the index input vector, not the number * of inputs that have valid DataObject's assigned. The \b Primary * inputs is handled as a special case. Use * GetNumberOfValidRequiredInputs() to determine how many indexed * inputs are non-null. * * All indexed inputs up to this value are defined. * * \sa GetNumberOfInputs * \sa GetNumberOfValidRequiredInputs */ DataObjectPointerArraySizeType GetNumberOfIndexedInputs() const; /** \brief Get the number of valid \b indexed inputs. * * Returns the number of non-null indexed inputs. This method is * used to determine whether the correct number of inputs are set to * valid values. * * \sa GetNumberOfInputs * \sa GetNumberOfIndexedInputs */ virtual DataObjectPointerArraySizeType GetNumberOfValidRequiredInputs() const; /** \brief Return an array with the indexed outputs. */ DataObjectPointerArray GetIndexedOutputs(); /** \brief The number of defined Indexed outputs. */ DataObjectPointerArraySizeType GetNumberOfIndexedOutputs() const; /** \brief Make a DataObject of the correct type to used as the specified output. * * Every ProcessObject subclass must be able to create a * DataObject that can be used as a specified output. This method * is automatically called when DataObject::DisconnectPipeline() is * called. DataObject::DisconnectPipeline, disconnects a data object * from being an output of its current source. When the data object * is disconnected, the ProcessObject needs to construct a replacement * output data object so that the ProcessObject is in a valid state. * So DataObject::DisconnectPipeline eventually calls * ProcessObject::MakeOutput. Note that MakeOutput always returns a * itkSmartPointer to a DataObject. ImageSource and MeshSource override * this method to create the correct type of image and mesh respectively. * If a filter has multiple outputs of different types, then that * filter must provide an implementation of MakeOutput(). */ virtual DataObjectPointer MakeOutput(DataObjectPointerArraySizeType idx); /** \brief Set the AbortGenerateData flag for the process object. * * Process objects may handle premature termination of execution in * different ways. */ itkSetMacro(AbortGenerateData, bool); /** \brief Get the AbortGenerateData flag for the process object. */ itkGetConstReferenceMacro(AbortGenerateData, bool); /** \brief Turn on and off the AbortGenerateData flag. */ itkBooleanMacro(AbortGenerateData); /** \deprecated * Set the execution progress of a process object. The progress is * a floating number in [0,1] with 0 meaning no progress and 1 meaning * the filter has completed execution. The ProgressEvent is NOT * invoked. * This method is deprecated because filters should not be calling * SetProgress directly but should be using UpdateProgress or IncrementProgress instead. */ #if !defined(ITK_LEGACY_REMOVE) void SetProgress(float progress) { m_Progress = progressFloatToFixed(progress); } #endif /** \brief Get the execution progress of a process object. * * The progress is a floating number in [0,1] with 0 meaning no * progress and 1 meaning the filter has completed execution. */ virtual float GetProgress() const { return progressFixedToFloat(m_Progress); } /** \brief Update the progress of the process object. * * Sets the Progress ivar to amount and invokes any observers for * the ProgressEvent. The parameter amount should be in [0,1] and is * the cumulative (not incremental) progress. * * Multiple thread should not call this method, since they may have computed different values and increments may get * lost. */ void UpdateProgress(float progress); /** \brief Increment the progress of the process object. * * Atomically add the current progress and may invoke observers of the ProgressEvent. Progress is represented in * [0.0,1.0] or percentage. This method will invoke the ProgressEvent when called by the same as the pipeline. * * Multiple threads may call this method and the total progress will be atomically incremented. */ void IncrementProgress(float increment); /** \brief Bring this filter up-to-date. * * Update() checks modified times against * last execution times, and re-executes objects if necessary. A side * effect of this method is that the whole pipeline may execute * in order to bring this filter up-to-date. This method updates the * currently prescribed requested region. If no requested region has * been set on the output, then the requested region will be set to the * largest possible region. Once the requested region is set, Update() * will make sure the specified requested region is up-to-date. This * is a confusing side effect to users who are just calling Update() on * a filter. A first call to Update() will cause the largest possible * region to be updated. A second call to Update() will update that * same region. If a modification to the upstream pipeline cause a * filter to have a different largest possible region, this second * call to Update() will not cause the output requested region to be * reset to the new largest possible region. Instead, the output requested * region will be the same as the last time Update() was called. To have * a filter always to produce its largest possible region, users should * call UpdateLargestPossibleRegion() instead. */ virtual void Update(); /** \brief Sets the output requested region to the largest possible * region and updates. * * This is the method users * should call if they want the entire dataset to be processed. If * a user wants to update the same output region as a previous call * to Update() or a previous call to UpdateLargestPossibleRegion(), * then they should call the method Update(). */ virtual void UpdateLargestPossibleRegion(); /** \brief Update the information describing the output data. * * This method * traverses up the pipeline gathering modified time information. * On the way back down the pipeline, this method calls * GenerateOutputInformation() to set any necessary information * about the output data objects. For instance, a filter that * shrinks an image will need to provide an implementation for * GenerateOutputInformation() that changes the spacing of the * pixels. Such filters should call their superclass' implementation * of GenerateOutputInformation prior to changing the information * values they need (i.e. GenerateOutputInformation() should call * Superclass::GenerateOutputInformation() prior to changing the * information. */ virtual void UpdateOutputInformation(); /** Send the requested region information back up the pipeline (to the * filters that precede this one). */ virtual void PropagateRequestedRegion(DataObject * output); /** Actually generate new output */ virtual void UpdateOutputData(DataObject * output); /** Give the process object a chance to indicate that it will produce more * output than it was requested to produce. For example, many imaging * filters must compute the entire output at once or can only produce output * in complete slices. Such filters cannot handle smaller requested regions. * These filters must provide an implementation of this method, setting * the output requested region to the size they will produce. By default, * a process object does not modify the size of the output requested * region. */ virtual void EnlargeOutputRequestedRegion(DataObject * itkNotUsed(output)) {} /** \brief Reset the pipeline. * * If an exception is thrown during an Update(), * the pipeline may be in an inconsistent state. This method clears * the internal state of the pipeline so Update() can be called. */ virtual void ResetPipeline(); /** \brief Make a DataObject of the correct type to used as the specified output. * * Every ProcessObject subclass must be able to create a * DataObject that can be used as a specified output. This method * is automatically called when DataObject::DisconnectPipeline() is * called. DataObject::DisconnectPipeline, disconnects a data object * from being an output of its current source. When the data object * is disconnected, the ProcessObject needs to construct a replacement * output data object so that the ProcessObject is in a valid state. * So DataObject::DisconnectPipeline eventually calls * ProcessObject::MakeOutput. Note that MakeOutput always returns a * itkSmartPointer to a DataObject. ImageSource and MeshSource override * this method to create the correct type of image and mesh respectively. * If a filter has multiple outputs of different types, then that * filter must provide an implementation of MakeOutput(). */ virtual DataObjectPointer MakeOutput(const DataObjectIdentifierType &); /** Turn on/off the flags to control whether the bulk data belonging * to the outputs of this ProcessObject are released after being * used by a downstream ProcessObject. Default value is off. Another * options for controlling memory utilization is the * ReleaseDataBeforeUpdateFlag. */ virtual void SetReleaseDataFlag(bool val); virtual bool GetReleaseDataFlag() const; void ReleaseDataFlagOn() { this->SetReleaseDataFlag(true); } void ReleaseDataFlagOff() { this->SetReleaseDataFlag(false); } /** Turn on/off the flags to control whether the bulk data belonging * to the outputs of this ProcessObject are released/reallocated * during an Update(). In limited memory scenarios, a user may want * to force the elements of a pipeline to release any bulk data that * is going to be regenerated anyway during an Update() in order to * control peak memory allocation. Note that this flag is different * from the ReleaseDataFlag. ReleaseDataFlag manages the * deallocation of a ProcessObject's bulk output data once that data * has been consumed by a downstream ProcessObject. The * ReleaseDataBeforeUpdateFlag manages the deallocation/reallocation * of bulk data during a pipeline update to control peak memory * utilization. Default value is on. */ itkSetMacro(ReleaseDataBeforeUpdateFlag, bool); itkGetConstReferenceMacro(ReleaseDataBeforeUpdateFlag, bool); itkBooleanMacro(ReleaseDataBeforeUpdateFlag); /** Get/Set the number of work units to create when executing. */ itkSetClampMacro(NumberOfWorkUnits, ThreadIdType, 1, ITK_MAX_THREADS); itkGetConstReferenceMacro(NumberOfWorkUnits, ThreadIdType); #if !defined(ITK_LEGACY_REMOVE) || defined(ITKV4_COMPATIBILITY) itkLegacyMacro(void SetNumberOfThreads(ThreadIdType count)) { this->SetNumberOfWorkUnits(count); } itkLegacyMacro(ThreadIdType GetNumberOfThreads() const) { return this->GetNumberOfWorkUnits(); } #endif // !ITK_LEGACY_REMOVE /** Return the multithreader used by this class. */ MultiThreaderType * GetMultiThreader() const { return m_MultiThreader; } /** Set the multithreader used by this class. */ void SetMultiThreader(MultiThreaderType * threader); /** An opportunity to deallocate a ProcessObject's bulk data * storage. Some filters may wish to reuse existing bulk data * storage to avoid unnecessary deallocation/allocation * sequences. The default implementation calls Initialize() on each * output. DataObject::Initialize() frees its bulk data by default. */ virtual void PrepareOutputs(); protected: ProcessObject(); ~ProcessObject() override; void PrintSelf(std::ostream & os, Indent indent) const override; // // Input Methods // /** \brief Return an input. * * nullptr is returned if the name or indexed input is undefined. */ DataObject * GetInput(const DataObjectIdentifierType & key); const DataObject * GetInput(const DataObjectIdentifierType & key) const; /** Method used internally for getting an indexed input. */ DataObject * GetInput(DataObjectPointerArraySizeType idx) { return idx < m_IndexedInputs.size() ? m_IndexedInputs[idx]->second.GetPointer() : nullptr; } const DataObject * GetInput(DataObjectPointerArraySizeType idx) const { return idx < m_IndexedInputs.size() ? m_IndexedInputs[idx]->second.GetPointer() : nullptr; } /** \brief Protected method for setting indexed and named inputs. * * Subclasses make use of them for setting input. As this method * only used the base DataObject pointer, derived classes should * expose a type check methods. */ virtual void SetInput(const DataObjectIdentifierType & key, DataObject * input); virtual void SetNthInput(DataObjectPointerArraySizeType idx, DataObject * input); /** Sets first nullptr indexed input, appends to the end otherwise */ virtual void AddInput(DataObject * input); /** \brief Push/Pop an indexed input of this process object. * * These methods allow a * filter to model its input vector as a queue or stack. These * routines may not be appropriate for all filters, especially * filters with different types of inputs. These routines follow * the semantics of STL. */ virtual void PushBackInput(const DataObject * input); virtual void PopBackInput(); virtual void PushFrontInput(const DataObject * input); virtual void PopFrontInput(); /** \brief Remove an input. * * If the input is the last indexed input the number of indexed * inputs will be reduced by one. Otherwise, if the input is * required or indexed it will be set to nullptr. */ virtual void RemoveInput(const DataObjectIdentifierType & key); virtual void RemoveInput(DataObjectPointerArraySizeType); /** Return the main input */ DataObject * GetPrimaryInput() { return m_IndexedInputs[0]->second; } const DataObject * GetPrimaryInput() const { return m_IndexedInputs[0]->second; } /** Set/Get the name associated with the Primary input. Defaults to "Primary". */ virtual void SetPrimaryInputName(const DataObjectIdentifierType & key); virtual const char * GetPrimaryInputName() const { return this->m_IndexedInputs[0]->first.c_str(); } /** Set the main input */ virtual void SetPrimaryInput(DataObject * object); /** \brief Define the number of indexed inputs defined. * * The new indexed inputs' values are set to * nullptr. If the size is reduced then the input definition is * removed entirely from the named input entries and index inputs. */ void SetNumberOfIndexedInputs(DataObjectPointerArraySizeType num); /** \brief Set the number of required \b indexed inputs. * * If an input is not associated with an index and only a named * entry, it is not considered in this count. In the method * VerifyPreconditions(), GetNumberOfValidRequiredInputs() is * checked to be at least this value. * * \note SetNumberOfRequiredIndexInputs maybe a better name. */ virtual void SetNumberOfRequiredInputs(DataObjectPointerArraySizeType); itkGetConstReferenceMacro(NumberOfRequiredInputs, DataObjectPointerArraySizeType); /** \brief Remove the named input from the required inputs * * The named input remains defined or set afterwards. */ bool RemoveRequiredInputName(const DataObjectIdentifierType &); /** \brief Query if the named input is required by name. */ bool IsRequiredInputName(const DataObjectIdentifierType &) const; /** \brief Set all required named inputs. * * All named inputs remain defined or set. */ void SetRequiredInputNames(const NameArray &); /** \brief Define a required named input and optionally associate it * with a numbered index. * * The previous named input associated with idx will be removed from * the defined input names. * * If the specified named inputs already exists with a non-null * value, then that value will be used. Otherwise if the specified * index has a non-null value, then that will be the value set. */ bool AddRequiredInputName(const DataObjectIdentifierType &); bool AddRequiredInputName(const DataObjectIdentifierType &, DataObjectPointerArraySizeType idx); /** \brief Define a named input that is not required and optionally * associate with a numbered index. * * The previous named input associated with idx will be removed from * the defined input names. * * If the specified named inputs already exists with a non-null * value, then that value will be used. Otherwise if the specified * index has a non-null value, then that will be the value set. */ void AddOptionalInputName(const DataObjectIdentifierType &); void AddOptionalInputName(const DataObjectIdentifierType &, DataObjectPointerArraySizeType idx); // // Output Methods // /** Return an output */ DataObject * GetOutput(const DataObjectIdentifierType & key); const DataObject * GetOutput(const DataObjectIdentifierType & key) const; /** Set/Get the name associated with the Primary output. Defaults to "Primary". */ virtual void SetPrimaryOutputName(const DataObjectIdentifierType & key); virtual const char * GetPrimaryOutputName() const { return this->m_IndexedOutputs[0]->first.c_str(); } /** Method used internally for getting an indexed output. */ DataObject * GetOutput(DataObjectPointerArraySizeType i); const DataObject * GetOutput(DataObjectPointerArraySizeType i) const; /** Set an output */ virtual void SetOutput(const DataObjectIdentifierType & name, DataObject * output); /** Remove an output */ virtual void RemoveOutput(const DataObjectIdentifierType & key); /** Return the main output */ DataObject * GetPrimaryOutput() { return m_IndexedOutputs[0]->second; } const DataObject * GetPrimaryOutput() const { return m_IndexedOutputs[0]->second; } /** Set the main output */ virtual void SetPrimaryOutput(DataObject * object); /** Protected methods for setting outputs. * Subclasses make use of them for getting output. */ virtual void SetNthOutput(DataObjectPointerArraySizeType idx, DataObject * output); virtual void AddOutput(DataObject * output); virtual void RemoveOutput(DataObjectPointerArraySizeType idx); itkSetMacro(NumberOfRequiredOutputs, DataObjectPointerArraySizeType); itkGetConstReferenceMacro(NumberOfRequiredOutputs, DataObjectPointerArraySizeType); /** Called to allocate the output array. Copies old outputs. */ void SetNumberOfIndexedOutputs(DataObjectPointerArraySizeType num); DataObjectIdentifierType MakeNameFromInputIndex(DataObjectPointerArraySizeType idx) const; DataObjectIdentifierType MakeNameFromOutputIndex(DataObjectPointerArraySizeType idx) const; DataObjectPointerArraySizeType MakeIndexFromInputName(const DataObjectIdentifierType & name) const; DataObjectPointerArraySizeType MakeIndexFromOutputName(const DataObjectIdentifierType & name) const; bool IsIndexedInputName(const DataObjectIdentifierType &) const; bool IsIndexedOutputName(const DataObjectIdentifierType &) const; // // Pipeline Methods // /** \brief Verifies that the process object has been configured * correctly, that all required inputs are set, and needed parameters * are set appropriately. If not valid an exceptions will be thrown. * * This method is called before UpdateOutputInformation() is * propagated to the inputs. * * The ProcessObject's implementation verifies that the * #m_NumberOfRequiredInputs are set and not null. * */ virtual void VerifyPreconditions() ITKv5_CONST; /** \brief Verifies that the inputs meta-data is consistent and valid * for continued execution of the pipeline, throws an exception if * not valid. * * This method is called immediately before GenerateOutputInformation(). * * The ProcessObject implementation does nothing. Subclasses might * check if all the inputs are in the same coordinate frame. * */ virtual void VerifyInputInformation() ITKv5_CONST; /** What is the input requested region that is required to produce the * output requested region? By default, the largest possible region is * always required but this is overridden in many subclasses. For instance, * for an image processing filter where an output pixel is a simple function * of an input pixel, the input requested region will be set to the output * requested region. For an image processing filter where an output pixel * is a function of the pixels in a neighborhood of an input pixel, then * the input requested region will need to be larger than the output * requested region (to avoid introducing artificial boundary conditions). * This function should never request an input region that is outside the * the input largest possible region (i.e. implementations of this method * should crop the input requested region at the boundaries of the input * largest possible region). */ virtual void GenerateInputRequestedRegion(); /** Given one output whose requested region has been set, how should * the requested regions for the remaining outputs of the process object * be set? By default, all the outputs are set to the same requested * region. If a filter needs to produce different requested regions * for each output, for instance an image processing filter producing * several outputs at different resolutions, then that filter may * override this method and set the requested regions appropriately. * * Note that a filter producing multiple outputs of different types is * required to override this method. The default implementation * can only correctly handle multiple outputs of the same type. */ virtual void GenerateOutputRequestedRegion(DataObject * output); /** Generate the information describing the output data. The default * implementation of this method will copy information from the input to * the output. A filter may override this method if its output will have * different information than its input. For instance, a filter that * shrinks an image will need to provide an implementation for this * method that changes the spacing of the pixels. Such filters should call * their superclass' implementation of this method prior to changing the * information values they need (i.e. GenerateOutputInformation() should * call Superclass::GenerateOutputInformation() prior to changing the * information. */ virtual void GenerateOutputInformation(); /** This method causes the filter to generate its output. */ virtual void GenerateData() {} /** Called to allocate the input array. Copies old inputs. */ /** Propagate a call to ResetPipeline() up the pipeline. Called only from * DataObject. */ virtual void PropagateResetPipeline(); /** A filter may need to release its input's bulk data after it has * finished calculating a new output. The filter may need to release * the inputs because the user has turned on the ReleaseDataFlag or * it may need to release the inputs because the filter is an "in * place" filter and it has overwritten its input with its output * data. The implementation here simply checks the ReleaseDataFlag * of the inputs. InPlaceImageFilter overrides this method so * release the input it has overwritten. * * \sa InPlaceImageFilter::ReleaseInputs() */ virtual void ReleaseInputs(); /** * Cache the state of any ReleaseDataFlag's on the inputs. While the * filter is executing, we need to set the ReleaseDataFlag's on the * inputs to false in case the current filter is implemented using a * mini-pipeline (which will try to release the inputs). After the * filter finishes, we restore the state of the ReleaseDataFlag's * before the call to ReleaseInputs(). */ virtual void CacheInputReleaseDataFlags(); /** * Restore the cached input ReleaseDataFlags. */ virtual void RestoreInputReleaseDataFlags(); /** * When true, the MultiThreader will report course grain progress. If set to false, a progress must be explicitly * updated in derived filters. */ itkGetConstMacro(ThreaderUpdateProgress, bool); itkBooleanMacro(ThreaderUpdateProgress); virtual void SetThreaderUpdateProgress(bool arg); /** * Internal method to convert internal integer progress to float [0.0, 1.0] */ static inline constexpr float progressFixedToFloat(uint32_t fixed) { return static_cast(fixed) / static_cast(std::numeric_limits::max()); }; /** * Internal method convert floating point progress [0.0, 1.0] to internal integer representation. Values outside the * [0.0, 1.0] range are clamped. */ static inline uint32_t progressFloatToFixed(float f) { if (f <= 0.0f) { return 0; } if (f >= 1.0f) { return std::numeric_limits::max(); } double temp = static_cast(f) * std::numeric_limits::max(); return static_cast(temp); }; /** These ivars are made protected so filters like itkStreamingImageFilter * can access them directly. */ /** This flag indicates when the pipeline is executing. * It prevents infinite recursion when pipelines have loops. */ bool m_Updating{}; /** Time when GenerateOutputInformation was last called. */ TimeStamp m_OutputInformationMTime{}; private: DataObjectIdentifierType MakeNameFromIndex(DataObjectPointerArraySizeType) const; DataObjectPointerArraySizeType MakeIndexFromName(const DataObjectIdentifierType &) const; /** STL map to store the named inputs and outputs */ using DataObjectPointerMap = std::map; /** Named input and outputs containers */ DataObjectPointerMap m_Inputs{}; DataObjectPointerMap m_Outputs{}; std::vector m_IndexedInputs{}; std::vector m_IndexedOutputs{}; /** An array that caches the ReleaseDataFlags of the inputs */ std::map m_CachedInputReleaseDataFlags{}; DataObjectPointerArraySizeType m_NumberOfRequiredInputs{}; DataObjectPointerArraySizeType m_NumberOfRequiredOutputs{}; /** STL map to store the named inputs and outputs */ using NameSet = std::set; /** The required inputs */ NameSet m_RequiredInputNames{}; /** These support the progress method and aborting filter execution. */ bool m_AbortGenerateData{}; std::atomic m_Progress{}; std::thread::id m_UpdateThreadID{}; /** Support processing data in multiple threads. Used by subclasses * (e.g., ImageSource). */ itk::SmartPointer m_MultiThreader; ThreadIdType m_NumberOfWorkUnits{}; bool m_ThreaderUpdateProgress{ true }; /** Memory management ivars */ bool m_ReleaseDataBeforeUpdateFlag{}; /** Friends of ProcessObject */ friend class DataObject; friend class ProgressReporter; friend class TotalProgressReporter; friend class DataObjectConstIterator; friend class InputDataObjectConstIterator; friend class OutputDataObjectConstIterator; friend class DataObjectIterator; friend class InputDataObjectIterator; friend class OutputDataObjectIterator; friend class TestProcessObject; }; } // end namespace itk #endif