1 /*=========================================================================
2 
3   Program:   Visualization Toolkit
4   Module:    vtkImageToImageStencil.cxx
5 
6   Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
7   All rights reserved.
8   See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
9 
10      This software is distributed WITHOUT ANY WARRANTY; without even
11      the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
12      PURPOSE.  See the above copyright notice for more information.
13 
14 =========================================================================*/
15 #include "vtkImageToImageStencil.h"
16 
17 #include "vtkDataArray.h"
18 #include "vtkImageData.h"
19 #include "vtkImageStencilData.h"
20 #include "vtkInformation.h"
21 #include "vtkInformationVector.h"
22 #include "vtkObjectFactory.h"
23 #include "vtkPointData.h"
24 #include "vtkStreamingDemandDrivenPipeline.h"
25 
26 #include <cmath>
27 
28 vtkStandardNewMacro(vtkImageToImageStencil);
29 
30 //----------------------------------------------------------------------------
vtkImageToImageStencil()31 vtkImageToImageStencil::vtkImageToImageStencil()
32 {
33   this->UpperThreshold = VTK_FLOAT_MAX;
34   this->LowerThreshold = -VTK_FLOAT_MAX;
35 }
36 
37 //----------------------------------------------------------------------------
38 vtkImageToImageStencil::~vtkImageToImageStencil() = default;
39 
40 //----------------------------------------------------------------------------
PrintSelf(ostream & os,vtkIndent indent)41 void vtkImageToImageStencil::PrintSelf(ostream& os, vtkIndent indent)
42 {
43   this->Superclass::PrintSelf(os,indent);
44 
45   os << indent << "Input: " << this->GetInput() << "\n";
46   os << indent << "UpperThreshold: " << this->UpperThreshold << "\n";
47   os << indent << "LowerThreshold: " << this->LowerThreshold << "\n";
48 }
49 
50 //----------------------------------------------------------------------------
SetInputData(vtkImageData * input)51 void vtkImageToImageStencil::SetInputData(vtkImageData *input)
52 {
53   this->SetInputDataInternal(0, input);
54 }
55 
56 //----------------------------------------------------------------------------
GetInput()57 vtkImageData *vtkImageToImageStencil::GetInput()
58 {
59   if (this->GetNumberOfInputConnections(0) < 1)
60   {
61     return nullptr;
62   }
63 
64   return vtkImageData::SafeDownCast(
65     this->GetExecutive()->GetInputData(0, 0));
66 }
67 
68 //----------------------------------------------------------------------------
69 // The values greater than or equal to the value match.
ThresholdByUpper(double thresh)70 void vtkImageToImageStencil::ThresholdByUpper(double thresh)
71 {
72   if (this->LowerThreshold != thresh || this->UpperThreshold < VTK_FLOAT_MAX)
73   {
74     this->LowerThreshold = thresh;
75     this->UpperThreshold = VTK_FLOAT_MAX;
76     this->Modified();
77   }
78 }
79 
80 //----------------------------------------------------------------------------
81 // The values less than or equal to the value match.
ThresholdByLower(double thresh)82 void vtkImageToImageStencil::ThresholdByLower(double thresh)
83 {
84   if (this->UpperThreshold != thresh || this->LowerThreshold > -VTK_FLOAT_MAX)
85   {
86     this->UpperThreshold = thresh;
87     this->LowerThreshold = -VTK_FLOAT_MAX;
88     this->Modified();
89   }
90 }
91 
92 //----------------------------------------------------------------------------
93 // The values in a range (inclusive) match
ThresholdBetween(double lower,double upper)94 void vtkImageToImageStencil::ThresholdBetween(double lower, double upper)
95 {
96   if (this->LowerThreshold != lower || this->UpperThreshold != upper)
97   {
98     this->LowerThreshold = lower;
99     this->UpperThreshold = upper;
100     this->Modified();
101   }
102 }
103 
104 //----------------------------------------------------------------------------
RequestData(vtkInformation *,vtkInformationVector ** inputVector,vtkInformationVector * outputVector)105 int vtkImageToImageStencil::RequestData(
106   vtkInformation *,
107   vtkInformationVector **inputVector,
108   vtkInformationVector *outputVector)
109 {
110   vtkInformation *inInfo = inputVector[0]->GetInformationObject(0);
111   vtkInformation *outInfo = outputVector->GetInformationObject(0);
112   vtkImageData *inData = vtkImageData::SafeDownCast(
113     inInfo->Get(vtkDataObject::DATA_OBJECT()));
114   vtkImageStencilData *data = vtkImageStencilData::SafeDownCast(
115     outInfo->Get(vtkDataObject::DATA_OBJECT()));
116 
117   int extent[6];
118   inData->GetExtent(extent);
119   // output extent is always the input extent
120   this->AllocateOutputData(data, extent);
121 
122   vtkDataArray *inScalars = inData->GetPointData()->GetScalars();
123   double upperThreshold = this->UpperThreshold;
124   double lowerThreshold = this->LowerThreshold;
125 
126   // for keeping track of progress
127   unsigned long count = 0;
128   unsigned long target = static_cast<unsigned long>(
129     (extent[5] - extent[4] + 1)*(extent[3] - extent[2] + 1)/50.0);
130   target++;
131 
132   for (int idZ = extent[4]; idZ <= extent[5]; idZ++)
133   {
134     for (int idY = extent[2]; idY <= extent[3]; idY++)
135     {
136       if (count%target == 0)
137       {
138         this->UpdateProgress(count/(50.0*target));
139       }
140       count++;
141 
142       int state = 1; // inside or outside, start outside
143       int r1 = extent[0];
144       int r2 = extent[1];
145 
146       // index into scalar array
147       int idS = ((extent[1] - extent[0] + 1)*
148                  ((extent[3] - extent[2] + 1)*(idZ - extent[4]) +
149                   (idY - extent[2])));
150 
151       for (int idX = extent[0]; idX <= extent[1]; idX++)
152       {
153         int newstate = 1;
154         double value = inScalars->GetComponent(idS++,0);
155         if (value >= lowerThreshold && value <= upperThreshold)
156         {
157           newstate = -1;
158           if (newstate != state)
159           { // sub extent starts
160             r1 = idX;
161           }
162         }
163         else if (newstate != state)
164         { // sub extent ends
165           r2 = idX - 1;
166           data->InsertNextExtent(r1, r2, idY, idZ);
167         }
168         state = newstate;
169       } // for idX
170       if (state < 0)
171       { // if inside at end, cap off the sub extent
172         data->InsertNextExtent(r1, extent[1], idY, idZ);
173       }
174     } // for idY
175   } // for idZ
176 
177   return 1;
178 }
179 
180 //----------------------------------------------------------------------------
RequestInformation(vtkInformation *,vtkInformationVector ** inputVector,vtkInformationVector * outputVector)181 int vtkImageToImageStencil::RequestInformation(
182   vtkInformation *,
183   vtkInformationVector **inputVector,
184   vtkInformationVector *outputVector)
185 {
186   vtkInformation *inInfo = inputVector[0]->GetInformationObject(0);
187   vtkInformation *outInfo = outputVector->GetInformationObject(0);
188 
189   int wholeExtent[6];
190   double spacing[3];
191   double origin[3];
192 
193   inInfo->Get(vtkStreamingDemandDrivenPipeline::WHOLE_EXTENT(),
194               wholeExtent);
195   inInfo->Get(vtkDataObject::SPACING(), spacing);
196   inInfo->Get(vtkDataObject::ORIGIN(), origin);
197 
198   outInfo->Set(vtkStreamingDemandDrivenPipeline::WHOLE_EXTENT(),
199                wholeExtent, 6);
200   outInfo->Set(vtkDataObject::SPACING(), spacing, 3);
201   outInfo->Set(vtkDataObject::ORIGIN(), origin, 3);
202 
203   outInfo->Set(
204     vtkStreamingDemandDrivenPipeline::UNRESTRICTED_UPDATE_EXTENT(), 1);
205 
206   return 1;
207 }
208 
209 //----------------------------------------------------------------------------
FillInputPortInformation(int,vtkInformation * info)210 int vtkImageToImageStencil::FillInputPortInformation(int,
211                                                      vtkInformation* info)
212 {
213   info->Set(vtkAlgorithm::INPUT_REQUIRED_DATA_TYPE(), "vtkImageData");
214   return 1;
215 }
216 
217 //----------------------------------------------------------------------------
RequestUpdateExtent(vtkInformation *,vtkInformationVector ** inputVector,vtkInformationVector * outputVector)218 int vtkImageToImageStencil::RequestUpdateExtent(
219   vtkInformation *,
220   vtkInformationVector **inputVector,
221   vtkInformationVector *outputVector)
222 {
223   vtkInformation *inInfo = inputVector[0]->GetInformationObject(0);
224   vtkInformation *outInfo = outputVector->GetInformationObject(0);
225   int extent[6], wholeExtent[6];
226   outInfo->Get(vtkStreamingDemandDrivenPipeline::UPDATE_EXTENT(), extent);
227   inInfo->Get(vtkStreamingDemandDrivenPipeline::WHOLE_EXTENT(), wholeExtent);
228 
229   // clip UpdateExtent with WholeExtent
230   extent[0] = (extent[0] > wholeExtent[0] ? extent[0] : wholeExtent[0]);
231   extent[1] = (extent[1] < wholeExtent[1] ? extent[1] : wholeExtent[1]);
232   extent[2] = (extent[2] > wholeExtent[2] ? extent[2] : wholeExtent[2]);
233   extent[3] = (extent[3] < wholeExtent[3] ? extent[3] : wholeExtent[3]);
234   extent[4] = (extent[4] > wholeExtent[4] ? extent[4] : wholeExtent[4]);
235   extent[5] = (extent[5] < wholeExtent[5] ? extent[5] : wholeExtent[5]);
236 
237   // if invalid, use the current data extent if allocated
238   if (extent[0] > extent[1] || extent[2] > extent[3] || extent[4] > extent[5])
239   {
240     for (int j = 0; j < 6; j += 2)
241     {
242       extent[j] = extent[j+1] = wholeExtent[j];
243     }
244     vtkImageData *inData = vtkImageData::SafeDownCast(
245       inInfo->Get(vtkDataObject::DATA_OBJECT()));
246     if (inData)
247     {
248       inData->GetExtent(extent);
249     }
250   }
251 
252   inInfo->Set(vtkStreamingDemandDrivenPipeline::UPDATE_EXTENT(), extent, 6);
253   return 1;
254 }
255