1 /*=========================================================================
2 
3   Program:   Visualization Toolkit
4   Module:    vtkImageStencil.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 "vtkImageStencil.h"
16 
17 #include "vtkImageData.h"
18 #include "vtkImageIterator.h"
19 #include "vtkImageStencilData.h"
20 #include "vtkImageStencilIterator.h"
21 #include "vtkInformation.h"
22 #include "vtkInformationVector.h"
23 #include "vtkObjectFactory.h"
24 #include "vtkStreamingDemandDrivenPipeline.h"
25 
26 #include <cmath>
27 
28 vtkStandardNewMacro(vtkImageStencil);
29 
30 //------------------------------------------------------------------------------
vtkImageStencil()31 vtkImageStencil::vtkImageStencil()
32 {
33   this->ReverseStencil = 0;
34 
35   this->BackgroundColor[0] = 1;
36   this->BackgroundColor[1] = 1;
37   this->BackgroundColor[2] = 1;
38   this->BackgroundColor[3] = 1;
39   this->SetNumberOfInputPorts(3);
40 }
41 
42 //------------------------------------------------------------------------------
43 vtkImageStencil::~vtkImageStencil() = default;
44 
45 //------------------------------------------------------------------------------
SetStencilData(vtkImageStencilData * stencil)46 void vtkImageStencil::SetStencilData(vtkImageStencilData* stencil)
47 {
48   this->SetInputData(2, stencil);
49 }
50 
51 //------------------------------------------------------------------------------
GetStencil()52 vtkImageStencilData* vtkImageStencil::GetStencil()
53 {
54   if (this->GetNumberOfInputConnections(2) < 1)
55   {
56     return nullptr;
57   }
58   else
59   {
60     return vtkImageStencilData::SafeDownCast(this->GetExecutive()->GetInputData(2, 0));
61   }
62 }
63 
64 //------------------------------------------------------------------------------
SetBackgroundInputData(vtkImageData * data)65 void vtkImageStencil::SetBackgroundInputData(vtkImageData* data)
66 {
67   this->SetInputData(1, data);
68 }
69 
70 //------------------------------------------------------------------------------
GetBackgroundInput()71 vtkImageData* vtkImageStencil::GetBackgroundInput()
72 {
73   if (this->GetNumberOfInputConnections(1) < 1)
74   {
75     return nullptr;
76   }
77   else
78   {
79     return vtkImageData::SafeDownCast(this->GetExecutive()->GetInputData(1, 0));
80   }
81 }
82 
83 //------------------------------------------------------------------------------
84 // Some helper functions for 'ThreadedRequestData'
85 //------------------------------------------------------------------------------
86 
87 //------------------------------------------------------------------------------
88 // copy a pixel, advance the output pointer but not the input pointer
89 
90 template <class T>
vtkCopyPixel(T * & out,const T * in,int numscalars)91 inline void vtkCopyPixel(T*& out, const T* in, int numscalars)
92 {
93   do
94   {
95     *out++ = *in++;
96   } while (--numscalars);
97 }
98 
99 //------------------------------------------------------------------------------
100 // Convert background color from double to appropriate type
101 
102 template <class T>
vtkAllocBackground(vtkImageStencil * self,T * & background,vtkInformation * outInfo)103 void vtkAllocBackground(vtkImageStencil* self, T*& background, vtkInformation* outInfo)
104 {
105   vtkImageData* output = vtkImageData::SafeDownCast(outInfo->Get(vtkDataObject::DATA_OBJECT()));
106   int numComponents = output->GetNumberOfScalarComponents();
107   int scalarType = output->GetScalarType();
108 
109   background = new T[numComponents];
110 
111   for (int i = 0; i < numComponents; i++)
112   {
113     if (i < 4)
114     {
115       if (scalarType == VTK_FLOAT || scalarType == VTK_DOUBLE)
116       {
117         background[i] = static_cast<T>(self->GetBackgroundColor()[i]);
118       }
119       else
120       { // round float to nearest int
121         background[i] = static_cast<T>(floor(self->GetBackgroundColor()[i] + 0.5));
122       }
123     }
124     else
125     { // all values past 4 are set to zero
126       background[i] = 0;
127     }
128   }
129 }
130 
131 //------------------------------------------------------------------------------
132 template <class T>
vtkFreeBackground(vtkImageStencil * vtkNotUsed (self),T * & background)133 void vtkFreeBackground(vtkImageStencil* vtkNotUsed(self), T*& background)
134 {
135   delete[] background;
136   background = nullptr;
137 }
138 
139 //------------------------------------------------------------------------------
140 template <class T>
vtkImageStencilExecute(vtkImageStencil * self,vtkImageData * inData,T *,vtkImageData * inData2,T *,vtkImageData * outData,T *,int outExt[6],int id,vtkInformation * outInfo)141 void vtkImageStencilExecute(vtkImageStencil* self, vtkImageData* inData, T*, vtkImageData* inData2,
142   T*, vtkImageData* outData, T*, int outExt[6], int id, vtkInformation* outInfo)
143 {
144   vtkImageStencilData* stencil = self->GetStencil();
145 
146   vtkImageIterator<T> inIter(inData, outExt);
147   vtkImageStencilIterator<T> outIter(outData, stencil, outExt, self, id);
148 
149   int numscalars = outData->GetNumberOfScalarComponents();
150 
151   // whether to reverse the stencil
152   bool reverseStencil = (self->GetReverseStencil() != 0);
153 
154   // if no background image is provided in inData2
155   if (inData2 == nullptr)
156   {
157     // set color for area outside of input volume extent
158     T* background;
159     vtkAllocBackground(self, background, outInfo);
160 
161     T* inPtr = inIter.BeginSpan();
162     T* inSpanEndPtr = inIter.EndSpan();
163     while (!outIter.IsAtEnd())
164     {
165       T* outPtr = outIter.BeginSpan();
166       T* outSpanEndPtr = outIter.EndSpan();
167 
168       T* tmpPtr = inPtr;
169       int tmpInc = numscalars;
170       if (!(outIter.IsInStencil() ^ reverseStencil))
171       {
172         tmpPtr = background;
173         tmpInc = 0;
174       }
175 
176       // move inPtr forward by the span size
177       inPtr += (outSpanEndPtr - outPtr);
178 
179       while (outPtr != outSpanEndPtr)
180       {
181         // CopyPixel increments outPtr but not tmpPtr
182         vtkCopyPixel(outPtr, tmpPtr, numscalars);
183         tmpPtr += tmpInc;
184       }
185 
186       outIter.NextSpan();
187 
188       // this occurs at the end of a full row
189       if (inPtr == inSpanEndPtr)
190       {
191         inIter.NextSpan();
192         inPtr = inIter.BeginSpan();
193         inSpanEndPtr = inIter.EndSpan();
194       }
195     }
196 
197     vtkFreeBackground(self, background);
198   }
199 
200   // if a background image is given in inData2
201   else
202   {
203     vtkImageIterator<T> inIter2(inData2, outExt);
204 
205     T* inPtr = inIter.BeginSpan();
206     T* inPtr2 = inIter2.BeginSpan();
207     T* inSpanEndPtr = inIter.EndSpan();
208     while (!outIter.IsAtEnd())
209     {
210       T* outPtr = outIter.BeginSpan();
211       T* outSpanEndPtr = outIter.EndSpan();
212 
213       T* tmpPtr = inPtr;
214       if (!(outIter.IsInStencil() ^ reverseStencil))
215       {
216         tmpPtr = inPtr2;
217       }
218 
219       // move inPtr forward by the span size
220       inPtr += (outSpanEndPtr - outPtr);
221       inPtr2 += (outSpanEndPtr - outPtr);
222 
223       while (outPtr != outSpanEndPtr)
224       {
225         // CopyPixel increments outPtr but not tmpPtr
226         vtkCopyPixel(outPtr, tmpPtr, numscalars);
227         tmpPtr += numscalars;
228       }
229 
230       outIter.NextSpan();
231 
232       // this occurs at the end of a full row
233       if (inPtr == inSpanEndPtr)
234       {
235         inIter.NextSpan();
236         inIter2.NextSpan();
237         inPtr = inIter.BeginSpan();
238         inPtr2 = inIter2.BeginSpan();
239         inSpanEndPtr = inIter.EndSpan();
240       }
241     }
242   }
243 }
244 
245 //------------------------------------------------------------------------------
ThreadedRequestData(vtkInformation * vtkNotUsed (request),vtkInformationVector ** inputVector,vtkInformationVector * outputVector,vtkImageData *** inData,vtkImageData ** outData,int outExt[6],int id)246 void vtkImageStencil::ThreadedRequestData(vtkInformation* vtkNotUsed(request),
247   vtkInformationVector** inputVector, vtkInformationVector* outputVector, vtkImageData*** inData,
248   vtkImageData** outData, int outExt[6], int id)
249 {
250   void *inPtr, *inPtr2;
251   void* outPtr;
252   vtkImageData* inData2 = this->GetBackgroundInput();
253 
254   inPtr = inData[0][0]->GetScalarPointer();
255   outPtr = outData[0]->GetScalarPointerForExtent(outExt);
256 
257   vtkInformation* outInfo = outputVector->GetInformationObject(0);
258 
259   inPtr2 = nullptr;
260   if (inData2)
261   {
262     inPtr2 = inData2->GetScalarPointer();
263     if (inData2->GetScalarType() != inData[0][0]->GetScalarType())
264     {
265       if (id == 0)
266       {
267         vtkErrorMacro("Execute: BackgroundInput ScalarType " << inData2->GetScalarType()
268                                                              << ", must match Input ScalarType "
269                                                              << inData[0][0]->GetScalarType());
270       }
271       return;
272     }
273     else if (inData2->GetNumberOfScalarComponents() != inData[0][0]->GetNumberOfScalarComponents())
274     {
275       if (id == 0)
276       {
277         vtkErrorMacro("Execute: BackgroundInput NumberOfScalarComponents "
278           << inData2->GetNumberOfScalarComponents()
279           << ", must match Input NumberOfScalarComponents "
280           << inData[0][0]->GetNumberOfScalarComponents());
281       }
282       return;
283     }
284     int wholeExt1[6], wholeExt2[6];
285     vtkInformation* inInfo = inputVector[0]->GetInformationObject(0);
286     vtkInformation* inInfo2 = inputVector[1]->GetInformationObject(0);
287     inInfo->Get(vtkStreamingDemandDrivenPipeline::WHOLE_EXTENT(), wholeExt1);
288     inInfo2->Get(vtkStreamingDemandDrivenPipeline::WHOLE_EXTENT(), wholeExt2);
289 
290     for (int i = 0; i < 6; i++)
291     {
292       if (wholeExt1[i] != wholeExt2[i])
293       {
294         if (id == 0)
295         {
296           vtkErrorMacro("Execute: BackgroundInput must have the same "
297                         "WholeExtent as the Input");
298         }
299         return;
300       }
301     }
302   }
303 
304   switch (inData[0][0]->GetScalarType())
305   {
306     vtkTemplateMacro(vtkImageStencilExecute(this, inData[0][0], static_cast<VTK_TT*>(inPtr),
307       inData2, static_cast<VTK_TT*>(inPtr2), outData[0], static_cast<VTK_TT*>(outPtr), outExt, id,
308       outInfo));
309     default:
310       vtkErrorMacro("Execute: Unknown ScalarType");
311       return;
312   }
313 }
314 
315 //------------------------------------------------------------------------------
FillInputPortInformation(int port,vtkInformation * info)316 int vtkImageStencil::FillInputPortInformation(int port, vtkInformation* info)
317 {
318   if (port == 2)
319   {
320     info->Set(vtkAlgorithm::INPUT_REQUIRED_DATA_TYPE(), "vtkImageStencilData");
321     info->Set(vtkAlgorithm::INPUT_IS_OPTIONAL(), 1);
322   }
323   else
324   {
325     info->Set(vtkAlgorithm::INPUT_REQUIRED_DATA_TYPE(), "vtkImageData");
326     if (port == 1)
327     {
328       info->Set(vtkAlgorithm::INPUT_IS_OPTIONAL(), 1);
329     }
330   }
331   return 1;
332 }
333 
PrintSelf(ostream & os,vtkIndent indent)334 void vtkImageStencil::PrintSelf(ostream& os, vtkIndent indent)
335 {
336   this->Superclass::PrintSelf(os, indent);
337 
338   os << indent << "Stencil: " << this->GetStencil() << "\n";
339   os << indent << "ReverseStencil: " << (this->ReverseStencil ? "On\n" : "Off\n");
340 
341   os << indent << "BackgroundInput: " << this->GetBackgroundInput() << "\n";
342   os << indent << "BackgroundValue: " << this->BackgroundColor[0] << "\n";
343 
344   os << indent << "BackgroundColor: (" << this->BackgroundColor[0] << ", "
345      << this->BackgroundColor[1] << ", " << this->BackgroundColor[2] << ", "
346      << this->BackgroundColor[3] << ")\n";
347 }
348