source: trunk/packages/vizservers/vtkvis/RpContour2D.cpp @ 3490

Last change on this file since 3490 was 3490, checked in by ldelgass, 12 years ago

Bring contour2d/3d code in vtkvis more in line with heightmap, make setting
number of contours/contour list faster.

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