source: trunk/packages/vizservers/vtkvis/Molecule.cpp @ 3693

Last change on this file since 3693 was 3693, checked in by ldelgass, 11 years ago

Add protocol to set atom/bond tesselation quality in molecules

  • Property svn:eol-style set to native
File size: 31.9 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 <cstdio>
9#include <cfloat>
10#include <cassert>
11
12#include <vtkDataSet.h>
13#include <vtkCellArray.h>
14#include <vtkPointData.h>
15#include <vtkFloatArray.h>
16#include <vtkDoubleArray.h>
17#include <vtkIntArray.h>
18#include <vtkStringArray.h>
19#include <vtkPolyData.h>
20#include <vtkPolyDataMapper.h>
21#include <vtkActor.h>
22#include <vtkProperty.h>
23#include <vtkSphereSource.h>
24#include <vtkCylinderSource.h>
25#include <vtkTransform.h>
26#include <vtkTransformPolyDataFilter.h>
27#include <vtkGlyph3DMapper.h>
28#include <vtkPointSetToLabelHierarchy.h>
29#include <vtkLabelPlacementMapper.h>
30#include <vtkTextProperty.h>
31
32#include "Molecule.h"
33#include "MoleculeData.h"
34#include "Renderer.h"
35#include "Trace.h"
36
37using namespace VtkVis;
38
39Molecule::Molecule() :
40    GraphicsObject(),
41    _radiusScale(0.3),
42    _atomScaling(COVALENT_RADIUS),
43    _labelsOn(false),
44    _colorMap(NULL),
45    _colorMode(COLOR_BY_ELEMENTS),
46    _colorFieldType(DataSet::POINT_DATA)
47{
48    _bondColor[0] = _bondColor[1] = _bondColor[2] = 1.0f;
49    _colorFieldRange[0] = DBL_MAX;
50    _colorFieldRange[1] = -DBL_MAX;
51    _faceCulling = true;
52}
53
54Molecule::~Molecule()
55{
56#ifdef WANT_TRACE
57    if (_dataSet != NULL)
58        TRACE("Deleting Molecule for %s", _dataSet->getName().c_str());
59    else
60        TRACE("Deleting Molecule with NULL DataSet");
61#endif
62}
63
64void Molecule::setDataSet(DataSet *dataSet,
65                          Renderer *renderer)
66{
67    if (_dataSet != dataSet) {
68        _dataSet = dataSet;
69
70        _renderer = renderer;
71
72        if (renderer->getUseCumulativeRange()) {
73            renderer->getCumulativeDataRange(_dataRange,
74                                             _dataSet->getActiveScalarsName(),
75                                             1);
76            renderer->getCumulativeDataRange(_vectorMagnitudeRange,
77                                             _dataSet->getActiveVectorsName(),
78                                             3);
79            for (int i = 0; i < 3; i++) {
80                renderer->getCumulativeDataRange(_vectorComponentRange[i],
81                                                 _dataSet->getActiveVectorsName(),
82                                                 3, i);
83            }
84        } else {
85            _dataSet->getScalarRange(_dataRange);
86            _dataSet->getVectorRange(_vectorMagnitudeRange);
87            for (int i = 0; i < 3; i++) {
88                _dataSet->getVectorRange(_vectorComponentRange[i], i);
89            }
90        }
91
92        update();
93    }
94}
95
96/**
97 * \brief Create and initialize VTK Props to render a Molecule
98 */
99void Molecule::initProp()
100{
101    if (_atomProp == NULL) {
102        _atomProp = vtkSmartPointer<vtkActor>::New();
103        if (_faceCulling && _opacity == 1.0)
104            setCulling(_atomProp->GetProperty(), true);
105        _atomProp->GetProperty()->EdgeVisibilityOff();
106        _atomProp->GetProperty()->SetEdgeColor(_edgeColor[0], _edgeColor[1], _edgeColor[2]);
107        _atomProp->GetProperty()->SetLineWidth(_edgeWidth);
108        _atomProp->GetProperty()->SetOpacity(_opacity);
109        _atomProp->GetProperty()->SetAmbient(.2);
110        if (!_lighting)
111            _atomProp->GetProperty()->LightingOff();
112    }
113    if (_bondProp == NULL) {
114        _bondProp = vtkSmartPointer<vtkActor>::New();
115        if (_faceCulling && _opacity == 1.0)
116            setCulling(_bondProp->GetProperty(), true);
117        _bondProp->GetProperty()->EdgeVisibilityOff();
118        _bondProp->GetProperty()->SetColor(_bondColor[0], _bondColor[1], _bondColor[2]);
119        _bondProp->GetProperty()->SetEdgeColor(_edgeColor[0], _edgeColor[1], _edgeColor[2]);
120        _bondProp->GetProperty()->SetLineWidth(_edgeWidth);
121        _bondProp->GetProperty()->SetOpacity(_opacity);
122        _bondProp->GetProperty()->SetAmbient(.2);
123        if (!_lighting)
124            _bondProp->GetProperty()->LightingOff();
125    }
126    if (_labelProp == NULL) {
127        _labelProp = vtkSmartPointer<vtkActor2D>::New();
128    }
129    if (_prop == NULL) {
130        _prop = vtkSmartPointer<vtkAssembly>::New();
131    }
132}
133
134/**
135 * \brief Internal method to set up pipeline after a state change
136 */
137void Molecule::update()
138{
139    if (_dataSet == NULL) {
140        return;
141    }
142    vtkDataSet *ds = _dataSet->getVtkDataSet();
143
144    if (_atomMapper == NULL) {
145        _atomMapper = vtkSmartPointer<vtkGlyph3DMapper>::New();
146        _atomMapper->SetResolveCoincidentTopologyToPolygonOffset();
147        _atomMapper->ScalarVisibilityOn();
148    }
149    if (_bondMapper == NULL) {
150        _bondMapper = vtkSmartPointer<vtkGlyph3DMapper>::New();
151        _bondMapper->SetResolveCoincidentTopologyToPolygonOffset();
152        _bondMapper->ScalarVisibilityOn();
153    }
154    if (_labelMapper == NULL) {
155        _labelMapper = vtkSmartPointer<vtkLabelPlacementMapper>::New();
156        _labelMapper->SetShapeToRoundedRect();
157        _labelMapper->SetBackgroundColor(1.0, 1.0, 0.7);
158        _labelMapper->SetBackgroundOpacity(0.8);
159        _labelMapper->SetMargin(3);
160    }
161
162    if (_lut == NULL) {
163        if (ds->GetPointData() == NULL ||
164            ds->GetPointData()->GetScalars() == NULL ||
165            strcmp(ds->GetPointData()->GetScalars()->GetName(), "element") != 0) {
166            WARN("No element array in dataset %s", _dataSet->getName().c_str());
167            setColorMap(ColorMap::getDefault());
168            if (_atomScaling != NO_ATOM_SCALING)
169                _atomScaling = NO_ATOM_SCALING;
170        } else {
171            TRACE("Using element default colormap");
172            setColorMap(ColorMap::getElementDefault());
173        }
174    }
175
176    initProp();
177
178    addLabelArray(ds);
179    addRadiusArray(ds, _atomScaling, _radiusScale);
180
181    vtkPolyData *pd = vtkPolyData::SafeDownCast(ds);
182    if (pd) {
183        TRACE("Points: %d Verts: %d Lines: %d Polys: %d Strips: %d",
184              pd->GetNumberOfPoints(),
185              pd->GetNumberOfVerts(),
186              pd->GetNumberOfLines(),
187              pd->GetNumberOfPolys(),
188              pd->GetNumberOfStrips());
189        // DataSet is a vtkPolyData
190        if (pd->GetNumberOfLines() > 0) {
191            // Bonds
192            setupBondPolyData();
193
194            if (_cylinderSource == NULL) {
195                _cylinderSource = vtkSmartPointer<vtkCylinderSource>::New();
196                _cylinderSource->SetRadius(0.075);
197                _cylinderSource->SetHeight(1.0);
198                _cylinderSource->SetResolution(12);
199                _cylinderSource->CappingOff();
200                _cylinderTrans = vtkSmartPointer<vtkTransformPolyDataFilter>::New();
201                _cylinderTrans->SetInputConnection(_cylinderSource->GetOutputPort());
202                vtkSmartPointer<vtkTransform> trans = vtkSmartPointer<vtkTransform>::New();
203                trans->RotateZ(-90.0);
204                _cylinderTrans->SetTransform(trans);
205            }
206            if (_lineSource == NULL) {
207                _lineSource = vtkSmartPointer<vtkLineSource>::New();
208                _lineSource->SetPoint1(-0.5, 0, 0);
209                _lineSource->SetPoint2(0.5, 0, 0);
210            }
211
212            _bondMapper->SetSourceConnection(_cylinderTrans->GetOutputPort());
213#ifdef USE_VTK6
214            _bondMapper->SetInputData(_bondPD);
215#else
216            _bondMapper->SetInputConnection(_bondPD->GetProducerPort());
217#endif
218            _bondMapper->SetOrientationArray("bond_orientations");
219            _bondMapper->SetOrientationModeToDirection();
220            _bondMapper->OrientOn();
221            _bondMapper->SetScaleArray("bond_scales");
222            _bondMapper->SetScaleModeToScaleByVectorComponents();
223            _bondMapper->ScalingOn();
224            _bondMapper->ClampingOff();
225
226            _bondProp->SetMapper(_bondMapper);
227            getAssembly()->AddPart(_bondProp);
228        }
229        if (pd->GetNumberOfPoints() > 0) {
230            if (_labelHierarchy == NULL) {
231                _labelHierarchy = vtkSmartPointer<vtkPointSetToLabelHierarchy>::New();
232            }
233#ifdef USE_VTK6
234            _labelHierarchy->SetInputData(pd);
235#else
236            _labelHierarchy->SetInput(pd);
237#endif
238            _labelHierarchy->SetLabelArrayName("_atom_labels");
239            _labelHierarchy->GetTextProperty()->SetColor(0, 0, 0);
240            _labelMapper->SetInputConnection(_labelHierarchy->GetOutputPort());
241            _labelProp->SetMapper(_labelMapper);
242
243            // Atoms
244            if (_sphereSource == NULL) {
245                _sphereSource = vtkSmartPointer<vtkSphereSource>::New();
246                _sphereSource->SetRadius(1.0);
247                _sphereSource->SetThetaResolution(14);
248                _sphereSource->SetPhiResolution(14);
249            }
250
251            _atomMapper->SetSourceConnection(_sphereSource->GetOutputPort());
252#ifdef USE_VTK6
253            _atomMapper->SetInputData(pd);
254#else
255            _atomMapper->SetInputConnection(pd->GetProducerPort());
256#endif
257            if (ds->GetPointData() != NULL &&
258                ds->GetPointData()->GetVectors() != NULL) {
259                _atomMapper->SetScaleArray(vtkDataSetAttributes::VECTORS);
260                _atomMapper->SetScaleModeToScaleByMagnitude();
261                _atomMapper->ScalingOn();
262            } else {
263                _atomMapper->SetScaleModeToNoDataScaling();
264                _atomMapper->ScalingOff();
265            }
266            _atomMapper->OrientOff();
267
268            _atomProp->SetMapper(_atomMapper);
269            getAssembly()->AddPart(_atomProp);
270        }
271    } else {
272        // DataSet is NOT a vtkPolyData
273        ERROR("DataSet is not a PolyData");
274        return;
275    }
276
277    setAtomLabelVisibility(_labelsOn);
278
279    if (pd->GetNumberOfPoints() > 0) {
280        _atomMapper->Update();
281        _labelMapper->Update();
282    }
283    if (pd->GetNumberOfLines() > 0) {
284        _bondMapper->Update();
285    }
286}
287
288void Molecule::updateRanges(Renderer *renderer)
289{
290    if (_dataSet == NULL) {
291        ERROR("called before setDataSet");
292        return;
293    }
294
295    if (renderer->getUseCumulativeRange()) {
296        renderer->getCumulativeDataRange(_dataRange,
297                                         _dataSet->getActiveScalarsName(),
298                                         1);
299        renderer->getCumulativeDataRange(_vectorMagnitudeRange,
300                                         _dataSet->getActiveVectorsName(),
301                                         3);
302        for (int i = 0; i < 3; i++) {
303            renderer->getCumulativeDataRange(_vectorComponentRange[i],
304                                             _dataSet->getActiveVectorsName(),
305                                             3, i);
306        }
307    } else {
308        _dataSet->getScalarRange(_dataRange);
309        _dataSet->getVectorRange(_vectorMagnitudeRange);
310        for (int i = 0; i < 3; i++) {
311            _dataSet->getVectorRange(_vectorComponentRange[i], i);
312        }
313    }
314
315    // Need to update color map ranges
316    double *rangePtr = _colorFieldRange;
317    if (_colorFieldRange[0] > _colorFieldRange[1]) {
318        rangePtr = NULL;
319    }
320    setColorMode(_colorMode, _colorFieldType, _colorFieldName.c_str(), rangePtr);
321}
322
323void Molecule::setColorMode(ColorMode mode)
324{
325    _colorMode = mode;
326    if (_dataSet == NULL)
327        return;
328
329    switch (mode) {
330    case COLOR_BY_ELEMENTS: // Assume default scalar is "element" array
331        setColorMode(mode,
332                     DataSet::POINT_DATA,
333                     "element");
334        break;
335    case COLOR_BY_SCALAR:
336        setColorMode(mode,
337                     _dataSet->getActiveScalarsType(),
338                     _dataSet->getActiveScalarsName(),
339                     _dataRange);
340        break;
341    case COLOR_BY_VECTOR_MAGNITUDE:
342        setColorMode(mode,
343                     _dataSet->getActiveVectorsType(),
344                     _dataSet->getActiveVectorsName(),
345                     _vectorMagnitudeRange);
346        break;
347    case COLOR_BY_VECTOR_X:
348        setColorMode(mode,
349                     _dataSet->getActiveVectorsType(),
350                     _dataSet->getActiveVectorsName(),
351                     _vectorComponentRange[0]);
352        break;
353    case COLOR_BY_VECTOR_Y:
354        setColorMode(mode,
355                     _dataSet->getActiveVectorsType(),
356                     _dataSet->getActiveVectorsName(),
357                     _vectorComponentRange[1]);
358        break;
359    case COLOR_BY_VECTOR_Z:
360        setColorMode(mode,
361                     _dataSet->getActiveVectorsType(),
362                     _dataSet->getActiveVectorsName(),
363                     _vectorComponentRange[2]);
364        break;
365    case COLOR_CONSTANT:
366    default:
367        setColorMode(mode, DataSet::POINT_DATA, NULL, NULL);
368        break;
369    }
370}
371
372void Molecule::setColorMode(ColorMode mode,
373                            const char *name, double range[2])
374{
375    if (_dataSet == NULL)
376        return;
377    DataSet::DataAttributeType type = DataSet::POINT_DATA;
378    int numComponents = 1;
379    if (name != NULL && strlen(name) > 0 &&
380        !_dataSet->getFieldInfo(name, &type, &numComponents)) {
381        ERROR("Field not found: %s", name);
382        return;
383    }
384    setColorMode(mode, type, name, range);
385}
386
387void Molecule::setColorMode(ColorMode mode, DataSet::DataAttributeType type,
388                            const char *name, double range[2])
389{
390    _colorMode = mode;
391    _colorFieldType = type;
392    if (name == NULL)
393        _colorFieldName.clear();
394    else
395        _colorFieldName = name;
396    if (range == NULL) {
397        _colorFieldRange[0] = DBL_MAX;
398        _colorFieldRange[1] = -DBL_MAX;
399    } else {
400        memcpy(_colorFieldRange, range, sizeof(double)*2);
401    }
402
403    if (_dataSet == NULL || (_atomMapper == NULL && _bondMapper == NULL))
404        return;
405
406    switch (type) {
407    case DataSet::POINT_DATA:
408        if (_atomMapper != NULL)
409            _atomMapper->SetScalarModeToUsePointFieldData();
410        if (_bondMapper != NULL)
411            _bondMapper->SetScalarModeToUsePointFieldData();
412        break;
413    case DataSet::CELL_DATA:
414        if (_atomMapper != NULL)
415            _atomMapper->SetScalarModeToUseCellFieldData();
416        if (_bondMapper != NULL)
417            _bondMapper->SetScalarModeToUseCellFieldData();
418        break;
419    default:
420        ERROR("Unsupported DataAttributeType: %d", type);
421        return;
422    }
423
424    if (name != NULL && strlen(name) > 0) {
425        if (_atomMapper != NULL)
426            _atomMapper->SelectColorArray(name);
427        if (_bondMapper != NULL)
428            _bondMapper->SelectColorArray(name);
429    } else {
430        if (_atomMapper != NULL)
431            _atomMapper->SetScalarModeToDefault();
432        if (_bondMapper != NULL)
433            _bondMapper->SetScalarModeToDefault();
434    }
435
436    if (_lut != NULL) {
437        if (range != NULL) {
438            _lut->SetRange(range);
439        } else if (mode == COLOR_BY_ELEMENTS) {
440            double range[2];
441            range[0] = 0;
442            range[1] = NUM_ELEMENTS;
443            _lut->SetRange(range);
444        } else if (name != NULL && strlen(name) > 0) {
445            double r[2];
446            int comp = -1;
447            if (mode == COLOR_BY_VECTOR_X)
448                comp = 0;
449            else if (mode == COLOR_BY_VECTOR_Y)
450                comp = 1;
451            else if (mode == COLOR_BY_VECTOR_Z)
452                comp = 2;
453
454            if (_renderer->getUseCumulativeRange()) {
455                int numComponents;
456                if  (!_dataSet->getFieldInfo(name, type, &numComponents)) {
457                    ERROR("Field not found: %s, type: %d", name, type);
458                    return;
459                } else if (numComponents < comp+1) {
460                    ERROR("Request for component %d in field with %d components",
461                          comp, numComponents);
462                    return;
463                }
464                _renderer->getCumulativeDataRange(r, name, type, numComponents, comp);
465            } else {
466                _dataSet->getDataRange(r, name, type, comp);
467            }
468            _lut->SetRange(r);
469        }
470    }
471
472    switch (mode) {
473    case COLOR_BY_ELEMENTS:
474        if (_atomMapper != NULL)
475            _atomMapper->ScalarVisibilityOn();
476        if (_bondMapper != NULL)
477            _bondMapper->ScalarVisibilityOn();
478        break;
479    case COLOR_BY_SCALAR:
480        if (_atomMapper != NULL)
481            _atomMapper->ScalarVisibilityOn();
482        if (_bondMapper != NULL)
483            _bondMapper->ScalarVisibilityOn();
484        break;
485    case COLOR_BY_VECTOR_MAGNITUDE:
486        if (_atomMapper != NULL)
487            _atomMapper->ScalarVisibilityOn();
488        if (_bondMapper != NULL)
489            _bondMapper->ScalarVisibilityOn();
490        if (_lut != NULL) {
491            _lut->SetVectorModeToMagnitude();
492        }
493        break;
494    case COLOR_BY_VECTOR_X:
495        if (_atomMapper != NULL)
496            _atomMapper->ScalarVisibilityOn();
497        if (_bondMapper != NULL)
498            _bondMapper->ScalarVisibilityOn();
499        if (_lut != NULL) {
500            _lut->SetVectorModeToComponent();
501            _lut->SetVectorComponent(0);
502        }
503        break;
504    case COLOR_BY_VECTOR_Y:
505        if (_atomMapper != NULL)
506            _atomMapper->ScalarVisibilityOn();
507        if (_bondMapper != NULL)
508            _bondMapper->ScalarVisibilityOn();
509        if (_lut != NULL) {
510            _lut->SetVectorModeToComponent();
511            _lut->SetVectorComponent(1);
512        }
513        break;
514    case COLOR_BY_VECTOR_Z:
515        if (_atomMapper != NULL)
516            _atomMapper->ScalarVisibilityOn();
517        if (_bondMapper != NULL)
518            _bondMapper->ScalarVisibilityOn();
519        if (_lut != NULL) {
520            _lut->SetVectorModeToComponent();
521            _lut->SetVectorComponent(2);
522        }
523        break;
524    case COLOR_CONSTANT:
525    default:
526        if (_atomMapper != NULL)
527            _atomMapper->ScalarVisibilityOff();
528        if (_bondMapper != NULL)
529            _bondMapper->ScalarVisibilityOff();
530        break;
531    }
532}
533
534/**
535 * \brief Called when the color map has been edited
536 */
537void Molecule::updateColorMap()
538{
539    setColorMap(_colorMap);
540}
541
542/**
543 * \brief Associate a colormap lookup table with the DataSet
544 */
545void Molecule::setColorMap(ColorMap *cmap)
546{
547    if (cmap == NULL)
548        return;
549
550    _colorMap = cmap;
551 
552    if (_lut == NULL) {
553        _lut = vtkSmartPointer<vtkLookupTable>::New();
554        if (_atomMapper != NULL) {
555            _atomMapper->UseLookupTableScalarRangeOn();
556            _atomMapper->SetLookupTable(_lut);
557        }
558        if (_bondMapper != NULL) {
559            _bondMapper->UseLookupTableScalarRangeOn();
560            _bondMapper->SetLookupTable(_lut);
561        }
562        _lut->DeepCopy(cmap->getLookupTable());
563        switch (_colorMode) {
564        case COLOR_BY_ELEMENTS: {
565            double range[2];
566            range[0] = 0;
567            range[1] = NUM_ELEMENTS;
568            _lut->SetRange(range);
569        }
570            break;
571        case COLOR_CONSTANT:
572        case COLOR_BY_SCALAR:
573            _lut->SetRange(_dataRange);
574            break;
575        case COLOR_BY_VECTOR_MAGNITUDE:
576            _lut->SetRange(_vectorMagnitudeRange);
577            break;
578        case COLOR_BY_VECTOR_X:
579            _lut->SetRange(_vectorComponentRange[0]);
580            break;
581        case COLOR_BY_VECTOR_Y:
582            _lut->SetRange(_vectorComponentRange[1]);
583            break;
584        case COLOR_BY_VECTOR_Z:
585            _lut->SetRange(_vectorComponentRange[2]);
586            break;
587        default:
588            break;
589        }
590    } else {
591        double range[2];
592        _lut->GetTableRange(range);
593        _lut->DeepCopy(cmap->getLookupTable());
594        _lut->SetRange(range);
595        _lut->Modified();
596    }
597}
598
599void Molecule::setAtomLabelField(const char *fieldName)
600{
601    if (_labelHierarchy != NULL) {
602        if (strcmp(fieldName, "default") == 0) {
603            _labelHierarchy->SetLabelArrayName("_atom_labels");
604        } else {
605            _labelHierarchy->SetLabelArrayName(fieldName);
606        }
607    }
608}
609
610/**
611 * \brief Turn on/off rendering of atom labels
612 */
613void Molecule::setAtomLabelVisibility(bool state)
614{
615    _labelsOn = state;
616    if (_labelProp != NULL) {
617        _labelProp->SetVisibility((state ? 1 : 0));
618    }
619}
620
621/**
622 * \brief Turn on/off rendering of the atoms
623 */
624void Molecule::setAtomVisibility(bool state)
625{
626    if (_atomProp != NULL) {
627        _atomProp->SetVisibility((state ? 1 : 0));
628    }
629}
630
631/**
632 * \brief Turn on/off rendering of the bonds
633 */
634void Molecule::setBondVisibility(bool state)
635{
636    if (_bondProp != NULL) {
637        _bondProp->SetVisibility((state ? 1 : 0));
638    }
639}
640
641/**
642 * \brief Toggle visibility of the prop
643 */
644void Molecule::setVisibility(bool state)
645{
646    GraphicsObject::setVisibility(state);
647    if (_labelProp != NULL) {
648        if (!state)
649            _labelProp->SetVisibility(0);
650        else
651            setAtomLabelVisibility(_labelsOn);
652    }
653}
654
655/**
656 * \brief Set opacity of molecule
657 */
658void Molecule::setOpacity(double opacity)
659{
660    GraphicsObject::setOpacity(opacity);
661    if (_labelMapper != NULL) {
662        _labelMapper->SetBackgroundOpacity(opacity);
663    }
664}
665
666void Molecule::setAtomQuality(double quality)
667{
668    if (_sphereSource == NULL)
669        return;
670
671    if (quality > 10.0)
672        quality = 10.0;
673
674    int thetaRes = (int)(quality * 14.0);
675    int phiRes = (int)(quality * 14.0);
676    if (thetaRes < 4) thetaRes = 4;
677    if (phiRes < 3) phiRes = 3;
678
679    _sphereSource->SetThetaResolution(thetaRes);
680    _sphereSource->SetPhiResolution(phiRes);
681
682    if (_atomMapper != NULL) {
683        _atomMapper->Modified();
684        _atomMapper->Update();
685    }
686}
687
688void Molecule::setBondQuality(double quality)
689{
690    if (_cylinderSource == NULL)
691        return;
692
693    if (quality > 10.0)
694        quality = 10.0;
695
696    int res = (int)(quality * 12.0);
697    if (res < 3) res = 3;
698
699    _cylinderSource->SetResolution(res);
700
701    if (_bondMapper != NULL) {
702        _bondMapper->Modified();
703        _bondMapper->Update();
704    }
705}
706
707void Molecule::setBondStyle(BondStyle style)
708{
709    switch (style) {
710    case BOND_STYLE_CYLINDER:
711        if (_bondProp != NULL) {
712            _bondProp->GetProperty()->SetLineWidth(_edgeWidth);
713            _bondProp->GetProperty()->SetLighting(_lighting ? 1 : 0);
714        }
715        if (_bondMapper != NULL && _cylinderTrans != NULL &&
716            _bondMapper->GetInputConnection(1, 0) != _cylinderTrans->GetOutputPort()) {
717            _cylinderTrans->Modified();
718            _bondMapper->SetSourceConnection(_cylinderTrans->GetOutputPort());
719            _bondMapper->Modified();
720        }
721        break;
722    case BOND_STYLE_LINE:
723        if (_bondProp != NULL) {
724            _bondProp->GetProperty()->LightingOff();
725        }
726        if (_bondMapper != NULL && _lineSource != NULL &&
727            _bondMapper->GetInputConnection(1, 0) != _lineSource->GetOutputPort()) {
728            _lineSource->Modified();
729            _bondMapper->SetSourceConnection(_lineSource->GetOutputPort());
730            _bondMapper->Modified();
731        }
732         break;
733    default:
734        WARN("Unknown bond style");   
735    }
736}
737
738/**
739 * \brief Set constant bond color
740 */
741void Molecule::setBondColor(float color[3])
742{
743    _bondColor[0] = color[0];
744    _bondColor[1] = color[1];
745    _bondColor[2] = color[2];
746    if (_bondProp != NULL) {
747        _bondProp->GetProperty()->SetColor(_bondColor[0], _bondColor[1], _bondColor[2]);
748    }
749}
750
751/**
752 * \brief Set mode to determine how bonds are colored
753 */
754void Molecule::setBondColorMode(BondColorMode mode)
755{
756    if (_bondMapper == NULL) return;
757
758    switch (mode) {
759    case BOND_COLOR_BY_ELEMENTS:
760        _bondMapper->ScalarVisibilityOn();
761        break;
762    case BOND_COLOR_CONSTANT:
763        _bondMapper->ScalarVisibilityOff();
764        break;
765    default:
766        WARN("Unknown bond color mode");
767    }
768}
769
770/**
771 * \brief Set a group of world coordinate planes to clip rendering
772 *
773 * Passing NULL for planes will remove all cliping planes
774 */
775void Molecule::setClippingPlanes(vtkPlaneCollection *planes)
776{
777    if (_atomMapper != NULL) {
778        _atomMapper->SetClippingPlanes(planes);
779    }
780    if (_bondMapper != NULL) {
781        _bondMapper->SetClippingPlanes(planes);
782    }
783}
784
785/**
786 * \brief Set the radius type used for scaling atoms
787 */
788void Molecule::setAtomScaling(AtomScaling state)
789{
790    if (state == _atomScaling)
791        return;
792
793    _atomScaling = state;
794    if (_dataSet != NULL) {
795        vtkDataSet *ds = _dataSet->getVtkDataSet();
796        addRadiusArray(ds, _atomScaling, _radiusScale);
797        if (_atomMapper != NULL) {
798             assert(ds->GetPointData() != NULL &&
799                    ds->GetPointData()->GetVectors() != NULL);
800            _atomMapper->SetScaleModeToScaleByMagnitude();
801            _atomMapper->SetScaleArray(vtkDataSetAttributes::VECTORS);
802            _atomMapper->ScalingOn();
803        }
804    }
805}
806
807/**
808 * \brief Set the constant radius scaling factor for atoms.  This
809 * can be used to convert from Angstroms to atom coordinates units.
810 */
811void Molecule::setAtomRadiusScale(double scale)
812{
813    if (scale == _radiusScale)
814        return;
815
816    _radiusScale = scale;
817    if (_dataSet != NULL) {
818        vtkDataSet *ds = _dataSet->getVtkDataSet();
819        addRadiusArray(ds, _atomScaling, _radiusScale);
820    }
821}
822
823/**
824 * \brief Set the constant radius scaling factor for bonds.
825 */
826void Molecule::setBondRadiusScale(double scale)
827{
828    if (_cylinderSource != NULL &&
829        _cylinderSource->GetRadius() != scale) {
830        _cylinderSource->SetRadius(scale);
831        // Workaround bug with source modification not causing
832        // mapper to be updated
833        if (_bondMapper != NULL) {
834            _bondMapper->Modified();
835        }
836    }
837}
838
839void Molecule::setupBondPolyData()
840{
841    if (_dataSet == NULL)
842        return;
843    if (_bondPD == NULL) {
844        _bondPD = vtkSmartPointer<vtkPolyData>::New();
845    } else {
846        _bondPD->Initialize();
847    }
848    vtkPolyData *pd = vtkPolyData::SafeDownCast(_dataSet->getVtkDataSet());
849    if (pd == NULL)
850        return;
851    vtkCellArray *lines = pd->GetLines();
852    lines->InitTraversal();
853    vtkIdType npts, *pts;
854    vtkSmartPointer<vtkPoints> bondPoints = vtkSmartPointer<vtkPoints>::New();
855    vtkSmartPointer<vtkIntArray> bondElements = vtkSmartPointer<vtkIntArray>::New();
856    vtkSmartPointer<vtkDoubleArray> bondVectors = vtkSmartPointer<vtkDoubleArray>::New();
857    vtkSmartPointer<vtkDoubleArray> bondScales = vtkSmartPointer<vtkDoubleArray>::New();
858    bondElements->SetName("element");
859    bondVectors->SetName("bond_orientations");
860    bondVectors->SetNumberOfComponents(3);
861    bondScales->SetName("bond_scales");
862    bondScales->SetNumberOfComponents(3);
863    vtkDataArray *elements = NULL;
864    if (pd->GetPointData() != NULL &&
865        pd->GetPointData()->GetScalars() != NULL &&
866        strcmp(pd->GetPointData()->GetScalars()->GetName(), "element") == 0) {
867        elements = pd->GetPointData()->GetScalars();
868    }
869    for (int i = 0; lines->GetNextCell(npts, pts); i++) {
870        assert(npts == 2);
871        double pt0[3], pt1[3];
872        double newPt0[3], newPt1[3];
873        //double *pt0 = pd->GetPoint(pts[0]);
874        //double *pt1 = pd->GetPoint(pts[1]);
875        pd->GetPoint(pts[0], pt0);
876        pd->GetPoint(pts[1], pt1);
877        double center[3];
878
879        for (int j = 0; j < 3; j++)
880            center[j] = pt0[j] + (pt1[j] - pt0[j]) * 0.5;
881        for (int j = 0; j < 3; j++)
882            newPt0[j] = pt0[j] + (pt1[j] - pt0[j]) * 0.25;
883        for (int j = 0; j < 3; j++)
884            newPt1[j] = pt0[j] + (pt1[j] - pt0[j]) * 0.75;
885
886        bondPoints->InsertNextPoint(newPt0);
887        bondPoints->InsertNextPoint(newPt1);
888
889        TRACE("Bond %d: (%g,%g,%g)-(%g,%g,%g)-(%g,%g,%g)", i,
890              pt0[0], pt0[1], pt0[2],
891              center[0], center[1], center[2],
892              pt1[0], pt1[1], pt1[2]);
893
894        double vec[3];
895        for (int j = 0; j < 3; j++)
896            vec[j] = center[j] - pt0[j];
897
898        bondVectors->InsertNextTupleValue(vec);
899        bondVectors->InsertNextTupleValue(vec);
900        TRACE("Bond %d, vec: %g,%g,%g", i, vec[0], vec[1], vec[2]);
901
902        double scale[3];
903        scale[0] = sqrt(vec[0]*vec[0] + vec[1]*vec[1] + vec[2]*vec[2]);
904        scale[1] = 1.0;
905        scale[2] = 1.0;
906
907        bondScales->InsertNextTupleValue(scale);
908        bondScales->InsertNextTupleValue(scale);
909
910        if (elements != NULL) {
911            int element = (int)elements->GetComponent(pts[0], 0);
912            TRACE("Bond %d, elt 0: %d", i, element);
913            bondElements->InsertNextValue(element);
914            element = (int)elements->GetComponent(pts[1], 0);
915            TRACE("Bond %d, elt 1: %d", i, element);
916            bondElements->InsertNextValue(element);
917        }
918    }
919    _bondPD->SetPoints(bondPoints);
920    if (elements != NULL)
921        _bondPD->GetPointData()->SetScalars(bondElements);
922    _bondPD->GetPointData()->AddArray(bondVectors);
923    _bondPD->GetPointData()->AddArray(bondScales);
924}
925
926void Molecule::addLabelArray(vtkDataSet *dataSet)
927{
928    vtkDataArray *elements = NULL;
929    if (dataSet->GetPointData() != NULL &&
930        dataSet->GetPointData()->GetScalars() != NULL &&
931        strcmp(dataSet->GetPointData()->GetScalars()->GetName(), "element") == 0) {
932        elements = dataSet->GetPointData()->GetScalars();
933    } else {
934        WARN("Can't label atoms without an element array");
935    }
936
937    vtkSmartPointer<vtkStringArray> labelArray = vtkSmartPointer<vtkStringArray>::New();
938    labelArray->SetName("_atom_labels");
939    vtkPolyData *pd = vtkPolyData::SafeDownCast(dataSet);
940    if (pd == NULL) {
941        ERROR("DataSet not a PolyData");
942        return;
943    }
944    for (int i = 0; i < pd->GetNumberOfPoints(); i++) {
945        char buf[32];
946        if (elements != NULL) {
947            int elt = (int)elements->GetComponent(i, 0);
948            sprintf(buf, "%s%d", g_elementNames[elt], i);
949        } else {
950            sprintf(buf, "%d", i);
951        }
952        labelArray->InsertNextValue(buf);
953    }
954    dataSet->GetPointData()->AddArray(labelArray);
955}
956
957/**
958 * \brief Add a scalar array to dataSet with sizes for the elements
959 * specified in the "element" scalar array
960 */
961void Molecule::addRadiusArray(vtkDataSet *dataSet, AtomScaling scaling, double scaleFactor)
962{
963    vtkDataArray *elements = NULL;
964    if (dataSet->GetPointData() != NULL &&
965        dataSet->GetPointData()->GetScalars() != NULL &&
966        strcmp(dataSet->GetPointData()->GetScalars()->GetName(), "element") == 0) {
967        elements = dataSet->GetPointData()->GetScalars();
968    } else if (scaling != NO_ATOM_SCALING) {
969        WARN("Can't use non-constant scaling without an element array");
970    }
971    const float *radiusSource = NULL;
972    switch (scaling) {
973    case VAN_DER_WAALS_RADIUS:
974        radiusSource = g_vdwRadii;
975        break;
976    case COVALENT_RADIUS:
977        radiusSource = g_covalentRadii;
978        break;
979    case ATOMIC_RADIUS:
980        radiusSource = g_atomicRadii;
981        break;
982    case NO_ATOM_SCALING:
983    default:
984        ;
985    }
986    vtkSmartPointer<vtkFloatArray> radii = vtkSmartPointer<vtkFloatArray>::New();
987    radii->SetName("_radii");
988    radii->SetNumberOfComponents(3);
989    vtkPolyData *pd = vtkPolyData::SafeDownCast(dataSet);
990    if (pd == NULL) {
991        ERROR("DataSet not a PolyData");
992        return;
993    }
994    for (int i = 0; i < pd->GetNumberOfPoints(); i++) {
995        float tuple[3];
996        tuple[1] = tuple[2] = 0;
997        if (elements != NULL && radiusSource != NULL) {
998            int elt = (int)elements->GetComponent(i, 0);
999            tuple[0] = radiusSource[elt] * scaleFactor;
1000        } else {
1001            tuple[0] = scaleFactor;
1002        }
1003        radii->InsertNextTupleValue(tuple);
1004    }
1005    dataSet->GetPointData()->SetVectors(radii);
1006}
1007
1008/**
1009 * \brief Create a color map to map atomic numbers to element colors
1010 */
1011ColorMap *Molecule::createElementColorMap()
1012{
1013    ColorMap *elementCmap = new ColorMap("elementDefault");
1014    ColorMap::ControlPoint cp[NUM_ELEMENTS+1];
1015
1016    elementCmap->setNumberOfTableEntries(NUM_ELEMENTS+1);
1017    for (int i = 0; i <= NUM_ELEMENTS; i++) {
1018        cp[i].value = i/((double)NUM_ELEMENTS);
1019        for (int c = 0; c < 3; c++) {
1020            cp[i].color[c] = ((double)g_elementColors[i][c])/255.;
1021        }
1022        elementCmap->addControlPoint(cp[i]);
1023    }
1024    ColorMap::OpacityControlPoint ocp[2];
1025    ocp[0].value = 0;
1026    ocp[0].alpha = 1.0;
1027    ocp[1].value = 1.0;
1028    ocp[1].alpha = 1.0;
1029    elementCmap->addOpacityControlPoint(ocp[0]);
1030    elementCmap->addOpacityControlPoint(ocp[1]);
1031    elementCmap->build();
1032    double range[2];
1033    range[0] = 0;
1034    range[1] = NUM_ELEMENTS;
1035    elementCmap->getLookupTable()->SetRange(range);
1036
1037    return elementCmap;
1038}
Note: See TracBrowser for help on using the repository browser.