source: vtkvis/trunk/Contour2D.cpp @ 6226

Last change on this file since 6226 was 6162, checked in by ldelgass, 9 years ago

merge r5843:5844 from 1.8 branch

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