source: branches/vtkvis_threaded/RpMolecule.cpp @ 2524

Last change on this file since 2524 was 2402, checked in by ldelgass, 13 years ago
  • Let graphics objects handle DataSet? cumulative range changes, track vectors as well as scalars, also supply cumulative ranges in setDataSet()
  • Be more consistent about naming enums and commands for vectors
  • Add constructor arguments to some graphics objects to speed initialization (eliminates some pipeline changes)
  • Apply a scale factor to glyphs based on cell sizes
  • Add line glyph shape
  • Don't delete ColorMaps? in use
  • Update graphics objects when a ColorMap? is edited
  • Property svn:eol-style set to native
File size: 10.9 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(bool useCumulative,
170                            double scalarRange[2],
171                            double vectorMagnitudeRange[2],
172                            double vectorComponentRange[3][2])
173{
174    if (useCumulative) {
175        _dataRange[0] = scalarRange[0];
176        _dataRange[1] = scalarRange[1];
177    } else if (_dataSet != NULL) {
178        _dataSet->getScalarRange(_dataRange);
179    }
180
181    if (_lut != NULL) {
182        vtkDataSet *ds = _dataSet->getVtkDataSet();
183        if (ds == NULL)
184            return;
185        if (ds->GetPointData() == NULL ||
186            ds->GetPointData()->GetScalars() == NULL ||
187            strcmp(ds->GetPointData()->GetScalars()->GetName(), "element") != 0) {
188            _lut->SetRange(_dataRange);
189        }
190    }
191}
192
193/**
194 * \brief Called when the color map has been edited
195 */
196void Molecule::updateColorMap()
197{
198    setColorMap(_colorMap);
199}
200
201/**
202 * \brief Associate a colormap lookup table with the DataSet
203 */
204void Molecule::setColorMap(ColorMap *cmap)
205{
206    if (cmap == NULL)
207        return;
208
209    _colorMap = cmap;
210 
211    if (_lut == NULL) {
212        _lut = vtkSmartPointer<vtkLookupTable>::New();
213        if (_atomMapper != NULL) {
214            _atomMapper->UseLookupTableScalarRangeOn();
215            _atomMapper->SetLookupTable(_lut);
216        }
217        if (_bondMapper != NULL) {
218            _bondMapper->UseLookupTableScalarRangeOn();
219            _bondMapper->SetLookupTable(_lut);
220        }
221    }
222
223    _lut->DeepCopy(cmap->getLookupTable());
224    _lut->Modified();
225
226    // Element color maps need to retain their range
227    // Only set LUT range if we are not coloring by element
228    vtkDataSet *ds = _dataSet->getVtkDataSet();
229    if (ds == NULL)
230        return;
231    if (ds->GetPointData() == NULL ||
232        ds->GetPointData()->GetScalars() == NULL ||
233        strcmp(ds->GetPointData()->GetScalars()->GetName(), "element") != 0) {
234        _lut->SetRange(_dataRange);
235    }
236}
237
238/**
239 * \brief Turn on/off rendering of the atoms
240 */
241void Molecule::setAtomVisibility(bool state)
242{
243    if (_atomProp != NULL) {
244        _atomProp->SetVisibility((state ? 1 : 0));
245    }
246}
247
248/**
249 * \brief Turn on/off rendering of the bonds
250 */
251void Molecule::setBondVisibility(bool state)
252{
253    if (_bondProp != NULL) {
254        _bondProp->SetVisibility((state ? 1 : 0));
255    }
256}
257
258/**
259 * \brief Set a group of world coordinate planes to clip rendering
260 *
261 * Passing NULL for planes will remove all cliping planes
262 */
263void Molecule::setClippingPlanes(vtkPlaneCollection *planes)
264{
265    if (_atomMapper != NULL) {
266        _atomMapper->SetClippingPlanes(planes);
267    }
268    if (_bondMapper != NULL) {
269        _bondMapper->SetClippingPlanes(planes);
270    }
271}
272
273/**
274 * \brief Set the radius type used for scaling atoms
275 */
276void Molecule::setAtomScaling(AtomScaling state)
277{
278    _atomScaling = state;
279    if (_dataSet != NULL) {
280        vtkDataSet *ds = _dataSet->getVtkDataSet();
281        addRadiusArray(ds, _atomScaling);
282        if (_glypher != NULL) {
283            if (_atomScaling != NO_ATOM_SCALING &&
284                ds->GetPointData() != NULL &&
285                ds->GetPointData()->GetVectors() != NULL) {
286                _glypher->SetScaleModeToScaleByVector();
287                _glypher->ScalingOn();
288            } else {
289                _glypher->SetScaleModeToDataScalingOff();
290                _glypher->ScalingOff();
291            }
292        }
293    }
294}
295
296/**
297 * \brief Add a scalar array to dataSet with sizes for the elements
298 * specified in the "element" scalar array
299 */
300void Molecule::addRadiusArray(vtkDataSet *dataSet, AtomScaling scaling)
301{
302    if (dataSet->GetPointData() == NULL ||
303        dataSet->GetPointData()->GetScalars() == NULL) {
304        return;
305    }
306    vtkDataArray *elements = dataSet->GetPointData()->GetScalars();
307    if (strcmp(elements->GetName(), "element") != 0) {
308        return;
309    }
310    const float *radiusSource = NULL;
311    switch (scaling) {
312    case VAN_DER_WAALS_RADIUS:
313        radiusSource = g_vdwRadii;
314        break;
315    case COVALENT_RADIUS:
316        radiusSource = g_covalentRadii;
317        break;
318    case ATOMIC_RADIUS:
319        radiusSource = g_atomicRadii;
320        break;
321    case NO_ATOM_SCALING:
322    default:
323        return;
324    }
325    vtkSmartPointer<vtkFloatArray> radii = vtkSmartPointer<vtkFloatArray>::New();
326    radii->SetName("radius");
327    radii->SetNumberOfComponents(3);
328    for (int i = 0; i < elements->GetNumberOfTuples(); i++) {
329        int elt = (int)elements->GetComponent(i, 0);
330        float tuple[3];
331        tuple[0] = radiusSource[elt];
332        tuple[1] = 0;
333        tuple[2] = 0;
334        radii->InsertNextTupleValue(tuple);
335    }
336    dataSet->GetPointData()->SetVectors(radii);
337}
338
339/**
340 * \brief Create a color map to map atomic numbers to element colors
341 */
342ColorMap *Molecule::createElementColorMap()
343{
344    ColorMap *elementCmap = new ColorMap("elementDefault");
345    ColorMap::ControlPoint cp[NUM_ELEMENTS+1];
346
347    elementCmap->setNumberOfTableEntries(NUM_ELEMENTS+1);
348    for (int i = 0; i <= NUM_ELEMENTS; i++) {
349        cp[i].value = i/((double)(NUM_ELEMENTS+1));
350        for (int c = 0; c < 3; c++) {
351            cp[i].color[c] = ((double)g_elementColors[i][c])/255.;
352        }
353        elementCmap->addControlPoint(cp[i]);
354    }
355    ColorMap::OpacityControlPoint ocp[2];
356    ocp[0].value = 0;
357    ocp[0].alpha = 1.0;
358    ocp[1].value = 1.0;
359    ocp[1].alpha = 1.0;
360    elementCmap->addOpacityControlPoint(ocp[0]);
361    elementCmap->addOpacityControlPoint(ocp[1]);
362    elementCmap->build();
363    double range[2];
364    range[0] = 0;
365    range[1] = NUM_ELEMENTS+1;
366    elementCmap->getLookupTable()->SetRange(range);
367
368    return elementCmap;
369}
Note: See TracBrowser for help on using the repository browser.