source: vtkvis/trunk/Contour2D.cpp @ 6128

Last change on this file since 6128 was 5835, checked in by ldelgass, 9 years ago

Require VTK >= 6.0.0

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