1 /*=========================================================================
2 
3   Program:   Visualization Toolkit
4   Module:    TestValuePassFloatingPoint.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 
16 // Description:
17 // Tests vtkValuePass in FLOATING_POINT mode. The test generates a 3-component
18 // float array ("elevationVector") using the loaded polygonal data (points and cells).
19 // Polygons are rendered with the ValuePass to its internal floating point frame-buffer.
20 // The rendered float image is then queried from the vtkValuePass and used to
21 // generate a color image using vtkLookupTable, the color image is rendered with
22 // an image actor on-screen. This is repeated for each component.
23 
24 #include "vtkActor.h"
25 #include "vtkArrayCalculator.h"
26 #include "vtkCamera.h"
27 #include "vtkCameraPass.h"
28 #include "vtkCellData.h"
29 #include "vtkElevationFilter.h"
30 #include "vtkFloatArray.h"
31 #include "vtkImageActor.h"
32 #include "vtkImageData.h"
33 #include "vtkImageMapper3D.h"
34 #include "vtkInteractorStyleTrackballCamera.h"
35 #include "vtkLookupTable.h"
36 #include "vtkOpenGLRenderer.h"
37 #include "vtkPointData.h"
38 #include "vtkPointDataToCellData.h"
39 #include "vtkPolyData.h"
40 #include "vtkPolyDataMapper.h"
41 #include "vtkRegressionTestImage.h"
42 #include "vtkRenderPassCollection.h"
43 #include "vtkRenderWindow.h"
44 #include "vtkRenderWindowInteractor.h"
45 #include "vtkSequencePass.h"
46 #include "vtkSmartPointer.h"
47 #include "vtkSphereSource.h"
48 #include "vtkTestUtilities.h"
49 #include "vtkValuePass.h"
50 
GenerateElevationArray(vtkSmartPointer<vtkPolyDataAlgorithm> source)51 void GenerateElevationArray(vtkSmartPointer<vtkPolyDataAlgorithm> source)
52 {
53   vtkPolyData* data = source->GetOutput();
54   const double* bounds = data->GetBounds();
55 
56   vtkSmartPointer<vtkElevationFilter> elevation = vtkSmartPointer<vtkElevationFilter>::New();
57   elevation->SetInputConnection(source->GetOutputPort());
58 
59   // Use vtkElevation to generate an array per component. vtkElevation generates
60   // a projected distance from each point in the dataset to the line, with respect to
61   // the LowPoint ([0, 1] in this case. This is different from having the actual
62   // coordinates of a given point.
63   for (int c = 0; c < 3; c++)
64   {
65     std::string name;
66     switch (c)
67     {
68       case 0:
69         name = "delta_x";
70         elevation->SetLowPoint(bounds[0], 0.0, 0.0);
71         elevation->SetHighPoint(bounds[1], 0.0, 0.0);
72         break;
73       case 1:
74         name = "delta_y";
75         elevation->SetLowPoint(0.0, bounds[2], 0.0);
76         elevation->SetHighPoint(0.0, bounds[3], 0.0);
77         break;
78       case 2:
79         name = "delta_z";
80         elevation->SetLowPoint(0.0, 0.0, bounds[4]);
81         elevation->SetHighPoint(0.0, 0.0, bounds[5]);
82         break;
83     }
84     elevation->Update();
85 
86     vtkPolyData* result = vtkPolyData::SafeDownCast(elevation->GetOutput());
87     int outCellFlag;
88     // Enums defined in vtkAbstractMapper
89     vtkDataArray* elevArray =
90       vtkAbstractMapper::GetScalars(result, VTK_SCALAR_MODE_USE_POINT_FIELD_DATA,
91         VTK_GET_ARRAY_BY_NAME /*acc mode*/, 0 /*arr id*/, "Elevation" /*arr name*/, outCellFlag);
92     if (!elevArray)
93     {
94       std::cout << "->> Error: could not find array!" << std::endl;
95       return;
96     }
97 
98     elevArray->SetName(name.c_str());
99     data->GetPointData()->AddArray(elevArray);
100   }
101 
102   // Generate a 3-component vector array using the single components
103   // form elevation
104 
105   // Point data
106   vtkSmartPointer<vtkArrayCalculator> calc = vtkSmartPointer<vtkArrayCalculator>::New();
107   calc->SetInputConnection(source->GetOutputPort());
108   calc->SetAttributeTypeToPointData();
109   calc->AddScalarArrayName("delta_x");
110   calc->AddScalarArrayName("delta_y");
111   calc->AddScalarArrayName("delta_z");
112   calc->SetFunction("delta_x * iHat + delta_y * jHat + delta_z * kHat");
113   calc->SetResultArrayName("elevationVector");
114   calc->Update();
115 
116   // Cell data
117   vtkSmartPointer<vtkPointDataToCellData> p2c = vtkSmartPointer<vtkPointDataToCellData>::New();
118   p2c->SetInputConnection(calc->GetOutputPort());
119   p2c->PassPointDataOn();
120   p2c->Update();
121 
122   /// Include the elevation vector (point and cell data) in the original data
123   vtkPolyData* outputP2c = vtkPolyData::SafeDownCast(p2c->GetOutput());
124   data->GetPointData()->AddArray(
125     vtkDataSet::SafeDownCast(calc->GetOutput())->GetPointData()->GetArray("elevationVector"));
126   data->GetCellData()->AddArray(outputP2c->GetCellData()->GetArray("elevationVector"));
127 };
128 
129 //------------------------------------------------------------------------------
RenderComponentImages(std::vector<vtkSmartPointer<vtkImageData>> & colorImOut,vtkRenderWindow * window,vtkRenderer * renderer,vtkValuePass * valuePass,int dataMode,char const * name)130 void RenderComponentImages(std::vector<vtkSmartPointer<vtkImageData>>& colorImOut,
131   vtkRenderWindow* window, vtkRenderer* renderer, vtkValuePass* valuePass, int dataMode,
132   char const* name)
133 {
134   valuePass->SetInputArrayToProcess(dataMode, name);
135 
136   // Prepare a lut to map the floating point values
137   vtkSmartPointer<vtkLookupTable> lut = vtkSmartPointer<vtkLookupTable>::New();
138   lut->SetAlpha(1.0);
139   lut->Build();
140 
141   // Render each component in a separate image
142   for (int c = 0; c < 3; c++)
143   {
144     valuePass->SetInputComponentToProcess(c);
145     window->Render();
146 
147     /// Get the resulting values
148     vtkFloatArray* result = valuePass->GetFloatImageDataArray(renderer);
149     int* ext = valuePass->GetFloatImageExtents();
150 
151     // Map the resulting float image to a color table
152     vtkUnsignedCharArray* colored =
153       lut->MapScalars(result, VTK_COLOR_MODE_DEFAULT, 0 /* single comp*/);
154 
155     // Create an image dataset to render in a quad.
156     vtkSmartPointer<vtkImageData> colorIm = vtkSmartPointer<vtkImageData>::New();
157     colorIm->SetExtent(ext);
158     colorIm->GetPointData()->SetScalars(colored);
159     colorImOut.push_back(colorIm);
160     colored->Delete();
161   }
162 };
163 
164 ///////////////////////////////////////////////////////////////////////////////
TestValuePassFloatingPoint(int argc,char * argv[])165 int TestValuePassFloatingPoint(int argc, char* argv[])
166 {
167   // Load data
168   vtkSmartPointer<vtkSphereSource> sphere = vtkSmartPointer<vtkSphereSource>::New();
169   sphere->SetThetaResolution(8.0);
170   sphere->SetPhiResolution(8.0);
171   sphere->Update();
172 
173   // Prepare a 3-component array (data will be appended to reader's output)
174   GenerateElevationArray(sphere);
175   vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
176   mapper->SetInputData(sphere->GetOutput());
177   mapper->ScalarVisibilityOn();
178 
179   vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
180   actor->SetMapper(mapper);
181 
182   // Setup rendering and interaction
183   vtkSmartPointer<vtkRenderWindowInteractor> interactor =
184     vtkSmartPointer<vtkRenderWindowInteractor>::New();
185 
186   vtkSmartPointer<vtkInteractorStyleTrackballCamera> style =
187     vtkSmartPointer<vtkInteractorStyleTrackballCamera>::New();
188   interactor->SetInteractorStyle(style);
189 
190   vtkSmartPointer<vtkRenderWindow> window = vtkSmartPointer<vtkRenderWindow>::New();
191   window->SetMultiSamples(0);
192   window->SetSize(640, 640);
193 
194   vtkSmartPointer<vtkRenderer> renderer = vtkSmartPointer<vtkRenderer>::New();
195 
196   window->AddRenderer(renderer);
197   interactor->SetRenderWindow(window);
198 
199   renderer->AddActor(actor);
200   renderer->SetBackground(0.2, 0.2, 0.5);
201 
202   // Setup the value pass
203   int const comp = 0;
204 
205   vtkSmartPointer<vtkValuePass> valuePass = vtkSmartPointer<vtkValuePass>::New();
206   valuePass->SetInputComponentToProcess(comp);
207   // Initial data mode
208   valuePass->SetInputArrayToProcess(VTK_SCALAR_MODE_USE_POINT_FIELD_DATA, "elevationVector");
209   // valuePass->SetInputArrayToProcess(VTK_SCALAR_MODE_USE_CELL_FIELD_DATA,
210   //  "elevationVector");
211 
212   // 3. Add it to a sequence of passes
213   vtkSmartPointer<vtkRenderPassCollection> passes = vtkSmartPointer<vtkRenderPassCollection>::New();
214   passes->AddItem(valuePass);
215 
216   vtkSmartPointer<vtkSequencePass> sequence = vtkSmartPointer<vtkSequencePass>::New();
217   sequence->SetPasses(passes);
218 
219   vtkSmartPointer<vtkCameraPass> cameraPass = vtkSmartPointer<vtkCameraPass>::New();
220   cameraPass->SetDelegatePass(sequence);
221 
222   vtkOpenGLRenderer* glRenderer = vtkOpenGLRenderer::SafeDownCast(renderer);
223 
224   // Render the value pass
225   glRenderer->SetPass(cameraPass);
226   window->Render();
227 
228   // Render point data images
229   std::vector<vtkSmartPointer<vtkImageData>> colorImagesPoint;
230   RenderComponentImages(colorImagesPoint, window, renderer, valuePass,
231     VTK_SCALAR_MODE_USE_POINT_FIELD_DATA, "elevationVector");
232 
233   // Render cell data images
234   std::vector<vtkSmartPointer<vtkImageData>> colorImagesCell;
235   RenderComponentImages(colorImagesCell, window, renderer, valuePass,
236     VTK_SCALAR_MODE_USE_CELL_FIELD_DATA, "elevationVector");
237 
238   ////// Render results on-screen
239   renderer->RemoveActor(actor);
240 
241   // Add image actors to display the point dataArray's components
242   vtkSmartPointer<vtkImageActor> ia_x = vtkSmartPointer<vtkImageActor>::New();
243   ia_x->GetMapper()->SetInputData(colorImagesPoint.at(0));
244   renderer->AddActor(ia_x);
245 
246   vtkSmartPointer<vtkImageActor> ia_y = vtkSmartPointer<vtkImageActor>::New();
247   ia_y->RotateX(90);
248   ia_y->GetMapper()->SetInputData(colorImagesPoint.at(1));
249   renderer->AddActor(ia_y);
250 
251   vtkSmartPointer<vtkImageActor> ia_z = vtkSmartPointer<vtkImageActor>::New();
252   ia_z->RotateY(-90);
253   ia_z->GetMapper()->SetInputData(colorImagesPoint.at(2));
254   renderer->AddActor(ia_z);
255 
256   // Add image actors to display cell dataArray's components
257   vtkSmartPointer<vtkImageActor> iacell_x = vtkSmartPointer<vtkImageActor>::New();
258   iacell_x->SetPosition(-500, 600, 600);
259   iacell_x->GetMapper()->SetInputData(colorImagesCell.at(0));
260   renderer->AddActor(iacell_x);
261 
262   vtkSmartPointer<vtkImageActor> iacell_y = vtkSmartPointer<vtkImageActor>::New();
263   iacell_y->RotateX(90);
264   iacell_y->SetPosition(-500, 600, 600);
265   iacell_y->GetMapper()->SetInputData(colorImagesCell.at(1));
266   renderer->AddActor(iacell_y);
267 
268   vtkSmartPointer<vtkImageActor> iacell_z = vtkSmartPointer<vtkImageActor>::New();
269   iacell_z->RotateY(-90);
270   iacell_z->SetPosition(-500, 600, 600);
271   iacell_z->GetMapper()->SetInputData(colorImagesCell.at(2));
272   renderer->AddActor(iacell_z);
273 
274   // Adjust viewpoint
275   vtkCamera* cam = renderer->GetActiveCamera();
276   cam->SetPosition(2, 2, 2);
277   cam->SetFocalPoint(0, 0, 1);
278   renderer->ResetCamera();
279 
280   // Use the default pass to render the colored image.
281   glRenderer->SetPass(nullptr);
282   window->Render();
283 
284   // initialize render loop
285   int retVal = vtkRegressionTestImage(window);
286   if (retVal == vtkRegressionTester::DO_INTERACTOR)
287   {
288     interactor->Start();
289   }
290 
291   valuePass->ReleaseGraphicsResources(window);
292   return !retVal;
293 }
294