source: trunk/packages/vizservers/vtkvis/PolyData.cpp @ 3818

Last change on this file since 3818 was 3818, checked in by ldelgass, 11 years ago

Add colormode for PolyData?, by default color map if an active scalar field with
multiple components is present (color scalars). Add protocol for image/text3d
drawing components. Make 'color' synonym for 'ccolor' in protocol commands,
also accept 'ccolor' or 'constant' as colormode. Add experimental commands for
simple legend (no field info required), extended colormode for heightmap with
explicit range. Add fontconfig support (needs testing). Added code to remove
duplicate points from unstructured grids. Should probably be optional. Stack
trace on error (if WANT_TRACE is on) using VTK.

  • 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(false);
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 (numComp > 1) {
263                setColorMode(COLOR_BY_SCALAR);
264            } else {
265                setColorMode(_colorMode);
266            }
267        } else {
268            setColorMode(_colorMode);
269        }
270    } else {
271        double *rangePtr = _colorFieldRange;
272        if (_colorFieldRange[0] > _colorFieldRange[1]) {
273            rangePtr = NULL;
274        }
275        setColorMode(_colorMode, _colorFieldType, _colorFieldName.c_str(), rangePtr);
276    }
277
278    initProp();
279    getActor()->SetMapper(_mapper);
280    _mapper->Update();
281#ifdef WANT_TRACE
282    double *b = getBounds();
283    TRACE("bounds: %g %g %g %g %g %g", b[0], b[1], b[2], b[3], b[4], b[5]);
284#endif
285}
286
287void PolyData::setInterpolateBeforeMapping(bool state)
288{
289    if (_mapper != NULL) {
290        _mapper->SetInterpolateScalarsBeforeMapping((state ? 1 : 0));
291    }
292}
293
294void PolyData::updateRanges(Renderer *renderer)
295{
296    if (_dataSet == NULL) {
297        ERROR("called before setDataSet");
298        return;
299    }
300
301    if (renderer->getUseCumulativeRange()) {
302        renderer->getCumulativeDataRange(_dataRange,
303                                         _dataSet->getActiveScalarsName(),
304                                         1);
305        renderer->getCumulativeDataRange(_vectorMagnitudeRange,
306                                         _dataSet->getActiveVectorsName(),
307                                         3);
308        for (int i = 0; i < 3; i++) {
309            renderer->getCumulativeDataRange(_vectorComponentRange[i],
310                                             _dataSet->getActiveVectorsName(),
311                                             3, i);
312        }
313    } else {
314        _dataSet->getScalarRange(_dataRange);
315        _dataSet->getVectorRange(_vectorMagnitudeRange);
316        for (int i = 0; i < 3; i++) {
317            _dataSet->getVectorRange(_vectorComponentRange[i], i);
318        }
319    }
320
321    // Need to update color map ranges
322    double *rangePtr = _colorFieldRange;
323    if (_colorFieldRange[0] > _colorFieldRange[1]) {
324        rangePtr = NULL;
325    }
326    setColorMode(_colorMode, _colorFieldType, _colorFieldName.c_str(), rangePtr);
327}
328
329void PolyData::setColorMode(ColorMode mode)
330{
331    _colorMode = mode;
332    if (_dataSet == NULL)
333        return;
334
335    switch (mode) {
336    case COLOR_BY_SCALAR:
337        setColorMode(mode,
338                     _dataSet->getActiveScalarsType(),
339                     _dataSet->getActiveScalarsName(),
340                     _dataRange);
341        break;
342    case COLOR_BY_VECTOR_MAGNITUDE:
343        setColorMode(mode,
344                     _dataSet->getActiveVectorsType(),
345                     _dataSet->getActiveVectorsName(),
346                     _vectorMagnitudeRange);
347        break;
348    case COLOR_BY_VECTOR_X:
349        setColorMode(mode,
350                     _dataSet->getActiveVectorsType(),
351                     _dataSet->getActiveVectorsName(),
352                     _vectorComponentRange[0]);
353        break;
354    case COLOR_BY_VECTOR_Y:
355        setColorMode(mode,
356                     _dataSet->getActiveVectorsType(),
357                     _dataSet->getActiveVectorsName(),
358                     _vectorComponentRange[1]);
359        break;
360    case COLOR_BY_VECTOR_Z:
361        setColorMode(mode,
362                     _dataSet->getActiveVectorsType(),
363                     _dataSet->getActiveVectorsName(),
364                     _vectorComponentRange[2]);
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.