source: vtkvis/trunk/PolyData.cpp @ 5073

Last change on this file since 5073 was 5073, checked in by ldelgass, 5 years ago

merge r5072 from release branch

  • Property svn:eol-style set to native
File size: 18.5 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        break;
346    case COLOR_BY_VECTOR_MAGNITUDE:
347        setColorMode(mode,
348                     _dataSet->getActiveVectorsType(),
349                     _dataSet->getActiveVectorsName());
350        break;
351    case COLOR_BY_VECTOR_X:
352        setColorMode(mode,
353                     _dataSet->getActiveVectorsType(),
354                     _dataSet->getActiveVectorsName());
355        break;
356    case COLOR_BY_VECTOR_Y:
357        setColorMode(mode,
358                     _dataSet->getActiveVectorsType(),
359                     _dataSet->getActiveVectorsName());
360        break;
361    case COLOR_BY_VECTOR_Z:
362        setColorMode(mode,
363                     _dataSet->getActiveVectorsType(),
364                     _dataSet->getActiveVectorsName());
365        break;
366    case COLOR_CONSTANT:
367    default:
368        setColorMode(mode, DataSet::POINT_DATA, NULL, NULL);
369        break;
370    }
371}
372
373void PolyData::setColorMode(ColorMode mode,
374                            const char *name, double range[2])
375{
376    if (_dataSet == NULL)
377        return;
378    DataSet::DataAttributeType type = DataSet::POINT_DATA;
379    int numComponents = 1;
380    if (name != NULL && strlen(name) > 0 &&
381        !_dataSet->getFieldInfo(name, &type, &numComponents)) {
382        ERROR("Field not found: %s", name);
383        return;
384    }
385    setColorMode(mode, type, name, range);
386}
387
388void PolyData::setColorMode(ColorMode mode, DataSet::DataAttributeType type,
389                            const char *name, double range[2])
390{
391    _colorMode = mode;
392    _colorFieldType = type;
393    if (name == NULL)
394        _colorFieldName.clear();
395    else
396        _colorFieldName = name;
397    if (range == NULL) {
398        _colorFieldRange[0] = DBL_MAX;
399        _colorFieldRange[1] = -DBL_MAX;
400    } else {
401        memcpy(_colorFieldRange, range, sizeof(double)*2);
402    }
403
404    if (_dataSet == NULL || _mapper == NULL)
405        return;
406
407    switch (type) {
408    case DataSet::POINT_DATA:
409        _mapper->SetScalarModeToUsePointFieldData();
410        break;
411    case DataSet::CELL_DATA:
412        _mapper->SetScalarModeToUseCellFieldData();
413        break;
414    case DataSet::FIELD_DATA:
415        _mapper->SetScalarModeToUseFieldData();
416        break;
417    default:
418        ERROR("Unsupported DataAttributeType: %d", type);
419        return;
420    }
421
422    if (name != NULL && strlen(name) > 0) {
423        _mapper->SelectColorArray(name);
424    } else {
425        _mapper->SetScalarModeToDefault();
426    }
427
428    if (_lut != NULL) {
429        if (range != NULL) {
430            _lut->SetRange(range);
431        } else if (name != NULL && strlen(name) > 0) {
432            double r[2];
433            int comp = -1;
434            if (mode == COLOR_BY_VECTOR_X)
435                comp = 0;
436            else if (mode == COLOR_BY_VECTOR_Y)
437                comp = 1;
438            else if (mode == COLOR_BY_VECTOR_Z)
439                comp = 2;
440
441            if (_renderer->getUseCumulativeRange()) {
442                int numComponents;
443                if  (!_dataSet->getFieldInfo(name, type, &numComponents)) {
444                    ERROR("Field not found: %s, type: %d", name, type);
445                    return;
446                } else if (numComponents < comp+1) {
447                    ERROR("Request for component %d in field with %d components",
448                          comp, numComponents);
449                    return;
450                }
451                _renderer->getCumulativeDataRange(r, name, type, numComponents, comp);
452            } else {
453                _dataSet->getDataRange(r, name, type, comp);
454            }
455            _lut->SetRange(r);
456        }
457    }
458
459    switch (mode) {
460    case COLOR_BY_SCALAR:
461        _mapper->ScalarVisibilityOn();
462        break;
463    case COLOR_BY_VECTOR_MAGNITUDE:
464        _mapper->ScalarVisibilityOn();
465        if (_lut != NULL) {
466            _lut->SetVectorModeToMagnitude();
467        }
468        break;
469    case COLOR_BY_VECTOR_X:
470        _mapper->ScalarVisibilityOn();
471        if (_lut != NULL) {
472            _lut->SetVectorModeToComponent();
473            _lut->SetVectorComponent(0);
474        }
475        break;
476    case COLOR_BY_VECTOR_Y:
477        _mapper->ScalarVisibilityOn();
478        if (_lut != NULL) {
479            _lut->SetVectorModeToComponent();
480            _lut->SetVectorComponent(1);
481        }
482        break;
483    case COLOR_BY_VECTOR_Z:
484        _mapper->ScalarVisibilityOn();
485        if (_lut != NULL) {
486            _lut->SetVectorModeToComponent();
487            _lut->SetVectorComponent(2);
488        }
489        break;
490    case COLOR_CONSTANT:
491    default:
492        _mapper->ScalarVisibilityOff();
493        break;
494    }
495}
496
497/**
498 * \brief Called when the color map has been edited
499 */
500void PolyData::updateColorMap()
501{
502    setColorMap(_colorMap);
503}
504
505/**
506 * \brief Associate a colormap lookup table with the DataSet
507 */
508void PolyData::setColorMap(ColorMap *cmap)
509{
510    if (cmap == NULL)
511        return;
512
513    _colorMap = cmap;
514 
515    if (_lut == NULL) {
516        _lut = vtkSmartPointer<vtkLookupTable>::New();
517        if (_mapper != NULL) {
518            _mapper->UseLookupTableScalarRangeOn();
519            _mapper->SetLookupTable(_lut);
520        }
521        _lut->DeepCopy(cmap->getLookupTable());
522        switch (_colorMode) {
523        case COLOR_CONSTANT:
524        case COLOR_BY_SCALAR:
525            _lut->SetRange(_dataRange);
526            break;
527        case COLOR_BY_VECTOR_MAGNITUDE:
528            _lut->SetRange(_vectorMagnitudeRange);
529            break;
530        case COLOR_BY_VECTOR_X:
531            _lut->SetRange(_vectorComponentRange[0]);
532            break;
533        case COLOR_BY_VECTOR_Y:
534            _lut->SetRange(_vectorComponentRange[1]);
535            break;
536        case COLOR_BY_VECTOR_Z:
537            _lut->SetRange(_vectorComponentRange[2]);
538            break;
539        default:
540            break;
541        }
542    } else {
543        double range[2];
544        _lut->GetTableRange(range);
545        _lut->DeepCopy(cmap->getLookupTable());
546        _lut->SetRange(range);
547        _lut->Modified();
548    }
549
550    switch (_colorMode) {
551    case COLOR_BY_VECTOR_MAGNITUDE:
552        _lut->SetVectorModeToMagnitude();
553        break;
554    case COLOR_BY_VECTOR_X:
555        _lut->SetVectorModeToComponent();
556        _lut->SetVectorComponent(0);
557        break;
558    case COLOR_BY_VECTOR_Y:
559        _lut->SetVectorModeToComponent();
560        _lut->SetVectorComponent(1);
561        break;
562    case COLOR_BY_VECTOR_Z:
563        _lut->SetVectorModeToComponent();
564        _lut->SetVectorComponent(2);
565        break;
566    default:
567         break;
568    }
569}
570
571/**
572 * \brief Set a group of world coordinate planes to clip rendering
573 *
574 * Passing NULL for planes will remove all cliping planes
575 */
576void PolyData::setClippingPlanes(vtkPlaneCollection *planes)
577{
578    if (_mapper != NULL) {
579        _mapper->SetClippingPlanes(planes);
580    }
581}
582
583void PolyData::setCloudStyle(CloudStyle style)
584{
585    if (style != _cloudStyle) {
586        _cloudStyle = style;
587        if (_dataSet != NULL) {
588            update();
589        }
590    }
591}
Note: See TracBrowser for help on using the repository browser.