1 /*=========================================================================
2 
3   Program:   Visualization Toolkit
4   Module:    ExerciseUnstructuredGridRayCastMapper.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 #include "ExerciseUnstructuredGridRayCastMapper.h"
17 
18 #include "vtkActor.h"
19 #include "vtkArrayCalculator.h"
20 #include "vtkAssignAttribute.h"
21 #include "vtkCamera.h"
22 #include "vtkCellData.h"
23 #include "vtkColorTransferFunction.h"
24 #include "vtkCubeSource.h"
25 #include "vtkDataSet.h"
26 #include "vtkDataSetTriangleFilter.h"
27 #include "vtkDoubleArray.h"
28 #include "vtkImageMandelbrotSource.h"
29 #include "vtkInformation.h"
30 #include "vtkInformationVector.h"
31 #include "vtkObjectFactory.h"
32 #include "vtkPiecewiseFunction.h"
33 #include "vtkPointData.h"
34 #include "vtkPointDataToCellData.h"
35 #include "vtkPolyDataMapper.h"
36 #include "vtkRenderer.h"
37 #include "vtkRenderWindow.h"
38 #include "vtkRenderWindowInteractor.h"
39 #include "vtkUnstructuredGridVolumeRayCastFunction.h"
40 #include "vtkUnstructuredGridVolumeRayCastMapper.h"
41 #include "vtkUnstructuredGridVolumeRayIntegrator.h"
42 #include "vtkVolume.h"
43 #include "vtkVolumeProperty.h"
44 
45 #include "vtkRegressionTestImage.h"
46 
47 //=============================================================================
48 
49 // A simple filter that will convert an array from independent scalars
50 // to dependent scalars.
51 class vtkClassifyVolume : public vtkDataSetAlgorithm
52 {
53 public:
54   vtkTypeMacro(vtkClassifyVolume, vtkDataSetAlgorithm);
55   static vtkClassifyVolume *New();
56 
57   vtkGetObjectMacro(TransferFunction, vtkVolumeProperty);
58   vtkSetObjectMacro(TransferFunction, vtkVolumeProperty);
59 
60 protected:
61   vtkClassifyVolume();
62   ~vtkClassifyVolume();
63 
64   virtual int RequestData(vtkInformation *, vtkInformationVector **,
65                           vtkInformationVector *);
66 
67   virtual void Classify(vtkDataSetAttributes *in, vtkDataSetAttributes *out);
68 
69   vtkVolumeProperty *TransferFunction;
70 
71 private:
72   vtkClassifyVolume(const vtkClassifyVolume&);  // Not implemented
73   void operator=(const vtkClassifyVolume&);     // Not implemented
74 };
75 
76 //-----------------------------------------------------------------------------
77 
78 vtkStandardNewMacro(vtkClassifyVolume);
79 
vtkClassifyVolume()80 vtkClassifyVolume::vtkClassifyVolume()
81 {
82   this->TransferFunction = NULL;
83 }
84 
~vtkClassifyVolume()85 vtkClassifyVolume::~vtkClassifyVolume()
86 {
87   this->SetTransferFunction(NULL);
88 }
89 
90 //-----------------------------------------------------------------------------
91 
RequestData(vtkInformation *,vtkInformationVector ** inputVector,vtkInformationVector * outputVector)92 int vtkClassifyVolume::RequestData(vtkInformation *,
93                                    vtkInformationVector **inputVector,
94                                    vtkInformationVector *outputVector)
95 {
96   vtkInformation *inInfo = inputVector[0]->GetInformationObject(0);
97   vtkDataSet *input = vtkDataSet::SafeDownCast(
98                                      inInfo->Get(vtkDataObject::DATA_OBJECT()));
99 
100   vtkInformation *outInfo = outputVector->GetInformationObject(0);
101   vtkDataSet *output = vtkDataSet::SafeDownCast(
102                                     outInfo->Get(vtkDataObject::DATA_OBJECT()));
103 
104   output->CopyStructure(input);
105   this->Classify(input->GetPointData(), output->GetPointData());
106   this->Classify(input->GetCellData(), output->GetCellData());
107 
108   return 1;
109 }
110 
111 //-----------------------------------------------------------------------------
112 
Classify(vtkDataSetAttributes * inAttrib,vtkDataSetAttributes * outAttrib)113 void vtkClassifyVolume::Classify(vtkDataSetAttributes *inAttrib,
114                                  vtkDataSetAttributes *outAttrib)
115 {
116   vtkDataArray *scalars = inAttrib->GetScalars();
117   if (!scalars) return;
118 
119   if (scalars->GetNumberOfComponents() != 1)
120     {
121     vtkErrorMacro(<< "Only 1-tuple scalars are supported now.");
122     return;
123     }
124   vtkIdType numScalars = scalars->GetNumberOfTuples();
125 
126   vtkDoubleArray *colors = vtkDoubleArray::New();
127   colors->SetName(scalars->GetName());
128 
129   if (this->TransferFunction->GetColorChannels() == 3)
130     {
131     colors->SetNumberOfComponents(4);
132     colors->SetNumberOfTuples(numScalars);
133 
134     vtkColorTransferFunction *rgb
135       = this->TransferFunction->GetRGBTransferFunction();
136     vtkPiecewiseFunction *alpha = this->TransferFunction->GetScalarOpacity();
137 
138     for (vtkIdType i = 0; i < numScalars; i++)
139       {
140       double c[4];
141       double x = scalars->GetComponent(i, 0);
142       rgb->GetColor(x, c);
143       c[3] = alpha->GetValue(x);
144       colors->SetTuple(i, c);
145       }
146     }
147   else
148     {
149     vtkErrorMacro(<< "Gray values are not supported now.");
150     }
151 
152   outAttrib->SetScalars(colors);
153   colors->Delete();
154 }
155 
156 //=============================================================================
157 
NewTestViewport(RayCastFunctionCreator NewFunction,RayIntegratorCreator NewIntegrator,vtkVolumeProperty * volumeProperty,int UseCellData,int UseDependentComponents,int UseMultipleTransferFunctions)158 static vtkRenderer *NewTestViewport(RayCastFunctionCreator NewFunction,
159                                     RayIntegratorCreator NewIntegrator,
160                                     vtkVolumeProperty *volumeProperty,
161                                     int UseCellData, int UseDependentComponents,
162                                     int UseMultipleTransferFunctions)
163 {
164   // Create the render window.
165   vtkRenderer *ren = vtkRenderer::New();
166 
167   // Create a small mesh.  The coarser and more opaque the mesh, the easier it
168   // is to see rendering errors.
169   vtkImageMandelbrotSource *input = vtkImageMandelbrotSource::New();
170   input->SetWholeExtent(0, 2, 0, 2, 0, 2);
171   input->SetSizeCX(2, 2, 2, 2);
172   input->SetMaximumNumberOfIterations(10);
173   vtkAlgorithmOutput *outputPort = input->GetOutputPort(0);
174 
175   // Make sure we have only tetrahedra.
176   vtkDataSetTriangleFilter *trifilter = vtkDataSetTriangleFilter::New();
177   trifilter->SetInputConnection(0, outputPort);
178   outputPort = trifilter->GetOutputPort(0);
179 
180   // Make multiple scalars if necessary.
181   vtkArrayCalculator *calc = NULL;
182   vtkAssignAttribute *assign = NULL;
183   if (UseMultipleTransferFunctions)
184     {
185     calc = vtkArrayCalculator::New();
186     calc->AddScalarArrayName("Iterations");
187     calc->SetResultArrayName("Result");
188     calc->SetFunction("Iterations*iHat + (10-Iterations)*jHat");
189     calc->SetInputConnection(0, outputPort);
190     outputPort = calc->GetOutputPort(0);
191 
192     assign = vtkAssignAttribute::New();
193     assign->Assign(vtkDataSetAttributes::VECTORS, vtkDataSetAttributes::SCALARS,
194                    vtkAssignAttribute::POINT_DATA);
195     assign->SetInputConnection(0, outputPort);
196     outputPort = assign->GetOutputPort(0);
197     }
198 
199   // Convert to cell centered data if requested.
200   vtkPointDataToCellData *celldata = NULL;
201   if (UseCellData)
202     {
203     celldata = vtkPointDataToCellData::New();
204     celldata->SetInputConnection(0, outputPort);
205     celldata->PassPointDataOff();
206     outputPort = celldata->GetOutputPort(0);
207     }
208 
209   // Classify the data if testing dependent components.
210   vtkClassifyVolume *classify = NULL;
211   if (UseDependentComponents)
212     {
213     classify = vtkClassifyVolume::New();
214     classify->SetTransferFunction(volumeProperty);
215     classify->SetInputConnection(0, outputPort);
216     outputPort = classify->GetOutputPort(0);
217     }
218 
219   // Set up the mapper.
220   vtkUnstructuredGridVolumeRayCastMapper *mapper
221     = vtkUnstructuredGridVolumeRayCastMapper::New();
222   mapper->SetInputConnection(0, outputPort);
223   if (NewFunction)
224     {
225     vtkUnstructuredGridVolumeRayCastFunction *function = NewFunction();
226     mapper->SetRayCastFunction(function);
227     function->Delete();
228     }
229   if (NewIntegrator)
230     {
231     vtkUnstructuredGridVolumeRayIntegrator *integrator = NewIntegrator();
232     mapper->SetRayIntegrator(integrator);
233     integrator->Delete();
234     }
235 
236   // The volume holds the mapper and property and can be used to position/orient
237   // the volume.
238   vtkVolume *volume = vtkVolume::New();
239   volume->SetMapper(mapper);
240   if (!UseDependentComponents)
241     {
242     volume->SetProperty(volumeProperty);
243     }
244   else
245     {
246     // Set up a volume property that does not have the transfer function.
247     vtkVolumeProperty *vp = vtkVolumeProperty::New();
248     vp->SetShade(volumeProperty->GetShade());
249     vp->SetInterpolationType(volumeProperty->GetInterpolationType());
250     vp->SetScalarOpacityUnitDistance(
251                                 volumeProperty->GetScalarOpacityUnitDistance());
252     vp->IndependentComponentsOff();
253     volume->SetProperty(vp);
254     vp->Delete();
255     }
256 
257   // Add the volume to the renderer.
258   ren->AddVolume(volume);
259 
260   ren->ResetCamera();
261   ren->GetActiveCamera()->Azimuth(20.0);
262   ren->GetActiveCamera()->Elevation(15.0);
263   ren->GetActiveCamera()->Zoom(1.5);
264 
265   // Delete objects.  Will not actually be destroyed due to reference counting.
266   input->Delete();
267   trifilter->Delete();
268   if (celldata) celldata->Delete();
269   if (calc) calc->Delete();
270   if (assign) assign->Delete();
271   if (classify) classify->Delete();
272   mapper->Delete();
273   volume->Delete();
274 
275   return ren;
276 }
277 
278 //-----------------------------------------------------------------------------
279 
NewPlaceholderViewport()280 static vtkRenderer *NewPlaceholderViewport()
281 {
282   vtkRenderer *ren = vtkRenderer::New();
283 
284   vtkCubeSource *cube = vtkCubeSource::New();
285 
286   vtkPolyDataMapper *mapper = vtkPolyDataMapper::New();
287   mapper->SetInputConnection(0, cube->GetOutputPort(0));
288   cube->Delete();
289 
290   vtkActor *actor = vtkActor::New();
291   actor->SetMapper(mapper);
292   mapper->Delete();
293 
294   ren->AddActor(actor);
295   ren->ResetCamera();
296   actor->Delete();
297 
298   return ren;
299 }
300 
301 //-----------------------------------------------------------------------------
302 
NewRGBVolumeProperty()303 static vtkVolumeProperty *NewRGBVolumeProperty()
304 {
305   // Create transfer mapping scalar value to opacity.
306   vtkPiecewiseFunction *opacityTransferFunction = vtkPiecewiseFunction::New();
307   opacityTransferFunction->AddPoint( 0.0, 0.0);
308   opacityTransferFunction->AddPoint(10.0, 1.0);
309 
310   // Create transfer mapping scalar value to color.
311   vtkColorTransferFunction *colorTransferFunction
312     = vtkColorTransferFunction::New();
313   colorTransferFunction->SetColorSpaceToHSV();
314   colorTransferFunction->HSVWrapOn();
315   colorTransferFunction->AddHSVPoint( 0.0, 4.0/6.0, 1.0, 1.0);
316   colorTransferFunction->AddHSVPoint( 4.0, 2.0/6.0, 1.0, 1.0);
317   colorTransferFunction->AddHSVPoint( 6.0, 1.0/6.0, 1.0, 1.0);
318   colorTransferFunction->AddHSVPoint(10.0, 5.0/6.0, 1.0, 1.0);
319 
320   vtkVolumeProperty *volumeProperty = vtkVolumeProperty::New();
321   volumeProperty->SetColor(colorTransferFunction);
322   volumeProperty->SetScalarOpacity(opacityTransferFunction);
323   volumeProperty->ShadeOff();
324   volumeProperty->SetInterpolationTypeToLinear();
325   volumeProperty->SetScalarOpacityUnitDistance(0.75);
326 
327   // Delete objects.  Will not actually be destroyed due to reference counting.
328   opacityTransferFunction->Delete();
329   colorTransferFunction->Delete();
330 
331   return volumeProperty;
332 }
333 
334 //-----------------------------------------------------------------------------
335 
NewGrayVolumeProperty()336 static vtkVolumeProperty *NewGrayVolumeProperty()
337 {
338   // Create transfer mapping scalar value to opacity.
339   vtkPiecewiseFunction *opacityTransferFunction = vtkPiecewiseFunction::New();
340   opacityTransferFunction->AddPoint( 0.0, 0.0);
341   opacityTransferFunction->AddPoint(10.0, 1.0);
342 
343   // Create transfer mapping scalar value to color.
344   vtkPiecewiseFunction *grayTransferFunction = vtkPiecewiseFunction::New();
345   grayTransferFunction->AddPoint( 0.0, 0.0);
346   grayTransferFunction->AddPoint(10.0, 1.0);
347 
348   vtkVolumeProperty *volumeProperty = vtkVolumeProperty::New();
349   volumeProperty->SetColor(grayTransferFunction);
350   volumeProperty->SetScalarOpacity(opacityTransferFunction);
351   volumeProperty->ShadeOff();
352   volumeProperty->SetInterpolationTypeToLinear();
353   volumeProperty->SetScalarOpacityUnitDistance(0.75);
354 
355   // Delete objects.  Will not actually be destroyed due to reference counting.
356   opacityTransferFunction->Delete();
357   grayTransferFunction->Delete();
358 
359   return volumeProperty;
360 }
361 
362 //-----------------------------------------------------------------------------
363 
NewMultiTFVolumeProperty()364 static vtkVolumeProperty *NewMultiTFVolumeProperty()
365 {
366   vtkVolumeProperty *volumeProperty = vtkVolumeProperty::New();
367   volumeProperty->ShadeOff();
368   volumeProperty->SetInterpolationTypeToLinear();
369   volumeProperty->SetScalarOpacityUnitDistance(0.75);
370 
371   vtkColorTransferFunction *rgb;
372   vtkPiecewiseFunction *a;
373 
374   // Create first tf.
375   rgb = vtkColorTransferFunction::New();
376   rgb->AddRGBPoint(0.0, 1.0, 0.0, 0.0);
377   volumeProperty->SetColor(0, rgb);
378   rgb->Delete();
379 
380   a = vtkPiecewiseFunction::New();
381   a->AddPoint(2.9, 0.0);
382   a->AddPoint(3.0, 1.0);
383   volumeProperty->SetScalarOpacity(0, a);
384   a->Delete();
385 
386   // Create second tf.
387   rgb = vtkColorTransferFunction::New();
388   rgb->AddRGBPoint(0.0, 0.0, 1.0, 1.0);
389   volumeProperty->SetColor(1, rgb);
390   rgb->Delete();
391 
392   a = vtkPiecewiseFunction::New();
393   a->AddPoint(4.9, 0.0);
394   a->AddPoint(5.0, 0.5);
395   volumeProperty->SetScalarOpacity(1, a);
396   a->Delete();
397 
398   // Create third tf.
399   rgb = vtkColorTransferFunction::New();
400   rgb->AddRGBPoint(0.0, 0.0, 0.0, 0.0);
401   volumeProperty->SetColor(2, rgb);
402   rgb->Delete();
403 
404   a = vtkPiecewiseFunction::New();
405   a->AddPoint(0.0, 0.0);
406   volumeProperty->SetScalarOpacity(2, a);
407   a->Delete();
408 
409   return volumeProperty;
410 }
411 
412 //-----------------------------------------------------------------------------
413 
ExerciseUnstructuredGridRayCastMapper(int argc,char * argv[],RayCastFunctionCreator NewFunction,RayIntegratorCreator NewIntegrator,int UseCellData,int TestDependentComponents)414 int ExerciseUnstructuredGridRayCastMapper(int argc, char *argv[],
415                                           RayCastFunctionCreator NewFunction,
416                                           RayIntegratorCreator NewIntegrator,
417                                           int UseCellData,
418                                           int TestDependentComponents)
419 {
420   // Create the standard render window and interactor.
421   vtkRenderWindow *renWin = vtkRenderWindow::New();
422   renWin->SetSize(300, 300);
423 
424   vtkRenderWindowInteractor *iren = vtkRenderWindowInteractor::New();
425   iren->SetRenderWindow(renWin);
426   iren->SetDesiredUpdateRate(3.0);
427 
428   // The property describes how the data will look.  Establish various
429   // rendering modes with the property and its transfer functions.
430   vtkVolumeProperty *volumeProperty;
431   vtkRenderer *viewport;
432 
433   // RGB transfer function.
434   volumeProperty = NewRGBVolumeProperty();
435   viewport = NewTestViewport(NewFunction, NewIntegrator, volumeProperty,
436                              UseCellData, 0, 0);
437   if (!viewport) return -1;
438   viewport->SetViewport(0.0, 0.0, 0.5, 0.5);
439   renWin->AddRenderer(viewport);
440   volumeProperty->Delete();
441   viewport->Delete();
442 
443   // Gray transfer function.
444   volumeProperty = NewGrayVolumeProperty();
445   viewport = NewTestViewport(NewFunction, NewIntegrator, volumeProperty,
446                              UseCellData, 0, 0);
447   if (!viewport) return -1;
448   viewport->SetViewport(0.5, 0.0, 1.0, 0.5);
449   renWin->AddRenderer(viewport);
450   volumeProperty->Delete();
451   viewport->Delete();
452 
453   if (TestDependentComponents)
454     {
455     // RGBA dependent components.
456     volumeProperty = NewRGBVolumeProperty();
457     viewport = NewTestViewport(NewFunction, NewIntegrator, volumeProperty,
458                                UseCellData, 1, 0);
459     volumeProperty->Delete();
460     }
461   else
462     {
463     viewport = NewPlaceholderViewport();
464     }
465   if (!viewport) return -1;
466   viewport->SetViewport(0.0, 0.5, 0.5, 1.0);
467   renWin->AddRenderer(viewport);
468   viewport->Delete();
469 
470   // Multiple transfer functions
471   volumeProperty = NewMultiTFVolumeProperty();
472   viewport = NewTestViewport(NewFunction, NewIntegrator, volumeProperty,
473                              UseCellData, 0, 1);
474   if (!viewport) return -1;
475   viewport->SetViewport(0.5, 0.5, 1.0, 1.0);
476   renWin->AddRenderer(viewport);
477   volumeProperty->Delete();
478   viewport->Delete();
479 
480   int retVal = vtkRegressionTestImageThreshold(renWin, 70);
481   if (retVal == vtkRegressionTester::DO_INTERACTOR)
482     {
483     iren->Start();
484     }
485 
486   // Delete objects.
487   renWin->Delete();
488   iren->Delete();
489 
490   return !retVal;
491 }
492