source: branches/blt4/packages/vizservers/vtkvis/RpMolecule.cpp @ 2681

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