1 /*=========================================================================
2 
3   Program:   Visualization Toolkit
4   Module:    vtkVolumeMapper.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 "vtkVolumeMapper.h"
16 
17 #include "vtkDataSet.h"
18 #include "vtkExecutive.h"
19 #include "vtkGarbageCollector.h"
20 #include "vtkImageData.h"
21 #include "vtkInformation.h"
22 #include "vtkRectilinearGrid.h"
23 
24 #include <cmath>
25 
26 // Construct a vtkVolumeMapper with empty scalar input and clipping off.
vtkVolumeMapper()27 vtkVolumeMapper::vtkVolumeMapper()
28 {
29   int i;
30 
31   this->BlendMode = vtkVolumeMapper::COMPOSITE_BLEND;
32   this->AverageIPScalarRange[0] = VTK_FLOAT_MIN;
33   this->AverageIPScalarRange[1] = VTK_FLOAT_MAX;
34 
35   this->Cropping = 0;
36   for (i = 0; i < 3; i++)
37   {
38     this->CroppingRegionPlanes[2 * i] = 0;
39     this->CroppingRegionPlanes[2 * i + 1] = 1;
40     this->VoxelCroppingRegionPlanes[2 * i] = 0;
41     this->VoxelCroppingRegionPlanes[2 * i + 1] = 1;
42   }
43   this->CroppingRegionFlags = VTK_CROP_SUBVOLUME;
44 }
45 
46 vtkVolumeMapper::~vtkVolumeMapper() = default;
47 
ConvertCroppingRegionPlanesToVoxels()48 void vtkVolumeMapper::ConvertCroppingRegionPlanesToVoxels()
49 {
50   vtkDataSet* input = this->GetInput();
51   const double* bds = this->GetInput()->GetBounds();
52   double physicalPt[3], ijk[3];
53   int dims[3];
54   vtkImageData* imageData = vtkImageData::SafeDownCast(input);
55   vtkRectilinearGrid* rectGrid = vtkRectilinearGrid::SafeDownCast(input);
56   if (imageData)
57   {
58     imageData->GetDimensions(dims);
59   }
60   else if (rectGrid)
61   {
62     rectGrid->GetDimensions(dims);
63   }
64   else
65   {
66     return;
67   }
68   for (int i = 0; i < 6; ++i)
69   {
70     for (int j = 0; j < 3; ++j)
71     {
72       physicalPt[j] = bds[2 * j];
73     }
74     physicalPt[i / 2] = this->CroppingRegionPlanes[i];
75     if (imageData)
76     {
77       imageData->TransformPhysicalPointToContinuousIndex(physicalPt, ijk);
78       ijk[i / 2] = ijk[i / 2] < 0 ? 0 : ijk[i / 2];
79       ijk[i / 2] = ijk[i / 2] > dims[i / 2] - 1 ? dims[i / 2] - 1 : ijk[i / 2];
80     }
81     else if (rectGrid)
82     {
83       int ijkI[3];
84       double pCoords[3];
85       if (!rectGrid->ComputeStructuredCoordinates(physicalPt, ijkI, pCoords))
86       {
87         if (physicalPt[i / 2] < bds[i / 2])
88         {
89           ijk[i / 2] = 0;
90         }
91         else
92         {
93           ijk[i / 2] = dims[i / 2] - 1;
94         }
95       }
96       else
97       {
98         ijk[i / 2] = static_cast<double>(ijkI[i / 2]);
99       }
100     }
101     this->VoxelCroppingRegionPlanes[i] = ijk[i / 2];
102   }
103 }
104 
SetInputData(vtkDataSet * genericInput)105 void vtkVolumeMapper::SetInputData(vtkDataSet* genericInput)
106 {
107   if (vtkImageData* imageData = vtkImageData::SafeDownCast(genericInput))
108   {
109     this->SetInputData(imageData);
110   }
111   else if (vtkRectilinearGrid* rectGrid = vtkRectilinearGrid::SafeDownCast(genericInput))
112   {
113     this->SetInputData(rectGrid);
114   }
115   else
116   {
117     vtkErrorMacro("The SetInput method of this mapper requires either"
118       << " a vtkImageData or a vtkRectilinearGrid as input");
119   }
120 }
121 
SetInputData(vtkImageData * input)122 void vtkVolumeMapper::SetInputData(vtkImageData* input)
123 {
124   this->SetInputDataInternal(0, input);
125 }
126 
SetInputData(vtkRectilinearGrid * input)127 void vtkVolumeMapper::SetInputData(vtkRectilinearGrid* input)
128 {
129   this->SetInputDataInternal(0, input);
130 }
131 
GetInput()132 vtkDataSet* vtkVolumeMapper::GetInput()
133 {
134   if (this->GetNumberOfInputConnections(0) < 1)
135   {
136     return nullptr;
137   }
138   return vtkDataSet::SafeDownCast(this->GetExecutive()->GetInputData(0, 0));
139 }
140 
GetInput(const int port)141 vtkDataSet* vtkVolumeMapper::GetInput(const int port)
142 {
143   if (this->GetNumberOfInputConnections(0) < 1)
144   {
145     return nullptr;
146   }
147 
148   return vtkDataSet::SafeDownCast(this->GetExecutive()->GetInputData(port, 0));
149 }
150 
151 // Print the vtkVolumeMapper
PrintSelf(ostream & os,vtkIndent indent)152 void vtkVolumeMapper::PrintSelf(ostream& os, vtkIndent indent)
153 {
154   this->Superclass::PrintSelf(os, indent);
155 
156   os << indent << "Cropping: " << (this->Cropping ? "On\n" : "Off\n");
157 
158   os << indent << "Cropping Region Planes: " << endl
159      << indent << "  In X: " << this->CroppingRegionPlanes[0] << " to "
160      << this->CroppingRegionPlanes[1] << endl
161      << indent << "  In Y: " << this->CroppingRegionPlanes[2] << " to "
162      << this->CroppingRegionPlanes[3] << endl
163      << indent << "  In Z: " << this->CroppingRegionPlanes[4] << " to "
164      << this->CroppingRegionPlanes[5] << endl;
165 
166   os << indent << "Cropping Region Flags: " << this->CroppingRegionFlags << endl;
167 
168   os << indent << "BlendMode: " << this->BlendMode << endl;
169 
170   // Don't print this->VoxelCroppingRegionPlanes
171 }
172 
173 //------------------------------------------------------------------------------
FillInputPortInformation(int port,vtkInformation * info)174 int vtkVolumeMapper::FillInputPortInformation(int port, vtkInformation* info)
175 {
176   if (!this->Superclass::FillInputPortInformation(port, info))
177   {
178     return 0;
179   }
180   info->Set(vtkAlgorithm::INPUT_REQUIRED_DATA_TYPE(), "vtkDataSet");
181   return 1;
182 }
183 
184 //------------------------------------------------------------------------------
SpacingAdjustedSampleDistance(double inputSpacing[3],int inputExtent[6])185 double vtkVolumeMapper::SpacingAdjustedSampleDistance(double inputSpacing[3], int inputExtent[6])
186 {
187   // compute 1/2 the average spacing
188   double dist = (inputSpacing[0] + inputSpacing[1] + inputSpacing[2]) / 6.0;
189   double avgNumVoxels =
190     pow(static_cast<double>((inputExtent[1] - inputExtent[0]) * (inputExtent[3] - inputExtent[2]) *
191           (inputExtent[5] - inputExtent[4])),
192       static_cast<double>(0.333));
193 
194   if (avgNumVoxels < 100)
195   {
196     dist *= 0.01 + (1 - 0.01) * avgNumVoxels / 100;
197   }
198 
199   return dist;
200 }
201