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