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 /*=========================================================================
19 *
20 * Portions of this file are subject to the VTK Toolkit Version 3 copyright.
21 *
22 * Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
23 *
24 * For complete copyright, license and disclaimer of warranty information
25 * please refer to the NOTICE file at the top of the ITK source tree.
26 *
27 *=========================================================================*/
28 #ifndef itkDataObject_h
29 #define itkDataObject_h
30
31 #include "itkObject.h"
32 #include "itkMacro.h"
33 #include "itkSingletonMacro.h"
34 #include "itkWeakPointer.h"
35 #include "itkRealTimeStamp.h"
36
37 namespace itk
38 {
39 // Forward reference because of circular dependencies
40 class ITK_FORWARD_EXPORT ProcessObject;
41 class ITK_FORWARD_EXPORT DataObject;
42
43 /*--------------------Data Object Exceptions---------------------------*/
44
45 /** \class DataObjectError
46 * \brief Exception object for DataObject exceptions.
47 * \ingroup ITKCommon
48 */
49 class ITKCommon_EXPORT DataObjectError:public ExceptionObject
50 {
51 public:
52 /** Default constructor. Needed to ensure the exception object can be
53 * copied. */
54 DataObjectError() noexcept;
55
56 /** Destructor. Need to specify empty throw() to avoid warnings. */
57 ~DataObjectError() noexcept override = default;
58
59 /** Constructor. Needed to ensure the exception object can be copied. */
60 DataObjectError(const char *file, unsigned int lineNumber);
61
62 /** Constructor. Needed to ensure the exception object can be copied. */
63 DataObjectError(const std::string & file, unsigned int lineNumber);
64
65 /** Copy constructor. Needed to ensure the exception object can be copied. */
66 DataObjectError(const DataObjectError & orig) noexcept;
67
68 /** Operator=. Needed to ensure the exception object can be copied. */
69 DataObjectError & operator=(const DataObjectError & orig) noexcept;
70
71 /** Standard type macro */
72 itkTypeMacro(DataObjectError, ExceptionObject);
73
74 /** Set the data object that is throwing this exception. */
75 void SetDataObject(DataObject *dobj) noexcept;
76
77 /** Get the data object that is throwing this exception. */
78 DataObject * GetDataObject() noexcept;
79
80 protected:
81 /** Print exception information. This method can be overridden by
82 * specific exception subtypes. The default is to print out the
83 * location where the exception was first thrown and any description
84 * provided by the "thrower". */
85 virtual void PrintSelf(std::ostream & os, Indent indent) const;
86
87 private:
88 DataObject *m_DataObject{nullptr};
89 };
90
91 /** \class InvalidRequestRegionError
92 * \brief Exception object for invalid requested region.
93 *
94 * Exception object for invalid requested region.
95 * \ingroup ITKCommon
96 */
97 class ITKCommon_EXPORT InvalidRequestedRegionError:public DataObjectError
98 {
99 public:
100 /** Default constructor. Needed to ensure the exception object can be copied.
101 */
102 InvalidRequestedRegionError() noexcept;
103
104 /** Destructor. Need to specify empty throw() to avoid warnings. */
105 ~InvalidRequestedRegionError() noexcept override = default;
106
107 /** Constructor. Needed to ensure the exception object can be copied. */
108 InvalidRequestedRegionError(const char *file, unsigned int lineNumber);
109
110 /** Constructor. Needed to ensure the exception object can be copied. */
111 InvalidRequestedRegionError(const std::string & file, unsigned int lineNumber);
112
113 /** Copy constructor. Needed to ensure the exception object can be copied. */
114 InvalidRequestedRegionError(const InvalidRequestedRegionError & orig) noexcept;
115
116 /** Operator=. Needed to ensure the exception object can be copied. */
117 InvalidRequestedRegionError & operator=(const InvalidRequestedRegionError & orig) noexcept;
118
119 /** Standard type macro */
120 itkTypeMacro(InvalidRequestedRegionError, DataObjectError);
121
122 protected:
123 /** Print exception information. This method can be overridden by
124 * specific exception subtypes. The default is to print out the
125 * location where the exception was first thrown and any description
126 * provided by the "thrower". */
127 void PrintSelf(std::ostream & os, Indent indent) const override;
128 };
129
130 /*----------------------------Data Object--------------------------------*/
131
132 /** \class DataObject
133 * \brief Base class for all data objects in ITK.
134 *
135 * This is the base class for all data objects in the Insight data
136 * processing pipeline. A data object is an object that represents and
137 * provides access to data. ProcessObjects (i.e., filters) operate on
138 * input data objects, producing new data objects as output.
139 * ProcessObject and DataObject are connected together into data flow
140 * pipelines.
141 *
142 * The data flow pipeline architecture requires that DataObjects and
143 * ProcessObjects negotiate the flow of information. When the tail of
144 * a pipeline is instructed to Update(), a series of requests are
145 * propagated up the pipeline (from a ProcessObject to its inputs
146 * (DataObjects), from these inputs to their sources (ProcessObjects),
147 * etc.). A call to Update() entails 3 passes up the pipeline (though
148 * not all passes will traverse the entire pipeline). The first pass
149 * up the pipeline determines when various components of the pipeline
150 * were last modified and hence which components will need to be
151 * updated. As this first pass in unwinding, meta information about
152 * the DataObjects (for instance image spacing and data size) are
153 * passed down the pipeline. The second pass up the pipeline
154 * propagates a request for a specific piece of information (for
155 * instance a sub-region of an image). A request for a piece of a
156 * DataObject is propagated to its source, from there to its inputs,
157 * etc. allowing each ProcessObject to determine whether (1) it can
158 * already satisfy the request (the requested block of data is already
159 * available) or (2) the ProcessObject will need to request a new
160 * block of data on input to satisfy the output request. Finally, a
161 * pass is made up the pipeline to actually calculate the values for
162 * the various blocks of data requested (i.e. pixel values are finally
163 * calculated). This final pass will only traverse up the pipeline as
164 * far as the first two passes have identified. For instance, to
165 * satisfy a given request at the tail of a pipeline, only the lower
166 * few ProcessObjects may have to re-execute.
167 *
168 * There are three types of information negotiated by the pipeline
169 * (prior to actual calculation of the bulk data): modified times,
170 * meta data, and regions. The modified times keep track of when
171 * various data objects were last modified and/updated and the when
172 * the various process objects were modified. The meta data is any
173 * extra information about the data object that is not part of the
174 * bulk data. For instance, an Image maintains pixel spacing and
175 * origin meta data. Finally, the pipeline negotiation process passes
176 * requests up the pipeline in the form of Regions. A DataObject can
177 * have as many as three regions (which themselves could be considered
178 * meta data): LargestPossibleRegion, RequestedRegion, and
179 * BufferedRegion. The LargestPossibleRegion is the entirety of the
180 * dataset (for instance how big is the dataset on disk).
181 * LargestPossibleRegions are negotiated during the first pass of a
182 * pipeline update (via the method
183 * ProcessObject::GenerateOutputInformation() which is called from
184 * ProcessObject::UpdateOutputInformation(). The RequestedRegion is
185 * the amount of the DataObject that is requested by the user or
186 * pipeline. RequestedRegions are negotiated during the second pass of
187 * a pipeline update (via the methods
188 * ProcessObject::EnlargeOutputRequestedRegion(),
189 * ProcessObject::GenerateOutputRequestedRegion(),
190 * ProcessObject::GenerateInputRequestedRegion() which are called from
191 * ProcessObject::PropagateRequestedRegion()). The BufferedRegion is
192 * the amount of the DataObject that is currently in memory.
193 * BufferedRegions are defined during the final pass of a pipeline
194 * update (when ProcessObjects finally calculate the bulk data via the
195 * methods ProcessObject::GenerateData() or
196 * ProcessObject::DynamicThreadedGenerateData() which are called by
197 * ProcessObject::UpdateOutputData()). These three regions can be
198 * different but must satisfy the relationship RequestedRegion <=
199 * BufferedRegion <= LargestPossibleRegion. For instance, an Image
200 * could be 512x512x200 on disk (LargestPossibleRegion) but the
201 * application may only have a 256x256x50 section of the dataset in
202 * memory (BufferedRegion) and the user wants to operate on a
203 * 100x100x1 section of the buffer (RequestedRegion).
204 *
205 * Region negotiation is not applicable for all types of DataObjects.
206 * For instance, an EquivalencyTable of segmentation labels can be
207 * passed from ProcessObject to ProcessObject as any other DataObject
208 * but an EquivalencyTable does not support the concept of a
209 * sub-region. Therefore, the region negotiations at the DataObject
210 * (superclass) level are implemented as "abstract" concepts (not to
211 * be confused with a C++ abstract methods), allowing subclasses to
212 * provide specialized implementations on an as needed basis. There
213 * are five methods provided in DataObject that a subclass of
214 * DataObject may have to override for that particular type of
215 * DataObject to flow through the pipeline. These methods should only
216 * have to be specialized for DataObjects that do support
217 * regions. These methods are:
218 *
219 * void UpdateOutputInformation(): This method implements the first
220 * pass of the pipeline update mechanism outlined above. It is
221 * responsible for identifying when upstream components of the
222 * pipeline have been change (ModifiedTimes and Pipeline
223 * ModifiedTimes) and is responsible for propagating meta data through
224 * the pipeline. In the simplest case, this method simply calls the
225 * DataObject's source's UpdateOutputInformation() method (this is the
226 * default implementation). For DataObjects that support streaming,
227 * this method also propagates LargestPossibleRegions to downstream
228 * ProcessObjects.
229 *
230 * bool VerifyRequestedRegion(): Verify that the RequestedRegion is
231 * within the LargestPossibleRegion. For DataObjects that do not
232 * support Regions, this method always returns true.
233 *
234 * bool RequestedRegionIsOutsideOfTheBufferedRegion(): Determine
235 * whether the RequestedRegion is outside of the current
236 * BufferedRegion. This method is used by the second pass of a
237 * pipeline update outlined above. It is used to determine whether a
238 * filter needs to re-execute in order to satisfy a given request. For
239 * DataObjects that do not support Regions, this method always returns
240 * false. By always returning false, these types of DataObjects will
241 * update solely on the basis of modified times (whereas Images
242 * update based on either modified times or the RequestedRegion
243 * needs). If this method always returned true, the DataObject would
244 * be updated on every single call to Update() (not recommended).
245 *
246 * void SetRequestedRegion(const DataObject *): Sets the RequestedRegion of
247 * this DataObject to match the RequestedRegion of the DataObject that
248 * is passed in as a parameter. This method is used by
249 * ProcessObject::GenerateOutputRequestedRegion() and by
250 * ProcessObject::SetNthOutput(). In the former case, it used as an
251 * abstract API so that a ProcessObject can copy a requested region
252 * from one output to all its outputs without knowing the particular
253 * subclass of DataObject. In the latter case, it used when a
254 * ProcessObject has to create an output object to replace one of its
255 * outputs (and needs to copy the former object's RequestedRegion). In
256 * either case, it allows ProcessObject to perform these actions
257 * without knowing the specifics about the particular subclass of
258 * DataObject. For DataObjects that do not support Regions, this
259 * method does nothing.
260 *
261 * void SetRequestedRegionToLargestPossibleRegion(): Sets the
262 * RequestedRegion of this DataObject to match its
263 * LargestPossibleRegion. This method is used to force a filter to
264 * produce all of its output on the next call to Update(). For
265 * DataObjects that do not support Regions, this method does nothing.
266 *
267 *
268 * \sa ProcessObject
269 * \sa ImageBase
270 * \sa Mesh
271 * \ingroup DataRepresentation
272 * \ingroup ITKSystemObjects
273 * \ingroup ITKCommon
274 */
ITK_FORCE_EXPORT_MACRO(ITKCommon)275 class ITK_FORCE_EXPORT_MACRO(ITKCommon) DataObject:public Object
276 {
277 public:
278 ITK_DISALLOW_COPY_AND_ASSIGN(DataObject);
279
280 /** Standard class type aliases. */
281 using Self = DataObject;
282 using Superclass = Object;
283 using Pointer = SmartPointer< Self >;
284 using ConstPointer = SmartPointer< const Self >;
285
286 using DataObjectIdentifierType = std::string;
287
288 /** Run-time type information (and related methods). */
289 itkTypeMacro(DataObject, Object);
290
291 /** Separate this data object from the pipeline. This routine disconnects
292 * a data object from the upstream pipeline. Hence an Update() from
293 * downstream will not propagate back past this data object. To completely
294 * isolate this data object from the pipeline, the application must remove
295 * this data object from any filters which it is connected as the input. */
296 void DisconnectPipeline();
297
298 /** Get the process object that generated this data object.
299 * If there is no process object, then the data object has
300 * been disconnected from the pipeline, or the data object
301 * was created manually. (Note: we cannot use the GetObjectMacro()
302 * defined in itkMacro because the mutual dependency of
303 * DataObject and ProcessObject causes compile problems. )
304 */
305 SmartPointer< ProcessObject > GetSource() const;
306
307 /** Which of the source's outputs corresponds to this data object? */
308 const DataObjectIdentifierType & GetSourceOutputName() const;
309
310 /** Which of the source's outputs corresponds to this data object? */
311 using DataObjectPointerArraySizeType = std::vector< Pointer >::size_type;
312 DataObjectPointerArraySizeType GetSourceOutputIndex() const;
313
314 /** Restore the data object to its initial state. This means releasing
315 * memory. */
316 virtual void Initialize();
317
318 /** Turn on/off a flag to control whether this object's data is released
319 * after being used by a filter. */
320 void SetReleaseDataFlag(bool flag)
321 {
322 m_ReleaseDataFlag = flag;
323 }
324
325 itkGetConstReferenceMacro(ReleaseDataFlag, bool);
326 itkBooleanMacro(ReleaseDataFlag);
327
328 /** Turn on/off a flag to control whether every object releases its data
329 * after being used by a filter. Being a global flag, it controls the
330 * behavior of all DataObjects and ProcessObjects. */
331 static void SetGlobalReleaseDataFlag(bool val);
332
333 static bool GetGlobalReleaseDataFlag();
334
335 static void GlobalReleaseDataFlagOn()
336 { Self::SetGlobalReleaseDataFlag(true); }
337 static void GlobalReleaseDataFlagOff()
338 { Self::SetGlobalReleaseDataFlag(false); }
339
340 /** Release data back to system to conserve memory resource. Used during
341 * pipeline execution. Releasing this data does not make
342 * down-stream data invalid, so it does not modify the MTime of this data
343 * object. */
344 void ReleaseData();
345
346 /** Return flag indicating whether data should be released after use
347 * by a filter. */
348 bool ShouldIReleaseData() const;
349
350 /** Get the flag indicating the data has been released. */
351 bool GetDataReleased() const
352 { return m_DataReleased; }
353
354 /** Provides opportunity for the data object to insure internal
355 * consistency before access. Also causes owning source/filter (if
356 * any) to update itself. The Update() method is composed of
357 * UpdateOutputInformation(), PropagateRequestedRegion(), and
358 * UpdateOutputData(). This method may call methods that throw an
359 * InvalidRequestedRegionError exception. This exception will leave
360 * the pipeline in an inconsistent state. You will need to call
361 * ResetPipeline() on the last ProcessObject in your pipeline in
362 * order to restore the pipeline to a state where you can call
363 * Update() again. */
364 virtual void Update();
365
366 /** Update the information for this DataObject so that it can be used
367 * as an output of a ProcessObject. This method is used in the pipeline
368 * mechanism to propagate information and initialize the meta data
369 * associated with a DataObject. Any implementation of this method in
370 * a derived class is assumed to call its source's
371 * ProcessObject::UpdateOutputInformation() which determines modified
372 * times, LargestPossibleRegions, and any extra meta data like spacing,
373 * origin, etc. Default implementation simply call's it's source's
374 * UpdateOutputInformation(). */
375 virtual void UpdateOutputInformation();
376
377 /** Methods to update the pipeline. Called internally by the
378 * pipeline mechanism. */
379 virtual void PropagateRequestedRegion();
380
381 virtual void UpdateOutputData();
382
383 /** Reset the pipeline. If an exception is thrown during an Update(),
384 * the pipeline may be in an inconsistent state. This method clears
385 * the internal state of the pipeline so Update() can be called. */
386 virtual void ResetPipeline();
387
388 /** The maximum MTime of all upstream filters and data objects.
389 * This does not include the MTime of this data object. */
390 void SetPipelineMTime(ModifiedTimeType time)
391 { m_PipelineMTime = time; }
392 itkGetConstReferenceMacro(PipelineMTime, ModifiedTimeType);
393
394 /** MTime for the last time this DataObject was generated. */
395 virtual ModifiedTimeType GetUpdateMTime() const;
396
397 /** RealTime stamp for the last time this DataObject was generated.
398 * By default, the real time stamp is initialized to the origin of
399 * the Unix epoch. That is the time 00:00:00 UTC on 1 January 1970
400 * (or 1970-01-01T00:00:00Z ISO 8601)
401 */
402 itkSetMacro( RealTimeStamp, RealTimeStamp );
403 itkGetConstReferenceMacro( RealTimeStamp, RealTimeStamp );
404
405 /** Setup a DataObject to receive new data. This method is called
406 * by the pipeline mechanism on each output of filter that needs
407 * to execute. The default implementation is to return a DataObject
408 * to its initial state. This may involve releasing previously
409 * allocated bulk data. Subclasses of DataObject may want to
410 * override this method and/or the Initialize() method if they
411 * want a different default behavior (for instance a DataObject
412 * might want finer control over its bulk data memory management). */
413 virtual void PrepareForNewData()
414 { this->Initialize(); }
415
416 /** Inform the pipeline mechanism that data has been generated. This
417 * method is called by ProcessObject::UpdateOutputData() once the
418 * process object has finished generating its data. This essentially
419 * marks the DataObject as being updated and ready for use. */
420 virtual void DataHasBeenGenerated();
421
422 /** Set the RequestedRegion to the LargestPossibleRegion. This
423 * forces a filter to produce all of the output in one execution
424 * (i.e. not streaming) on the next call to Update(). */
425 virtual void SetRequestedRegionToLargestPossibleRegion() {}
426
427 /** Determine whether the RequestedRegion is outside of the
428 * BufferedRegion. This method returns true if the RequestedRegion
429 * is outside the BufferedRegion (true if at least one pixel is
430 * outside). This is used by the pipeline mechanism to determine
431 * whether a filter needs to re-execute in order to satisfy the
432 * current request. If the current RequestedRegion is already
433 * inside the BufferedRegion from the previous execution (and the
434 * current filter is up to date), then a given filter does not need
435 * to re-execute */
436 virtual bool RequestedRegionIsOutsideOfTheBufferedRegion()
437 { return false; }
438
439 /** Verify that the RequestedRegion is within the LargestPossibleRegion.
440 *
441 * If the RequestedRegion is not within the LargestPossibleRegion,
442 * then the filter cannot possibly satisfy the request. This method
443 * returns true if the request can be satisfied (even if it will be
444 * necessary to process the entire LargestPossibleRegion) and
445 * returns false otherwise. This method is used by
446 * PropagateRequestedRegion(). PropagateRequestedRegion() throws a
447 * InvalidRequestedRegionError exception if the requested region is
448 * not within the LargestPossibleRegion. Default implementation
449 * simply returns true in order to support DataObjects that do not
450 * need regions (for instance itk::EquivalencyTable). */
451 virtual bool VerifyRequestedRegion() { return true; }
452
453 /** Copy information from the specified data set. This method is
454 * part of the pipeline execution model. By default, a ProcessObject
455 * will copy meta-data from the first input to all of its
456 * outputs. See ProcessObject::GenerateOutputInformation(). Each
457 * subclass of DataObject is responsible for being able to copy
458 * whatever meta-data it needs from from another DataObject.
459 * The default implementation of this method is empty. If a subclass
460 * overrides this method, it should always call its superclass'
461 * version. */
462 virtual void CopyInformation(const DataObject *) {}
463
464 /** Set the requested region from this data object to match the requested
465 * region of the data object passed in as a parameter. For
466 * DataObject's that do not support Regions, this method does
467 * nothing. Subclasses of DataObject that do support Regions,
468 * provide an alternative implementation. */
469 virtual void SetRequestedRegion(const DataObject *) {}
470
471 /** Method for grafting the content of one data object into another one.
472 * This method is intended to be overloaded by derived classes. Each one of
473 * them should use dynamic_casting in order to verify that the grafted
474 * object is actually of the same type as the class on which the Graft()
475 * method was invoked. */
476 virtual void Graft(const DataObject *) {}
477
478 protected:
479 DataObject();
480 ~DataObject() override;
481 void PrintSelf(std::ostream & os, Indent indent) const override;
482
483 /** Propagate a call to ResetPipeline(). Called only from ProcessObject. */
484 virtual void PropagateResetPipeline();
485
486 private:
487 /** Who generated this data? */
488 WeakPointer< ProcessObject > m_Source;
489 DataObjectIdentifierType m_SourceOutputName;
490
491 /** When was this data last generated?
492 * This time stamp is an integer number and it is intended to synchronize the
493 * activities of the pipeline. It doesn't relates to the clock time of
494 * acquiring or processing the data. */
495 TimeStamp m_UpdateMTime;
496
497 /** When, in real time, this data was generated. */
498 RealTimeStamp m_RealTimeStamp;
499
500 bool m_ReleaseDataFlag; //Data will release after use by a filter if on
501 bool m_DataReleased; //Keep track of data release during pipeline execution
502
503 /** The maximum MTime of all upstream filters and data objects.
504 * This does not include the MTime of this data object. */
505 ModifiedTimeType m_PipelineMTime;
506
507 /** Static member that controls global data release after use by filter. */
508 static bool *m_GlobalReleaseDataFlag;
509
510 /** Connect the specified process object to the data object. This
511 * should only be called from a process object. The second parameter
512 * indicates which of the source's outputs corresponds to this data
513 * object. */
514 bool ConnectSource(ProcessObject *s, const DataObjectIdentifierType & name);
515
516 /** Disconnect the specified process object from the data
517 * object. This should only be called from a process object. An
518 * application should call DataObject::DisconnectPipeline() if it
519 * wants to disconnect a data object from a pipeline. The second
520 * parameter indicates which of the source's outputs corresponds to
521 * this data object. If the specified source output name does not
522 * match the name cached when the data object was connected to the
523 * pipeline (see ConnectSource), then nothing is done. */
524 bool DisconnectSource(ProcessObject *s, const DataObjectIdentifierType & name);
525
526 /** Only used to synchronize the global variable across static libraries.*/
527 itkGetGlobalDeclarationMacro(bool, GlobalReleaseDataFlag);
528
529
530 /** Friends of DataObject */
531 friend class ProcessObject;
532 friend class DataObjectError;
533 };
534 } // end namespace itk
535
536 #endif
537