source: trunk/packages/vizservers/vtkvis/RpMolecule.cpp @ 2393

Last change on this file since 2393 was 2393, checked in by ldelgass, 13 years ago
  • Color mode for streamlines to allow color mapping by scalar or vector data
  • Set active scalar/vector arrays on data sets
  • Constant color option for glyphs/streamlines
  • Fixes for face culling (2 glyph shapes have flipped faces)

Note that these changes will require some fixes for cumulative ranges on multiple data sets as well as legend rendering.

  • Property svn:eol-style set to native
File size: 10.6 KB
Line 
1/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2/*
3 * Copyright (C) 2011, Purdue Research Foundation
4 *
5 * Author: Leif Delgass <ldelgass@purdue.edu>
6 */
7
8#include <cassert>
9
10#include <vtkDataSet.h>
11#include <vtkPointData.h>
12#include <vtkFloatArray.h>
13#include <vtkPolyData.h>
14#include <vtkPolyDataMapper.h>
15#include <vtkActor.h>
16#include <vtkProperty.h>
17#include <vtkTubeFilter.h>
18#include <vtkSphereSource.h>
19#include <vtkGlyph3D.h>
20
21#include "RpMolecule.h"
22#include "RpMoleculeData.h"
23#include "Trace.h"
24
25using namespace Rappture::VtkVis;
26
27Molecule::Molecule() :
28    VtkGraphicsObject(),
29    _atomScaling(NO_ATOM_SCALING)
30{
31    _faceCulling = true;
32}
33
34Molecule::~Molecule()
35{
36#ifdef WANT_TRACE
37    if (_dataSet != NULL)
38        TRACE("Deleting Molecule for %s", _dataSet->getName().c_str());
39    else
40        TRACE("Deleting Molecule with NULL DataSet");
41#endif
42}
43
44/**
45 * \brief Create and initialize VTK Props to render a Molecule
46 */
47void Molecule::initProp()
48{
49    if (_atomProp == NULL) {
50        _atomProp = vtkSmartPointer<vtkActor>::New();
51        if (_faceCulling && _opacity == 1.0)
52            setCulling(_atomProp->GetProperty(), true);
53        _atomProp->GetProperty()->EdgeVisibilityOff();
54        _atomProp->GetProperty()->SetEdgeColor(_edgeColor[0], _edgeColor[1], _edgeColor[2]);
55        _atomProp->GetProperty()->SetLineWidth(_edgeWidth);
56        _atomProp->GetProperty()->SetOpacity(_opacity);
57        _atomProp->GetProperty()->SetAmbient(.2);
58        if (!_lighting)
59            _atomProp->GetProperty()->LightingOff();
60    }
61    if (_bondProp == NULL) {
62        _bondProp = vtkSmartPointer<vtkActor>::New();
63        if (_faceCulling && _opacity == 1.0)
64            setCulling(_bondProp->GetProperty(), true);
65        _bondProp->GetProperty()->EdgeVisibilityOff();
66        _bondProp->GetProperty()->SetEdgeColor(_edgeColor[0], _edgeColor[1], _edgeColor[2]);
67        _bondProp->GetProperty()->SetLineWidth(_edgeWidth);
68        _bondProp->GetProperty()->SetOpacity(_opacity);
69        _bondProp->GetProperty()->SetAmbient(.2);
70        if (!_lighting)
71            _bondProp->GetProperty()->LightingOff();
72    }
73    if (_prop == NULL) {
74        _prop = vtkSmartPointer<vtkAssembly>::New();
75    }
76}
77
78/**
79 * \brief Internal method to set up pipeline after a state change
80 */
81void Molecule::update()
82{
83    if (_dataSet == NULL) {
84        return;
85    }
86    vtkDataSet *ds = _dataSet->getVtkDataSet();
87
88    double dataRange[2];
89    _dataSet->getDataRange(dataRange);
90
91    if (ds->GetPointData() == NULL ||
92        ds->GetPointData()->GetScalars() == NULL) {
93        WARN("No scalar point data in dataset %s", _dataSet->getName().c_str());
94        if (_lut == NULL) {
95            _lut = vtkSmartPointer<vtkLookupTable>::New();
96            _lut->DeepCopy(ColorMap::getDefault()->getLookupTable());
97            _lut->SetRange(dataRange);
98        }
99    } else {
100        vtkLookupTable *lut = ds->GetPointData()->GetScalars()->GetLookupTable();
101        TRACE("Data set scalars lookup table: %p\n", lut);
102        if (_lut == NULL) {
103            if (lut) {
104                _lut = lut;
105                if (strcmp(ds->GetPointData()->GetScalars()->GetName(), "element") == 0) {
106                    double range[2];
107                    range[0] = 0;
108                    range[1] = NUM_ELEMENTS+1;
109                    _lut->SetRange(range);
110                } else {
111                    _lut->SetRange(dataRange);
112                }
113            } else {
114                if (strcmp(ds->GetPointData()->GetScalars()->GetName(), "element") == 0) {
115                    _lut = ColorMap::getElementDefault()->getLookupTable();
116                } else {
117                    _lut = vtkSmartPointer<vtkLookupTable>::New();
118                    _lut->DeepCopy(ColorMap::getDefault()->getLookupTable());
119                    _lut->SetRange(dataRange);
120                }
121            }
122        }
123    }
124
125    if (_atomMapper == NULL) {
126        _atomMapper = vtkSmartPointer<vtkPolyDataMapper>::New();
127        _atomMapper->SetResolveCoincidentTopologyToPolygonOffset();
128        _atomMapper->ScalarVisibilityOn();
129        _atomMapper->SetColorModeToMapScalars();
130        _atomMapper->UseLookupTableScalarRangeOn();
131        _atomMapper->SetLookupTable(_lut);
132    }
133    if (_bondMapper == NULL) {
134        _bondMapper = vtkSmartPointer<vtkPolyDataMapper>::New();
135        _bondMapper->SetResolveCoincidentTopologyToPolygonOffset();
136        _bondMapper->ScalarVisibilityOn();
137        _bondMapper->SetColorModeToMapScalars();
138        _bondMapper->UseLookupTableScalarRangeOn();
139        _bondMapper->SetLookupTable(_lut);
140    }
141
142    initProp();
143
144    addRadiusArray(ds, _atomScaling);
145
146    vtkPolyData *pd = vtkPolyData::SafeDownCast(ds);
147    if (pd) {
148        TRACE("Verts: %d Lines: %d Polys: %d Strips: %d",
149                  pd->GetNumberOfVerts(),
150                  pd->GetNumberOfLines(),
151                  pd->GetNumberOfPolys(),
152                  pd->GetNumberOfStrips());
153        // DataSet is a vtkPolyData
154        if (pd->GetNumberOfLines() > 0) {
155            // Bonds
156            vtkSmartPointer<vtkTubeFilter> tuber = vtkSmartPointer<vtkTubeFilter>::New();
157            tuber->SetInput(pd);
158            tuber->SetNumberOfSides(6);
159            tuber->CappingOff();
160            tuber->SetRadius(.03);
161            tuber->SetVaryRadiusToVaryRadiusOff();
162            _bondMapper->SetInputConnection(tuber->GetOutputPort());
163            _bondProp->SetMapper(_bondMapper);
164            getAssembly()->AddPart(_bondProp);
165        }
166        if (pd->GetNumberOfVerts() > 0) {
167            // Atoms
168            vtkSmartPointer<vtkSphereSource> sphereSource = vtkSmartPointer<vtkSphereSource>::New();
169            sphereSource->SetRadius(.08);
170            if (_glypher == NULL)
171                _glypher = vtkSmartPointer<vtkGlyph3D>::New();
172            _glypher->SetSourceConnection(sphereSource->GetOutputPort());
173            _glypher->SetInput(pd);
174            if (_atomScaling != NO_ATOM_SCALING &&
175                ds->GetPointData() != NULL &&
176                ds->GetPointData()->GetVectors() != NULL) {
177                _glypher->SetScaleModeToScaleByVector();
178                _glypher->ScalingOn();
179            } else {
180                _glypher->SetScaleModeToDataScalingOff();
181                _glypher->ScalingOff();
182            }
183            _glypher->SetColorModeToColorByScalar();
184            _glypher->OrientOff();
185            _atomMapper->SetInputConnection(_glypher->GetOutputPort());
186            _atomProp->SetMapper(_atomMapper);
187            getAssembly()->AddPart(_atomProp);
188        }
189    } else {
190        // DataSet is NOT a vtkPolyData
191        ERROR("DataSet is not a PolyData");
192        return;
193    }
194
195    _atomMapper->Update();
196    _bondMapper->Update();
197}
198
199/**
200 * \brief Get the VTK colormap lookup table in use
201 */
202vtkLookupTable *Molecule::getLookupTable()
203{
204    return _lut;
205}
206
207/**
208 * \brief Associate a colormap lookup table with the DataSet
209 */
210void Molecule::setLookupTable(vtkLookupTable *lut)
211{
212    if (lut == NULL) {
213        _lut = vtkSmartPointer<vtkLookupTable>::New();
214    } else {
215        _lut = lut;
216    }
217
218    if (_atomMapper != NULL) {
219        _atomMapper->UseLookupTableScalarRangeOn();
220        _atomMapper->SetLookupTable(_lut);
221    }
222    if (_bondMapper != NULL) {
223        _bondMapper->UseLookupTableScalarRangeOn();
224        _bondMapper->SetLookupTable(_lut);
225    }
226}
227
228/**
229 * \brief Turn on/off rendering of the atoms
230 */
231void Molecule::setAtomVisibility(bool state)
232{
233    if (_atomProp != NULL) {
234        _atomProp->SetVisibility((state ? 1 : 0));
235    }
236}
237
238/**
239 * \brief Turn on/off rendering of the bonds
240 */
241void Molecule::setBondVisibility(bool state)
242{
243    if (_bondProp != NULL) {
244        _bondProp->SetVisibility((state ? 1 : 0));
245    }
246}
247
248/**
249 * \brief Set a group of world coordinate planes to clip rendering
250 *
251 * Passing NULL for planes will remove all cliping planes
252 */
253void Molecule::setClippingPlanes(vtkPlaneCollection *planes)
254{
255    if (_atomMapper != NULL) {
256        _atomMapper->SetClippingPlanes(planes);
257    }
258    if (_bondMapper != NULL) {
259        _bondMapper->SetClippingPlanes(planes);
260    }
261}
262
263/**
264 * \brief Set the radius type used for scaling atoms
265 */
266void Molecule::setAtomScaling(AtomScaling state)
267{
268    _atomScaling = state;
269    if (_dataSet != NULL) {
270        vtkDataSet *ds = _dataSet->getVtkDataSet();
271        addRadiusArray(ds, _atomScaling);
272        if (_glypher != NULL) {
273            if (_atomScaling != NO_ATOM_SCALING &&
274                ds->GetPointData() != NULL &&
275                ds->GetPointData()->GetVectors() != NULL) {
276                _glypher->SetScaleModeToScaleByVector();
277                _glypher->ScalingOn();
278            } else {
279                _glypher->SetScaleModeToDataScalingOff();
280                _glypher->ScalingOff();
281            }
282        }
283    }
284}
285
286void Molecule::addRadiusArray(vtkDataSet *dataSet, AtomScaling scaling)
287{
288    if (dataSet->GetPointData() == NULL ||
289        dataSet->GetPointData()->GetScalars() == NULL) {
290        return;
291    }
292    vtkDataArray *elements = dataSet->GetPointData()->GetScalars();
293    if (strcmp(elements->GetName(), "element") != 0) {
294        return;
295    }
296    const float *radiusSource = NULL;
297    switch (scaling) {
298    case VAN_DER_WAALS_RADIUS:
299        radiusSource = g_vdwRadii;
300        break;
301    case COVALENT_RADIUS:
302        radiusSource = g_covalentRadii;
303        break;
304    case ATOMIC_RADIUS:
305        radiusSource = g_atomicRadii;
306        break;
307    case NO_ATOM_SCALING:
308    default:
309        return;
310    }
311    vtkSmartPointer<vtkFloatArray> radii = vtkSmartPointer<vtkFloatArray>::New();
312    radii->SetName("radius");
313    radii->SetNumberOfComponents(3);
314    for (int i = 0; i < elements->GetNumberOfTuples(); i++) {
315        int elt = (int)elements->GetComponent(i, 0);
316        float tuple[3];
317        tuple[0] = radiusSource[elt];
318        tuple[1] = 0;
319        tuple[2] = 0;
320        radii->InsertNextTupleValue(tuple);
321    }
322    dataSet->GetPointData()->SetVectors(radii);
323}
324
325ColorMap *Molecule::createElementColorMap()
326{
327    ColorMap *elementLUT = new ColorMap("elementDefault");
328    ColorMap::ControlPoint cp[NUM_ELEMENTS+1];
329
330    elementLUT->setNumberOfTableEntries(NUM_ELEMENTS+1);
331    for (int i = 0; i <= NUM_ELEMENTS; i++) {
332        cp[i].value = i/((double)(NUM_ELEMENTS+1));
333        for (int c = 0; c < 3; c++) {
334            cp[i].color[c] = ((double)g_elementColors[i][c])/255.;
335        }
336        elementLUT->addControlPoint(cp[i]);
337    }
338    ColorMap::OpacityControlPoint ocp[2];
339    ocp[0].value = 0;
340    ocp[0].alpha = 1.0;
341    ocp[1].value = 1.0;
342    ocp[1].alpha = 1.0;
343    elementLUT->addOpacityControlPoint(ocp[0]);
344    elementLUT->addOpacityControlPoint(ocp[1]);
345    elementLUT->build();
346    double range[2];
347    range[0] = 0;
348    range[1] = NUM_ELEMENTS+1;
349    elementLUT->getLookupTable()->SetRange(range);
350
351    return elementLUT;
352}
Note: See TracBrowser for help on using the repository browser.