1 /*=========================================================================
2
3 Program: Visualization Toolkit
4 Module: vtkTransformToGrid.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 "vtkTransformToGrid.h"
16
17 #include "vtkAbstractTransform.h"
18 #include "vtkIdentityTransform.h"
19 #include "vtkImageData.h"
20 #include "vtkInformation.h"
21 #include "vtkInformationVector.h"
22 #include "vtkObjectFactory.h"
23 #include "vtkStreamingDemandDrivenPipeline.h"
24
25 vtkStandardNewMacro(vtkTransformToGrid);
26
27 vtkCxxSetObjectMacro(vtkTransformToGrid, Input, vtkAbstractTransform);
28
29 //------------------------------------------------------------------------------
vtkTransformToGrid()30 vtkTransformToGrid::vtkTransformToGrid()
31 {
32 this->Input = nullptr;
33
34 this->GridScalarType = VTK_FLOAT;
35
36 for (int i = 0; i < 3; i++)
37 {
38 this->GridExtent[2 * i] = this->GridExtent[2 * i + 1] = 0;
39 this->GridOrigin[i] = 0.0;
40 this->GridSpacing[i] = 1.0;
41 }
42
43 this->DisplacementScale = 1.0;
44 this->DisplacementShift = 0.0;
45 this->SetNumberOfInputPorts(0);
46 this->SetNumberOfOutputPorts(1);
47 }
48
49 //------------------------------------------------------------------------------
~vtkTransformToGrid()50 vtkTransformToGrid::~vtkTransformToGrid()
51 {
52 this->SetInput(static_cast<vtkAbstractTransform*>(nullptr));
53 }
54
55 //------------------------------------------------------------------------------
PrintSelf(ostream & os,vtkIndent indent)56 void vtkTransformToGrid::PrintSelf(ostream& os, vtkIndent indent)
57 {
58 int i;
59
60 this->Superclass::PrintSelf(os, indent);
61
62 os << indent << "Input: (" << this->Input << ")\n";
63
64 os << indent << "GridSpacing: (" << this->GridSpacing[0];
65 for (i = 1; i < 3; ++i)
66 {
67 os << ", " << this->GridSpacing[i];
68 }
69 os << ")\n";
70
71 os << indent << "GridOrigin: (" << this->GridOrigin[0];
72 for (i = 1; i < 3; ++i)
73 {
74 os << ", " << this->GridOrigin[i];
75 }
76 os << ")\n";
77
78 os << indent << "GridExtent: (" << this->GridExtent[0];
79 for (i = 1; i < 6; ++i)
80 {
81 os << ", " << this->GridExtent[i];
82 }
83 os << ")\n";
84
85 os << indent << "GridScalarType: " << vtkImageScalarTypeNameMacro(this->GridScalarType) << "\n";
86
87 this->UpdateShiftScale();
88
89 os << indent << "DisplacementScale: " << this->DisplacementScale << "\n";
90 os << indent << "DisplacementShift: " << this->DisplacementShift << "\n";
91 }
92
93 //------------------------------------------------------------------------------
94 // This method returns the largest data that can be generated.
RequestInformation(vtkInformation * vtkNotUsed (request),vtkInformationVector ** vtkNotUsed (inputVector),vtkInformationVector * outputVector)95 void vtkTransformToGrid::RequestInformation(vtkInformation* vtkNotUsed(request),
96 vtkInformationVector** vtkNotUsed(inputVector), vtkInformationVector* outputVector)
97 {
98 // get the info objects
99 vtkInformation* outInfo = outputVector->GetInformationObject(0);
100
101 if (this->GetInput() == nullptr)
102 {
103 vtkErrorMacro("Missing input");
104 return;
105 }
106
107 // update the transform, maybe in the future make transforms part of the
108 // pipeline
109 this->Input->Update();
110
111 outInfo->Set(vtkStreamingDemandDrivenPipeline::WHOLE_EXTENT(), this->GridExtent, 6);
112 outInfo->Set(vtkDataObject::SPACING(), this->GridSpacing, 3);
113 outInfo->Set(vtkDataObject::ORIGIN(), this->GridOrigin, 3);
114 vtkDataObject::SetPointDataActiveScalarInfo(outInfo, this->GridScalarType, 3);
115 }
116
117 //------------------------------------------------------------------------------
118 // Return the maximum absolute displacement of the transform over
119 // the entire grid extent -- this is extremely robust and extremely
120 // inefficient, it should be possible to do much better than this.
vtkTransformToGridMinMax(vtkTransformToGrid * self,int extent[6],double & minDisplacement,double & maxDisplacement)121 static void vtkTransformToGridMinMax(
122 vtkTransformToGrid* self, int extent[6], double& minDisplacement, double& maxDisplacement)
123 {
124 vtkAbstractTransform* transform = self->GetInput();
125 transform->Update();
126
127 if (!transform)
128 {
129 minDisplacement = -1.0;
130 maxDisplacement = +1.0;
131 return;
132 }
133
134 double* spacing = self->GetGridSpacing();
135 double* origin = self->GetGridOrigin();
136
137 maxDisplacement = -1e37;
138 minDisplacement = +1e37;
139
140 double point[3], newPoint[3], displacement;
141
142 for (int k = extent[4]; k <= extent[5]; k++)
143 {
144 point[2] = k * spacing[2] + origin[2];
145 for (int j = extent[2]; j <= extent[3]; j++)
146 {
147 point[1] = j * spacing[1] + origin[1];
148 for (int i = extent[0]; i <= extent[1]; i++)
149 {
150 point[0] = i * spacing[0] + origin[0];
151
152 transform->InternalTransformPoint(point, newPoint);
153
154 for (int l = 0; l < 3; l++)
155 {
156 displacement = newPoint[l] - point[l];
157
158 if (displacement > maxDisplacement)
159 {
160 maxDisplacement = displacement;
161 }
162
163 if (displacement < minDisplacement)
164 {
165 minDisplacement = displacement;
166 }
167 }
168 }
169 }
170 }
171 }
172
173 //------------------------------------------------------------------------------
UpdateShiftScale()174 void vtkTransformToGrid::UpdateShiftScale()
175 {
176 int gridType = this->GridScalarType;
177
178 // nothing to do for double or float
179 if (gridType == VTK_DOUBLE || gridType == VTK_FLOAT)
180 {
181 this->DisplacementShift = 0.0;
182 this->DisplacementScale = 1.0;
183 vtkDebugMacro(<< "displacement (scale, shift) = (" << this->DisplacementScale << ", "
184 << this->DisplacementShift << ")");
185 return;
186 }
187
188 // check mtime
189 if (this->ShiftScaleTime.GetMTime() > this->GetMTime())
190 {
191 return;
192 }
193
194 // get the maximum displacement
195 double minDisplacement, maxDisplacement;
196 vtkTransformToGridMinMax(this, this->GridExtent, minDisplacement, maxDisplacement);
197
198 vtkDebugMacro(<< "displacement (min, max) = (" << minDisplacement << ", " << maxDisplacement
199 << ")");
200
201 double typeMin, typeMax;
202
203 switch (gridType)
204 {
205 case VTK_SHORT:
206 typeMin = VTK_SHORT_MIN;
207 typeMax = VTK_SHORT_MAX;
208 break;
209 case VTK_UNSIGNED_SHORT:
210 typeMin = VTK_UNSIGNED_SHORT_MIN;
211 typeMax = VTK_UNSIGNED_SHORT_MAX;
212 break;
213 case VTK_CHAR:
214 typeMin = VTK_CHAR_MIN;
215 typeMax = VTK_CHAR_MAX;
216 break;
217 case VTK_UNSIGNED_CHAR:
218 typeMin = VTK_UNSIGNED_CHAR_MIN;
219 typeMax = VTK_UNSIGNED_CHAR_MAX;
220 break;
221 default:
222 vtkErrorMacro(<< "UpdateShiftScale: Unknown input ScalarType");
223 return;
224 }
225
226 this->DisplacementScale = ((maxDisplacement - minDisplacement) / (typeMax - typeMin));
227 this->DisplacementShift =
228 ((typeMax * minDisplacement - typeMin * maxDisplacement) / (typeMax - typeMin));
229
230 if (this->DisplacementScale == 0.0)
231 {
232 this->DisplacementScale = 1.0;
233 }
234
235 vtkDebugMacro(<< "displacement (scale, shift) = (" << this->DisplacementScale << ", "
236 << this->DisplacementShift << ")");
237
238 this->ShiftScaleTime.Modified();
239 }
240
241 //------------------------------------------------------------------------------
242 // macros to ensure proper round-to-nearest behaviour
243
vtkGridRound(double val,unsigned char & rnd)244 inline void vtkGridRound(double val, unsigned char& rnd)
245 {
246 rnd = (unsigned char)(val + 0.5f);
247 }
248
vtkGridRound(double val,char & rnd)249 inline void vtkGridRound(double val, char& rnd)
250 {
251 rnd = (char)((val + 128.5f) - 128);
252 }
253
vtkGridRound(double val,short & rnd)254 inline void vtkGridRound(double val, short& rnd)
255 {
256 rnd = (short)((int)(val + 32768.5f) - 32768);
257 }
258
vtkGridRound(double val,unsigned short & rnd)259 inline void vtkGridRound(double val, unsigned short& rnd)
260 {
261 rnd = (unsigned short)(val + 0.5f);
262 }
263
vtkGridRound(double val,float & rnd)264 inline void vtkGridRound(double val, float& rnd)
265 {
266 rnd = (float)(val);
267 }
268
vtkGridRound(double val,double & rnd)269 inline void vtkGridRound(double val, double& rnd)
270 {
271 rnd = (double)(val);
272 }
273
274 //------------------------------------------------------------------------------
275 template <class T>
vtkTransformToGridExecute(vtkTransformToGrid * self,vtkImageData * grid,T * gridPtr,int extent[6],double shift,double scale,int id)276 void vtkTransformToGridExecute(vtkTransformToGrid* self, vtkImageData* grid, T* gridPtr,
277 int extent[6], double shift, double scale, int id)
278 {
279 vtkAbstractTransform* transform = self->GetInput();
280 int isIdentity = 0;
281 if (transform == nullptr)
282 {
283 transform = vtkIdentityTransform::New();
284 isIdentity = 1;
285 }
286
287 double* spacing = grid->GetSpacing();
288 double* origin = grid->GetOrigin();
289 vtkIdType increments[3];
290 grid->GetIncrements(increments);
291
292 double invScale = 1.0 / scale;
293
294 double point[3];
295 double newPoint[3];
296
297 T* gridPtr0 = gridPtr;
298
299 unsigned long count = 0;
300 unsigned long target =
301 (unsigned long)((extent[5] - extent[4] + 1) * (extent[3] - extent[2] + 1) / 50.0);
302 target++;
303
304 for (int k = extent[4]; k <= extent[5]; k++)
305 {
306 point[2] = k * spacing[2] + origin[2];
307 T* gridPtr1 = gridPtr0;
308
309 for (int j = extent[2]; j <= extent[3]; j++)
310 {
311
312 if (id == 0)
313 {
314 if (count % target == 0)
315 {
316 self->UpdateProgress(count / (50.0 * target));
317 }
318 count++;
319 }
320
321 point[1] = j * spacing[1] + origin[1];
322 gridPtr = gridPtr1;
323
324 for (int i = extent[0]; i <= extent[1]; i++)
325 {
326 point[0] = i * spacing[0] + origin[0];
327
328 transform->InternalTransformPoint(point, newPoint);
329
330 vtkGridRound((newPoint[0] - point[0] - shift) * invScale, *gridPtr++);
331 vtkGridRound((newPoint[1] - point[1] - shift) * invScale, *gridPtr++);
332 vtkGridRound((newPoint[2] - point[2] - shift) * invScale, *gridPtr++);
333 }
334
335 gridPtr1 += increments[1];
336 }
337
338 gridPtr0 += increments[2];
339 }
340
341 if (isIdentity)
342 {
343 transform->Delete();
344 }
345 }
346
347 //------------------------------------------------------------------------------
RequestData(vtkInformation * vtkNotUsed (request),vtkInformationVector ** vtkNotUsed (inputVector),vtkInformationVector * outputVector)348 void vtkTransformToGrid::RequestData(vtkInformation* vtkNotUsed(request),
349 vtkInformationVector** vtkNotUsed(inputVector), vtkInformationVector* outputVector)
350 {
351 // get the data object
352 vtkInformation* outInfo = outputVector->GetInformationObject(0);
353 vtkImageData* grid = vtkImageData::SafeDownCast(outInfo->Get(vtkDataObject::DATA_OBJECT()));
354
355 grid->SetExtent(outInfo->Get(vtkStreamingDemandDrivenPipeline::WHOLE_EXTENT()));
356 grid->AllocateScalars(outInfo);
357 int* extent = grid->GetExtent();
358
359 void* gridPtr = grid->GetScalarPointerForExtent(extent);
360 int gridType = grid->GetScalarType();
361
362 this->UpdateShiftScale();
363
364 double scale = this->DisplacementScale;
365 double shift = this->DisplacementShift;
366
367 int id = 0;
368
369 switch (gridType)
370 {
371 case VTK_DOUBLE:
372 vtkTransformToGridExecute(this, grid, (double*)(gridPtr), extent, shift, scale, id);
373 break;
374 case VTK_FLOAT:
375 vtkTransformToGridExecute(this, grid, (float*)(gridPtr), extent, shift, scale, id);
376 break;
377 case VTK_SHORT:
378 vtkTransformToGridExecute(this, grid, (short*)(gridPtr), extent, shift, scale, id);
379 break;
380 case VTK_UNSIGNED_SHORT:
381 vtkTransformToGridExecute(this, grid, (unsigned short*)(gridPtr), extent, shift, scale, id);
382 break;
383 case VTK_CHAR:
384 vtkTransformToGridExecute(this, grid, (char*)(gridPtr), extent, shift, scale, id);
385 break;
386 case VTK_UNSIGNED_CHAR:
387 vtkTransformToGridExecute(this, grid, (unsigned char*)(gridPtr), extent, shift, scale, id);
388 break;
389 default:
390 vtkErrorMacro(<< "Execute: Unknown input ScalarType");
391 }
392 }
393
394 //------------------------------------------------------------------------------
GetMTime()395 vtkMTimeType vtkTransformToGrid::GetMTime()
396 {
397 vtkMTimeType mtime = this->Superclass::GetMTime();
398
399 if (this->Input)
400 {
401 vtkMTimeType mtime2 = this->Input->GetMTime();
402 if (mtime2 > mtime)
403 {
404 mtime = mtime2;
405 }
406 }
407
408 return mtime;
409 }
410
411 //------------------------------------------------------------------------------
ProcessRequest(vtkInformation * request,vtkInformationVector ** inputVector,vtkInformationVector * outputVector)412 vtkTypeBool vtkTransformToGrid::ProcessRequest(
413 vtkInformation* request, vtkInformationVector** inputVector, vtkInformationVector* outputVector)
414 {
415 // generate the data
416 if (request->Has(vtkDemandDrivenPipeline::REQUEST_DATA()))
417 {
418 this->RequestData(request, inputVector, outputVector);
419 return 1;
420 }
421
422 // execute information
423 if (request->Has(vtkDemandDrivenPipeline::REQUEST_INFORMATION()))
424 {
425 this->RequestInformation(request, inputVector, outputVector);
426 // after executing set the origin and spacing from the
427 // info
428 int i;
429 for (i = 0; i < this->GetNumberOfOutputPorts(); ++i)
430 {
431 vtkInformation* info = outputVector->GetInformationObject(i);
432 vtkImageData* output = vtkImageData::SafeDownCast(info->Get(vtkDataObject::DATA_OBJECT()));
433 // if execute info didn't set origin and spacing then we set them
434 if (!info->Has(vtkDataObject::ORIGIN()))
435 {
436 info->Set(vtkDataObject::ORIGIN(), 0, 0, 0);
437 info->Set(vtkDataObject::SPACING(), 1, 1, 1);
438 }
439 if (output)
440 {
441 output->SetOrigin(info->Get(vtkDataObject::ORIGIN()));
442 output->SetSpacing(info->Get(vtkDataObject::SPACING()));
443 }
444 }
445 return 1;
446 }
447
448 return this->Superclass::ProcessRequest(request, inputVector, outputVector);
449 }
450
451 //------------------------------------------------------------------------------
GetOutput()452 vtkImageData* vtkTransformToGrid::GetOutput()
453 {
454 return vtkImageData::SafeDownCast(this->GetOutputDataObject(0));
455 }
456
FillOutputPortInformation(int vtkNotUsed (port),vtkInformation * info)457 int vtkTransformToGrid::FillOutputPortInformation(int vtkNotUsed(port), vtkInformation* info)
458 {
459 // now add our info
460 info->Set(vtkDataObject::DATA_TYPE_NAME(), "vtkImageData");
461 return 1;
462 }
463