source: trunk/packages/vizservers/vtkvis/RpLIC.cpp @ 2573

Last change on this file since 2573 was 2573, checked in by ldelgass, 13 years ago

Merge vtkvis_threaded branch to trunk. (Threading off by default in Makefile)

  • Property svn:eol-style set to native
File size: 13.7 KB
Line 
1/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2/*
3 * Copyright (C) 2011, Purdue Research Foundation
4 *
5 * Author: Leif Delgass <ldelgass@purdue.edu>
6 */
7
8#include <cassert>
9
10#include <vtkActor.h>
11#include <vtkProperty.h>
12#include <vtkPointData.h>
13#include <vtkCellData.h>
14#include <vtkCellDataToPointData.h>
15#include <vtkImageData.h>
16#include <vtkPolyData.h>
17#include <vtkDataSetMapper.h>
18#include <vtkPainterPolyDataMapper.h>
19#include <vtkDataSetSurfaceFilter.h>
20#include <vtkCutter.h>
21#include <vtkImageMask.h>
22#include <vtkImageCast.h>
23
24#include "RpLIC.h"
25#include "Trace.h"
26
27using namespace Rappture::VtkVis;
28
29LIC::LIC() :
30    VtkGraphicsObject(),
31    _sliceAxis(Z_AXIS),
32    _colorMap(NULL)
33{
34}
35
36LIC::~LIC()
37{
38#ifdef WANT_TRACE
39    if (_dataSet != NULL)
40        TRACE("Deleting LIC for %s", _dataSet->getName().c_str());
41    else
42        TRACE("Deleting LIC with NULL DataSet");
43#endif
44}
45
46void LIC::initProp()
47{
48    if (_prop == NULL) {
49        _prop = vtkSmartPointer<vtkActor>::New();
50        vtkProperty *property = getActor()->GetProperty();
51        property->SetOpacity(_opacity);
52        property->SetEdgeColor(_edgeColor[0], _edgeColor[1], _edgeColor[2]);
53        property->SetLineWidth(_edgeWidth);
54        property->EdgeVisibilityOff();
55        property->SetAmbient(.2);
56        if (!_lighting)
57            property->LightingOff();
58    }
59}
60
61void LIC::update()
62{
63    if (_dataSet == NULL)
64        return;
65
66    vtkDataSet *ds = _dataSet->getVtkDataSet();
67
68    vtkSmartPointer<vtkCellDataToPointData> cellToPtData;
69    if (ds->GetPointData() == NULL ||
70        ds->GetPointData()->GetVectors() == NULL) {
71         WARN("No vector point data in dataset %s", _dataSet->getName().c_str());
72         if (ds->GetCellData() != NULL &&
73             ds->GetCellData()->GetVectors() != NULL) {
74             cellToPtData =
75                 vtkSmartPointer<vtkCellDataToPointData>::New();
76             cellToPtData->SetInput(ds);
77             //cellToPtData->PassCellDataOn();
78             cellToPtData->Update();
79             ds = cellToPtData->GetOutput();
80         } else {
81             ERROR("No vector cell data in dataset %s", _dataSet->getName().c_str());
82             return;
83         }
84    }
85
86    vtkImageData *imageData = vtkImageData::SafeDownCast(ds);
87    if (imageData != NULL) {
88        if (_lic == NULL) {
89            _lic = vtkSmartPointer<vtkImageDataLIC2D>::New();
90        }
91        if (!_dataSet->is2D()) {
92            // 3D image/volume/uniform grid
93            if (_volumeSlicer == NULL)
94                _volumeSlicer = vtkSmartPointer<vtkExtractVOI>::New();
95            int dims[3];
96            imageData->GetDimensions(dims);
97            TRACE("Image data dimensions: %d %d %d", dims[0], dims[1], dims[2]);
98            _volumeSlicer->SetInput(ds);
99            _volumeSlicer->SetVOI(0, dims[0]-1, 0, dims[1]-1, (dims[2]-1)/2, (dims[2]-1)/2);
100            _volumeSlicer->SetSampleRate(1, 1, 1);
101            _lic->SetInputConnection(_volumeSlicer->GetOutputPort());
102        } else {
103            // 2D image/volume/uniform grid
104            _lic->SetInput(ds);
105        }
106        if (_mapper == NULL) {
107            _mapper = vtkSmartPointer<vtkDataSetMapper>::New();
108        }
109        _mapper->SetInputConnection(_lic->GetOutputPort());
110    } else if (vtkPolyData::SafeDownCast(ds) == NULL) {
111        // structured grid, unstructured grid, or rectilinear grid
112        if (_lic == NULL) {
113            _lic = vtkSmartPointer<vtkImageDataLIC2D>::New();
114        }
115
116        // Need to convert to vtkImageData
117        double bounds[6];
118        ds->GetBounds(bounds);
119        double xSize = bounds[1] - bounds[0];
120        double ySize = bounds[3] - bounds[2];
121        double zSize = bounds[5] - bounds[4];
122        int minDir = 2;
123        if (xSize < ySize && xSize < zSize)
124            minDir = 0;
125        if (ySize < xSize && ySize < zSize)
126            minDir = 1;
127        if (_probeFilter == NULL)
128            _probeFilter = vtkSmartPointer<vtkProbeFilter>::New();
129
130        if (!_dataSet->is2D()) {
131            // Sample a plane within the grid bounding box
132            vtkSmartPointer<vtkCutter> cutter = vtkSmartPointer<vtkCutter>::New();
133            if (_cutPlane == NULL) {
134                _cutPlane = vtkSmartPointer<vtkPlane>::New();
135            }
136            if (minDir == 0) {
137                _cutPlane->SetNormal(1, 0, 0);
138                _cutPlane->SetOrigin(bounds[0] + (bounds[1]-bounds[0])/2.,
139                                     0,
140                                     0);
141            } else if (minDir == 1) {
142                _cutPlane->SetNormal(0, 1, 0);
143                _cutPlane->SetOrigin(0,
144                                     bounds[2] + (bounds[3]-bounds[2])/2.,
145                                     0);
146            } else {
147                _cutPlane->SetNormal(0, 0, 1);
148                _cutPlane->SetOrigin(0,
149                                     0,
150                                     bounds[4] + (bounds[5]-bounds[4])/2.);
151            }
152            cutter->SetInput(ds);
153            cutter->SetCutFunction(_cutPlane);
154            _probeFilter->SetSourceConnection(cutter->GetOutputPort());
155        } else {
156            _probeFilter->SetSource(ds);
157        }
158
159        vtkSmartPointer<vtkImageData> imageData = vtkSmartPointer<vtkImageData>::New();
160        int xdim, ydim, zdim;
161        double origin[3], spacing[3];
162        if (minDir == 0) {
163            xdim = 1;
164            ydim = 128;
165            zdim = 128;
166            origin[0] = bounds[0] + xSize/2.;
167            origin[1] = bounds[2];
168            origin[2] = bounds[4];
169            spacing[0] = 0;
170            spacing[1] = ySize/((double)(ydim-1));
171            spacing[2] = zSize/((double)(zdim-1));
172            _sliceAxis = X_AXIS;
173        } else if (minDir == 1) {
174            xdim = 128;
175            ydim = 1;
176            zdim = 128;
177            origin[0] = bounds[0];
178            origin[1] = bounds[2] + ySize/2.;
179            origin[2] = bounds[4];
180            spacing[0] = xSize/((double)(xdim-1));
181            spacing[1] = 0;
182            spacing[2] = zSize/((double)(zdim-1));
183            _sliceAxis = Y_AXIS;
184        } else {
185            xdim = 128;
186            ydim = 128;
187            zdim = 1;
188            origin[0] = bounds[0];
189            origin[1] = bounds[2];
190            origin[2] = bounds[4] + zSize/2.;
191            spacing[0] = xSize/((double)(xdim-1));
192            spacing[1] = ySize/((double)(ydim-1));
193            spacing[2] = 0;
194            _sliceAxis = Z_AXIS;
195        }
196        imageData->SetDimensions(xdim, ydim, zdim);
197        imageData->SetOrigin(origin);
198        imageData->SetSpacing(spacing);
199        _probeFilter->SetInput(imageData);
200        _lic->SetInputConnection(_probeFilter->GetOutputPort());
201
202        if (_mapper == NULL) {
203            _mapper = vtkSmartPointer<vtkDataSetMapper>::New();
204            _mapper->SetColorModeToMapScalars();
205        }
206        _lic->Update();
207        vtkSmartPointer<vtkImageCast> cast = vtkSmartPointer<vtkImageCast>::New();
208        cast->SetInputConnection(_probeFilter->GetOutputPort());
209        cast->SetInputArrayToProcess(0, 0, 0, vtkDataObject::FIELD_ASSOCIATION_POINTS,
210                                     _probeFilter->GetValidPointMaskArrayName());
211        cast->SetOutputScalarTypeToUnsignedChar();
212        vtkSmartPointer<vtkImageMask> mask = vtkSmartPointer<vtkImageMask>::New();
213        mask->SetInputConnection(0, _lic->GetOutputPort());
214        mask->SetInputConnection(1, cast->GetOutputPort());
215        _mapper->SetInputConnection(mask->GetOutputPort());
216    } else {
217        // DataSet is a PolyData
218        vtkPolyData *pd = vtkPolyData::SafeDownCast(ds);
219        assert(pd != NULL);
220
221        // XXX: This mapper seems to conflict with offscreen rendering, so the main
222        // renderer needs to be set not to use FBOs for this to work
223        _mapper = vtkSmartPointer<vtkPainterPolyDataMapper>::New();
224        vtkPainterPolyDataMapper *ppdmapper = vtkPainterPolyDataMapper::SafeDownCast(_mapper);
225        if (_painter == NULL) {
226            _painter = vtkSmartPointer<vtkSurfaceLICPainter>::New();
227            _painter->SetDelegatePainter(ppdmapper->GetPainter());
228         }
229        ppdmapper->SetPainter(_painter);
230        ppdmapper->SetInput(pd);
231    }
232
233    if (_lut == NULL) {
234        setColorMap(ColorMap::getGrayDefault());
235    }
236
237    initProp();
238    getActor()->SetMapper(_mapper);
239
240    _mapper->Update();
241#ifdef WANT_TRACE
242    if (_lic != NULL) {
243        TRACE("FBO status: %d LIC status: %d", _lic->GetFBOSuccess(), _lic->GetLICSuccess());
244    } else if (_painter != NULL) {
245        TRACE("LIC status: %d", _painter->GetLICSuccess());
246    }
247#endif
248}
249
250/**
251 * \brief Select a 2D slice plane from a 3D DataSet
252 *
253 * \param[in] axis Axis of slice plane
254 * \param[in] ratio Position [0,1] of slice plane along axis
255 */
256void LIC::selectVolumeSlice(Axis axis, double ratio)
257{
258    if (_dataSet->is2D()) {
259        WARN("DataSet not 3D, returning");
260        return;
261    }
262
263    if (_volumeSlicer == NULL &&
264        _probeFilter == NULL) {
265        WARN("Called before update() or DataSet is not a volume");
266        return;
267    }
268
269    int dims[3];
270
271    vtkImageData *imageData = vtkImageData::SafeDownCast(_dataSet->getVtkDataSet());
272    if (imageData == NULL) {
273        if (_probeFilter != NULL) {
274            imageData = vtkImageData::SafeDownCast(_probeFilter->GetInput());
275            if (imageData == NULL) {
276                ERROR("Couldn't get probe filter input image");
277                return;
278            }
279        } else {
280            ERROR("Not a volume data set");
281            return;
282        }
283    }
284    imageData->GetDimensions(dims);
285
286    _sliceAxis = axis;
287
288    if (_probeFilter != NULL) {
289        vtkImageData *imageData = vtkImageData::SafeDownCast(_probeFilter->GetInput());
290        double bounds[6];
291        assert(vtkDataSet::SafeDownCast(_probeFilter->GetSource()) != NULL);
292        _dataSet->getBounds(bounds);
293        int dim = 128;
294
295        switch (axis) {
296        case X_AXIS:
297            imageData->SetDimensions(1, dim, dim);
298            imageData->SetOrigin(bounds[0] + (bounds[1]-bounds[0])*ratio, bounds[2], bounds[4]);
299            imageData->SetSpacing(0,
300                                  (bounds[3]-bounds[2])/((double)(dim-1)),
301                                  (bounds[5]-bounds[4])/((double)(dim-1)));
302            if (_cutPlane != NULL) {
303                _cutPlane->SetNormal(1, 0, 0);
304                _cutPlane->SetOrigin(bounds[0] + (bounds[1]-bounds[0])*ratio, 0, 0);
305            }
306            break;
307        case Y_AXIS:
308            imageData->SetDimensions(dim, 1, dim);
309            imageData->SetOrigin(bounds[0], bounds[2] + (bounds[3]-bounds[2])*ratio, bounds[4]);
310            imageData->SetSpacing((bounds[1]-bounds[0])/((double)(dim-1)),
311                                  0,
312                                  (bounds[5]-bounds[4])/((double)(dim-1)));
313            if (_cutPlane != NULL) {
314                _cutPlane->SetNormal(0, 1, 0);
315                _cutPlane->SetOrigin(0, bounds[2] + (bounds[3]-bounds[2])*ratio, 0);
316            }
317            break;
318        case Z_AXIS:
319            imageData->SetDimensions(dim, dim, 1);
320            imageData->SetOrigin(bounds[0], bounds[2], bounds[4] + (bounds[5]-bounds[4])*ratio);
321            imageData->SetSpacing((bounds[1]-bounds[0])/((double)(dim-1)),
322                                  (bounds[3]-bounds[2])/((double)(dim-1)),
323                                  0);
324            if (_cutPlane != NULL) {
325                _cutPlane->SetNormal(0, 0, 1);
326                _cutPlane->SetOrigin(0, 0, bounds[4] + (bounds[5]-bounds[4])*ratio);
327            }
328            break;
329        default:
330            ERROR("Invalid Axis");
331            return;
332        }
333    } else {
334        int voi[6];
335
336        switch (axis) {
337        case X_AXIS:
338            voi[0] = voi[1] = (int)((dims[0]-1) * ratio);
339            voi[2] = 0;
340            voi[3] = dims[1]-1;
341            voi[4] = 0;
342            voi[5] = dims[2]-1;
343            break;
344        case Y_AXIS:
345            voi[2] = voi[3] = (int)((dims[1]-1) * ratio);
346            voi[0] = 0;
347            voi[1] = dims[0]-1;
348            voi[4] = 0;
349            voi[5] = dims[2]-1;
350            break;
351        case Z_AXIS:
352            voi[4] = voi[5] = (int)((dims[2]-1) * ratio);
353            voi[0] = 0;
354            voi[1] = dims[0]-1;
355            voi[2] = 0;
356            voi[3] = dims[1]-1;
357            break;
358        default:
359            ERROR("Invalid Axis");
360            return;
361        }
362
363        _volumeSlicer->SetVOI(voi);
364    }
365
366    if (_lic != NULL)
367        _lic->Update();
368
369    if (_mapper != NULL)
370        _mapper->Update();
371}
372
373/**
374 * \brief Called when the color map has been edited
375 */
376void LIC::updateColorMap()
377{
378    setColorMap(_colorMap);
379}
380
381/**
382 * \brief Associate a colormap lookup table with the DataSet
383 */
384void LIC::setColorMap(ColorMap *cmap)
385{
386    if (cmap == NULL)
387        return;
388
389    _colorMap = cmap;
390 
391    if (_lut == NULL) {
392        _lut = vtkSmartPointer<vtkLookupTable>::New();
393        if (_mapper != NULL) {
394            _mapper->UseLookupTableScalarRangeOff();
395            _mapper->SetLookupTable(_lut);
396        }
397    }
398
399    _lut->DeepCopy(cmap->getLookupTable());
400    _lut->SetRange(_dataRange);
401}
402
403void LIC::updateRanges(bool useCumulative,
404                       double scalarRange[2],
405                       double vectorMagnitudeRange[2],
406                       double vectorComponentRange[3][2])
407{
408    if (useCumulative) {
409        _dataRange[0] = scalarRange[0];
410        _dataRange[1] = scalarRange[1];
411    } else if (_dataSet != NULL) {
412        _dataSet->getScalarRange(_dataRange);
413    }
414
415    if (_lut != NULL) {
416        _lut->SetRange(_dataRange);
417    }
418}
419
420/**
421 * \brief Set a group of world coordinate planes to clip rendering
422 *
423 * Passing NULL for planes will remove all cliping planes
424 */
425void LIC::setClippingPlanes(vtkPlaneCollection *planes)
426{
427    if (_mapper != NULL) {
428        _mapper->SetClippingPlanes(planes);
429    }
430}
Note: See TracBrowser for help on using the repository browser.