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