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

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

When field data is missing, send user error instead of sending error to syslog.

  • 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            TRACE("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                USER_ERROR("No scalar field was found in the data set");
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.