source: vtkvis/trunk/PolyData.cpp @ 6505

Last change on this file since 6505 was 6458, checked in by ldelgass, 8 years ago

Apply fix from r6408 (setting colormode with empty field name) across all
graphics objects.

  • 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            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        } else {
425            switch (mode) {
426            case COLOR_CONSTANT:
427            case COLOR_BY_SCALAR:
428                _lut->SetRange(_dataRange);
429                break;
430            case COLOR_BY_VECTOR_MAGNITUDE:
431                _lut->SetRange(_vectorMagnitudeRange);
432                break;
433            case COLOR_BY_VECTOR_X:
434                _lut->SetRange(_vectorComponentRange[0]);
435                break;
436            case COLOR_BY_VECTOR_Y:
437                _lut->SetRange(_vectorComponentRange[1]);
438                break;
439            case COLOR_BY_VECTOR_Z:
440                _lut->SetRange(_vectorComponentRange[2]);
441                break;
442            default:
443                break;
444            }
445        }
446    }
447
448    switch (mode) {
449    case COLOR_BY_SCALAR:
450        _mapper->ScalarVisibilityOn();
451        break;
452    case COLOR_BY_VECTOR_MAGNITUDE:
453        _mapper->ScalarVisibilityOn();
454        if (_lut != NULL) {
455            _lut->SetVectorModeToMagnitude();
456        }
457        break;
458    case COLOR_BY_VECTOR_X:
459        _mapper->ScalarVisibilityOn();
460        if (_lut != NULL) {
461            _lut->SetVectorModeToComponent();
462            _lut->SetVectorComponent(0);
463        }
464        break;
465    case COLOR_BY_VECTOR_Y:
466        _mapper->ScalarVisibilityOn();
467        if (_lut != NULL) {
468            _lut->SetVectorModeToComponent();
469            _lut->SetVectorComponent(1);
470        }
471        break;
472    case COLOR_BY_VECTOR_Z:
473        _mapper->ScalarVisibilityOn();
474        if (_lut != NULL) {
475            _lut->SetVectorModeToComponent();
476            _lut->SetVectorComponent(2);
477        }
478        break;
479    case COLOR_CONSTANT:
480    default:
481        _mapper->ScalarVisibilityOff();
482        break;
483    }
484}
485
486/**
487 * \brief Called when the color map has been edited
488 */
489void PolyData::updateColorMap()
490{
491    setColorMap(_colorMap);
492}
493
494/**
495 * \brief Associate a colormap lookup table with the DataSet
496 */
497void PolyData::setColorMap(ColorMap *cmap)
498{
499    if (cmap == NULL)
500        return;
501
502    _colorMap = cmap;
503 
504    if (_lut == NULL) {
505        _lut = vtkSmartPointer<vtkLookupTable>::New();
506        if (_mapper != NULL) {
507            _mapper->UseLookupTableScalarRangeOn();
508            _mapper->SetLookupTable(_lut);
509        }
510        _lut->DeepCopy(cmap->getLookupTable());
511        switch (_colorMode) {
512        case COLOR_CONSTANT:
513        case COLOR_BY_SCALAR:
514            _lut->SetRange(_dataRange);
515            break;
516        case COLOR_BY_VECTOR_MAGNITUDE:
517            _lut->SetRange(_vectorMagnitudeRange);
518            break;
519        case COLOR_BY_VECTOR_X:
520            _lut->SetRange(_vectorComponentRange[0]);
521            break;
522        case COLOR_BY_VECTOR_Y:
523            _lut->SetRange(_vectorComponentRange[1]);
524            break;
525        case COLOR_BY_VECTOR_Z:
526            _lut->SetRange(_vectorComponentRange[2]);
527            break;
528        default:
529            break;
530        }
531    } else {
532        double range[2];
533        _lut->GetTableRange(range);
534        _lut->DeepCopy(cmap->getLookupTable());
535        _lut->SetRange(range);
536        _lut->Modified();
537    }
538
539    switch (_colorMode) {
540    case COLOR_BY_VECTOR_MAGNITUDE:
541        _lut->SetVectorModeToMagnitude();
542        break;
543    case COLOR_BY_VECTOR_X:
544        _lut->SetVectorModeToComponent();
545        _lut->SetVectorComponent(0);
546        break;
547    case COLOR_BY_VECTOR_Y:
548        _lut->SetVectorModeToComponent();
549        _lut->SetVectorComponent(1);
550        break;
551    case COLOR_BY_VECTOR_Z:
552        _lut->SetVectorModeToComponent();
553        _lut->SetVectorComponent(2);
554        break;
555    default:
556         break;
557    }
558}
559
560/**
561 * \brief Set a group of world coordinate planes to clip rendering
562 *
563 * Passing NULL for planes will remove all cliping planes
564 */
565void PolyData::setClippingPlanes(vtkPlaneCollection *planes)
566{
567    if (_mapper != NULL) {
568        _mapper->SetClippingPlanes(planes);
569    }
570}
571
572void PolyData::setCloudStyle(CloudStyle style)
573{
574    if (style != _cloudStyle) {
575        _cloudStyle = style;
576        if (_dataSet != NULL) {
577            update();
578        }
579    }
580}
Note: See TracBrowser for help on using the repository browser.