source: vtkvis/trunk/PolyData.cpp @ 5036

Last change on this file since 5036 was 4139, checked in by ldelgass, 10 years ago

Don't stripify meshes extracted from non-polydata/non-cloud datasets. This will
make the mesh viewer more useful for seeing the original cells wihout added
tesselation. If performance becomes an issue, we can look at adding an option
to turn on strips.

  • Property svn:eol-style set to native
File size: 18.7 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#ifdef USE_VTK6
132            vgf->SetInputData(ds);
133#else
134            vgf->SetInput(ds);
135#endif
136            _mapper->SetInputConnection(vgf->GetOutputPort());
137        } else if (_dataSet->is2D(&plane, &offset)) {
138            vtkSmartPointer<vtkDelaunay2D> mesher = vtkSmartPointer<vtkDelaunay2D>::New();
139            if (plane == PLANE_ZY) {
140                vtkSmartPointer<vtkTransform> trans = vtkSmartPointer<vtkTransform>::New();
141                trans->RotateWXYZ(90, 0, 1, 0);
142                if (offset != 0.0) {
143                    trans->Translate(-offset, 0, 0);
144                }
145                mesher->SetTransform(trans);
146            } else if (plane == PLANE_XZ) {
147                vtkSmartPointer<vtkTransform> trans = vtkSmartPointer<vtkTransform>::New();
148                trans->RotateWXYZ(-90, 1, 0, 0);
149                if (offset != 0.0) {
150                    trans->Translate(0, -offset, 0);
151                }
152                mesher->SetTransform(trans);
153            } else if (offset != 0.0) {
154                // XY with Z offset
155                vtkSmartPointer<vtkTransform> trans = vtkSmartPointer<vtkTransform>::New();
156                trans->Translate(0, 0, -offset);
157                mesher->SetTransform(trans);
158            }
159#ifdef USE_VTK6
160            mesher->SetInputData(ds);
161#else
162            mesher->SetInput(ds);
163#endif
164            mesher->ReleaseDataFlagOn();
165            mesher->Update();
166            vtkPolyData *outpd = mesher->GetOutput();
167            TRACE("Delaunay2D Verts: %d Lines: %d Polys: %d Strips: %d",
168                  outpd->GetNumberOfVerts(),
169                  outpd->GetNumberOfLines(),
170                  outpd->GetNumberOfPolys(),
171                  outpd->GetNumberOfStrips());
172            if (outpd->GetNumberOfPolys() == 0) {
173                WARN("Delaunay2D mesher failed");
174                vtkSmartPointer<vtkVertexGlyphFilter> vgf = vtkSmartPointer<vtkVertexGlyphFilter>::New();
175#ifdef USE_VTK6
176                vgf->SetInputData(ds);
177#else
178                vgf->SetInput(ds);
179#endif
180                _mapper->SetInputConnection(vgf->GetOutputPort());
181            } else {
182                vtkSmartPointer<vtkPolyDataNormals> normalFilter = vtkSmartPointer<vtkPolyDataNormals>::New();
183                normalFilter->SetInputConnection(mesher->GetOutputPort());
184                _mapper->SetInputConnection(normalFilter->GetOutputPort());
185            }
186        } else {
187            vtkSmartPointer<vtkDelaunay3D> mesher = vtkSmartPointer<vtkDelaunay3D>::New();
188#ifdef USE_VTK6
189            mesher->SetInputData(ds);
190#else
191            mesher->SetInput(ds);
192#endif
193            mesher->ReleaseDataFlagOn();
194            mesher->Update();
195            vtkUnstructuredGrid *grid = mesher->GetOutput();
196            TRACE("Delaunay3D Cells: %d",
197                  grid->GetNumberOfCells());
198            if (grid->GetNumberOfCells() == 0) {
199                WARN("Delaunay3D mesher failed");
200                vtkSmartPointer<vtkVertexGlyphFilter> vgf = vtkSmartPointer<vtkVertexGlyphFilter>::New();
201#ifdef USE_VTK6
202                vgf->SetInputData(ds);
203#else
204                vgf->SetInput(ds);
205#endif
206                _mapper->SetInputConnection(vgf->GetOutputPort());
207            } else {
208                // Delaunay3D returns an UnstructuredGrid, so feed it
209                // through a surface filter to get the grid boundary
210                // as a PolyData
211                vtkSmartPointer<vtkDataSetSurfaceFilter> gf = vtkSmartPointer<vtkDataSetSurfaceFilter>::New();
212                gf->UseStripsOn();
213                gf->ReleaseDataFlagOn();
214                gf->SetInputConnection(mesher->GetOutputPort());
215                vtkSmartPointer<vtkPolyDataNormals> normalFilter = vtkSmartPointer<vtkPolyDataNormals>::New();
216                normalFilter->SetInputConnection(gf->GetOutputPort());
217                _mapper->SetInputConnection(normalFilter->GetOutputPort());
218            }
219        }
220    } else if (pd) {
221        // DataSet is a vtkPolyData with cells
222        if (hasNormals) {
223#ifdef USE_VTK6
224            _mapper->SetInputData(pd);
225#else
226            _mapper->SetInput(pd);
227#endif
228        } else {
229            vtkSmartPointer<vtkPolyDataNormals> normalFilter = vtkSmartPointer<vtkPolyDataNormals>::New();
230#ifdef USE_VTK6
231            normalFilter->SetInputData(pd);
232#else
233            normalFilter->SetInput(pd);
234#endif
235            _mapper->SetInputConnection(normalFilter->GetOutputPort());
236        }
237    } else {
238        // DataSet is NOT a vtkPolyData
239        TRACE("DataSet is not a PolyData");
240        vtkSmartPointer<vtkDataSetSurfaceFilter> gf = vtkSmartPointer<vtkDataSetSurfaceFilter>::New();
241        //gf->UseStripsOn();
242        gf->ReleaseDataFlagOn();
243#ifdef USE_VTK6
244        gf->SetInputData(ds);
245#else
246        gf->SetInput(ds);
247#endif
248        vtkSmartPointer<vtkPolyDataNormals> normalFilter = vtkSmartPointer<vtkPolyDataNormals>::New();
249        normalFilter->SetInputConnection(gf->GetOutputPort());
250        _mapper->SetInputConnection(normalFilter->GetOutputPort());
251    }
252
253    setInterpolateBeforeMapping(true);
254
255    if (_lut == NULL) {
256        setColorMap(ColorMap::getDefault());
257        if (_dataSet->getActiveScalarsName() != NULL) {
258            int numComp;
259            _dataSet->getFieldInfo(_dataSet->getActiveScalarsName(),
260                                   _dataSet->getActiveScalarsType(),
261                                   &numComp);
262            // If DataSet is a PolyData with a scalar field, or has color scalars
263            if (pd != NULL || numComp > 1) {
264                if (numComp > 1) {
265                    // If we have color scalars, use triangle interpolation
266                    setInterpolateBeforeMapping(false);
267                }
268                setColorMode(COLOR_BY_SCALAR);
269            } else {
270                setColorMode(_colorMode);
271            }
272        } else {
273            setColorMode(_colorMode);
274        }
275    } else {
276        double *rangePtr = _colorFieldRange;
277        if (_colorFieldRange[0] > _colorFieldRange[1]) {
278            rangePtr = NULL;
279        }
280        setColorMode(_colorMode, _colorFieldType, _colorFieldName.c_str(), rangePtr);
281    }
282
283    initProp();
284    getActor()->SetMapper(_mapper);
285    _mapper->Update();
286#ifdef WANT_TRACE
287    double *b = getBounds();
288    TRACE("bounds: %g %g %g %g %g %g", b[0], b[1], b[2], b[3], b[4], b[5]);
289#endif
290}
291
292void PolyData::setInterpolateBeforeMapping(bool state)
293{
294    if (_mapper != NULL) {
295        _mapper->SetInterpolateScalarsBeforeMapping((state ? 1 : 0));
296    }
297}
298
299void PolyData::updateRanges(Renderer *renderer)
300{
301    if (_dataSet == NULL) {
302        ERROR("called before setDataSet");
303        return;
304    }
305
306    if (renderer->getUseCumulativeRange()) {
307        renderer->getCumulativeDataRange(_dataRange,
308                                         _dataSet->getActiveScalarsName(),
309                                         1);
310        renderer->getCumulativeDataRange(_vectorMagnitudeRange,
311                                         _dataSet->getActiveVectorsName(),
312                                         3);
313        for (int i = 0; i < 3; i++) {
314            renderer->getCumulativeDataRange(_vectorComponentRange[i],
315                                             _dataSet->getActiveVectorsName(),
316                                             3, i);
317        }
318    } else {
319        _dataSet->getScalarRange(_dataRange);
320        _dataSet->getVectorRange(_vectorMagnitudeRange);
321        for (int i = 0; i < 3; i++) {
322            _dataSet->getVectorRange(_vectorComponentRange[i], i);
323        }
324    }
325
326    // Need to update color map ranges
327    double *rangePtr = _colorFieldRange;
328    if (_colorFieldRange[0] > _colorFieldRange[1]) {
329        rangePtr = NULL;
330    }
331    setColorMode(_colorMode, _colorFieldType, _colorFieldName.c_str(), rangePtr);
332}
333
334void PolyData::setColorMode(ColorMode mode)
335{
336    _colorMode = mode;
337    if (_dataSet == NULL)
338        return;
339
340    switch (mode) {
341    case COLOR_BY_SCALAR:
342        setColorMode(mode,
343                     _dataSet->getActiveScalarsType(),
344                     _dataSet->getActiveScalarsName(),
345                     _dataRange);
346        break;
347    case COLOR_BY_VECTOR_MAGNITUDE:
348        setColorMode(mode,
349                     _dataSet->getActiveVectorsType(),
350                     _dataSet->getActiveVectorsName(),
351                     _vectorMagnitudeRange);
352        break;
353    case COLOR_BY_VECTOR_X:
354        setColorMode(mode,
355                     _dataSet->getActiveVectorsType(),
356                     _dataSet->getActiveVectorsName(),
357                     _vectorComponentRange[0]);
358        break;
359    case COLOR_BY_VECTOR_Y:
360        setColorMode(mode,
361                     _dataSet->getActiveVectorsType(),
362                     _dataSet->getActiveVectorsName(),
363                     _vectorComponentRange[1]);
364        break;
365    case COLOR_BY_VECTOR_Z:
366        setColorMode(mode,
367                     _dataSet->getActiveVectorsType(),
368                     _dataSet->getActiveVectorsName(),
369                     _vectorComponentRange[2]);
370        break;
371    case COLOR_CONSTANT:
372    default:
373        setColorMode(mode, DataSet::POINT_DATA, NULL, NULL);
374        break;
375    }
376}
377
378void PolyData::setColorMode(ColorMode mode,
379                            const char *name, double range[2])
380{
381    if (_dataSet == NULL)
382        return;
383    DataSet::DataAttributeType type = DataSet::POINT_DATA;
384    int numComponents = 1;
385    if (name != NULL && strlen(name) > 0 &&
386        !_dataSet->getFieldInfo(name, &type, &numComponents)) {
387        ERROR("Field not found: %s", name);
388        return;
389    }
390    setColorMode(mode, type, name, range);
391}
392
393void PolyData::setColorMode(ColorMode mode, DataSet::DataAttributeType type,
394                            const char *name, double range[2])
395{
396    _colorMode = mode;
397    _colorFieldType = type;
398    if (name == NULL)
399        _colorFieldName.clear();
400    else
401        _colorFieldName = name;
402    if (range == NULL) {
403        _colorFieldRange[0] = DBL_MAX;
404        _colorFieldRange[1] = -DBL_MAX;
405    } else {
406        memcpy(_colorFieldRange, range, sizeof(double)*2);
407    }
408
409    if (_dataSet == NULL || _mapper == NULL)
410        return;
411
412    switch (type) {
413    case DataSet::POINT_DATA:
414        _mapper->SetScalarModeToUsePointFieldData();
415        break;
416    case DataSet::CELL_DATA:
417        _mapper->SetScalarModeToUseCellFieldData();
418        break;
419    case DataSet::FIELD_DATA:
420        _mapper->SetScalarModeToUseFieldData();
421        break;
422    default:
423        ERROR("Unsupported DataAttributeType: %d", type);
424        return;
425    }
426
427    if (name != NULL && strlen(name) > 0) {
428        _mapper->SelectColorArray(name);
429    } else {
430        _mapper->SetScalarModeToDefault();
431    }
432
433    if (_lut != NULL) {
434        if (range != NULL) {
435            _lut->SetRange(range);
436        } else if (name != NULL && strlen(name) > 0) {
437            double r[2];
438            int comp = -1;
439            if (mode == COLOR_BY_VECTOR_X)
440                comp = 0;
441            else if (mode == COLOR_BY_VECTOR_Y)
442                comp = 1;
443            else if (mode == COLOR_BY_VECTOR_Z)
444                comp = 2;
445
446            if (_renderer->getUseCumulativeRange()) {
447                int numComponents;
448                if  (!_dataSet->getFieldInfo(name, type, &numComponents)) {
449                    ERROR("Field not found: %s, type: %d", name, type);
450                    return;
451                } else if (numComponents < comp+1) {
452                    ERROR("Request for component %d in field with %d components",
453                          comp, numComponents);
454                    return;
455                }
456                _renderer->getCumulativeDataRange(r, name, type, numComponents, comp);
457            } else {
458                _dataSet->getDataRange(r, name, type, comp);
459            }
460            _lut->SetRange(r);
461        }
462    }
463
464    switch (mode) {
465    case COLOR_BY_SCALAR:
466        _mapper->ScalarVisibilityOn();
467        break;
468    case COLOR_BY_VECTOR_MAGNITUDE:
469        _mapper->ScalarVisibilityOn();
470        if (_lut != NULL) {
471            _lut->SetVectorModeToMagnitude();
472        }
473        break;
474    case COLOR_BY_VECTOR_X:
475        _mapper->ScalarVisibilityOn();
476        if (_lut != NULL) {
477            _lut->SetVectorModeToComponent();
478            _lut->SetVectorComponent(0);
479        }
480        break;
481    case COLOR_BY_VECTOR_Y:
482        _mapper->ScalarVisibilityOn();
483        if (_lut != NULL) {
484            _lut->SetVectorModeToComponent();
485            _lut->SetVectorComponent(1);
486        }
487        break;
488    case COLOR_BY_VECTOR_Z:
489        _mapper->ScalarVisibilityOn();
490        if (_lut != NULL) {
491            _lut->SetVectorModeToComponent();
492            _lut->SetVectorComponent(2);
493        }
494        break;
495    case COLOR_CONSTANT:
496    default:
497        _mapper->ScalarVisibilityOff();
498        break;
499    }
500}
501
502/**
503 * \brief Called when the color map has been edited
504 */
505void PolyData::updateColorMap()
506{
507    setColorMap(_colorMap);
508}
509
510/**
511 * \brief Associate a colormap lookup table with the DataSet
512 */
513void PolyData::setColorMap(ColorMap *cmap)
514{
515    if (cmap == NULL)
516        return;
517
518    _colorMap = cmap;
519 
520    if (_lut == NULL) {
521        _lut = vtkSmartPointer<vtkLookupTable>::New();
522        if (_mapper != NULL) {
523            _mapper->UseLookupTableScalarRangeOn();
524            _mapper->SetLookupTable(_lut);
525        }
526        _lut->DeepCopy(cmap->getLookupTable());
527        switch (_colorMode) {
528        case COLOR_CONSTANT:
529        case COLOR_BY_SCALAR:
530            _lut->SetRange(_dataRange);
531            break;
532        case COLOR_BY_VECTOR_MAGNITUDE:
533            _lut->SetRange(_vectorMagnitudeRange);
534            break;
535        case COLOR_BY_VECTOR_X:
536            _lut->SetRange(_vectorComponentRange[0]);
537            break;
538        case COLOR_BY_VECTOR_Y:
539            _lut->SetRange(_vectorComponentRange[1]);
540            break;
541        case COLOR_BY_VECTOR_Z:
542            _lut->SetRange(_vectorComponentRange[2]);
543            break;
544        default:
545            break;
546        }
547    } else {
548        double range[2];
549        _lut->GetTableRange(range);
550        _lut->DeepCopy(cmap->getLookupTable());
551        _lut->SetRange(range);
552        _lut->Modified();
553    }
554
555    switch (_colorMode) {
556    case COLOR_BY_VECTOR_MAGNITUDE:
557        _lut->SetVectorModeToMagnitude();
558        break;
559    case COLOR_BY_VECTOR_X:
560        _lut->SetVectorModeToComponent();
561        _lut->SetVectorComponent(0);
562        break;
563    case COLOR_BY_VECTOR_Y:
564        _lut->SetVectorModeToComponent();
565        _lut->SetVectorComponent(1);
566        break;
567    case COLOR_BY_VECTOR_Z:
568        _lut->SetVectorModeToComponent();
569        _lut->SetVectorComponent(2);
570        break;
571    default:
572         break;
573    }
574}
575
576/**
577 * \brief Set a group of world coordinate planes to clip rendering
578 *
579 * Passing NULL for planes will remove all cliping planes
580 */
581void PolyData::setClippingPlanes(vtkPlaneCollection *planes)
582{
583    if (_mapper != NULL) {
584        _mapper->SetClippingPlanes(planes);
585    }
586}
587
588void PolyData::setCloudStyle(CloudStyle style)
589{
590    if (style != _cloudStyle) {
591        _cloudStyle = style;
592        if (_dataSet != NULL) {
593            update();
594        }
595    }
596}
Note: See TracBrowser for help on using the repository browser.