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