source: vtkvis/branches/1.7/LIC.cpp @ 4643

Last change on this file since 4643 was 4603, checked in by ldelgass, 10 years ago

merge r4060 from trunk

  • Property svn:eol-style set to native
File size: 16.6 KB
Line 
1/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2/*
3 * Copyright (C) 2004-2012  HUBzero Foundation, LLC
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#include <vtkDelaunay2D.h>
24#include <vtkDelaunay3D.h>
25#include <vtkTransform.h>
26
27#include "LIC.h"
28#include "Trace.h"
29
30using namespace VtkVis;
31
32LIC::LIC() :
33    GraphicsObject(),
34    _sliceAxis(Z_AXIS),
35    _colorMap(NULL),
36    _resolution(128)
37{
38}
39
40LIC::~LIC()
41{
42#ifdef WANT_TRACE
43    if (_dataSet != NULL)
44        TRACE("Deleting LIC for %s", _dataSet->getName().c_str());
45    else
46        TRACE("Deleting LIC with NULL DataSet");
47#endif
48}
49
50void LIC::initProp()
51{
52    if (_prop == NULL) {
53        _prop = vtkSmartPointer<vtkActor>::New();
54        vtkProperty *property = getActor()->GetProperty();
55        property->SetOpacity(_opacity);
56        property->SetEdgeColor(_edgeColor[0], _edgeColor[1], _edgeColor[2]);
57        property->SetLineWidth(_edgeWidth);
58        property->EdgeVisibilityOff();
59        property->SetAmbient(.2);
60        if (!_lighting)
61            property->LightingOff();
62    }
63}
64
65void LIC::update()
66{
67    if (_dataSet == NULL)
68        return;
69
70    vtkDataSet *ds = _dataSet->getVtkDataSet();
71
72    vtkSmartPointer<vtkCellDataToPointData> cellToPtData;
73    if (ds->GetPointData() == NULL ||
74        ds->GetPointData()->GetVectors() == NULL) {
75         TRACE("No vector point data in dataset %s", _dataSet->getName().c_str());
76         if (ds->GetCellData() != NULL &&
77             ds->GetCellData()->GetVectors() != NULL) {
78             cellToPtData =
79                 vtkSmartPointer<vtkCellDataToPointData>::New();
80#ifdef USE_VTK6
81             cellToPtData->SetInputData(ds);
82#else
83             cellToPtData->SetInput(ds);
84#endif
85             //cellToPtData->PassCellDataOn();
86             cellToPtData->Update();
87             ds = cellToPtData->GetOutput();
88         } else {
89             USER_ERROR("No vector field was found in the data set");
90             return;
91         }
92    }
93
94    vtkImageData *imageData = vtkImageData::SafeDownCast(ds);
95    if (imageData != NULL) {
96        if (_lic == NULL) {
97            _lic = vtkSmartPointer<vtkImageDataLIC2D>::New();
98        }
99        if (!_dataSet->is2D()) {
100            // 3D image/volume/uniform grid
101            if (_volumeSlicer == NULL)
102                _volumeSlicer = vtkSmartPointer<vtkExtractVOI>::New();
103            int dims[3];
104            imageData->GetDimensions(dims);
105            TRACE("Image data dimensions: %d %d %d", dims[0], dims[1], dims[2]);
106#ifdef USE_VTK6
107            _volumeSlicer->SetInputData(ds);
108#else
109            _volumeSlicer->SetInput(ds);
110#endif
111            _volumeSlicer->SetVOI(0, dims[0]-1, 0, dims[1]-1, (dims[2]-1)/2, (dims[2]-1)/2);
112            _volumeSlicer->SetSampleRate(1, 1, 1);
113            _lic->SetInputConnection(_volumeSlicer->GetOutputPort());
114        } else {
115            // 2D image/uniform grid
116#ifdef USE_VTK6
117            _lic->SetInputData(ds);
118#else
119            _lic->SetInput(ds);
120#endif
121        }
122        if (_mapper == NULL) {
123            _mapper = vtkSmartPointer<vtkDataSetMapper>::New();
124        }
125        _mapper->SetInputConnection(_lic->GetOutputPort());
126    } else if (vtkPolyData::SafeDownCast(ds) == NULL ||
127               _dataSet->isCloud() ||
128               _dataSet->is2D()) {
129        // structured/rectilinear/unstructured grid, cloud or 2D polydata
130        if (_lic == NULL) {
131            _lic = vtkSmartPointer<vtkImageDataLIC2D>::New();
132        }
133
134        // Need to convert to vtkImageData
135        double bounds[6];
136        ds->GetBounds(bounds);
137        double xSize = bounds[1] - bounds[0];
138        double ySize = bounds[3] - bounds[2];
139        double zSize = bounds[5] - bounds[4];
140        int minDir = 2;
141        if (xSize < ySize && xSize < zSize)
142            minDir = 0;
143        if (ySize < xSize && ySize < zSize)
144            minDir = 1;
145        if (_probeFilter == NULL)
146            _probeFilter = vtkSmartPointer<vtkProbeFilter>::New();
147
148        PrincipalPlane plane;
149        double offset;
150        if (!_dataSet->is2D(&plane, &offset)) {
151            // 3D Data: Sample a plane within the bounding box
152            vtkSmartPointer<vtkCutter> cutter = vtkSmartPointer<vtkCutter>::New();
153            if (_cutPlane == NULL) {
154                _cutPlane = vtkSmartPointer<vtkPlane>::New();
155            }
156            if (minDir == 0) {
157                _cutPlane->SetNormal(1, 0, 0);
158                _cutPlane->SetOrigin(bounds[0] + (bounds[1]-bounds[0])/2.,
159                                     0,
160                                     0);
161            } else if (minDir == 1) {
162                _cutPlane->SetNormal(0, 1, 0);
163                _cutPlane->SetOrigin(0,
164                                     bounds[2] + (bounds[3]-bounds[2])/2.,
165                                     0);
166            } else {
167                _cutPlane->SetNormal(0, 0, 1);
168                _cutPlane->SetOrigin(0,
169                                     0,
170                                     bounds[4] + (bounds[5]-bounds[4])/2.);
171            }
172
173            if (_dataSet->isCloud()) {
174                // 3D cloud -- Need to mesh it before we can resample
175                vtkSmartPointer<vtkDelaunay3D> mesher = vtkSmartPointer<vtkDelaunay3D>::New();
176#ifdef USE_VTK6
177                mesher->SetInputData(ds);
178#else
179                mesher->SetInput(ds);
180#endif
181                cutter->SetInputConnection(mesher->GetOutputPort());
182            } else {
183#ifdef USE_VTK6
184                cutter->SetInputData(ds);
185#else
186                cutter->SetInput(ds);
187#endif
188            }
189            cutter->SetCutFunction(_cutPlane);
190            _probeFilter->SetSourceConnection(cutter->GetOutputPort());
191        } else {
192            if (_dataSet->isCloud()) {
193                // 2D cloud -- Need to mesh it before we can resample
194                vtkSmartPointer<vtkDelaunay2D> mesher = vtkSmartPointer<vtkDelaunay2D>::New();
195                if (plane == PLANE_ZY) {
196                    vtkSmartPointer<vtkTransform> trans = vtkSmartPointer<vtkTransform>::New();
197                    trans->RotateWXYZ(90, 0, 1, 0);
198                    if (offset != 0.0) {
199                        trans->Translate(-offset, 0, 0);
200                    }
201                    mesher->SetTransform(trans);
202                } else if (plane == PLANE_XZ) {
203                    vtkSmartPointer<vtkTransform> trans = vtkSmartPointer<vtkTransform>::New();
204                    trans->RotateWXYZ(-90, 1, 0, 0);
205                    if (offset != 0.0) {
206                        trans->Translate(0, -offset, 0);
207                    }
208                    mesher->SetTransform(trans);
209                } else if (offset != 0.0) {
210                    // XY with Z offset
211                    vtkSmartPointer<vtkTransform> trans = vtkSmartPointer<vtkTransform>::New();
212                    trans->Translate(0, 0, -offset);
213                    mesher->SetTransform(trans);
214                }
215#ifdef USE_VTK6
216                mesher->SetInputData(ds);
217#else
218                mesher->SetInput(ds);
219#endif
220                _probeFilter->SetSourceConnection(mesher->GetOutputPort());
221            } else {
222#ifdef USE_VTK6
223                _probeFilter->SetSourceData(ds);
224#else
225                _probeFilter->SetSource(ds);
226#endif
227            }
228        }
229
230        vtkSmartPointer<vtkImageData> imageData = vtkSmartPointer<vtkImageData>::New();
231        int xdim, ydim, zdim;
232        double origin[3], spacing[3];
233        int res = _resolution;
234        if (minDir == 0) {
235            xdim = 1;
236            ydim = res;
237            zdim = res;
238            origin[0] = bounds[0] + xSize/2.;
239            origin[1] = bounds[2];
240            origin[2] = bounds[4];
241            spacing[0] = 0;
242            spacing[1] = ySize/((double)(ydim-1));
243            spacing[2] = zSize/((double)(zdim-1));
244            _sliceAxis = X_AXIS;
245        } else if (minDir == 1) {
246            xdim = res;
247            ydim = 1;
248            zdim = res;
249            origin[0] = bounds[0];
250            origin[1] = bounds[2] + ySize/2.;
251            origin[2] = bounds[4];
252            spacing[0] = xSize/((double)(xdim-1));
253            spacing[1] = 0;
254            spacing[2] = zSize/((double)(zdim-1));
255            _sliceAxis = Y_AXIS;
256        } else {
257            xdim = res;
258            ydim = res;
259            zdim = 1;
260            origin[0] = bounds[0];
261            origin[1] = bounds[2];
262            origin[2] = bounds[4] + zSize/2.;
263            spacing[0] = xSize/((double)(xdim-1));
264            spacing[1] = ySize/((double)(ydim-1));
265            spacing[2] = 0;
266            _sliceAxis = Z_AXIS;
267        }
268        imageData->SetDimensions(xdim, ydim, zdim);
269        imageData->SetOrigin(origin);
270        imageData->SetSpacing(spacing);
271#ifdef USE_VTK6
272        _probeFilter->SetInputData(imageData);
273#else
274        _probeFilter->SetInput(imageData);
275#endif
276        _lic->SetInputConnection(_probeFilter->GetOutputPort());
277
278        if (_mapper == NULL) {
279            _mapper = vtkSmartPointer<vtkDataSetMapper>::New();
280            _mapper->SetColorModeToMapScalars();
281        }
282        _lic->Update();
283        if (1) {
284            vtkSmartPointer<vtkImageData> imgData = _probeFilter->GetImageDataOutput();
285            imgData->GetPointData()->SetActiveScalars(_probeFilter->GetValidPointMaskArrayName());
286            vtkSmartPointer<vtkImageCast> maskCast = vtkSmartPointer<vtkImageCast>::New();
287            maskCast->SetInputData(imgData);
288            //maskCast->SetInputConnection(_probeFilter->GetOutputPort());
289            //maskCast->SetInputArrayToProcess(0, 0, 0, vtkDataObject::FIELD_ASSOCIATION_POINTS,
290            //                                 _probeFilter->GetValidPointMaskArrayName());
291            maskCast->SetOutputScalarTypeToUnsignedChar();
292            vtkSmartPointer<vtkImageCast> licCast = vtkSmartPointer<vtkImageCast>::New();
293            licCast->SetInputConnection(_lic->GetOutputPort());
294            licCast->SetOutputScalarTypeToDouble();
295            vtkSmartPointer<vtkImageMask> mask = vtkSmartPointer<vtkImageMask>::New();
296            mask->SetInputConnection(0, licCast->GetOutputPort());
297            mask->SetInputConnection(1, maskCast->GetOutputPort());
298            _mapper->SetInputConnection(mask->GetOutputPort());
299        } else {
300            // Mask not working in VTK 6.1?
301            _mapper->SetInputConnection(_lic->GetOutputPort());
302        }
303    } else {
304        // DataSet is a 3D PolyData with cells
305        vtkPolyData *pd = vtkPolyData::SafeDownCast(ds);
306        assert(pd != NULL);
307
308        // XXX: This mapper seems to conflict with offscreen rendering, so the main
309        // renderer needs to be set not to use FBOs for this to work
310        _mapper = vtkSmartPointer<vtkPainterPolyDataMapper>::New();
311        vtkPainterPolyDataMapper *ppdmapper = vtkPainterPolyDataMapper::SafeDownCast(_mapper);
312        if (_painter == NULL) {
313            _painter = vtkSmartPointer<vtkSurfaceLICPainter>::New();
314            _painter->SetDelegatePainter(ppdmapper->GetPainter());
315         }
316        ppdmapper->SetPainter(_painter);
317#ifdef USE_VTK6
318        ppdmapper->SetInputData(pd);
319#else
320        ppdmapper->SetInput(pd);
321#endif
322    }
323
324    setInterpolateBeforeMapping(true);
325
326    if (_lut == NULL) {
327        setColorMap(ColorMap::getGrayDefault());
328    }
329
330    initProp();
331    getActor()->SetMapper(_mapper);
332
333    _mapper->Update();
334}
335
336void LIC::setInterpolateBeforeMapping(bool state)
337{
338    if (_mapper != NULL) {
339        _mapper->SetInterpolateScalarsBeforeMapping((state ? 1 : 0));
340    }
341}
342
343/**
344 * \brief Select a 2D slice plane from a 3D DataSet
345 *
346 * \param[in] axis Axis of slice plane
347 * \param[in] ratio Position [0,1] of slice plane along axis
348 */
349void LIC::selectVolumeSlice(Axis axis, double ratio)
350{
351    if (_dataSet->is2D()) {
352        WARN("DataSet not 3D, returning");
353        return;
354    }
355
356    if (_volumeSlicer == NULL &&
357        _probeFilter == NULL) {
358        WARN("Called before update() or DataSet is not a volume");
359        return;
360    }
361
362    int dims[3];
363
364    vtkImageData *imageData = vtkImageData::SafeDownCast(_dataSet->getVtkDataSet());
365    if (imageData == NULL) {
366        if (_probeFilter != NULL) {
367            imageData = vtkImageData::SafeDownCast(_probeFilter->GetInput());
368            if (imageData == NULL) {
369                ERROR("Couldn't get probe filter input image");
370                return;
371            }
372        } else {
373            ERROR("Not a volume data set");
374            return;
375        }
376    }
377    imageData->GetDimensions(dims);
378
379    _sliceAxis = axis;
380
381    if (_probeFilter != NULL) {
382        vtkImageData *imageData = vtkImageData::SafeDownCast(_probeFilter->GetInput());
383        double bounds[6];
384        assert(vtkDataSet::SafeDownCast(_probeFilter->GetSource()) != NULL);
385        _dataSet->getBounds(bounds);
386        int dim = _resolution;
387
388        switch (axis) {
389        case X_AXIS:
390            imageData->SetDimensions(1, dim, dim);
391            imageData->SetOrigin(bounds[0] + (bounds[1]-bounds[0])*ratio, bounds[2], bounds[4]);
392            imageData->SetSpacing(0,
393                                  (bounds[3]-bounds[2])/((double)(dim-1)),
394                                  (bounds[5]-bounds[4])/((double)(dim-1)));
395            if (_cutPlane != NULL) {
396                _cutPlane->SetNormal(1, 0, 0);
397                _cutPlane->SetOrigin(bounds[0] + (bounds[1]-bounds[0])*ratio, 0, 0);
398            }
399            break;
400        case Y_AXIS:
401            imageData->SetDimensions(dim, 1, dim);
402            imageData->SetOrigin(bounds[0], bounds[2] + (bounds[3]-bounds[2])*ratio, bounds[4]);
403            imageData->SetSpacing((bounds[1]-bounds[0])/((double)(dim-1)),
404                                  0,
405                                  (bounds[5]-bounds[4])/((double)(dim-1)));
406            if (_cutPlane != NULL) {
407                _cutPlane->SetNormal(0, 1, 0);
408                _cutPlane->SetOrigin(0, bounds[2] + (bounds[3]-bounds[2])*ratio, 0);
409            }
410            break;
411        case Z_AXIS:
412            imageData->SetDimensions(dim, dim, 1);
413            imageData->SetOrigin(bounds[0], bounds[2], bounds[4] + (bounds[5]-bounds[4])*ratio);
414            imageData->SetSpacing((bounds[1]-bounds[0])/((double)(dim-1)),
415                                  (bounds[3]-bounds[2])/((double)(dim-1)),
416                                  0);
417            if (_cutPlane != NULL) {
418                _cutPlane->SetNormal(0, 0, 1);
419                _cutPlane->SetOrigin(0, 0, bounds[4] + (bounds[5]-bounds[4])*ratio);
420            }
421            break;
422        default:
423            ERROR("Invalid Axis");
424            return;
425        }
426    } else {
427        int voi[6];
428
429        switch (axis) {
430        case X_AXIS:
431            voi[0] = voi[1] = (int)((dims[0]-1) * ratio);
432            voi[2] = 0;
433            voi[3] = dims[1]-1;
434            voi[4] = 0;
435            voi[5] = dims[2]-1;
436            break;
437        case Y_AXIS:
438            voi[2] = voi[3] = (int)((dims[1]-1) * ratio);
439            voi[0] = 0;
440            voi[1] = dims[0]-1;
441            voi[4] = 0;
442            voi[5] = dims[2]-1;
443            break;
444        case Z_AXIS:
445            voi[4] = voi[5] = (int)((dims[2]-1) * ratio);
446            voi[0] = 0;
447            voi[1] = dims[0]-1;
448            voi[2] = 0;
449            voi[3] = dims[1]-1;
450            break;
451        default:
452            ERROR("Invalid Axis");
453            return;
454        }
455
456        _volumeSlicer->SetVOI(voi);
457    }
458
459    if (_lic != NULL)
460        _lic->Update();
461
462    if (_mapper != NULL)
463        _mapper->Update();
464}
465
466/**
467 * \brief Called when the color map has been edited
468 */
469void LIC::updateColorMap()
470{
471    setColorMap(_colorMap);
472}
473
474/**
475 * \brief Associate a colormap lookup table with the DataSet
476 */
477void LIC::setColorMap(ColorMap *cmap)
478{
479    if (cmap == NULL)
480        return;
481
482    _colorMap = cmap;
483 
484    if (_lut == NULL) {
485        _lut = vtkSmartPointer<vtkLookupTable>::New();
486        if (_mapper != NULL) {
487            _mapper->UseLookupTableScalarRangeOff();
488            _mapper->SetLookupTable(_lut);
489        }
490    }
491
492    _lut->DeepCopy(cmap->getLookupTable());
493    _lut->SetRange(_dataRange);
494    _lut->Modified();
495}
496
497void LIC::updateRanges(Renderer *renderer)
498{
499    GraphicsObject::updateRanges(renderer);
500
501    if (_lut != NULL) {
502        _lut->SetRange(_dataRange);
503    }
504}
505
506/**
507 * \brief Set a group of world coordinate planes to clip rendering
508 *
509 * Passing NULL for planes will remove all cliping planes
510 */
511void LIC::setClippingPlanes(vtkPlaneCollection *planes)
512{
513    if (_mapper != NULL) {
514        _mapper->SetClippingPlanes(planes);
515    }
516}
Note: See TracBrowser for help on using the repository browser.