source: vtkvis/trunk/PolyData.cpp @ 6128

Last change on this file since 6128 was 5835, checked in by ldelgass, 9 years ago

Require VTK >= 6.0.0

  • Property svn:eol-style set to native
File size: 18.0 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 <vtkDataSet.h>
11#include <vtkPolyData.h>
12#include <vtkPolyDataNormals.h>
13#include <vtkPointData.h>
14#include <vtkCellData.h>
15#include <vtkUnstructuredGrid.h>
16#include <vtkPolyDataMapper.h>
17#include <vtkActor.h>
18#include <vtkProperty.h>
19#include <vtkTransform.h>
20#include <vtkDelaunay2D.h>
21#include <vtkDelaunay3D.h>
22#include <vtkDataSetSurfaceFilter.h>
23#include <vtkVertexGlyphFilter.h>
24#include <vtkLookupTable.h>
25
26#include "PolyData.h"
27#include "Renderer.h"
28#include "Trace.h"
29
30using namespace VtkVis;
31
32PolyData::PolyData() :
33    GraphicsObject(),
34    _colorMap(NULL),
35    _colorMode(COLOR_CONSTANT),
36    _colorFieldType(DataSet::POINT_DATA),
37    _renderer(NULL),
38    _cloudStyle(CLOUD_MESH)
39{
40    _colorFieldRange[0] = DBL_MAX;
41    _colorFieldRange[1] = -DBL_MAX;
42}
43
44PolyData::~PolyData()
45{
46#ifdef WANT_TRACE
47    if (_dataSet != NULL)
48        TRACE("Deleting PolyData for %s", _dataSet->getName().c_str());
49    else
50        TRACE("Deleting PolyData with NULL DataSet");
51#endif
52}
53
54void PolyData::setDataSet(DataSet *dataSet,
55                          Renderer *renderer)
56{
57    if (_dataSet != dataSet) {
58        _dataSet = dataSet;
59
60        _renderer = renderer;
61
62        if (renderer->getUseCumulativeRange()) {
63            renderer->getCumulativeDataRange(_dataRange,
64                                             _dataSet->getActiveScalarsName(),
65                                             1);
66            renderer->getCumulativeDataRange(_vectorMagnitudeRange,
67                                             _dataSet->getActiveVectorsName(),
68                                             3);
69            for (int i = 0; i < 3; i++) {
70                renderer->getCumulativeDataRange(_vectorComponentRange[i],
71                                                 _dataSet->getActiveVectorsName(),
72                                                 3, i);
73            }
74        } else {
75            _dataSet->getScalarRange(_dataRange);
76            _dataSet->getVectorRange(_vectorMagnitudeRange);
77            for (int i = 0; i < 3; i++) {
78                _dataSet->getVectorRange(_vectorComponentRange[i], i);
79            }
80        }
81
82        update();
83    }
84}
85
86/**
87 * \brief Internal method to set up pipeline after a state change
88 */
89void PolyData::update()
90{
91    if (_dataSet == NULL) {
92        return;
93    }
94
95    vtkDataSet *ds = _dataSet->getVtkDataSet();
96
97    if (_mapper == NULL) {
98        _mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
99        _mapper->SetResolveCoincidentTopologyToPolygonOffset();
100        // If there are color scalars, use them without lookup table (if scalar visibility is on)
101        _mapper->SetColorModeToDefault();
102        // Use Point data if available, else cell data
103        _mapper->SetScalarModeToDefault();
104        _mapper->ScalarVisibilityOff();
105    }
106
107    vtkPolyData *pd = vtkPolyData::SafeDownCast(ds);
108    if (pd) {
109        TRACE("Points: %d Verts: %d Lines: %d Polys: %d Strips: %d",
110              pd->GetNumberOfPoints(),
111              pd->GetNumberOfVerts(),
112              pd->GetNumberOfLines(),
113              pd->GetNumberOfPolys(),
114              pd->GetNumberOfStrips());
115    }
116    bool hasNormals = false;
117    if ((ds->GetPointData() != NULL &&
118         ds->GetPointData()->GetNormals() != NULL) ||
119        (ds->GetCellData() != NULL &&
120         ds->GetCellData()->GetNormals() != NULL)) {
121        hasNormals = true;
122    }
123
124    if (_dataSet->isCloud()) {
125        // DataSet is a point cloud
126        PrincipalPlane plane;
127        double offset;
128        if (_cloudStyle == CLOUD_POINTS ||
129            _dataSet->numDimensions() < 2 || ds->GetNumberOfPoints() < 3) { // 0D or 1D or not enough points to mesh
130            vtkSmartPointer<vtkVertexGlyphFilter> vgf = vtkSmartPointer<vtkVertexGlyphFilter>::New();
131            vgf->SetInputData(ds);
132            _mapper->SetInputConnection(vgf->GetOutputPort());
133        } else if (_dataSet->is2D(&plane, &offset)) {
134            vtkSmartPointer<vtkDelaunay2D> mesher = vtkSmartPointer<vtkDelaunay2D>::New();
135            if (plane == PLANE_ZY) {
136                vtkSmartPointer<vtkTransform> trans = vtkSmartPointer<vtkTransform>::New();
137                trans->RotateWXYZ(90, 0, 1, 0);
138                if (offset != 0.0) {
139                    trans->Translate(-offset, 0, 0);
140                }
141                mesher->SetTransform(trans);
142            } else if (plane == PLANE_XZ) {
143                vtkSmartPointer<vtkTransform> trans = vtkSmartPointer<vtkTransform>::New();
144                trans->RotateWXYZ(-90, 1, 0, 0);
145                if (offset != 0.0) {
146                    trans->Translate(0, -offset, 0);
147                }
148                mesher->SetTransform(trans);
149            } else if (offset != 0.0) {
150                // XY with Z offset
151                vtkSmartPointer<vtkTransform> trans = vtkSmartPointer<vtkTransform>::New();
152                trans->Translate(0, 0, -offset);
153                mesher->SetTransform(trans);
154            }
155            mesher->SetInputData(ds);
156            mesher->ReleaseDataFlagOn();
157            mesher->Update();
158            vtkPolyData *outpd = mesher->GetOutput();
159            TRACE("Delaunay2D Verts: %d Lines: %d Polys: %d Strips: %d",
160                  outpd->GetNumberOfVerts(),
161                  outpd->GetNumberOfLines(),
162                  outpd->GetNumberOfPolys(),
163                  outpd->GetNumberOfStrips());
164            if (outpd->GetNumberOfPolys() == 0) {
165                WARN("Delaunay2D mesher failed");
166                vtkSmartPointer<vtkVertexGlyphFilter> vgf = vtkSmartPointer<vtkVertexGlyphFilter>::New();
167                vgf->SetInputData(ds);
168                _mapper->SetInputConnection(vgf->GetOutputPort());
169            } else {
170                vtkSmartPointer<vtkPolyDataNormals> normalFilter = vtkSmartPointer<vtkPolyDataNormals>::New();
171                normalFilter->SetInputConnection(mesher->GetOutputPort());
172                _mapper->SetInputConnection(normalFilter->GetOutputPort());
173            }
174        } else {
175            vtkSmartPointer<vtkDelaunay3D> mesher = vtkSmartPointer<vtkDelaunay3D>::New();
176            mesher->SetInputData(ds);
177            mesher->ReleaseDataFlagOn();
178            mesher->Update();
179            vtkUnstructuredGrid *grid = mesher->GetOutput();
180            TRACE("Delaunay3D Cells: %d",
181                  grid->GetNumberOfCells());
182            if (grid->GetNumberOfCells() == 0) {
183                WARN("Delaunay3D mesher failed");
184                vtkSmartPointer<vtkVertexGlyphFilter> vgf = vtkSmartPointer<vtkVertexGlyphFilter>::New();
185                vgf->SetInputData(ds);
186                _mapper->SetInputConnection(vgf->GetOutputPort());
187            } else {
188                // Delaunay3D returns an UnstructuredGrid, so feed it
189                // through a surface filter to get the grid boundary
190                // as a PolyData
191                vtkSmartPointer<vtkDataSetSurfaceFilter> gf = vtkSmartPointer<vtkDataSetSurfaceFilter>::New();
192                gf->UseStripsOn();
193                gf->ReleaseDataFlagOn();
194                gf->SetInputConnection(mesher->GetOutputPort());
195                vtkSmartPointer<vtkPolyDataNormals> normalFilter = vtkSmartPointer<vtkPolyDataNormals>::New();
196                normalFilter->SetInputConnection(gf->GetOutputPort());
197                _mapper->SetInputConnection(normalFilter->GetOutputPort());
198            }
199        }
200    } else if (pd) {
201        // DataSet is a vtkPolyData with cells
202        if (hasNormals) {
203            _mapper->SetInputData(pd);
204        } else {
205            vtkSmartPointer<vtkPolyDataNormals> normalFilter = vtkSmartPointer<vtkPolyDataNormals>::New();
206            normalFilter->SetInputData(pd);
207            _mapper->SetInputConnection(normalFilter->GetOutputPort());
208        }
209    } else {
210        // DataSet is NOT a vtkPolyData
211        TRACE("DataSet is not a PolyData");
212        vtkSmartPointer<vtkDataSetSurfaceFilter> gf = vtkSmartPointer<vtkDataSetSurfaceFilter>::New();
213        //gf->UseStripsOn();
214        gf->ReleaseDataFlagOn();
215        gf->SetInputData(ds);
216        vtkSmartPointer<vtkPolyDataNormals> normalFilter = vtkSmartPointer<vtkPolyDataNormals>::New();
217        normalFilter->SetInputConnection(gf->GetOutputPort());
218        _mapper->SetInputConnection(normalFilter->GetOutputPort());
219    }
220
221    setInterpolateBeforeMapping(true);
222
223    if (_lut == NULL) {
224        setColorMap(ColorMap::getDefault());
225        if (_dataSet->getActiveScalarsName() != NULL) {
226            int numComp;
227            _dataSet->getFieldInfo(_dataSet->getActiveScalarsName(),
228                                   _dataSet->getActiveScalarsType(),
229                                   &numComp);
230            // If DataSet is a PolyData with a scalar field, or has color scalars
231            if (pd != NULL || numComp > 1) {
232                if (numComp > 1) {
233                    // If we have color scalars, use triangle interpolation
234                    setInterpolateBeforeMapping(false);
235                }
236                setColorMode(COLOR_BY_SCALAR);
237            } else {
238                setColorMode(_colorMode);
239            }
240        } else {
241            setColorMode(_colorMode);
242        }
243    } else {
244        double *rangePtr = _colorFieldRange;
245        if (_colorFieldRange[0] > _colorFieldRange[1]) {
246            rangePtr = NULL;
247        }
248        setColorMode(_colorMode, _colorFieldType, _colorFieldName.c_str(), rangePtr);
249    }
250
251    initProp();
252    getActor()->SetMapper(_mapper);
253    _mapper->Update();
254#ifdef WANT_TRACE
255    double *b = getBounds();
256    TRACE("bounds: %g %g %g %g %g %g", b[0], b[1], b[2], b[3], b[4], b[5]);
257#endif
258}
259
260void PolyData::setInterpolateBeforeMapping(bool state)
261{
262    if (_mapper != NULL) {
263        _mapper->SetInterpolateScalarsBeforeMapping((state ? 1 : 0));
264    }
265}
266
267void PolyData::updateRanges(Renderer *renderer)
268{
269    if (_dataSet == NULL) {
270        ERROR("called before setDataSet");
271        return;
272    }
273
274    if (renderer->getUseCumulativeRange()) {
275        renderer->getCumulativeDataRange(_dataRange,
276                                         _dataSet->getActiveScalarsName(),
277                                         1);
278        renderer->getCumulativeDataRange(_vectorMagnitudeRange,
279                                         _dataSet->getActiveVectorsName(),
280                                         3);
281        for (int i = 0; i < 3; i++) {
282            renderer->getCumulativeDataRange(_vectorComponentRange[i],
283                                             _dataSet->getActiveVectorsName(),
284                                             3, i);
285        }
286    } else {
287        _dataSet->getScalarRange(_dataRange);
288        _dataSet->getVectorRange(_vectorMagnitudeRange);
289        for (int i = 0; i < 3; i++) {
290            _dataSet->getVectorRange(_vectorComponentRange[i], i);
291        }
292    }
293
294    // Need to update color map ranges
295    double *rangePtr = _colorFieldRange;
296    if (_colorFieldRange[0] > _colorFieldRange[1]) {
297        rangePtr = NULL;
298    }
299    setColorMode(_colorMode, _colorFieldType, _colorFieldName.c_str(), rangePtr);
300}
301
302void PolyData::setColorMode(ColorMode mode)
303{
304    _colorMode = mode;
305    if (_dataSet == NULL)
306        return;
307
308    switch (mode) {
309    case COLOR_BY_SCALAR:
310        setColorMode(mode,
311                     _dataSet->getActiveScalarsType(),
312                     _dataSet->getActiveScalarsName());
313        break;
314    case COLOR_BY_VECTOR_MAGNITUDE:
315        setColorMode(mode,
316                     _dataSet->getActiveVectorsType(),
317                     _dataSet->getActiveVectorsName());
318        break;
319    case COLOR_BY_VECTOR_X:
320        setColorMode(mode,
321                     _dataSet->getActiveVectorsType(),
322                     _dataSet->getActiveVectorsName());
323        break;
324    case COLOR_BY_VECTOR_Y:
325        setColorMode(mode,
326                     _dataSet->getActiveVectorsType(),
327                     _dataSet->getActiveVectorsName());
328        break;
329    case COLOR_BY_VECTOR_Z:
330        setColorMode(mode,
331                     _dataSet->getActiveVectorsType(),
332                     _dataSet->getActiveVectorsName());
333        break;
334    case COLOR_CONSTANT:
335    default:
336        setColorMode(mode, DataSet::POINT_DATA, NULL, NULL);
337        break;
338    }
339}
340
341void PolyData::setColorMode(ColorMode mode,
342                            const char *name, double range[2])
343{
344    if (_dataSet == NULL)
345        return;
346    DataSet::DataAttributeType type = DataSet::POINT_DATA;
347    int numComponents = 1;
348    if (name != NULL && strlen(name) > 0 &&
349        !_dataSet->getFieldInfo(name, &type, &numComponents)) {
350        ERROR("Field not found: %s", name);
351        return;
352    }
353    setColorMode(mode, type, name, range);
354}
355
356void PolyData::setColorMode(ColorMode mode, DataSet::DataAttributeType type,
357                            const char *name, double range[2])
358{
359    _colorMode = mode;
360    _colorFieldType = type;
361    if (name == NULL)
362        _colorFieldName.clear();
363    else
364        _colorFieldName = name;
365    if (range == NULL) {
366        _colorFieldRange[0] = DBL_MAX;
367        _colorFieldRange[1] = -DBL_MAX;
368    } else {
369        memcpy(_colorFieldRange, range, sizeof(double)*2);
370    }
371
372    if (_dataSet == NULL || _mapper == NULL)
373        return;
374
375    switch (type) {
376    case DataSet::POINT_DATA:
377        _mapper->SetScalarModeToUsePointFieldData();
378        break;
379    case DataSet::CELL_DATA:
380        _mapper->SetScalarModeToUseCellFieldData();
381        break;
382    case DataSet::FIELD_DATA:
383        _mapper->SetScalarModeToUseFieldData();
384        break;
385    default:
386        ERROR("Unsupported DataAttributeType: %d", type);
387        return;
388    }
389
390    if (name != NULL && strlen(name) > 0) {
391        _mapper->SelectColorArray(name);
392    } else {
393        _mapper->SetScalarModeToDefault();
394    }
395
396    if (_lut != NULL) {
397        if (range != NULL) {
398            _lut->SetRange(range);
399        } else if (name != NULL && strlen(name) > 0) {
400            double r[2];
401            int comp = -1;
402            if (mode == COLOR_BY_VECTOR_X)
403                comp = 0;
404            else if (mode == COLOR_BY_VECTOR_Y)
405                comp = 1;
406            else if (mode == COLOR_BY_VECTOR_Z)
407                comp = 2;
408
409            if (_renderer->getUseCumulativeRange()) {
410                int numComponents;
411                if  (!_dataSet->getFieldInfo(name, type, &numComponents)) {
412                    ERROR("Field not found: %s, type: %d", name, type);
413                    return;
414                } else if (numComponents < comp+1) {
415                    ERROR("Request for component %d in field with %d components",
416                          comp, numComponents);
417                    return;
418                }
419                _renderer->getCumulativeDataRange(r, name, type, numComponents, comp);
420            } else {
421                _dataSet->getDataRange(r, name, type, comp);
422            }
423            _lut->SetRange(r);
424        }
425    }
426
427    switch (mode) {
428    case COLOR_BY_SCALAR:
429        _mapper->ScalarVisibilityOn();
430        break;
431    case COLOR_BY_VECTOR_MAGNITUDE:
432        _mapper->ScalarVisibilityOn();
433        if (_lut != NULL) {
434            _lut->SetVectorModeToMagnitude();
435        }
436        break;
437    case COLOR_BY_VECTOR_X:
438        _mapper->ScalarVisibilityOn();
439        if (_lut != NULL) {
440            _lut->SetVectorModeToComponent();
441            _lut->SetVectorComponent(0);
442        }
443        break;
444    case COLOR_BY_VECTOR_Y:
445        _mapper->ScalarVisibilityOn();
446        if (_lut != NULL) {
447            _lut->SetVectorModeToComponent();
448            _lut->SetVectorComponent(1);
449        }
450        break;
451    case COLOR_BY_VECTOR_Z:
452        _mapper->ScalarVisibilityOn();
453        if (_lut != NULL) {
454            _lut->SetVectorModeToComponent();
455            _lut->SetVectorComponent(2);
456        }
457        break;
458    case COLOR_CONSTANT:
459    default:
460        _mapper->ScalarVisibilityOff();
461        break;
462    }
463}
464
465/**
466 * \brief Called when the color map has been edited
467 */
468void PolyData::updateColorMap()
469{
470    setColorMap(_colorMap);
471}
472
473/**
474 * \brief Associate a colormap lookup table with the DataSet
475 */
476void PolyData::setColorMap(ColorMap *cmap)
477{
478    if (cmap == NULL)
479        return;
480
481    _colorMap = cmap;
482 
483    if (_lut == NULL) {
484        _lut = vtkSmartPointer<vtkLookupTable>::New();
485        if (_mapper != NULL) {
486            _mapper->UseLookupTableScalarRangeOn();
487            _mapper->SetLookupTable(_lut);
488        }
489        _lut->DeepCopy(cmap->getLookupTable());
490        switch (_colorMode) {
491        case COLOR_CONSTANT:
492        case COLOR_BY_SCALAR:
493            _lut->SetRange(_dataRange);
494            break;
495        case COLOR_BY_VECTOR_MAGNITUDE:
496            _lut->SetRange(_vectorMagnitudeRange);
497            break;
498        case COLOR_BY_VECTOR_X:
499            _lut->SetRange(_vectorComponentRange[0]);
500            break;
501        case COLOR_BY_VECTOR_Y:
502            _lut->SetRange(_vectorComponentRange[1]);
503            break;
504        case COLOR_BY_VECTOR_Z:
505            _lut->SetRange(_vectorComponentRange[2]);
506            break;
507        default:
508            break;
509        }
510    } else {
511        double range[2];
512        _lut->GetTableRange(range);
513        _lut->DeepCopy(cmap->getLookupTable());
514        _lut->SetRange(range);
515        _lut->Modified();
516    }
517
518    switch (_colorMode) {
519    case COLOR_BY_VECTOR_MAGNITUDE:
520        _lut->SetVectorModeToMagnitude();
521        break;
522    case COLOR_BY_VECTOR_X:
523        _lut->SetVectorModeToComponent();
524        _lut->SetVectorComponent(0);
525        break;
526    case COLOR_BY_VECTOR_Y:
527        _lut->SetVectorModeToComponent();
528        _lut->SetVectorComponent(1);
529        break;
530    case COLOR_BY_VECTOR_Z:
531        _lut->SetVectorModeToComponent();
532        _lut->SetVectorComponent(2);
533        break;
534    default:
535         break;
536    }
537}
538
539/**
540 * \brief Set a group of world coordinate planes to clip rendering
541 *
542 * Passing NULL for planes will remove all cliping planes
543 */
544void PolyData::setClippingPlanes(vtkPlaneCollection *planes)
545{
546    if (_mapper != NULL) {
547        _mapper->SetClippingPlanes(planes);
548    }
549}
550
551void PolyData::setCloudStyle(CloudStyle style)
552{
553    if (style != _cloudStyle) {
554        _cloudStyle = style;
555        if (_dataSet != NULL) {
556            update();
557        }
558    }
559}
Note: See TracBrowser for help on using the repository browser.