source: trunk/packages/vizservers/vtkvis/RpVtkRendererGraphicsObjs.cpp @ 2864

Last change on this file since 2864 was 2757, checked in by ldelgass, 12 years ago

Add volume quality command to adjust relative sampling distance (quality is in
[0,1] range and is used to adjust sample distance relative to volume spacing.
Also first pass at supporting point cloud input to volume renderer.

  • Property svn:eol-style set to native
File size: 41.3 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 <cstring>
9#include <typeinfo>
10
11#include <vtkSmartPointer.h>
12#include <vtkDataSet.h>
13#include <vtkCharArray.h>
14#include <vtkDataSetReader.h>
15
16#include "RpVtkRenderer.h"
17#include "RpVtkDataSet.h"
18#include "RpContour2D.h"
19#include "RpContour3D.h"
20#include "RpCutplane.h"
21#include "RpGlyphs.h"
22#include "RpHeightMap.h"
23#include "RpLIC.h"
24#include "RpMolecule.h"
25#include "RpPolyData.h"
26#include "RpPseudoColor.h"
27#include "RpStreamlines.h"
28#include "RpVolume.h"
29#include "ColorMap.h"
30#include "Trace.h"
31
32// Template specializations
33namespace Rappture {
34namespace VtkVis {
35
36template<>
37Renderer::Contour2DHashmap &
38Renderer::getGraphicsObjectHashmap<Contour2D>()
39{ return _contour2Ds; }
40
41template<>
42Renderer::Contour3DHashmap &
43Renderer::getGraphicsObjectHashmap<Contour3D>()
44{ return _contour3Ds; }
45
46template<>
47Renderer::CutplaneHashmap &
48Renderer::getGraphicsObjectHashmap<Cutplane>()
49{ return _cutplanes; }
50
51template<>
52Renderer::GlyphsHashmap &
53Renderer::getGraphicsObjectHashmap<Glyphs>()
54{ return _glyphs; }
55
56template<>
57Renderer::HeightMapHashmap &
58Renderer::getGraphicsObjectHashmap<HeightMap>()
59{ return _heightMaps; }
60
61template<>
62Renderer::LICHashmap &
63Renderer::getGraphicsObjectHashmap<LIC>()
64{ return _lics; }
65
66template<>
67Renderer::MoleculeHashmap &
68Renderer::getGraphicsObjectHashmap<Molecule>()
69{ return _molecules; }
70
71template<>
72Renderer::PolyDataHashmap &
73Renderer::getGraphicsObjectHashmap<PolyData>()
74{ return _polyDatas; }
75
76template<>
77Renderer::PseudoColorHashmap &
78Renderer::getGraphicsObjectHashmap<PseudoColor>()
79{ return _pseudoColors; }
80
81template<>
82Renderer::StreamlinesHashmap &
83Renderer::getGraphicsObjectHashmap<Streamlines>()
84{ return _streamlines; }
85
86template<>
87Renderer::VolumeHashmap &
88Renderer::getGraphicsObjectHashmap<Volume>()
89{ return _volumes; }
90
91/**
92 * \brief Set the volume slice used for mapping volumetric data
93 */
94template <>
95void Renderer::setGraphicsObjectVolumeSlice<HeightMap>(const DataSetId& id, Axis axis, double ratio)
96{
97    HeightMapHashmap::iterator itr;
98
99    bool doAll = false;
100
101    if (id.compare("all") == 0) {
102        itr = _heightMaps.begin();
103        doAll = true;
104    } else {
105        itr = _heightMaps.find(id);
106    }
107
108    if (itr == _heightMaps.end()) {
109        ERROR("HeightMap not found: %s", id.c_str());
110        return;
111    }
112
113    bool initCam = false;
114    do {
115        itr->second->selectVolumeSlice(axis, ratio);
116        if (itr->second->getHeightScale() > 0.0)
117            initCam = true;
118     } while (doAll && ++itr != _heightMaps.end());
119
120    if (initCam)
121        initCamera();
122    else
123        _renderer->ResetCameraClippingRange();
124    _needsRedraw = true;
125}
126
127}
128}
129
130using namespace Rappture::VtkVis;
131
132/**
133 * \brief Create a new Contour2D and associate it with the named DataSet
134 */
135bool Renderer::addContour2D(const DataSetId& id, int numContours)
136{
137    DataSetHashmap::iterator itr;
138
139    bool doAll = false;
140
141    if (id.compare("all") == 0) {
142        itr = _dataSets.begin();
143    } else {
144        itr = _dataSets.find(id);
145    }
146    if (itr == _dataSets.end()) {
147        ERROR("Unknown dataset %s", id.c_str());
148        return false;
149    }
150
151    do {
152        DataSet *ds = itr->second;
153        const DataSetId& dsID = ds->getName();
154
155        if (getGraphicsObject<Contour2D>(dsID)) {
156            WARN("Replacing existing Contour2D %s", dsID.c_str());
157            deleteGraphicsObject<Contour2D>(dsID);
158        }
159
160        Contour2D *contour = new Contour2D(numContours);
161 
162        contour->setDataSet(ds, this);
163
164        if (contour->getProp() == NULL) {
165            delete contour;
166            return false;
167        } else {
168            _renderer->AddViewProp(contour->getProp());
169        }
170
171        _contour2Ds[dsID] = contour;
172    } while (doAll && ++itr != _dataSets.end());
173
174    initCamera();
175    _needsRedraw = true;
176    return true;
177}
178
179/**
180 * \brief Create a new Contour2D and associate it with the named DataSet
181 */
182bool Renderer::addContour2D(const DataSetId& id, const std::vector<double>& contours)
183{
184    DataSetHashmap::iterator itr;
185
186    bool doAll = false;
187
188    if (id.compare("all") == 0) {
189        itr = _dataSets.begin();
190    } else {
191        itr = _dataSets.find(id);
192    }
193    if (itr == _dataSets.end()) {
194        ERROR("Unknown dataset %s", id.c_str());
195        return false;
196    }
197
198    do {
199        DataSet *ds = itr->second;
200        const DataSetId& dsID = ds->getName();
201
202        if (getGraphicsObject<Contour2D>(dsID)) {
203            WARN("Replacing existing Contour2D %s", dsID.c_str());
204            deleteGraphicsObject<Contour2D>(dsID);
205        }
206
207        Contour2D *contour = new Contour2D(contours);
208
209        contour->setDataSet(ds, this);
210
211        if (contour->getProp() == NULL) {
212            delete contour;
213            return false;
214        } else {
215            _renderer->AddViewProp(contour->getProp());
216        }
217
218        _contour2Ds[dsID] = contour;
219    } while (doAll && ++itr != _dataSets.end());
220
221    initCamera();
222    _needsRedraw = true;
223    return true;
224}
225
226/**
227 * \brief Set the number of equally spaced contour isolines for the given DataSet
228 */
229void Renderer::setContour2DContours(const DataSetId& id, int numContours)
230{
231    Contour2DHashmap::iterator itr;
232
233    bool doAll = false;
234
235    if (id.compare("all") == 0) {
236        itr = _contour2Ds.begin();
237        doAll = true;
238    } else {
239        itr = _contour2Ds.find(id);
240    }
241    if (itr == _contour2Ds.end()) {
242        ERROR("Contour2D not found: %s", id.c_str());
243        return;
244    }
245
246    do {
247        itr->second->setContours(numContours);
248    } while (doAll && ++itr != _contour2Ds.end());
249
250    _needsRedraw = true;
251}
252
253/**
254 * \brief Set a list of isovalues for the given DataSet
255 */
256void Renderer::setContour2DContourList(const DataSetId& id, const std::vector<double>& contours)
257{
258    Contour2DHashmap::iterator itr;
259
260    bool doAll = false;
261
262    if (id.compare("all") == 0) {
263        itr = _contour2Ds.begin();
264        doAll = true;
265    } else {
266        itr = _contour2Ds.find(id);
267    }
268    if (itr == _contour2Ds.end()) {
269        ERROR("Contour2D not found: %s", id.c_str());
270        return;
271    }
272
273    do {
274        itr->second->setContourList(contours);
275    } while (doAll && ++itr != _contour2Ds.end());
276
277     _needsRedraw = true;
278}
279
280/**
281 * \brief Create a new Contour3D and associate it with the named DataSet
282 */
283bool Renderer::addContour3D(const DataSetId& id, int numContours)
284{
285    DataSetHashmap::iterator itr;
286
287    bool doAll = false;
288
289    if (id.compare("all") == 0) {
290        itr = _dataSets.begin();
291    } else {
292        itr = _dataSets.find(id);
293    }
294    if (itr == _dataSets.end()) {
295        ERROR("Unknown dataset %s", id.c_str());
296        return false;
297    }
298
299    do {
300        DataSet *ds = itr->second;
301        const DataSetId& dsID = ds->getName();
302
303        if (getGraphicsObject<Contour3D>(dsID)) {
304            WARN("Replacing existing Contour3D %s", dsID.c_str());
305            deleteGraphicsObject<Contour3D>(dsID);
306        }
307
308        Contour3D *contour = new Contour3D(numContours);
309
310        contour->setDataSet(ds, this);
311
312        if (contour->getProp() == NULL) {
313            delete contour;
314            return false;
315        } else {
316            _renderer->AddViewProp(contour->getProp());
317        }
318
319        _contour3Ds[dsID] = contour;
320    } while (doAll && ++itr != _dataSets.end());
321
322    if (_cameraMode == IMAGE)
323        setCameraMode(PERSPECTIVE);
324    initCamera();
325    _needsRedraw = true;
326    return true;
327}
328
329/**
330 * \brief Create a new Contour3D and associate it with the named DataSet
331 */
332bool Renderer::addContour3D(const DataSetId& id,const std::vector<double>& contours)
333{
334    DataSetHashmap::iterator itr;
335
336    bool doAll = false;
337
338    if (id.compare("all") == 0) {
339        itr = _dataSets.begin();
340    } else {
341        itr = _dataSets.find(id);
342    }
343    if (itr == _dataSets.end()) {
344        ERROR("Unknown dataset %s", id.c_str());
345        return false;
346    }
347
348    do {
349        DataSet *ds = itr->second;
350        const DataSetId& dsID = ds->getName();
351
352        if (getGraphicsObject<Contour3D>(dsID)) {
353            WARN("Replacing existing Contour3D %s", dsID.c_str());
354            deleteGraphicsObject<Contour3D>(dsID);
355        }
356
357        Contour3D *contour = new Contour3D(contours);
358
359        contour->setDataSet(ds, this);
360
361        if (contour->getProp() == NULL) {
362            delete contour;
363            return false;
364        } else {
365            _renderer->AddViewProp(contour->getProp());
366        }
367
368        _contour3Ds[dsID] = contour;
369    } while (doAll && ++itr != _dataSets.end());
370
371    initCamera();
372    _needsRedraw = true;
373    return true;
374}
375
376/**
377 * \brief Set the number of equally spaced isosurfaces for the given DataSet
378 */
379void Renderer::setContour3DContours(const DataSetId& id, int numContours)
380{
381    Contour3DHashmap::iterator itr;
382
383    bool doAll = false;
384
385    if (id.compare("all") == 0) {
386        itr = _contour3Ds.begin();
387        doAll = true;
388    } else {
389        itr = _contour3Ds.find(id);
390    }
391    if (itr == _contour3Ds.end()) {
392        ERROR("Contour3D not found: %s", id.c_str());
393        return;
394    }
395
396    do {
397        itr->second->setContours(numContours);
398     } while (doAll && ++itr != _contour3Ds.end());
399
400    initCamera();
401    _needsRedraw = true;
402}
403
404/**
405 * \brief Set a list of isovalues for the given DataSet
406 */
407void Renderer::setContour3DContourList(const DataSetId& id, const std::vector<double>& contours)
408{
409    Contour3DHashmap::iterator itr;
410
411    bool doAll = false;
412
413    if (id.compare("all") == 0) {
414        itr = _contour3Ds.begin();
415        doAll = true;
416    } else {
417        itr = _contour3Ds.find(id);
418    }
419    if (itr == _contour3Ds.end()) {
420        ERROR("Contour3D not found: %s", id.c_str());
421        return;
422    }
423
424    do {
425        itr->second->setContourList(contours);
426    } while (doAll && ++itr != _contour3Ds.end());
427
428    initCamera();
429     _needsRedraw = true;
430}
431
432/**
433 * \brief Set the visibility of cutplane outlines
434 */
435void Renderer::setCutplaneOutlineVisibility(const DataSetId& id, bool state)
436{
437    CutplaneHashmap::iterator itr;
438
439    bool doAll = false;
440
441    if (id.compare("all") == 0) {
442        itr = _cutplanes.begin();
443        doAll = true;
444    } else {
445        itr = _cutplanes.find(id);
446    }
447
448    if (itr == _cutplanes.end()) {
449        ERROR("Cutplane not found: %s", id.c_str());
450        return;
451    }
452
453    do {
454        itr->second->setOutlineVisibility(state);
455     } while (doAll && ++itr != _cutplanes.end());
456
457    _renderer->ResetCameraClippingRange();
458    _needsRedraw = true;
459}
460
461/**
462 * \brief Set the visibility of slices in one of the three axes
463 */
464void Renderer::setCutplaneSliceVisibility(const DataSetId& id, Axis axis, bool state)
465{
466    CutplaneHashmap::iterator itr;
467
468    bool doAll = false;
469
470    if (id.compare("all") == 0) {
471        itr = _cutplanes.begin();
472        doAll = true;
473    } else {
474        itr = _cutplanes.find(id);
475    }
476
477    if (itr == _cutplanes.end()) {
478        ERROR("Cutplane not found: %s", id.c_str());
479        return;
480    }
481
482    do {
483        itr->second->setSliceVisibility(axis, state);
484     } while (doAll && ++itr != _cutplanes.end());
485
486    _renderer->ResetCameraClippingRange();
487    _needsRedraw = true;
488}
489
490/**
491 * \brief Set the color mode for the specified DataSet
492 */
493void Renderer::setCutplaneColorMode(const DataSetId& id,
494                                    Cutplane::ColorMode mode,
495                                    DataSet::DataAttributeType type,
496                                    const char *name, double range[2])
497{
498    CutplaneHashmap::iterator itr;
499
500    bool doAll = false;
501
502    if (id.compare("all") == 0) {
503        itr = _cutplanes.begin();
504        doAll = true;
505    } else {
506        itr = _cutplanes.find(id);
507    }
508    if (itr == _cutplanes.end()) {
509        ERROR("Cutplane not found: %s", id.c_str());
510        return;
511    }
512
513    do {
514        itr->second->setColorMode(mode, type, name, range);
515    } while (doAll && ++itr != _cutplanes.end());
516
517    _needsRedraw = true;
518}
519
520/**
521 * \brief Set the color mode for the specified DataSet
522 */
523void Renderer::setCutplaneColorMode(const DataSetId& id,
524                                    Cutplane::ColorMode mode,
525                                    const char *name, double range[2])
526{
527    CutplaneHashmap::iterator itr;
528
529    bool doAll = false;
530
531    if (id.compare("all") == 0) {
532        itr = _cutplanes.begin();
533        doAll = true;
534    } else {
535        itr = _cutplanes.find(id);
536    }
537    if (itr == _cutplanes.end()) {
538        ERROR("Cutplane not found: %s", id.c_str());
539        return;
540    }
541
542    do {
543        itr->second->setColorMode(mode, name, range);
544    } while (doAll && ++itr != _cutplanes.end());
545
546    _needsRedraw = true;
547}
548
549/**
550 * \brief Create a new Glyphs and associate it with the named DataSet
551 */
552bool Renderer::addGlyphs(const DataSetId& id, Glyphs::GlyphShape shape)
553{
554    DataSetHashmap::iterator itr;
555
556    bool doAll = false;
557
558    if (id.compare("all") == 0) {
559        itr = _dataSets.begin();
560    } else {
561        itr = _dataSets.find(id);
562    }
563    if (itr == _dataSets.end()) {
564        ERROR("Unknown dataset %s", id.c_str());
565        return false;
566    }
567
568    do {
569        DataSet *ds = itr->second;
570        const DataSetId& dsID = ds->getName();
571
572        if (getGraphicsObject<Glyphs>(dsID)) {
573            WARN("Replacing existing Glyphs %s", dsID.c_str());
574            deleteGraphicsObject<Glyphs>(dsID);
575        }
576
577        Glyphs *glyphs = new Glyphs(shape);
578
579        glyphs->setDataSet(ds, this);
580
581        if (glyphs->getProp() == NULL) {
582            delete glyphs;
583            return false;
584        } else {
585            _renderer->AddViewProp(glyphs->getProp());
586        }
587
588        _glyphs[dsID] = glyphs;
589    } while (doAll && ++itr != _dataSets.end());
590
591    initCamera();
592
593    _needsRedraw = true;
594    return true;
595}
596
597/**
598 * \brief Set the color mode for the specified DataSet
599 */
600void Renderer::setGlyphsColorMode(const DataSetId& id,
601                                  Glyphs::ColorMode mode,
602                                  const char *name, double range[2])
603{
604    GlyphsHashmap::iterator itr;
605
606    bool doAll = false;
607
608    if (id.compare("all") == 0) {
609        itr = _glyphs.begin();
610        doAll = true;
611    } else {
612        itr = _glyphs.find(id);
613    }
614    if (itr == _glyphs.end()) {
615        ERROR("Glyphs not found: %s", id.c_str());
616        return;
617    }
618
619    do {
620#ifdef HAVE_GLYPH3D_MAPPER
621        itr->second->setColorMode(mode, name, range);
622#else
623        if (name != NULL && strlen(name) > 0) {
624            WARN("Glyphs color mode doesn't support named fields for VTK < 5.8.0");
625        }
626        itr->second->setColorMode(mode);
627#endif
628    } while (doAll && ++itr != _glyphs.end());
629
630    _needsRedraw = true;
631}
632
633/**
634 * \brief Controls the array used to scale glyphs for the given DataSet
635 */
636void Renderer::setGlyphsScalingMode(const DataSetId& id,
637                                    Glyphs::ScalingMode mode,
638                                    const char *name, double range[2])
639{
640    GlyphsHashmap::iterator itr;
641
642    bool doAll = false;
643
644    if (id.compare("all") == 0) {
645        itr = _glyphs.begin();
646        doAll = true;
647    } else {
648        itr = _glyphs.find(id);
649    }
650    if (itr == _glyphs.end()) {
651        ERROR("Glyphs not found: %s", id.c_str());
652        return;
653    }
654
655    do {
656#ifdef HAVE_GLYPH3D_MAPPER
657        itr->second->setScalingMode(mode, name, range);
658#else
659        if (name != NULL && strlen(name) > 0) {
660            WARN("Glyphs scaling mode doesn't support named fields for VTK < 5.8.0");
661        }
662        itr->second->setScalingMode(mode);
663#endif
664    } while (doAll && ++itr != _glyphs.end());
665
666    _renderer->ResetCameraClippingRange();
667    _needsRedraw = true;
668}
669
670/**
671 * \brief Controls if field data range is normalized to [0,1] before
672 * applying scale factor for the given DataSet
673 */
674void Renderer::setGlyphsNormalizeScale(const DataSetId& id, bool normalize)
675{
676    GlyphsHashmap::iterator itr;
677
678    bool doAll = false;
679
680    if (id.compare("all") == 0) {
681        itr = _glyphs.begin();
682        doAll = true;
683    } else {
684        itr = _glyphs.find(id);
685    }
686    if (itr == _glyphs.end()) {
687        ERROR("Glyphs not found: %s", id.c_str());
688        return;
689    }
690
691    do {
692        itr->second->setNormalizeScale(normalize);
693    } while (doAll && ++itr != _glyphs.end());
694
695    _renderer->ResetCameraClippingRange();
696    _needsRedraw = true;
697}
698
699/**
700 * \brief Set the shape of Glyphs for the given DataSet
701 */
702void Renderer::setGlyphsShape(const DataSetId& id, Glyphs::GlyphShape shape)
703{
704    GlyphsHashmap::iterator itr;
705
706    bool doAll = false;
707
708    if (id.compare("all") == 0) {
709        itr = _glyphs.begin();
710        doAll = true;
711    } else {
712        itr = _glyphs.find(id);
713    }
714    if (itr == _glyphs.end()) {
715        ERROR("Glyphs not found: %s", id.c_str());
716        return;
717    }
718
719    do {
720        itr->second->setGlyphShape(shape);
721    } while (doAll && ++itr != _glyphs.end());
722
723    _renderer->ResetCameraClippingRange();
724    _needsRedraw = true;
725}
726
727/**
728 * \brief Set the glyph scaling factor for the given DataSet
729 */
730void Renderer::setGlyphsScaleFactor(const DataSetId& id, double scale)
731{
732    GlyphsHashmap::iterator itr;
733
734    bool doAll = false;
735
736    if (id.compare("all") == 0) {
737        itr = _glyphs.begin();
738        doAll = true;
739    } else {
740        itr = _glyphs.find(id);
741    }
742    if (itr == _glyphs.end()) {
743        ERROR("Glyphs not found: %s", id.c_str());
744        return;
745    }
746
747    do {
748        itr->second->setScaleFactor(scale);
749    } while (doAll && ++itr != _glyphs.end());
750
751    initCamera();
752    _needsRedraw = true;
753}
754
755/**
756 * \brief Create a new HeightMap and associate it with the named DataSet
757 */
758bool Renderer::addHeightMap(const DataSetId& id, int numContours, double heightScale)
759{
760    DataSetHashmap::iterator itr;
761
762    bool doAll = false;
763
764    if (id.compare("all") == 0) {
765        itr = _dataSets.begin();
766    } else {
767        itr = _dataSets.find(id);
768    }
769    if (itr == _dataSets.end()) {
770        ERROR("Unknown dataset %s", id.c_str());
771        return false;
772    }
773
774    do {
775        DataSet *ds = itr->second;
776        const DataSetId& dsID = ds->getName();
777
778        if (getGraphicsObject<HeightMap>(dsID)) {
779            WARN("Replacing existing HeightMap %s", dsID.c_str());
780            deleteGraphicsObject<HeightMap>(dsID);
781        }
782
783        HeightMap *hmap = new HeightMap(numContours, heightScale);
784
785        hmap->setDataSet(ds, this);
786
787        if (hmap->getProp() == NULL) {
788            delete hmap;
789            return false;
790        } else {
791            _renderer->AddViewProp(hmap->getProp());
792        }
793
794        _heightMaps[dsID] = hmap;
795    } while (doAll && ++itr != _dataSets.end());
796
797    initCamera();
798
799    _needsRedraw = true;
800    return true;
801}
802
803/**
804 * \brief Create a new HeightMap and associate it with the named DataSet
805 */
806bool Renderer::addHeightMap(const DataSetId& id, const std::vector<double>& contours, double heightScale)
807{
808    DataSetHashmap::iterator itr;
809
810    bool doAll = false;
811
812    if (id.compare("all") == 0) {
813        itr = _dataSets.begin();
814    } else {
815        itr = _dataSets.find(id);
816    }
817    if (itr == _dataSets.end()) {
818        ERROR("Unknown dataset %s", id.c_str());
819        return false;
820    }
821
822    do {
823        DataSet *ds = itr->second;
824        const DataSetId& dsID = ds->getName();
825
826        if (getGraphicsObject<HeightMap>(dsID)) {
827            WARN("Replacing existing HeightMap %s", dsID.c_str());
828            deleteGraphicsObject<HeightMap>(dsID);
829        }
830
831        HeightMap *hmap = new HeightMap(contours, heightScale);
832
833        hmap->setDataSet(ds, this);
834
835        if (hmap->getProp() == NULL) {
836            delete hmap;
837            return false;
838        } else {
839            _renderer->AddViewProp(hmap->getProp());
840        }
841
842        _heightMaps[dsID] = hmap;
843    } while (doAll && ++itr != _dataSets.end());
844
845    initCamera();
846
847    _needsRedraw = true;
848    return true;
849}
850
851/**
852 * \brief Set amount to scale scalar values when creating elevations
853 * in the height map
854 */
855void Renderer::setHeightMapHeightScale(const DataSetId& id, double scale)
856{
857    HeightMapHashmap::iterator itr;
858
859    bool doAll = false;
860
861    if (id.compare("all") == 0) {
862        itr = _heightMaps.begin();
863        doAll = true;
864    } else {
865        itr = _heightMaps.find(id);
866    }
867
868    if (itr == _heightMaps.end()) {
869        ERROR("HeightMap not found: %s", id.c_str());
870        return;
871    }
872
873    do {
874        itr->second->setHeightScale(scale);
875     } while (doAll && ++itr != _heightMaps.end());
876
877    initCamera();
878    _needsRedraw = true;
879}
880
881/**
882 * \brief Set the number of equally spaced contour isolines for the given DataSet
883 */
884void Renderer::setHeightMapNumContours(const DataSetId& id, int numContours)
885{
886    HeightMapHashmap::iterator itr;
887
888    bool doAll = false;
889
890    if (id.compare("all") == 0) {
891        itr = _heightMaps.begin();
892        doAll = true;
893    } else {
894        itr = _heightMaps.find(id);
895    }
896    if (itr == _heightMaps.end()) {
897        ERROR("HeightMap not found: %s", id.c_str());
898        return;
899    }
900
901    do {
902        itr->second->setNumContours(numContours);
903    } while (doAll && ++itr != _heightMaps.end());
904
905    _needsRedraw = true;
906}
907
908/**
909 * \brief Set a list of height map contour isovalues for the given DataSet
910 */
911void Renderer::setHeightMapContourList(const DataSetId& id, const std::vector<double>& contours)
912{
913    HeightMapHashmap::iterator itr;
914
915    bool doAll = false;
916
917    if (id.compare("all") == 0) {
918        itr = _heightMaps.begin();
919        doAll = true;
920    } else {
921        itr = _heightMaps.find(id);
922    }
923    if (itr == _heightMaps.end()) {
924        ERROR("HeightMap not found: %s", id.c_str());
925        return;
926    }
927
928    do {
929        itr->second->setContourList(contours);
930    } while (doAll && ++itr != _heightMaps.end());
931
932     _needsRedraw = true;
933}
934
935/**
936 * \brief Turn on/off rendering height map contour lines for the given DataSet
937 */
938void Renderer::setHeightMapContourLineVisibility(const DataSetId& id, bool state)
939{
940    HeightMapHashmap::iterator itr;
941
942    bool doAll = false;
943
944    if (id.compare("all") == 0) {
945        itr = _heightMaps.begin();
946        doAll = true;
947    } else {
948        itr = _heightMaps.find(id);
949    }
950    if (itr == _heightMaps.end()) {
951        ERROR("HeightMap not found: %s", id.c_str());
952        return;
953    }
954
955    do {
956        itr->second->setContourLineVisibility(state);
957    } while (doAll && ++itr != _heightMaps.end());
958
959    _needsRedraw = true;
960}
961
962/**
963 * \brief Turn on/off rendering height map colormap surface for the given DataSet
964 */
965void Renderer::setHeightMapContourSurfaceVisibility(const DataSetId& id, bool state)
966{
967    HeightMapHashmap::iterator itr;
968
969    bool doAll = false;
970
971    if (id.compare("all") == 0) {
972        itr = _heightMaps.begin();
973        doAll = true;
974    } else {
975        itr = _heightMaps.find(id);
976    }
977    if (itr == _heightMaps.end()) {
978        ERROR("HeightMap not found: %s", id.c_str());
979        return;
980    }
981
982    do {
983        itr->second->setContourSurfaceVisibility(state);
984    } while (doAll && ++itr != _heightMaps.end());
985
986    _needsRedraw = true;
987}
988
989/**
990 * \brief Set the RGB height map isoline color for the specified DataSet
991 */
992void Renderer::setHeightMapContourEdgeColor(const DataSetId& id, float color[3])
993{
994    HeightMapHashmap::iterator itr;
995
996    bool doAll = false;
997
998    if (id.compare("all") == 0) {
999        itr = _heightMaps.begin();
1000        doAll = true;
1001    } else {
1002        itr = _heightMaps.find(id);
1003    }
1004    if (itr == _heightMaps.end()) {
1005        ERROR("HeightMap not found: %s", id.c_str());
1006        return;
1007    }
1008
1009    do {
1010        itr->second->setContourEdgeColor(color);
1011    } while (doAll && ++itr != _heightMaps.end());
1012
1013    _needsRedraw = true;
1014}
1015
1016/**
1017 * \brief Set the height map isoline width for the specified DataSet (may be a no-op)
1018 *
1019 * If the OpenGL implementation/hardware does not support wide lines,
1020 * this function may not have an effect.
1021 */
1022void Renderer::setHeightMapContourEdgeWidth(const DataSetId& id, float edgeWidth)
1023{
1024    HeightMapHashmap::iterator itr;
1025
1026    bool doAll = false;
1027
1028    if (id.compare("all") == 0) {
1029        itr = _heightMaps.begin();
1030        doAll = true;
1031    } else {
1032        itr = _heightMaps.find(id);
1033    }
1034    if (itr == _heightMaps.end()) {
1035        ERROR("HeightMap not found: %s", id.c_str());
1036        return;
1037    }
1038
1039    do {
1040        itr->second->setContourEdgeWidth(edgeWidth);
1041    } while (doAll && ++itr != _heightMaps.end());
1042
1043    _needsRedraw = true;
1044}
1045
1046/**
1047 * \brief Set radius standard for scaling atoms
1048 */
1049void Renderer::setMoleculeAtomScaling(const DataSetId& id, Molecule::AtomScaling scaling)
1050{
1051    MoleculeHashmap::iterator itr;
1052
1053    bool doAll = false;
1054
1055    if (id.compare("all") == 0) {
1056        itr = _molecules.begin();
1057        doAll = true;
1058    } else {
1059        itr = _molecules.find(id);
1060    }
1061    if (itr == _molecules.end()) {
1062        ERROR("Molecule not found: %s", id.c_str());
1063        return;
1064    }
1065
1066    do {
1067        itr->second->setAtomScaling(scaling);
1068    } while (doAll && ++itr != _molecules.end());
1069
1070    _needsRedraw = true;
1071}
1072
1073/**
1074 * \brief Turn on/off rendering of the Molecule atoms for the given DataSet
1075 */
1076void Renderer::setMoleculeAtomVisibility(const DataSetId& id, bool state)
1077{
1078    MoleculeHashmap::iterator itr;
1079
1080    bool doAll = false;
1081
1082    if (id.compare("all") == 0) {
1083        itr = _molecules.begin();
1084        doAll = true;
1085    } else {
1086        itr = _molecules.find(id);
1087    }
1088    if (itr == _molecules.end()) {
1089        ERROR("Molecule not found: %s", id.c_str());
1090        return;
1091    }
1092
1093    do {
1094        itr->second->setAtomVisibility(state);
1095    } while (doAll && ++itr != _molecules.end());
1096
1097    _needsRedraw = true;
1098}
1099
1100/**
1101 * \brief Turn on/off rendering of the Molecule bonds for the given DataSet
1102 */
1103void Renderer::setMoleculeBondVisibility(const DataSetId& id, bool state)
1104{
1105    MoleculeHashmap::iterator itr;
1106
1107    bool doAll = false;
1108
1109    if (id.compare("all") == 0) {
1110        itr = _molecules.begin();
1111        doAll = true;
1112    } else {
1113        itr = _molecules.find(id);
1114    }
1115    if (itr == _molecules.end()) {
1116        ERROR("Molecule not found: %s", id.c_str());
1117        return;
1118    }
1119
1120    do {
1121        itr->second->setBondVisibility(state);
1122    } while (doAll && ++itr != _molecules.end());
1123
1124    _needsRedraw = true;
1125}
1126
1127/**
1128 * \brief Set the color mode for the specified DataSet
1129 */
1130void Renderer::setPseudoColorColorMode(const DataSetId& id,
1131                                       PseudoColor::ColorMode mode,
1132                                       DataSet::DataAttributeType type,
1133                                       const char *name, double range[2])
1134{
1135    PseudoColorHashmap::iterator itr;
1136
1137    bool doAll = false;
1138
1139    if (id.compare("all") == 0) {
1140        itr = _pseudoColors.begin();
1141        doAll = true;
1142    } else {
1143        itr = _pseudoColors.find(id);
1144    }
1145    if (itr == _pseudoColors.end()) {
1146        ERROR("PseudoColor not found: %s", id.c_str());
1147        return;
1148    }
1149
1150    do {
1151        itr->second->setColorMode(mode, type, name, range);
1152    } while (doAll && ++itr != _pseudoColors.end());
1153
1154    _needsRedraw = true;
1155}
1156
1157/**
1158 * \brief Set the color mode for the specified DataSet
1159 */
1160void Renderer::setPseudoColorColorMode(const DataSetId& id,
1161                                       PseudoColor::ColorMode mode,
1162                                       const char *name, double range[2])
1163{
1164    PseudoColorHashmap::iterator itr;
1165
1166    bool doAll = false;
1167
1168    if (id.compare("all") == 0) {
1169        itr = _pseudoColors.begin();
1170        doAll = true;
1171    } else {
1172        itr = _pseudoColors.find(id);
1173    }
1174    if (itr == _pseudoColors.end()) {
1175        ERROR("PseudoColor not found: %s", id.c_str());
1176        return;
1177    }
1178
1179    do {
1180        itr->second->setColorMode(mode, name, range);
1181    } while (doAll && ++itr != _pseudoColors.end());
1182
1183    _needsRedraw = true;
1184}
1185
1186/**
1187 * \brief Set the streamlines seed to points of the streamlines DataSet
1188 */
1189void Renderer::setStreamlinesNumberOfSeedPoints(const DataSetId& id, int numPoints)
1190{
1191    StreamlinesHashmap::iterator itr;
1192
1193    bool doAll = false;
1194
1195    if (id.compare("all") == 0) {
1196        itr = _streamlines.begin();
1197        doAll = true;
1198    } else {
1199        itr = _streamlines.find(id);
1200    }
1201    if (itr == _streamlines.end()) {
1202        ERROR("Streamlines not found: %s", id.c_str());
1203        return;
1204    }
1205
1206    do {
1207        itr->second->setNumberOfSeedPoints(numPoints);
1208    } while (doAll && ++itr != _streamlines.end());
1209
1210    _needsRedraw = true;
1211}
1212
1213/**
1214 * \brief Set the streamlines seed to points of the streamlines DataSet
1215 */
1216void Renderer::setStreamlinesSeedToMeshPoints(const DataSetId& id)
1217{
1218    StreamlinesHashmap::iterator itr;
1219
1220    bool doAll = false;
1221
1222    if (id.compare("all") == 0) {
1223        itr = _streamlines.begin();
1224        doAll = true;
1225    } else {
1226        itr = _streamlines.find(id);
1227    }
1228    if (itr == _streamlines.end()) {
1229        ERROR("Streamlines not found: %s", id.c_str());
1230        return;
1231    }
1232
1233    do {
1234        itr->second->setSeedToMeshPoints();
1235    } while (doAll && ++itr != _streamlines.end());
1236
1237    _needsRedraw = true;
1238}
1239
1240/**
1241 * \brief Set the streamlines seed to points distributed randomly inside
1242 * cells of the streamlines DataSet
1243 */
1244void Renderer::setStreamlinesSeedToFilledMesh(const DataSetId& id, int numPoints)
1245{
1246    StreamlinesHashmap::iterator itr;
1247
1248    bool doAll = false;
1249
1250    if (id.compare("all") == 0) {
1251        itr = _streamlines.begin();
1252        doAll = true;
1253    } else {
1254        itr = _streamlines.find(id);
1255    }
1256    if (itr == _streamlines.end()) {
1257        ERROR("Streamlines not found: %s", id.c_str());
1258        return;
1259    }
1260
1261    do {
1262        itr->second->setSeedToFilledMesh(numPoints);
1263    } while (doAll && ++itr != _streamlines.end());
1264
1265    _needsRedraw = true;
1266}
1267
1268/**
1269 * \brief Set the streamlines seed to points of a DataSet
1270 *
1271 * \param[in] id DataSet identifier
1272 * \param[in] data Bytes of VTK DataSet file
1273 * \param[in] nbytes Length of data array
1274 *
1275 * \return boolean indicating success or failure
1276 */
1277bool Renderer::setStreamlinesSeedToMeshPoints(const DataSetId& id,
1278                                              char *data, size_t nbytes)
1279{
1280    vtkSmartPointer<vtkDataSetReader> reader = vtkSmartPointer<vtkDataSetReader>::New();
1281    vtkSmartPointer<vtkCharArray> dataSetString = vtkSmartPointer<vtkCharArray>::New();
1282
1283    dataSetString->SetArray(data, nbytes, 1);
1284    reader->SetInputArray(dataSetString);
1285    reader->ReadFromInputStringOn();
1286    reader->Update();
1287
1288    vtkSmartPointer<vtkDataSet> dataSet = reader->GetOutput();
1289    if (dataSet == NULL) {
1290        return false;
1291    }
1292    dataSet->SetPipelineInformation(NULL);
1293
1294    StreamlinesHashmap::iterator itr;
1295
1296    bool doAll = false;
1297
1298    if (id.compare("all") == 0) {
1299        itr = _streamlines.begin();
1300        doAll = true;
1301    } else {
1302        itr = _streamlines.find(id);
1303    }
1304    if (itr == _streamlines.end()) {
1305        ERROR("Streamlines not found: %s", id.c_str());
1306        return false;
1307    }
1308
1309    do {
1310        itr->second->setSeedToMeshPoints(dataSet);
1311    } while (doAll && ++itr != _streamlines.end());
1312
1313    _needsRedraw = true;
1314    return true;
1315}
1316
1317/**
1318 * \brief Set the streamlines seed to points distributed randomly inside
1319 * cells of DataSet
1320 *
1321 * \param[in] id DataSet identifier
1322 * \param[in] data Bytes of VTK DataSet file
1323 * \param[in] nbytes Length of data array
1324 * \param[in] numPoints Number of random seed points to generate
1325 *
1326 * \return boolean indicating success or failure
1327 */
1328bool Renderer::setStreamlinesSeedToFilledMesh(const DataSetId& id,
1329                                              char *data, size_t nbytes,
1330                                              int numPoints)
1331{
1332    vtkSmartPointer<vtkDataSetReader> reader = vtkSmartPointer<vtkDataSetReader>::New();
1333    vtkSmartPointer<vtkCharArray> dataSetString = vtkSmartPointer<vtkCharArray>::New();
1334
1335    dataSetString->SetArray(data, nbytes, 1);
1336    reader->SetInputArray(dataSetString);
1337    reader->ReadFromInputStringOn();
1338    reader->Update();
1339
1340    vtkSmartPointer<vtkDataSet> dataSet = reader->GetOutput();
1341    if (dataSet == NULL) {
1342        return false;
1343    }
1344    dataSet->SetPipelineInformation(NULL);
1345
1346    StreamlinesHashmap::iterator itr;
1347
1348    bool doAll = false;
1349
1350    if (id.compare("all") == 0) {
1351        itr = _streamlines.begin();
1352        doAll = true;
1353    } else {
1354        itr = _streamlines.find(id);
1355    }
1356    if (itr == _streamlines.end()) {
1357        ERROR("Streamlines not found: %s", id.c_str());
1358        return false;
1359    }
1360
1361    do {
1362        itr->second->setSeedToFilledMesh(dataSet, numPoints);
1363    } while (doAll && ++itr != _streamlines.end());
1364
1365    _needsRedraw = true;
1366    return true;
1367}
1368
1369/**
1370 * \brief Set the streamlines seed to points along a line
1371 */
1372void Renderer::setStreamlinesSeedToRake(const DataSetId& id,
1373                                        double start[3], double end[3],
1374                                        int numPoints)
1375{
1376    StreamlinesHashmap::iterator itr;
1377
1378    bool doAll = false;
1379
1380    if (id.compare("all") == 0) {
1381        itr = _streamlines.begin();
1382        doAll = true;
1383    } else {
1384        itr = _streamlines.find(id);
1385    }
1386    if (itr == _streamlines.end()) {
1387        ERROR("Streamlines not found: %s", id.c_str());
1388        return;
1389    }
1390
1391    do {
1392        itr->second->setSeedToRake(start, end, numPoints);
1393    } while (doAll && ++itr != _streamlines.end());
1394
1395    _needsRedraw = true;
1396}
1397
1398/**
1399 * \brief Set the streamlines seed to points inside a disk, with optional
1400 * hole
1401 */
1402void Renderer::setStreamlinesSeedToDisk(const DataSetId& id,
1403                                        double center[3], double normal[3],
1404                                        double radius, double innerRadius,
1405                                        int numPoints)
1406{
1407    StreamlinesHashmap::iterator itr;
1408
1409    bool doAll = false;
1410
1411    if (id.compare("all") == 0) {
1412        itr = _streamlines.begin();
1413        doAll = true;
1414    } else {
1415        itr = _streamlines.find(id);
1416    }
1417    if (itr == _streamlines.end()) {
1418        ERROR("Streamlines not found: %s", id.c_str());
1419        return;
1420    }
1421
1422    do {
1423        itr->second->setSeedToDisk(center, normal, radius, innerRadius, numPoints);
1424    } while (doAll && ++itr != _streamlines.end());
1425
1426    _needsRedraw = true;
1427}
1428
1429/**
1430 * \brief Set the streamlines seed to vertices of an n-sided polygon
1431 */
1432void Renderer::setStreamlinesSeedToPolygon(const DataSetId& id,
1433                                           double center[3], double normal[3],
1434                                           double angle, double radius,
1435                                           int numSides)
1436{
1437    StreamlinesHashmap::iterator itr;
1438
1439    bool doAll = false;
1440
1441    if (id.compare("all") == 0) {
1442        itr = _streamlines.begin();
1443        doAll = true;
1444    } else {
1445        itr = _streamlines.find(id);
1446    }
1447    if (itr == _streamlines.end()) {
1448        ERROR("Streamlines not found: %s", id.c_str());
1449        return;
1450    }
1451
1452    do {
1453        itr->second->setSeedToPolygon(center, normal, angle, radius, numSides);
1454    } while (doAll && ++itr != _streamlines.end());
1455
1456    _needsRedraw = true;
1457}
1458
1459/**
1460 * \brief Set the streamlines seed to vertices of an n-sided polygon
1461 */
1462void Renderer::setStreamlinesSeedToFilledPolygon(const DataSetId& id,
1463                                                 double center[3],
1464                                                 double normal[3],
1465                                                 double angle, double radius,
1466                                                 int numSides, int numPoints)
1467{
1468    StreamlinesHashmap::iterator itr;
1469
1470    bool doAll = false;
1471
1472    if (id.compare("all") == 0) {
1473        itr = _streamlines.begin();
1474        doAll = true;
1475    } else {
1476        itr = _streamlines.find(id);
1477    }
1478    if (itr == _streamlines.end()) {
1479        ERROR("Streamlines not found: %s", id.c_str());
1480        return;
1481    }
1482
1483    do {
1484        itr->second->setSeedToFilledPolygon(center, normal, angle,
1485                                            radius, numSides, numPoints);
1486    } while (doAll && ++itr != _streamlines.end());
1487
1488    _needsRedraw = true;
1489}
1490
1491/**
1492 * \brief Set Streamlines rendering to polylines for the specified DataSet
1493 */
1494void Renderer::setStreamlinesTypeToLines(const DataSetId& id)
1495{
1496    StreamlinesHashmap::iterator itr;
1497
1498    bool doAll = false;
1499
1500    if (id.compare("all") == 0) {
1501        itr = _streamlines.begin();
1502        doAll = true;
1503    } else {
1504        itr = _streamlines.find(id);
1505    }
1506    if (itr == _streamlines.end()) {
1507        ERROR("Streamlines not found: %s", id.c_str());
1508        return;
1509    }
1510
1511    do {
1512        itr->second->setLineTypeToLines();
1513    } while (doAll && ++itr != _streamlines.end());
1514
1515    _needsRedraw = true;
1516}
1517
1518/**
1519 * \brief Set Streamlines rendering to tubes for the specified DataSet
1520 */
1521void Renderer::setStreamlinesTypeToTubes(const DataSetId& id, int numSides, double radius)
1522{
1523    StreamlinesHashmap::iterator itr;
1524
1525    bool doAll = false;
1526
1527    if (id.compare("all") == 0) {
1528        itr = _streamlines.begin();
1529        doAll = true;
1530    } else {
1531        itr = _streamlines.find(id);
1532    }
1533    if (itr == _streamlines.end()) {
1534        ERROR("Streamlines not found: %s", id.c_str());
1535        return;
1536    }
1537
1538    do {
1539        itr->second->setLineTypeToTubes(numSides, radius);
1540    } while (doAll && ++itr != _streamlines.end());
1541
1542    _needsRedraw = true;
1543}
1544
1545/**
1546 * \brief Set Streamlines rendering to ribbons for the specified DataSet
1547 */
1548void Renderer::setStreamlinesTypeToRibbons(const DataSetId& id, double width, double angle)
1549{
1550    StreamlinesHashmap::iterator itr;
1551
1552    bool doAll = false;
1553
1554    if (id.compare("all") == 0) {
1555        itr = _streamlines.begin();
1556        doAll = true;
1557    } else {
1558        itr = _streamlines.find(id);
1559    }
1560    if (itr == _streamlines.end()) {
1561        ERROR("Streamlines not found: %s", id.c_str());
1562        return;
1563    }
1564
1565    do {
1566        itr->second->setLineTypeToRibbons(width, angle);
1567    } while (doAll && ++itr != _streamlines.end());
1568
1569    _needsRedraw = true;
1570}
1571
1572/**
1573 * \brief Set Streamlines maximum length for the specified DataSet
1574 */
1575void Renderer::setStreamlinesLength(const DataSetId& id, double length)
1576{
1577    StreamlinesHashmap::iterator itr;
1578
1579    bool doAll = false;
1580
1581    if (id.compare("all") == 0) {
1582        itr = _streamlines.begin();
1583        doAll = true;
1584    } else {
1585        itr = _streamlines.find(id);
1586    }
1587    if (itr == _streamlines.end()) {
1588        ERROR("Streamlines not found: %s", id.c_str());
1589        return;
1590    }
1591
1592    do {
1593        itr->second->setMaxPropagation(length);
1594    } while (doAll && ++itr != _streamlines.end());
1595
1596    _needsRedraw = true;
1597}
1598
1599/**
1600 * \brief Turn on/off rendering of the Streamlines seed geometry for the given DataSet
1601 */
1602void Renderer::setStreamlinesSeedVisibility(const DataSetId& id, bool state)
1603{
1604    StreamlinesHashmap::iterator itr;
1605
1606    bool doAll = false;
1607
1608    if (id.compare("all") == 0) {
1609        itr = _streamlines.begin();
1610        doAll = true;
1611    } else {
1612        itr = _streamlines.find(id);
1613    }
1614    if (itr == _streamlines.end()) {
1615        ERROR("Streamlines not found: %s", id.c_str());
1616        return;
1617    }
1618
1619    do {
1620        itr->second->setSeedVisibility(state);
1621    } while (doAll && ++itr != _streamlines.end());
1622
1623    _needsRedraw = true;
1624}
1625
1626/**
1627 * \brief Set the color mode for the specified DataSet
1628 */
1629void Renderer::setStreamlinesColorMode(const DataSetId& id,
1630                                       Streamlines::ColorMode mode,
1631                                       DataSet::DataAttributeType type,
1632                                       const char *name, double range[2])
1633{
1634    StreamlinesHashmap::iterator itr;
1635
1636    bool doAll = false;
1637
1638    if (id.compare("all") == 0) {
1639        itr = _streamlines.begin();
1640        doAll = true;
1641    } else {
1642        itr = _streamlines.find(id);
1643    }
1644    if (itr == _streamlines.end()) {
1645        ERROR("Streamlines not found: %s", id.c_str());
1646        return;
1647    }
1648
1649    do {
1650        itr->second->setColorMode(mode, type, name, range);
1651    } while (doAll && ++itr != _streamlines.end());
1652
1653    _needsRedraw = true;
1654}
1655
1656/**
1657 * \brief Set the color mode for the specified DataSet
1658 */
1659void Renderer::setStreamlinesColorMode(const DataSetId& id,
1660                                       Streamlines::ColorMode mode,
1661                                       const char *name, double range[2])
1662{
1663    StreamlinesHashmap::iterator itr;
1664
1665    bool doAll = false;
1666
1667    if (id.compare("all") == 0) {
1668        itr = _streamlines.begin();
1669        doAll = true;
1670    } else {
1671        itr = _streamlines.find(id);
1672    }
1673    if (itr == _streamlines.end()) {
1674        ERROR("Streamlines not found: %s", id.c_str());
1675        return;
1676    }
1677
1678    do {
1679        itr->second->setColorMode(mode, name, range);
1680    } while (doAll && ++itr != _streamlines.end());
1681
1682    _needsRedraw = true;
1683}
1684
1685/**
1686 * \brief Set the RGB line/edge color for the specified DataSet
1687 */
1688void Renderer::setStreamlinesSeedColor(const DataSetId& id, float color[3])
1689{
1690    StreamlinesHashmap::iterator itr;
1691
1692    bool doAll = false;
1693
1694    if (id.compare("all") == 0) {
1695        itr = _streamlines.begin();
1696        doAll = true;
1697    } else {
1698        itr = _streamlines.find(id);
1699    }
1700    if (itr == _streamlines.end()) {
1701        ERROR("Streamlines not found: %s", id.c_str());
1702        return;
1703    }
1704
1705    do {
1706        itr->second->setSeedColor(color);
1707    } while (doAll && ++itr != _streamlines.end());
1708
1709    _needsRedraw = true;
1710}
1711
1712/**
1713 * \brief Set the sample rate for the volume shader
1714 *
1715 * Smaller values will give better rendering at the cost
1716 * of slower rendering
1717 */
1718void Renderer::setVolumeSampleDistance(const DataSetId& id, double distance)
1719{
1720    VolumeHashmap::iterator itr;
1721
1722    bool doAll = false;
1723
1724    if (id.compare("all") == 0) {
1725        itr = _volumes.begin();
1726        doAll = true;
1727    } else {
1728        itr = _volumes.find(id);
1729    }
1730    if (itr == _volumes.end()) {
1731        ERROR("Volume not found: %s", id.c_str());
1732        return;
1733    }
1734
1735    do {
1736        distance *= itr->second->getAverageSpacing();
1737        itr->second->setSampleDistance((float)distance);
1738    } while (doAll && ++itr != _volumes.end());
1739
1740    _needsRedraw = true;
1741}
Note: See TracBrowser for help on using the repository browser.