Index: /trunk/packages/vizservers/vtkvis/Arc.cpp
===================================================================
--- /trunk/packages/vizservers/vtkvis/Arc.cpp	(revision 3616)
+++ /trunk/packages/vizservers/vtkvis/Arc.cpp	(revision 3616)
@@ -0,0 +1,45 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (C) 2004-2012  HUBzero Foundation, LLC
+ *
+ * Author: Leif Delgass <ldelgass@purdue.edu>
+ */
+
+#include <vtkPolyDataMapper.h>
+#include <vtkActor.h>
+#include <vtkArcSource.h>
+
+#include "Arc.h"
+#include "Trace.h"
+
+using namespace VtkVis;
+
+Arc::Arc() :
+    Shape()
+{
+}
+
+Arc::~Arc()
+{
+    TRACE("Deleting Arc");
+}
+
+void Arc::update()
+{
+    if (_arc == NULL) {
+	_arc = vtkSmartPointer<vtkArcSource>::New();
+    }
+
+    if (_pdMapper == NULL) {
+        _pdMapper = vtkSmartPointer<vtkPolyDataMapper>::New();
+        _pdMapper->SetResolveCoincidentTopologyToPolygonOffset();
+        _pdMapper->ScalarVisibilityOff();
+    }
+
+    _pdMapper->SetInputConnection(_arc->GetOutputPort());
+
+    initProp();
+
+    getActor()->SetMapper(_pdMapper);
+    _pdMapper->Update();
+}
Index: /trunk/packages/vizservers/vtkvis/Arc.h
===================================================================
--- /trunk/packages/vizservers/vtkvis/Arc.h	(revision 3616)
+++ /trunk/packages/vizservers/vtkvis/Arc.h	(revision 3616)
@@ -0,0 +1,67 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (C) 2004-2012  HUBzero Foundation, LLC
+ *
+ * Author: Leif Delgass <ldelgass@purdue.edu>
+ */
+
+#ifndef VTKVIS_ARC_H
+#define VTKVIS_ARC_H
+
+#include <vtkSmartPointer.h>
+#include <vtkPolyDataMapper.h>
+#include <vtkActor.h>
+#include <vtkArcSource.h>
+
+#include "Shape.h"
+#include "VtkDataSet.h"
+
+namespace VtkVis {
+
+/**
+ * \brief VTK PolyData Arc
+ *
+ * This class creates a arc
+ */
+class Arc : public Shape
+{
+public:
+    Arc();
+    virtual ~Arc();
+
+    virtual const char *getClassName() const
+    {
+        return "Arc";
+    }
+
+    void setCenter(double center[3])
+    {
+        if (_arc != NULL) {
+            _arc->SetCenter(center);
+	}
+    }
+
+    void setEndPoints(double pt1[3], double pt2[3])
+    {
+        if (_arc != NULL) {
+            _arc->SetPoint1(pt1);
+            _arc->SetPoint2(pt2);
+	}
+    }
+
+    void setResolution(int res)
+    {
+        if (_arc != NULL) {
+            _arc->SetResolution(res);
+	}
+    }
+
+private:
+    virtual void update();
+
+    vtkSmartPointer<vtkArcSource> _arc;
+};
+
+}
+
+#endif
Index: /trunk/packages/vizservers/vtkvis/Arrow.cpp
===================================================================
--- /trunk/packages/vizservers/vtkvis/Arrow.cpp	(revision 3616)
+++ /trunk/packages/vizservers/vtkvis/Arrow.cpp	(revision 3616)
@@ -0,0 +1,45 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (C) 2004-2012  HUBzero Foundation, LLC
+ *
+ * Author: Leif Delgass <ldelgass@purdue.edu>
+ */
+
+#include <vtkPolyDataMapper.h>
+#include <vtkActor.h>
+#include <vtkArrowSource.h>
+
+#include "Arrow.h"
+#include "Trace.h"
+
+using namespace VtkVis;
+
+Arrow::Arrow() :
+    Shape()
+{
+}
+
+Arrow::~Arrow()
+{
+    TRACE("Deleting Arrow");
+}
+
+void Arrow::update()
+{
+    if (_arrow == NULL) {
+	_arrow = vtkSmartPointer<vtkArrowSource>::New();
+    }
+
+    if (_pdMapper == NULL) {
+        _pdMapper = vtkSmartPointer<vtkPolyDataMapper>::New();
+        _pdMapper->SetResolveCoincidentTopologyToPolygonOffset();
+        _pdMapper->ScalarVisibilityOff();
+    }
+
+    _pdMapper->SetInputConnection(_arrow->GetOutputPort());
+
+    initProp();
+
+    getActor()->SetMapper(_pdMapper);
+    _pdMapper->Update();
+}
Index: /trunk/packages/vizservers/vtkvis/Arrow.h
===================================================================
--- /trunk/packages/vizservers/vtkvis/Arrow.h	(revision 3616)
+++ /trunk/packages/vizservers/vtkvis/Arrow.h	(revision 3616)
@@ -0,0 +1,75 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (C) 2004-2012  HUBzero Foundation, LLC
+ *
+ * Author: Leif Delgass <ldelgass@purdue.edu>
+ */
+
+#ifndef VTKVIS_ARROW_H
+#define VTKVIS_ARROW_H
+
+#include <vtkSmartPointer.h>
+#include <vtkPolyDataMapper.h>
+#include <vtkActor.h>
+#include <vtkArrowSource.h>
+
+#include "Shape.h"
+#include "VtkDataSet.h"
+
+namespace VtkVis {
+
+/**
+ * \brief VTK PolyData 3D Arrow
+ *
+ * This class creates a mesh arrow
+ */
+class Arrow : public Shape
+{
+public:
+    Arrow();
+    virtual ~Arrow();
+
+    virtual const char *getClassName() const
+    {
+        return "Arrow";
+    }
+
+    void setTipLength(double len)
+    {
+        if (_arrow != NULL) {
+            _arrow->SetTipLength(len);
+	}
+    }
+
+    void setRadii(double tipRadius, double shaftRadius)
+    {
+        if (_arrow != NULL) {
+            _arrow->SetTipRadius(tipRadius);
+            _arrow->SetShaftRadius(shaftRadius);
+	}
+    }
+
+    void setResolution(int tipRes, int shaftRes)
+    {
+        if (_arrow != NULL) {
+            _arrow->SetTipResolution(tipRes);
+            _arrow->SetShaftResolution(shaftRes);
+	}
+    }
+
+    void setInvert(bool state)
+    {
+        if (_arrow != NULL) {
+            _arrow->SetInvert(state);
+	}
+    }
+
+private:
+    virtual void update();
+
+    vtkSmartPointer<vtkArrowSource> _arrow;
+};
+
+}
+
+#endif
Index: /trunk/packages/vizservers/vtkvis/Box.cpp
===================================================================
--- /trunk/packages/vizservers/vtkvis/Box.cpp	(revision 3616)
+++ /trunk/packages/vizservers/vtkvis/Box.cpp	(revision 3616)
@@ -0,0 +1,51 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (C) 2004-2012  HUBzero Foundation, LLC
+ *
+ * Author: Leif Delgass <ldelgass@purdue.edu>
+ */
+
+#include <cassert>
+
+#include <vtkDataSet.h>
+#include <vtkPolyData.h>
+#include <vtkPolyDataMapper.h>
+#include <vtkActor.h>
+#include <vtkProperty.h>
+#include <vtkTransform.h>
+#include <vtkCubeSource.h>
+
+#include "Box.h"
+#include "Trace.h"
+
+using namespace VtkVis;
+
+Box::Box() :
+    Shape()
+{
+}
+
+Box::~Box()
+{
+    TRACE("Deleting Box");
+}
+
+void Box::update()
+{
+    if (_box == NULL) {
+	_box = vtkSmartPointer<vtkCubeSource>::New();
+    }
+
+    if (_pdMapper == NULL) {
+        _pdMapper = vtkSmartPointer<vtkPolyDataMapper>::New();
+        _pdMapper->SetResolveCoincidentTopologyToPolygonOffset();
+        _pdMapper->ScalarVisibilityOff();
+    }
+
+    _pdMapper->SetInputConnection(_box->GetOutputPort());
+
+    initProp();
+
+    getActor()->SetMapper(_pdMapper);
+    _pdMapper->Update();
+}
Index: /trunk/packages/vizservers/vtkvis/Box.h
===================================================================
--- /trunk/packages/vizservers/vtkvis/Box.h	(revision 3616)
+++ /trunk/packages/vizservers/vtkvis/Box.h	(revision 3616)
@@ -0,0 +1,54 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (C) 2004-2012  HUBzero Foundation, LLC
+ *
+ * Author: Leif Delgass <ldelgass@purdue.edu>
+ */
+
+#ifndef VTKVIS_BOX_H
+#define VTKVIS_BOX_H
+
+#include <vtkSmartPointer.h>
+#include <vtkPolyDataMapper.h>
+#include <vtkActor.h>
+#include <vtkCubeSource.h>
+
+#include "Shape.h"
+#include "VtkDataSet.h"
+
+namespace VtkVis {
+
+/**
+ * \brief VTK PolyData box
+ *
+ * This class creates a mesh box
+ */
+class Box : public Shape
+{
+public:
+    Box();
+    virtual ~Box();
+
+    virtual const char *getClassName() const
+    {
+        return "Box";
+    }
+
+    void setSize(double xlen, double ylen, double zlen)
+    {
+        if (_box != NULL) {
+            _box->SetXLength(xlen);
+	    _box->SetYLength(ylen);
+	    _box->SetZLength(zlen);
+	}
+    }
+
+private:
+    virtual void update();
+
+    vtkSmartPointer<vtkCubeSource> _box;
+};
+
+}
+
+#endif
Index: /trunk/packages/vizservers/vtkvis/ColorMap.cpp
===================================================================
--- /trunk/packages/vizservers/vtkvis/ColorMap.cpp	(revision 3615)
+++ /trunk/packages/vizservers/vtkvis/ColorMap.cpp	(revision 3616)
@@ -10,4 +10,5 @@
 #include <cstring>
 #include <cassert>
+
 #include <vtkLookupTable.h>
 #include <vtkColorTransferFunction.h>
@@ -15,5 +16,5 @@
 
 #include "ColorMap.h"
-#include "RpMolecule.h"
+#include "Molecule.h"
 #include "Trace.h"
 
Index: /trunk/packages/vizservers/vtkvis/ColorMap.h
===================================================================
--- /trunk/packages/vizservers/vtkvis/ColorMap.h	(revision 3615)
+++ /trunk/packages/vizservers/vtkvis/ColorMap.h	(revision 3616)
@@ -12,4 +12,5 @@
 #include <list>
 #include <cstring>
+
 #include <vtkSmartPointer.h>
 #include <vtkColorTransferFunction.h>
Index: /trunk/packages/vizservers/vtkvis/Cone.cpp
===================================================================
--- /trunk/packages/vizservers/vtkvis/Cone.cpp	(revision 3616)
+++ /trunk/packages/vizservers/vtkvis/Cone.cpp	(revision 3616)
@@ -0,0 +1,45 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (C) 2004-2012  HUBzero Foundation, LLC
+ *
+ * Author: Leif Delgass <ldelgass@purdue.edu>
+ */
+
+#include <vtkPolyDataMapper.h>
+#include <vtkActor.h>
+#include <vtkConeSource.h>
+
+#include "Cone.h"
+#include "Trace.h"
+
+using namespace VtkVis;
+
+Cone::Cone() :
+    Shape()
+{
+}
+
+Cone::~Cone()
+{
+    TRACE("Deleting Cone");
+}
+
+void Cone::update()
+{
+    if (_cone == NULL) {
+	_cone = vtkSmartPointer<vtkConeSource>::New();
+    }
+
+    if (_pdMapper == NULL) {
+        _pdMapper = vtkSmartPointer<vtkPolyDataMapper>::New();
+        _pdMapper->SetResolveCoincidentTopologyToPolygonOffset();
+        _pdMapper->ScalarVisibilityOff();
+    }
+
+    _pdMapper->SetInputConnection(_cone->GetOutputPort());
+
+    initProp();
+
+    getActor()->SetMapper(_pdMapper);
+    _pdMapper->Update();
+}
Index: /trunk/packages/vizservers/vtkvis/Cone.h
===================================================================
--- /trunk/packages/vizservers/vtkvis/Cone.h	(revision 3616)
+++ /trunk/packages/vizservers/vtkvis/Cone.h	(revision 3616)
@@ -0,0 +1,87 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (C) 2004-2012  HUBzero Foundation, LLC
+ *
+ * Author: Leif Delgass <ldelgass@purdue.edu>
+ */
+
+#ifndef VTKVIS_CONE_H
+#define VTKVIS_CONE_H
+
+#include <vtkSmartPointer.h>
+#include <vtkPolyDataMapper.h>
+#include <vtkActor.h>
+#include <vtkConeSource.h>
+
+#include "Shape.h"
+#include "VtkDataSet.h"
+
+namespace VtkVis {
+
+/**
+ * \brief VTK PolyData cone
+ *
+ * This class creates a mesh cone
+ */
+class Cone : public Shape
+{
+public:
+    Cone();
+    virtual ~Cone();
+
+    virtual const char *getClassName() const
+    {
+        return "Cone";
+    }
+
+    void setCenter(double center[3])
+    {
+        if (_cone != NULL) {
+            _cone->SetCenter(center);
+	}
+    }
+
+    void setHeight(double height)
+    {
+        if (_cone != NULL) {
+            _cone->SetHeight(height);
+	}
+    }
+
+    void setRadius(double radius)
+    {
+        if (_cone != NULL) {
+            _cone->SetRadius(radius);
+	}
+    }
+
+    void setDirection(double x, double y, double z)
+    {
+        if (_cone != NULL) {
+            _cone->SetDirection(x, y, z);
+	}
+    }
+
+    void setResolution(int res)
+    {
+        if (_cone != NULL) {
+            _cone->SetResolution(res);
+	}
+    }
+
+    void setCapping(bool state)
+    {
+        if (_cone != NULL) {
+            _cone->SetCapping(state ? 1 : 0);
+	}
+    }
+
+private:
+    virtual void update();
+
+    vtkSmartPointer<vtkConeSource> _cone;
+};
+
+}
+
+#endif
Index: /trunk/packages/vizservers/vtkvis/Contour2D.cpp
===================================================================
--- /trunk/packages/vizservers/vtkvis/Contour2D.cpp	(revision 3616)
+++ /trunk/packages/vizservers/vtkvis/Contour2D.cpp	(revision 3616)
@@ -0,0 +1,604 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (C) 2004-2012  HUBzero Foundation, LLC
+ *
+ * Author: Leif Delgass <ldelgass@purdue.edu>
+ */
+
+#include <cfloat>
+
+#include <vtkVersion.h>
+#include <vtkDataSet.h>
+#include <vtkPointData.h>
+#include <vtkCellData.h>
+#include <vtkCellDataToPointData.h>
+#include <vtkContourFilter.h>
+#include <vtkStripper.h>
+#include <vtkPolyDataMapper.h>
+#include <vtkUnstructuredGrid.h>
+#include <vtkProperty.h>
+#include <vtkTransform.h>
+#include <vtkDelaunay2D.h>
+#include <vtkDelaunay3D.h>
+#include <vtkDataSetSurfaceFilter.h>
+
+#include "Contour2D.h"
+#include "VtkRenderer.h"
+#include "Trace.h"
+
+using namespace VtkVis;
+
+Contour2D::Contour2D(int numContours) :
+    VtkGraphicsObject(),
+    _numContours(numContours),
+    _pipelineInitialized(false),
+    _colorMap(NULL),
+    _colorMode(COLOR_BY_SCALAR),
+    _colorFieldType(DataSet::POINT_DATA),
+    _renderer(NULL)
+{
+    _edgeColor[0] = _color[0];
+    _edgeColor[1] = _color[0];
+    _edgeColor[2] = _color[0];
+    _colorFieldRange[0] = DBL_MAX;
+    _colorFieldRange[1] = -DBL_MAX;
+    _lighting = false;
+}
+
+Contour2D::Contour2D(const std::vector<double>& contours) :
+    VtkGraphicsObject(),
+    _numContours(contours.size()),
+    _contours(contours),
+    _pipelineInitialized(false),
+    _colorMap(NULL),
+    _colorMode(COLOR_BY_SCALAR),
+    _colorFieldType(DataSet::POINT_DATA),
+    _renderer(NULL)
+{
+    _edgeColor[0] = _color[0];
+    _edgeColor[1] = _color[0];
+    _edgeColor[2] = _color[0];
+    _colorFieldRange[0] = DBL_MAX;
+    _colorFieldRange[1] = -DBL_MAX;
+    _lighting = false;
+}
+
+Contour2D::~Contour2D()
+{
+#ifdef WANT_TRACE
+    if (_dataSet != NULL)
+        TRACE("Deleting Contour2D for %s", _dataSet->getName().c_str());
+    else
+        TRACE("Deleting Contour2D with NULL DataSet");
+#endif
+}
+
+void Contour2D::setDataSet(DataSet *dataSet,
+                           Renderer *renderer)
+{
+    if (_dataSet != dataSet) {
+        _dataSet = dataSet;
+        _renderer = renderer;
+
+        if (renderer->getUseCumulativeRange()) {
+            renderer->getCumulativeDataRange(_dataRange,
+                                             _dataSet->getActiveScalarsName(),
+                                             1);
+            const char *activeVectors = _dataSet->getActiveVectorsName();
+            if (activeVectors != NULL) {
+                renderer->getCumulativeDataRange(_vectorMagnitudeRange,
+                                                 _dataSet->getActiveVectorsName(),
+                                                 3);
+                for (int i = 0; i < 3; i++) {
+                    renderer->getCumulativeDataRange(_vectorComponentRange[i],
+                                                     _dataSet->getActiveVectorsName(),
+                                                     3, i);
+                }
+            }
+        } else {
+            _dataSet->getScalarRange(_dataRange);
+            _dataSet->getVectorRange(_vectorMagnitudeRange);
+            for (int i = 0; i < 3; i++) {
+                _dataSet->getVectorRange(_vectorComponentRange[i], i);
+            }
+        }
+
+        update();
+    }
+}
+
+/**
+ * \brief Internal method to re-compute contours after a state change
+ */
+void Contour2D::update()
+{
+    if (_dataSet == NULL) {
+        return;
+    }
+    vtkDataSet *ds = _dataSet->getVtkDataSet();
+
+    // Contour filter to generate isolines
+    if (_contourFilter == NULL) {
+        _contourFilter = vtkSmartPointer<vtkContourFilter>::New();
+    }
+
+    if (!_pipelineInitialized) {
+        vtkSmartPointer<vtkCellDataToPointData> cellToPtData;
+
+        if (ds->GetPointData() == NULL ||
+            ds->GetPointData()->GetScalars() == NULL) {
+            TRACE("No scalar point data in dataset %s", _dataSet->getName().c_str());
+            if (ds->GetCellData() != NULL &&
+                ds->GetCellData()->GetScalars() != NULL) {
+                cellToPtData = 
+                    vtkSmartPointer<vtkCellDataToPointData>::New();
+#ifdef USE_VTK6
+                cellToPtData->SetInputData(ds);
+#else
+                cellToPtData->SetInput(ds);
+#endif
+                //cellToPtData->PassCellDataOn();
+                cellToPtData->Update();
+                ds = cellToPtData->GetOutput();
+            } else {
+                USER_ERROR("No scalar field was found in the data set");
+            }
+        }
+
+        vtkPolyData *pd = vtkPolyData::SafeDownCast(ds);
+        if (pd) {
+            // DataSet is a vtkPolyData
+            if (pd->GetNumberOfLines() == 0 &&
+                pd->GetNumberOfPolys() == 0 &&
+                pd->GetNumberOfStrips() == 0) {
+                // DataSet is a point cloud
+                PrincipalPlane plane;
+                double offset;
+                if (_dataSet->is2D(&plane, &offset)) {
+                    vtkSmartPointer<vtkDelaunay2D> mesher = vtkSmartPointer<vtkDelaunay2D>::New();
+                    if (plane == PLANE_ZY) {
+                        vtkSmartPointer<vtkTransform> trans = vtkSmartPointer<vtkTransform>::New();
+                        trans->RotateWXYZ(90, 0, 1, 0);
+                        if (offset != 0.0) {
+                            trans->Translate(-offset, 0, 0);
+                        }
+                        mesher->SetTransform(trans);
+                    } else if (plane == PLANE_XZ) {
+                        vtkSmartPointer<vtkTransform> trans = vtkSmartPointer<vtkTransform>::New();
+                        trans->RotateWXYZ(-90, 1, 0, 0);
+                        if (offset != 0.0) {
+                            trans->Translate(0, -offset, 0);
+                        }
+                        mesher->SetTransform(trans);
+                    } else if (offset != 0.0) {
+                        // XY with Z offset
+                        vtkSmartPointer<vtkTransform> trans = vtkSmartPointer<vtkTransform>::New();
+                        trans->Translate(0, 0, -offset);
+                        mesher->SetTransform(trans);
+                    }
+#ifdef USE_VTK6
+                    mesher->SetInputData(pd);
+#else
+                    mesher->SetInput(pd);
+#endif
+                    _contourFilter->SetInputConnection(mesher->GetOutputPort());
+                } else {
+                    vtkSmartPointer<vtkDelaunay3D> mesher = vtkSmartPointer<vtkDelaunay3D>::New();
+#ifdef USE_VTK6
+                    mesher->SetInputData(pd);
+#else
+                    mesher->SetInput(pd);
+#endif
+                    vtkSmartPointer<vtkDataSetSurfaceFilter> gf = vtkSmartPointer<vtkDataSetSurfaceFilter>::New();
+                    gf->SetInputConnection(mesher->GetOutputPort());
+                    _contourFilter->SetInputConnection(gf->GetOutputPort());
+                }
+            } else {
+                // DataSet is a vtkPolyData with lines and/or polygons
+#ifdef USE_VTK6
+                _contourFilter->SetInputData(ds);
+#else
+                _contourFilter->SetInput(ds);
+#endif
+            }
+        } else {
+            TRACE("Generating surface for data set");
+            // DataSet is NOT a vtkPolyData
+            vtkSmartPointer<vtkDataSetSurfaceFilter> gf = vtkSmartPointer<vtkDataSetSurfaceFilter>::New();
+#ifdef USE_VTK6
+            gf->SetInputData(ds);
+#else
+            gf->SetInput(ds);
+#endif
+            _contourFilter->SetInputConnection(gf->GetOutputPort());
+        }
+    }
+
+    _pipelineInitialized = true;
+
+    _contourFilter->ComputeNormalsOff();
+    _contourFilter->ComputeGradientsOff();
+
+    // Speed up multiple contour computation at cost of extra memory use
+    if (_numContours > 1) {
+        _contourFilter->UseScalarTreeOn();
+    } else {
+        _contourFilter->UseScalarTreeOff();
+    }
+
+    _contourFilter->SetNumberOfContours(_numContours);
+
+    if (_contours.empty()) {
+        // Evenly spaced isovalues
+        _contourFilter->GenerateValues(_numContours, _dataRange[0], _dataRange[1]);
+    } else {
+        // User-supplied isovalues
+        for (int i = 0; i < _numContours; i++) {
+            _contourFilter->SetValue(i, _contours[i]);
+        }
+    }
+
+    initProp();
+
+    if (_dsMapper == NULL) {
+        _dsMapper = vtkSmartPointer<vtkPolyDataMapper>::New();
+        _dsMapper->SetResolveCoincidentTopologyToPolygonOffset();
+        _dsMapper->ScalarVisibilityOff();
+        vtkSmartPointer<vtkStripper> stripper = vtkSmartPointer<vtkStripper>::New();
+        stripper->SetInputConnection(_contourFilter->GetOutputPort());
+        _dsMapper->SetInputConnection(stripper->GetOutputPort());
+        getActor()->SetMapper(_dsMapper);
+    }
+
+    if (_lut == NULL) {
+        setColorMap(ColorMap::getDefault());
+        setColorMode(_colorMode);
+    }
+
+    _dsMapper->Update();
+}
+
+void Contour2D::updateRanges(Renderer *renderer)
+{
+    if (_dataSet == NULL) {
+        ERROR("called before setDataSet");
+        return;
+    }
+
+    if (renderer->getUseCumulativeRange()) {
+        renderer->getCumulativeDataRange(_dataRange,
+                                         _dataSet->getActiveScalarsName(),
+                                         1);
+        const char *activeVectors = _dataSet->getActiveVectorsName();
+        if (activeVectors != NULL) {
+            renderer->getCumulativeDataRange(_vectorMagnitudeRange,
+                                             _dataSet->getActiveVectorsName(),
+                                             3);
+            for (int i = 0; i < 3; i++) {
+                renderer->getCumulativeDataRange(_vectorComponentRange[i],
+                                                 _dataSet->getActiveVectorsName(),
+                                                 3, i);
+            }
+        }
+    } else {
+        _dataSet->getScalarRange(_dataRange);
+        _dataSet->getVectorRange(_vectorMagnitudeRange);
+        for (int i = 0; i < 3; i++) {
+            _dataSet->getVectorRange(_vectorComponentRange[i], i);
+        }
+    }
+ 
+    // Need to update color map ranges
+    double *rangePtr = _colorFieldRange;
+    if (_colorFieldRange[0] > _colorFieldRange[1]) {
+        rangePtr = NULL;
+    }
+    setColorMode(_colorMode, _colorFieldType, _colorFieldName.c_str(), rangePtr);
+
+    if (_contours.empty() && _numContours > 0) {
+        // Contour isovalues need to be recomputed
+        update();
+    }
+}
+
+void Contour2D::setContourField(const char *name)
+{
+    if (_contourFilter != NULL) {
+        _contourFilter->SetInputArrayToProcess(0, 0, 0, vtkDataObject::FIELD_ASSOCIATION_POINTS, name);
+        update();
+    }
+}
+
+void Contour2D::setColorMode(ColorMode mode)
+{
+    _colorMode = mode;
+    if (_dataSet == NULL)
+        return;
+
+    switch (mode) {
+    case COLOR_BY_SCALAR:
+        setColorMode(mode,
+                     _dataSet->getActiveScalarsType(),
+                     _dataSet->getActiveScalarsName(),
+                     _dataRange);
+        break;
+    case COLOR_BY_VECTOR_MAGNITUDE:
+        setColorMode(mode,
+                     _dataSet->getActiveVectorsType(),
+                     _dataSet->getActiveVectorsName(),
+                     _vectorMagnitudeRange);
+        break;
+    case COLOR_BY_VECTOR_X:
+        setColorMode(mode,
+                     _dataSet->getActiveVectorsType(),
+                     _dataSet->getActiveVectorsName(),
+                     _vectorComponentRange[0]);
+        break;
+    case COLOR_BY_VECTOR_Y:
+        setColorMode(mode,
+                     _dataSet->getActiveVectorsType(),
+                     _dataSet->getActiveVectorsName(),
+                     _vectorComponentRange[1]);
+        break;
+    case COLOR_BY_VECTOR_Z:
+        setColorMode(mode,
+                     _dataSet->getActiveVectorsType(),
+                     _dataSet->getActiveVectorsName(),
+                     _vectorComponentRange[2]);
+        break;
+    case COLOR_CONSTANT:
+    default:
+        setColorMode(mode, DataSet::POINT_DATA, NULL, NULL);
+        break;
+    }
+}
+
+void Contour2D::setColorMode(ColorMode mode,
+                             const char *name, double range[2])
+{
+    if (_dataSet == NULL)
+        return;
+    DataSet::DataAttributeType type = DataSet::POINT_DATA;
+    int numComponents = 1;
+    if (name != NULL && strlen(name) > 0 &&
+        !_dataSet->getFieldInfo(name, &type, &numComponents)) {
+        ERROR("Field not found: %s", name);
+        return;
+    }
+    setColorMode(mode, type, name, range);
+}
+
+void Contour2D::setColorMode(ColorMode mode, DataSet::DataAttributeType type,
+                             const char *name, double range[2])
+{
+    _colorMode = mode;
+    _colorFieldType = type;
+    if (name == NULL)
+        _colorFieldName.clear();
+    else
+        _colorFieldName = name;
+    if (range == NULL) {
+        _colorFieldRange[0] = DBL_MAX;
+        _colorFieldRange[1] = -DBL_MAX;
+    } else {
+        memcpy(_colorFieldRange, range, sizeof(double)*2);
+    }
+
+    if (_dataSet == NULL || _dsMapper == NULL)
+        return;
+
+    switch (type) {
+    case DataSet::POINT_DATA:
+        _dsMapper->SetScalarModeToUsePointFieldData();
+        break;
+    case DataSet::CELL_DATA:
+        _dsMapper->SetScalarModeToUseCellFieldData();
+        break;
+    default:
+        ERROR("Unsupported DataAttributeType: %d", type);
+        return;
+    }
+
+    if (name != NULL && strlen(name) > 0) {
+        _dsMapper->SelectColorArray(name);
+    } else {
+        _dsMapper->SetScalarModeToDefault();
+    }
+
+    if (_lut != NULL) {
+        if (range != NULL) {
+            _lut->SetRange(range);
+        } else if (name != NULL && strlen(name) > 0) {
+            double r[2];
+            int comp = -1;
+            if (mode == COLOR_BY_VECTOR_X)
+                comp = 0;
+            else if (mode == COLOR_BY_VECTOR_Y)
+                comp = 1;
+            else if (mode == COLOR_BY_VECTOR_Z)
+                comp = 2;
+
+            if (_renderer->getUseCumulativeRange()) {
+                int numComponents;
+                if  (!_dataSet->getFieldInfo(name, type, &numComponents)) {
+                    ERROR("Field not found: %s, type: %d", name, type);
+                    return;
+                } else if (numComponents < comp+1) {
+                    ERROR("Request for component %d in field with %d components",
+                          comp, numComponents);
+                    return;
+                }
+                _renderer->getCumulativeDataRange(r, name, type, numComponents, comp);
+            } else {
+                _dataSet->getDataRange(r, name, type, comp);
+            }
+            _lut->SetRange(r);
+        }
+    }
+
+    switch (mode) {
+    case COLOR_BY_SCALAR:
+        _dsMapper->ScalarVisibilityOn();
+        break;
+    case COLOR_BY_VECTOR_MAGNITUDE:
+        _dsMapper->ScalarVisibilityOn();
+        if (_lut != NULL) {
+            _lut->SetVectorModeToMagnitude();
+        }
+        break;
+    case COLOR_BY_VECTOR_X:
+        _dsMapper->ScalarVisibilityOn();
+        if (_lut != NULL) {
+            _lut->SetVectorModeToComponent();
+            _lut->SetVectorComponent(0);
+        }
+        break;
+    case COLOR_BY_VECTOR_Y:
+        _dsMapper->ScalarVisibilityOn();
+        if (_lut != NULL) {
+            _lut->SetVectorModeToComponent();
+            _lut->SetVectorComponent(1);
+        }
+        break;
+    case COLOR_BY_VECTOR_Z:
+        _dsMapper->ScalarVisibilityOn();
+        if (_lut != NULL) {
+            _lut->SetVectorModeToComponent();
+            _lut->SetVectorComponent(2);
+        }
+        break;
+    case COLOR_CONSTANT:
+    default:
+        _dsMapper->ScalarVisibilityOff();
+        break;
+    }
+}
+
+/**
+ * \brief Called when the color map has been edited
+ */
+void Contour2D::updateColorMap()
+{
+    setColorMap(_colorMap);
+}
+
+/**
+ * \brief Associate a colormap lookup table with the DataSet
+ */
+void Contour2D::setColorMap(ColorMap *cmap)
+{
+    if (cmap == NULL)
+        return;
+
+    _colorMap = cmap;
+ 
+    if (_lut == NULL) {
+        _lut = vtkSmartPointer<vtkLookupTable>::New();
+        if (_dsMapper != NULL) {
+            _dsMapper->UseLookupTableScalarRangeOn();
+            _dsMapper->SetLookupTable(_lut);
+        }
+        _lut->DeepCopy(cmap->getLookupTable());
+        switch (_colorMode) {
+        case COLOR_CONSTANT:
+        case COLOR_BY_SCALAR:
+            _lut->SetRange(_dataRange);
+            break;
+        case COLOR_BY_VECTOR_MAGNITUDE:
+            _lut->SetRange(_vectorMagnitudeRange);
+            break;
+        case COLOR_BY_VECTOR_X:
+            _lut->SetRange(_vectorComponentRange[0]);
+            break;
+        case COLOR_BY_VECTOR_Y:
+            _lut->SetRange(_vectorComponentRange[1]);
+            break;
+        case COLOR_BY_VECTOR_Z:
+            _lut->SetRange(_vectorComponentRange[2]);
+            break;
+        default:
+            break;
+        }
+    } else {
+        double range[2];
+        _lut->GetTableRange(range);
+        _lut->DeepCopy(cmap->getLookupTable());
+        _lut->SetRange(range);
+        _lut->Modified();
+    }
+
+    switch (_colorMode) {
+    case COLOR_BY_VECTOR_MAGNITUDE:
+        _lut->SetVectorModeToMagnitude();
+        break;
+    case COLOR_BY_VECTOR_X:
+        _lut->SetVectorModeToComponent();
+        _lut->SetVectorComponent(0);
+        break;
+    case COLOR_BY_VECTOR_Y:
+        _lut->SetVectorModeToComponent();
+        _lut->SetVectorComponent(1);
+        break;
+    case COLOR_BY_VECTOR_Z:
+        _lut->SetVectorModeToComponent();
+        _lut->SetVectorComponent(2);
+        break;
+    default:
+         break;
+    }
+}
+
+/**
+ * \brief Specify number of evenly spaced contour lines to render
+ *
+ * Will override any existing contours
+ */
+void Contour2D::setNumContours(int numContours)
+{
+    _contours.clear();
+    _numContours = numContours;
+
+    update();
+}
+
+/**
+ * \brief Specify an explicit list of contour isovalues
+ *
+ * Will override any existing contours
+ */
+void Contour2D::setContourList(const std::vector<double>& contours)
+{
+    _contours = contours;
+    _numContours = (int)_contours.size();
+
+    update();
+}
+
+/**
+ * \brief Get the number of contours
+ */
+int Contour2D::getNumContours() const
+{
+    return _numContours;
+}
+
+/**
+ * \brief Get the contour list (may be empty if number of contours
+ * was specified in place of a list)
+ */
+const std::vector<double>& Contour2D::getContourList() const
+{
+    return _contours;
+}
+
+/**
+ * \brief Set a group of world coordinate planes to clip rendering
+ *
+ * Passing NULL for planes will remove all cliping planes
+ */
+void Contour2D::setClippingPlanes(vtkPlaneCollection *planes)
+{
+    if (_dsMapper != NULL) {
+        _dsMapper->SetClippingPlanes(planes);
+    }
+}
Index: /trunk/packages/vizservers/vtkvis/Contour2D.h
===================================================================
--- /trunk/packages/vizservers/vtkvis/Contour2D.h	(revision 3616)
+++ /trunk/packages/vizservers/vtkvis/Contour2D.h	(revision 3616)
@@ -0,0 +1,124 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (C) 2004-2012  HUBzero Foundation, LLC
+ *
+ * Author: Leif Delgass <ldelgass@purdue.edu>
+ */
+
+#ifndef VTKVIS_CONTOUR2D_H
+#define VTKVIS_CONTOUR2D_H
+
+#include <vtkSmartPointer.h>
+#include <vtkContourFilter.h>
+#include <vtkPolyDataMapper.h>
+#include <vtkActor.h>
+#include <vtkPlaneCollection.h>
+#include <vtkLookupTable.h>
+
+#include <vector>
+
+#include "ColorMap.h"
+#include "VtkGraphicsObject.h"
+
+namespace VtkVis {
+
+/**
+ * \brief 2D Contour lines (isolines)
+ */
+class Contour2D : public VtkGraphicsObject {
+public:
+    enum ColorMode {
+        COLOR_BY_SCALAR,
+        COLOR_BY_VECTOR_MAGNITUDE,
+        COLOR_BY_VECTOR_X,
+        COLOR_BY_VECTOR_Y,
+        COLOR_BY_VECTOR_Z,
+        COLOR_CONSTANT
+    };
+
+    Contour2D(int numContours);
+
+    Contour2D(const std::vector<double>& contours);
+
+    virtual ~Contour2D();
+
+    virtual const char *getClassName() const
+    {
+        return "Contour2D";
+    }
+
+    virtual void setDataSet(DataSet *dataSet,
+                            Renderer *renderer);
+
+    virtual void setClippingPlanes(vtkPlaneCollection *planes);
+
+    void setContourField(const char *name);
+
+    void setNumContours(int numContours);
+
+    void setContourList(const std::vector<double>& contours);
+
+    int getNumContours() const;
+
+    const std::vector<double>& getContourList() const;
+
+    void setColorMode(ColorMode mode, DataSet::DataAttributeType type,
+                      const char *name, double range[2] = NULL);
+
+    void setColorMode(ColorMode mode,
+                      const char *name, double range[2] = NULL);
+
+    void setColorMode(ColorMode mode);
+
+    void setColorMap(ColorMap *colorMap);
+
+    /**
+     * \brief Return the ColorMap in use
+     */
+    ColorMap *getColorMap()
+    {
+        return _colorMap;
+    }
+
+    void updateColorMap();
+
+    virtual void updateRanges(Renderer *renderer);
+
+    virtual void setColor(float color[3])
+    {
+        VtkGraphicsObject::setColor(color);
+        VtkGraphicsObject::setEdgeColor(color);
+    }
+
+    virtual void setEdgeColor(float color[3])
+    {
+        setColor(color);
+    }
+
+private:
+    Contour2D();
+
+    virtual void update();
+
+    int _numContours;
+    std::vector<double> _contours;
+
+    bool _pipelineInitialized;
+
+    ColorMap *_colorMap;
+    ColorMode _colorMode;
+    std::string _colorFieldName;
+    DataSet::DataAttributeType _colorFieldType;
+    double _colorFieldRange[2];
+    double _vectorMagnitudeRange[2];
+    double _vectorComponentRange[3][2];
+    Renderer *_renderer;
+
+    vtkSmartPointer<vtkLookupTable> _lut;
+    vtkSmartPointer<vtkContourFilter> _contourFilter;
+    vtkSmartPointer<vtkPolyDataMapper> _dsMapper;
+};
+
+}
+
+#endif
Index: /trunk/packages/vizservers/vtkvis/Contour3D.cpp
===================================================================
--- /trunk/packages/vizservers/vtkvis/Contour3D.cpp	(revision 3616)
+++ /trunk/packages/vizservers/vtkvis/Contour3D.cpp	(revision 3616)
@@ -0,0 +1,571 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (C) 2004-2012  HUBzero Foundation, LLC
+ *
+ * Author: Leif Delgass <ldelgass@purdue.edu>
+ */
+
+#include <cassert>
+
+#include <vtkVersion.h>
+#include <vtkDataSet.h>
+#include <vtkPointData.h>
+#include <vtkCellData.h>
+#include <vtkCellDataToPointData.h>
+#include <vtkContourFilter.h>
+#include <vtkPolyDataMapper.h>
+#include <vtkUnstructuredGrid.h>
+#include <vtkProperty.h>
+#include <vtkDelaunay2D.h>
+#include <vtkDelaunay3D.h>
+#include <vtkDataSetSurfaceFilter.h>
+
+#include "Contour3D.h"
+#include "VtkRenderer.h"
+#include "Trace.h"
+
+using namespace VtkVis;
+
+Contour3D::Contour3D(int numContours) :
+    VtkGraphicsObject(),
+    _numContours(numContours),
+    _pipelineInitialized(false),
+    _colorMap(NULL),
+    _colorMode(COLOR_BY_SCALAR),
+    _colorFieldType(DataSet::POINT_DATA),
+    _renderer(NULL)
+{
+    _colorFieldRange[0] = DBL_MAX;
+    _colorFieldRange[1] = -DBL_MAX;
+}
+
+Contour3D::Contour3D(const std::vector<double>& contours) :
+    VtkGraphicsObject(),
+    _numContours(contours.size()),
+    _contours(contours),
+    _pipelineInitialized(false),
+    _colorMap(NULL),
+    _colorMode(COLOR_BY_SCALAR),
+    _colorFieldType(DataSet::POINT_DATA),
+    _renderer(NULL)
+{
+    _colorFieldRange[0] = DBL_MAX;
+    _colorFieldRange[1] = -DBL_MAX;
+}
+
+Contour3D::~Contour3D()
+{
+#ifdef WANT_TRACE
+    if (_dataSet != NULL)
+        TRACE("Deleting Contour3D for %s", _dataSet->getName().c_str());
+    else
+        TRACE("Deleting Contour3D with NULL DataSet");
+#endif
+}
+
+void Contour3D::setDataSet(DataSet *dataSet,
+                           Renderer *renderer)
+{
+    if (_dataSet != dataSet) {
+        _dataSet = dataSet;
+        _renderer = renderer;
+
+        if (renderer->getUseCumulativeRange()) {
+            renderer->getCumulativeDataRange(_dataRange,
+                                             _dataSet->getActiveScalarsName(),
+                                             1);
+            const char *activeVectors = _dataSet->getActiveVectorsName();
+            if (activeVectors != NULL) {
+                renderer->getCumulativeDataRange(_vectorMagnitudeRange,
+                                                 _dataSet->getActiveVectorsName(),
+                                                 3);
+                for (int i = 0; i < 3; i++) {
+                    renderer->getCumulativeDataRange(_vectorComponentRange[i],
+                                                     _dataSet->getActiveVectorsName(),
+                                                     3, i);
+                }
+            }
+        } else {
+            _dataSet->getScalarRange(_dataRange);
+            _dataSet->getVectorRange(_vectorMagnitudeRange);
+            for (int i = 0; i < 3; i++) {
+                _dataSet->getVectorRange(_vectorComponentRange[i], i);
+            }
+        }
+
+        update();
+    }
+}
+
+/**
+ * \brief Internal method to re-compute contours after a state change
+ */
+void Contour3D::update()
+{
+    if (_dataSet == NULL) {
+        return;
+    }
+    vtkDataSet *ds = _dataSet->getVtkDataSet();
+
+    if (_dataSet->is2D()) {
+        USER_ERROR("Cannot create isosurface(s) since the data set is not 3D");
+        return;
+    }
+
+    // Contour filter to generate isosurfaces
+    if (_contourFilter == NULL) {
+        _contourFilter = vtkSmartPointer<vtkContourFilter>::New();
+    }
+
+    if (!_pipelineInitialized) {
+        vtkSmartPointer<vtkCellDataToPointData> cellToPtData;
+
+        if (ds->GetPointData() == NULL ||
+            ds->GetPointData()->GetScalars() == NULL) {
+            TRACE("No scalar point data in dataset %s", _dataSet->getName().c_str());
+            if (ds->GetCellData() != NULL &&
+                ds->GetCellData()->GetScalars() != NULL) {
+                cellToPtData = 
+                    vtkSmartPointer<vtkCellDataToPointData>::New();
+#ifdef USE_VTK6
+                cellToPtData->SetInputData(ds);
+#else
+                cellToPtData->SetInput(ds);
+#endif
+                //cellToPtData->PassCellDataOn();
+                cellToPtData->Update();
+                ds = cellToPtData->GetOutput();
+            } else {
+                USER_ERROR("No scalar field was found in the data set.");
+            }
+        }
+
+        vtkPolyData *pd = vtkPolyData::SafeDownCast(ds);
+        if (pd) {
+            // DataSet is a vtkPolyData
+            if (pd->GetNumberOfLines() == 0 &&
+                pd->GetNumberOfPolys() == 0 &&
+                pd->GetNumberOfStrips() == 0) {
+                // DataSet is a point cloud
+                // Generate a 3D unstructured grid
+                vtkSmartPointer<vtkDelaunay3D> mesher = vtkSmartPointer<vtkDelaunay3D>::New();
+#ifdef USE_VTK6
+                mesher->SetInputData(pd);
+#else
+                mesher->SetInput(pd);
+#endif
+                _contourFilter->SetInputConnection(mesher->GetOutputPort());
+            } else {
+                // DataSet is a vtkPolyData with lines and/or polygons
+                ERROR("Not a 3D DataSet");
+                return;
+            }
+        } else {
+            // DataSet is NOT a vtkPolyData
+#ifdef USE_VTK6
+            _contourFilter->SetInputData(ds);
+#else
+            _contourFilter->SetInput(ds);
+#endif
+        }
+    }
+
+    _pipelineInitialized = true;
+
+    _contourFilter->ComputeNormalsOff();
+    _contourFilter->ComputeGradientsOff();
+
+    // Speed up multiple contour computation at cost of extra memory use
+    if (_numContours > 1) {
+        _contourFilter->UseScalarTreeOn();
+    } else {
+        _contourFilter->UseScalarTreeOff();
+    }
+
+    _contourFilter->SetNumberOfContours(_numContours);
+
+    if (_contours.empty()) {
+        // Evenly spaced isovalues
+        TRACE("Setting %d contours between %g and %g", _numContours, _dataRange[0], _dataRange[1]);
+        _contourFilter->GenerateValues(_numContours, _dataRange[0], _dataRange[1]);
+    } else {
+        // User-supplied isovalues
+        for (int i = 0; i < _numContours; i++) {
+            _contourFilter->SetValue(i, _contours[i]);
+        }
+    }
+
+    initProp();
+
+    if (_normalsGenerator == NULL) {
+        _normalsGenerator = vtkSmartPointer<vtkPolyDataNormals>::New();
+        _normalsGenerator->SetInputConnection(_contourFilter->GetOutputPort());
+        _normalsGenerator->SetFeatureAngle(90.);
+        _normalsGenerator->AutoOrientNormalsOff();
+        _normalsGenerator->ComputePointNormalsOn();
+    }
+
+    if (_dsMapper == NULL) {
+        _dsMapper = vtkSmartPointer<vtkPolyDataMapper>::New();
+        _dsMapper->SetResolveCoincidentTopologyToPolygonOffset();
+        _dsMapper->SetInputConnection(_normalsGenerator->GetOutputPort());
+        _dsMapper->ScalarVisibilityOff();
+        //_dsMapper->SetColorModeToMapScalars();
+        getActor()->SetMapper(_dsMapper);
+    }
+
+    if (_lut == NULL) {
+        setColorMap(ColorMap::getDefault());
+        setColorMode(_colorMode);
+    }
+
+    _dsMapper->Update();
+    TRACE("Contour output %d polys, %d strips",
+          _contourFilter->GetOutput()->GetNumberOfPolys(),
+          _contourFilter->GetOutput()->GetNumberOfStrips());
+}
+
+void Contour3D::updateRanges(Renderer *renderer)
+{
+    if (_dataSet == NULL) {
+        ERROR("called before setDataSet");
+        return;
+    }
+
+    if (renderer->getUseCumulativeRange()) {
+        renderer->getCumulativeDataRange(_dataRange,
+                                         _dataSet->getActiveScalarsName(),
+                                         1);
+        const char *activeVectors = _dataSet->getActiveVectorsName();
+        if (activeVectors != NULL) {
+            renderer->getCumulativeDataRange(_vectorMagnitudeRange,
+                                             _dataSet->getActiveVectorsName(),
+                                             3);
+            for (int i = 0; i < 3; i++) {
+                renderer->getCumulativeDataRange(_vectorComponentRange[i],
+                                                 _dataSet->getActiveVectorsName(),
+                                                 3, i);
+            }
+        }
+    } else {
+        _dataSet->getScalarRange(_dataRange);
+        _dataSet->getVectorRange(_vectorMagnitudeRange);
+        for (int i = 0; i < 3; i++) {
+            _dataSet->getVectorRange(_vectorComponentRange[i], i);
+        }
+    }
+ 
+    // Need to update color map ranges
+    double *rangePtr = _colorFieldRange;
+    if (_colorFieldRange[0] > _colorFieldRange[1]) {
+        rangePtr = NULL;
+    }
+    setColorMode(_colorMode, _colorFieldType, _colorFieldName.c_str(), rangePtr);
+
+    if (_contours.empty() && _numContours > 0) {
+        // Contour isovalues need to be recomputed
+        update();
+    }
+}
+
+void Contour3D::setContourField(const char *name)
+{
+    if (_contourFilter != NULL) {
+        _contourFilter->SetInputArrayToProcess(0, 0, 0, vtkDataObject::FIELD_ASSOCIATION_POINTS, name);
+        update();
+    }
+}
+
+void Contour3D::setColorMode(ColorMode mode)
+{
+    _colorMode = mode;
+    if (_dataSet == NULL)
+        return;
+
+    switch (mode) {
+    case COLOR_BY_SCALAR:
+        setColorMode(mode,
+                     _dataSet->getActiveScalarsType(),
+                     _dataSet->getActiveScalarsName(),
+                     _dataRange);
+        break;
+    case COLOR_BY_VECTOR_MAGNITUDE:
+        setColorMode(mode,
+                     _dataSet->getActiveVectorsType(),
+                     _dataSet->getActiveVectorsName(),
+                     _vectorMagnitudeRange);
+        break;
+    case COLOR_BY_VECTOR_X:
+        setColorMode(mode,
+                     _dataSet->getActiveVectorsType(),
+                     _dataSet->getActiveVectorsName(),
+                     _vectorComponentRange[0]);
+        break;
+    case COLOR_BY_VECTOR_Y:
+        setColorMode(mode,
+                     _dataSet->getActiveVectorsType(),
+                     _dataSet->getActiveVectorsName(),
+                     _vectorComponentRange[1]);
+        break;
+    case COLOR_BY_VECTOR_Z:
+        setColorMode(mode,
+                     _dataSet->getActiveVectorsType(),
+                     _dataSet->getActiveVectorsName(),
+                     _vectorComponentRange[2]);
+        break;
+    case COLOR_CONSTANT:
+    default:
+        setColorMode(mode, DataSet::POINT_DATA, NULL, NULL);
+        break;
+    }
+}
+
+void Contour3D::setColorMode(ColorMode mode,
+                             const char *name, double range[2])
+{
+    if (_dataSet == NULL)
+        return;
+    DataSet::DataAttributeType type = DataSet::POINT_DATA;
+    int numComponents = 1;
+    if (name != NULL && strlen(name) > 0 &&
+        !_dataSet->getFieldInfo(name, &type, &numComponents)) {
+        ERROR("Field not found: %s", name);
+        return;
+    }
+    setColorMode(mode, type, name, range);
+}
+
+void Contour3D::setColorMode(ColorMode mode, DataSet::DataAttributeType type,
+                             const char *name, double range[2])
+{
+    _colorMode = mode;
+    _colorFieldType = type;
+    if (name == NULL)
+        _colorFieldName.clear();
+    else
+        _colorFieldName = name;
+    if (range == NULL) {
+        _colorFieldRange[0] = DBL_MAX;
+        _colorFieldRange[1] = -DBL_MAX;
+    } else {
+        memcpy(_colorFieldRange, range, sizeof(double)*2);
+    }
+
+    if (_dataSet == NULL || _dsMapper == NULL)
+        return;
+
+    switch (type) {
+    case DataSet::POINT_DATA:
+        _dsMapper->SetScalarModeToUsePointFieldData();
+        break;
+    case DataSet::CELL_DATA:
+        _dsMapper->SetScalarModeToUseCellFieldData();
+        break;
+    default:
+        ERROR("Unsupported DataAttributeType: %d", type);
+        return;
+    }
+
+    if (name != NULL && strlen(name) > 0) {
+        _dsMapper->SelectColorArray(name);
+    } else {
+        _dsMapper->SetScalarModeToDefault();
+    }
+
+    if (_lut != NULL) {
+        if (range != NULL) {
+            _lut->SetRange(range);
+        } else if (name != NULL && strlen(name) > 0) {
+            double r[2];
+            int comp = -1;
+            if (mode == COLOR_BY_VECTOR_X)
+                comp = 0;
+            else if (mode == COLOR_BY_VECTOR_Y)
+                comp = 1;
+            else if (mode == COLOR_BY_VECTOR_Z)
+                comp = 2;
+
+            if (_renderer->getUseCumulativeRange()) {
+                int numComponents;
+                if  (!_dataSet->getFieldInfo(name, type, &numComponents)) {
+                    ERROR("Field not found: %s, type: %d", name, type);
+                    return;
+                } else if (numComponents < comp+1) {
+                    ERROR("Request for component %d in field with %d components",
+                          comp, numComponents);
+                    return;
+                }
+                _renderer->getCumulativeDataRange(r, name, type, numComponents, comp);
+            } else {
+                _dataSet->getDataRange(r, name, type, comp);
+            }
+            _lut->SetRange(r);
+        }
+    }
+
+    switch (mode) {
+    case COLOR_BY_SCALAR:
+        _dsMapper->ScalarVisibilityOn();
+        break;
+    case COLOR_BY_VECTOR_MAGNITUDE:
+        _dsMapper->ScalarVisibilityOn();
+        if (_lut != NULL) {
+            _lut->SetVectorModeToMagnitude();
+        }
+        break;
+    case COLOR_BY_VECTOR_X:
+        _dsMapper->ScalarVisibilityOn();
+        if (_lut != NULL) {
+            _lut->SetVectorModeToComponent();
+            _lut->SetVectorComponent(0);
+        }
+        break;
+    case COLOR_BY_VECTOR_Y:
+        _dsMapper->ScalarVisibilityOn();
+        if (_lut != NULL) {
+            _lut->SetVectorModeToComponent();
+            _lut->SetVectorComponent(1);
+        }
+        break;
+    case COLOR_BY_VECTOR_Z:
+        _dsMapper->ScalarVisibilityOn();
+        if (_lut != NULL) {
+            _lut->SetVectorModeToComponent();
+            _lut->SetVectorComponent(2);
+        }
+        break;
+    case COLOR_CONSTANT:
+    default:
+        _dsMapper->ScalarVisibilityOff();
+        break;
+    }
+}
+
+/**
+ * \brief Called when the color map has been edited
+ */
+void Contour3D::updateColorMap()
+{
+    setColorMap(_colorMap);
+}
+
+/**
+ * \brief Associate a colormap lookup table with the DataSet
+ */
+void Contour3D::setColorMap(ColorMap *cmap)
+{
+    if (cmap == NULL)
+        return;
+
+    _colorMap = cmap;
+ 
+    if (_lut == NULL) {
+        _lut = vtkSmartPointer<vtkLookupTable>::New();
+        if (_dsMapper != NULL) {
+            _dsMapper->UseLookupTableScalarRangeOn();
+            _dsMapper->SetLookupTable(_lut);
+        }
+        _lut->DeepCopy(cmap->getLookupTable());
+        switch (_colorMode) {
+        case COLOR_CONSTANT:
+        case COLOR_BY_SCALAR:
+            _lut->SetRange(_dataRange);
+            break;
+        case COLOR_BY_VECTOR_MAGNITUDE:
+            _lut->SetRange(_vectorMagnitudeRange);
+            break;
+        case COLOR_BY_VECTOR_X:
+            _lut->SetRange(_vectorComponentRange[0]);
+            break;
+        case COLOR_BY_VECTOR_Y:
+            _lut->SetRange(_vectorComponentRange[1]);
+            break;
+        case COLOR_BY_VECTOR_Z:
+            _lut->SetRange(_vectorComponentRange[2]);
+            break;
+        default:
+            break;
+        }
+    } else {
+        double range[2];
+        _lut->GetTableRange(range);
+        _lut->DeepCopy(cmap->getLookupTable());
+        _lut->SetRange(range);
+        _lut->Modified();
+    }
+
+    switch (_colorMode) {
+    case COLOR_BY_VECTOR_MAGNITUDE:
+        _lut->SetVectorModeToMagnitude();
+        break;
+    case COLOR_BY_VECTOR_X:
+        _lut->SetVectorModeToComponent();
+        _lut->SetVectorComponent(0);
+        break;
+    case COLOR_BY_VECTOR_Y:
+        _lut->SetVectorModeToComponent();
+        _lut->SetVectorComponent(1);
+        break;
+    case COLOR_BY_VECTOR_Z:
+        _lut->SetVectorModeToComponent();
+        _lut->SetVectorComponent(2);
+        break;
+    default:
+         break;
+    }
+}
+
+/**
+ * \brief Specify number of evenly spaced isosurfaces to render
+ *
+ * Will override any existing contours
+ */
+void Contour3D::setNumContours(int numContours)
+{
+    _contours.clear();
+    _numContours = numContours;
+
+    update();
+}
+
+/**
+ * \brief Specify an explicit list of contour isovalues
+ *
+ * Will override any existing contours
+ */
+void Contour3D::setContourList(const std::vector<double>& contours)
+{
+    _contours = contours;
+    _numContours = (int)_contours.size();
+
+    update();
+}
+
+/**
+ * \brief Get the number of contours
+ */
+int Contour3D::getNumContours() const
+{
+    return _numContours;
+}
+
+/**
+ * \brief Get the contour list (may be empty if number of contours
+ * was specified in place of a list)
+ */
+const std::vector<double>& Contour3D::getContourList() const
+{
+    return _contours;
+}
+
+/**
+ * \brief Set a group of world coordinate planes to clip rendering
+ *
+ * Passing NULL for planes will remove all cliping planes
+ */
+void Contour3D::setClippingPlanes(vtkPlaneCollection *planes)
+{
+    if (_dsMapper != NULL) {
+        _dsMapper->SetClippingPlanes(planes);
+    }
+}
Index: /trunk/packages/vizservers/vtkvis/Contour3D.h
===================================================================
--- /trunk/packages/vizservers/vtkvis/Contour3D.h	(revision 3616)
+++ /trunk/packages/vizservers/vtkvis/Contour3D.h	(revision 3616)
@@ -0,0 +1,115 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (C) 2004-2012  HUBzero Foundation, LLC
+ *
+ * Author: Leif Delgass <ldelgass@purdue.edu>
+ */
+
+#ifndef VTKVIS_CONTOUR3D_H
+#define VTKVIS_CONTOUR3D_H
+
+#include <vtkSmartPointer.h>
+#include <vtkContourFilter.h>
+#include <vtkPolyDataNormals.h>
+#include <vtkLookupTable.h>
+#include <vtkPolyDataMapper.h>
+#include <vtkActor.h>
+#include <vtkPlaneCollection.h>
+
+#include <vector>
+
+#include "ColorMap.h"
+#include "VtkGraphicsObject.h"
+
+namespace VtkVis {
+
+/**
+ * \brief 3D Contour isosurfaces (geometry)
+ */
+class Contour3D : public VtkGraphicsObject {
+public:
+    enum ColorMode {
+        COLOR_BY_SCALAR,
+        COLOR_BY_VECTOR_MAGNITUDE,
+        COLOR_BY_VECTOR_X,
+        COLOR_BY_VECTOR_Y,
+        COLOR_BY_VECTOR_Z,
+        COLOR_CONSTANT
+    };
+
+    Contour3D(int numContours);
+
+    Contour3D(const std::vector<double>& contours);
+
+    virtual ~Contour3D();
+
+    virtual const char *getClassName() const
+    {
+        return "Contour3D";
+    }
+
+    virtual void setDataSet(DataSet *dataSet,
+                            Renderer *renderer);
+
+    virtual void setClippingPlanes(vtkPlaneCollection *planes);
+
+    void setNumContours(int numContours);
+
+    void setContourList(const std::vector<double>& contours);
+
+    int getNumContours() const;
+
+    const std::vector<double>& getContourList() const;
+
+    void setContourField(const char *name);
+
+    void setColorMode(ColorMode mode, DataSet::DataAttributeType type,
+                      const char *name, double range[2] = NULL);
+
+    void setColorMode(ColorMode mode,
+                      const char *name, double range[2] = NULL);
+
+    void setColorMode(ColorMode mode);
+
+    void setColorMap(ColorMap *colorMap);
+
+    /**
+     * \brief Return the ColorMap in use
+     */
+    ColorMap *getColorMap()
+    {
+        return _colorMap;
+    }
+
+    void updateColorMap();
+
+    virtual void updateRanges(Renderer *renderer);
+
+private:
+    Contour3D();
+
+    virtual void update();
+
+    int _numContours;
+    std::vector<double> _contours;
+
+    bool _pipelineInitialized;
+
+    ColorMap *_colorMap;
+    ColorMode _colorMode;
+    std::string _colorFieldName;
+    DataSet::DataAttributeType _colorFieldType;
+    double _colorFieldRange[2];
+    double _vectorMagnitudeRange[2];
+    double _vectorComponentRange[3][2];
+    Renderer *_renderer;
+
+    vtkSmartPointer<vtkLookupTable> _lut;
+    vtkSmartPointer<vtkContourFilter> _contourFilter;
+    vtkSmartPointer<vtkPolyDataNormals> _normalsGenerator;
+    vtkSmartPointer<vtkPolyDataMapper> _dsMapper;
+};
+
+}
+
+#endif
Index: /trunk/packages/vizservers/vtkvis/Cutplane.cpp
===================================================================
--- /trunk/packages/vizservers/vtkvis/Cutplane.cpp	(revision 3616)
+++ /trunk/packages/vizservers/vtkvis/Cutplane.cpp	(revision 3616)
@@ -0,0 +1,880 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (C) 2004-2012  HUBzero Foundation, LLC
+ *
+ * Author: Leif Delgass <ldelgass@purdue.edu>
+ */
+
+#include <cassert>
+#include <cfloat>
+#include <cstring>
+
+#include <vtkDataSet.h>
+#include <vtkPointData.h>
+#include <vtkCellData.h>
+#include <vtkDataSetMapper.h>
+#include <vtkUnstructuredGrid.h>
+#include <vtkProperty.h>
+#include <vtkImageData.h>
+#include <vtkLookupTable.h>
+#include <vtkTransform.h>
+#include <vtkDelaunay2D.h>
+#include <vtkDelaunay3D.h>
+#include <vtkGaussianSplatter.h>
+#include <vtkExtractVOI.h>
+#include <vtkCutter.h>
+#include <vtkDataSetSurfaceFilter.h>
+
+#include "Cutplane.h"
+#include "VtkRenderer.h"
+#include "Trace.h"
+
+#define MESH_POINT_CLOUDS
+
+using namespace VtkVis;
+
+Cutplane::Cutplane() :
+    VtkGraphicsObject(),
+    _pipelineInitialized(false),
+    _colorMap(NULL),
+    _colorMode(COLOR_BY_SCALAR),
+    _colorFieldType(DataSet::POINT_DATA),
+    _renderer(NULL)
+{
+    _colorFieldRange[0] = DBL_MAX;
+    _colorFieldRange[1] = -DBL_MAX;
+}
+
+Cutplane::~Cutplane()
+{
+#ifdef WANT_TRACE
+    if (_dataSet != NULL)
+        TRACE("Deleting Cutplane for %s", _dataSet->getName().c_str());
+    else
+        TRACE("Deleting Cutplane with NULL DataSet");
+#endif
+}
+
+void Cutplane::setDataSet(DataSet *dataSet,
+                          Renderer *renderer)
+{
+    if (_dataSet != dataSet) {
+        _dataSet = dataSet;
+
+        _renderer = renderer;
+
+        if (renderer->getUseCumulativeRange()) {
+            renderer->getCumulativeDataRange(_dataRange,
+                                             _dataSet->getActiveScalarsName(),
+                                             1);
+            renderer->getCumulativeDataRange(_vectorMagnitudeRange,
+                                             _dataSet->getActiveVectorsName(),
+                                             3);
+            for (int i = 0; i < 3; i++) {
+                renderer->getCumulativeDataRange(_vectorComponentRange[i],
+                                                 _dataSet->getActiveVectorsName(),
+                                                 3, i);
+            }
+        } else {
+            _dataSet->getScalarRange(_dataRange);
+            _dataSet->getVectorRange(_vectorMagnitudeRange);
+            for (int i = 0; i < 3; i++) {
+                _dataSet->getVectorRange(_vectorComponentRange[i], i);
+            }
+        }
+
+        update();
+    }
+}
+
+/**
+ * \brief Create and initialize a VTK Prop to render the object
+ */
+void Cutplane::initProp()
+{
+    if (_prop == NULL) {
+        _prop = vtkSmartPointer<vtkAssembly>::New();
+
+        for (int i = 0; i < 3; i++) {
+            _actor[i] = vtkSmartPointer<vtkActor>::New();
+            _borderActor[i] = vtkSmartPointer<vtkActor>::New();
+            //_actor[i]->VisibilityOff();
+            vtkProperty *property = _actor[i]->GetProperty();
+            property->SetColor(_color[0], _color[1], _color[2]);
+            property->SetEdgeColor(_edgeColor[0], _edgeColor[1], _edgeColor[2]);
+            property->SetLineWidth(_edgeWidth);
+            property->SetPointSize(_pointSize);
+            property->EdgeVisibilityOff();
+            property->SetOpacity(_opacity);
+            property->SetAmbient(.2);
+            if (!_lighting)
+                property->LightingOff();
+            if (_faceCulling && _opacity == 1.0) {
+                setCulling(property, true);
+            }
+            property = _borderActor[i]->GetProperty();
+            property->SetColor(_color[0], _color[1], _color[2]);
+            property->SetEdgeColor(_edgeColor[0], _edgeColor[1], _edgeColor[2]);
+            property->SetLineWidth(_edgeWidth);
+            property->SetPointSize(_pointSize);
+            property->EdgeVisibilityOff();
+            property->SetOpacity(_opacity);
+            property->SetAmbient(.2);
+            property->LightingOff();
+            
+            getAssembly()->AddPart(_borderActor[i]);
+        }
+    } else {
+        for (int i = 0; i < 3; i++) {
+            getAssembly()->RemovePart(_actor[i]);
+        }
+    }
+}
+
+/**
+ * \brief Set the material color (sets ambient, diffuse, and specular)
+ */
+void Cutplane::setColor(float color[3])
+{
+    for (int i = 0; i < 3; i++)
+        _color[i] = color[i];
+
+    for (int i = 0; i < 3; i++) {
+        if (_borderActor[i] != NULL) {
+            _borderActor[i]->GetProperty()->SetColor(color[0], color[1], color[2]);
+        }
+    }
+}
+
+void Cutplane::update()
+{
+    if (_dataSet == NULL)
+        return;
+
+    vtkDataSet *ds = _dataSet->getVtkDataSet();
+
+    double bounds[6];
+    _dataSet->getBounds(bounds);
+    // Mapper, actor to render color-mapped data set
+    for (int i = 0; i < 3; i++) {
+        if (_mapper[i] == NULL) {
+            _mapper[i] = vtkSmartPointer<vtkDataSetMapper>::New();
+            // Map scalars through lookup table regardless of type
+            _mapper[i]->SetColorModeToMapScalars();
+        }
+        if (_cutPlane[i] == NULL) {
+            _cutPlane[i] = vtkSmartPointer<vtkPlane>::New();
+            switch (i) {
+            case 0:
+                _cutPlane[i]->SetNormal(1, 0, 0);
+                _cutPlane[i]->SetOrigin(bounds[0] + (bounds[1]-bounds[0])/2.,
+                                        0,
+                                        0);
+                break;
+            case 1:
+                _cutPlane[i]->SetNormal(0, 1, 0);
+                _cutPlane[i]->SetOrigin(0,
+                                        bounds[2] + (bounds[3]-bounds[2])/2.,
+                                        0);
+                break;
+            case 2:
+            default:
+                _cutPlane[i]->SetNormal(0, 0, 1);
+                _cutPlane[i]->SetOrigin(0,
+                                        0,
+                                        bounds[4] + (bounds[5]-bounds[4])/2.);
+                break;
+            }
+        }
+        if (_cutter[i] == NULL) {
+            _cutter[i] = vtkSmartPointer<vtkCutter>::New();
+            _cutter[i]->SetCutFunction(_cutPlane[i]);
+        }
+    }
+
+    initProp();
+
+    if (!_pipelineInitialized) {
+        vtkPolyData *pd = vtkPolyData::SafeDownCast(ds);
+        if (pd && 
+            pd->GetNumberOfLines() == 0 &&
+            pd->GetNumberOfPolys() == 0 &&
+            pd->GetNumberOfStrips() == 0) {
+            // DataSet is a point cloud
+            PrincipalPlane plane;
+            double offset;
+            if (_dataSet->is2D(&plane, &offset)) {
+                // DataSet is a 2D point cloud
+#ifdef MESH_POINT_CLOUDS
+                vtkSmartPointer<vtkDelaunay2D> mesher = vtkSmartPointer<vtkDelaunay2D>::New();
+                if (plane == PLANE_ZY) {
+                    vtkSmartPointer<vtkTransform> trans = vtkSmartPointer<vtkTransform>::New();
+                    trans->RotateWXYZ(90, 0, 1, 0);
+                    if (offset != 0.0) {
+                        trans->Translate(-offset, 0, 0);
+                    }
+                    mesher->SetTransform(trans);
+                    _actor[1]->VisibilityOff();
+                    _actor[2]->VisibilityOff();
+                } else if (plane == PLANE_XZ) {
+                    vtkSmartPointer<vtkTransform> trans = vtkSmartPointer<vtkTransform>::New();
+                    trans->RotateWXYZ(-90, 1, 0, 0);
+                    if (offset != 0.0) {
+                        trans->Translate(0, -offset, 0);
+                    }
+                    mesher->SetTransform(trans);
+                    _actor[0]->VisibilityOff();
+                    _actor[2]->VisibilityOff();
+                } else if (offset != 0.0) {
+                    // XY with Z offset
+                    vtkSmartPointer<vtkTransform> trans = vtkSmartPointer<vtkTransform>::New();
+                    trans->Translate(0, 0, -offset);
+                    mesher->SetTransform(trans);
+                    _actor[0]->VisibilityOff();
+                    _actor[1]->VisibilityOff();
+                }
+#ifdef USE_VTK6
+                mesher->SetInputData(pd);
+#else
+                mesher->SetInput(pd);
+#endif
+                for (int i = 0; i < 3; i++) {
+                    _mapper[i]->SetInputConnection(mesher->GetOutputPort());
+                }
+#else
+                if (_splatter == NULL) {
+                    _splatter = vtkSmartPointer<vtkGaussianSplatter>::New();
+                }
+#ifdef USE_VTK6
+                _splatter->SetInputData(pd);
+#else
+                _splatter->SetInput(pd);
+#endif
+                int dims[3];
+                _splatter->GetSampleDimensions(dims);
+                TRACE("Sample dims: %d %d %d", dims[0], dims[1], dims[2]);
+                if (plane == PLANE_ZY) {
+                    dims[0] = 3;
+                } else if (plane == PLANE_XZ) {
+                    dims[1] = 3;
+                } else {
+                    dims[2] = 3;
+                }
+                _splatter->SetSampleDimensions(dims);
+                for (int i = 0; i < 3; i++) {
+                    _cutter[i]->SetInputConnection(_splatter->GetOutputPort());
+                    vtkSmartPointer<vtkDataSetSurfaceFilter> gf = vtkSmartPointer<vtkDataSetSurfaceFilter>::New();
+                    gf->UseStripsOn();
+                    gf->SetInputConnection(_cutter[i]->GetOutputPort());
+                    _mapper[i]->SetInputConnection(gf->GetOutputPort());
+                }
+#endif
+            } else {
+#ifdef MESH_POINT_CLOUDS
+                // Data Set is a 3D point cloud
+                // Result of Delaunay3D mesher is unstructured grid
+                vtkSmartPointer<vtkDelaunay3D> mesher = vtkSmartPointer<vtkDelaunay3D>::New();
+#ifdef USE_VTK6
+                mesher->SetInputData(pd);
+#else
+                mesher->SetInput(pd);
+#endif
+                // Sample a plane within the grid bounding box
+                for (int i = 0; i < 3; i++) {
+                    _cutter[i]->SetInputConnection(mesher->GetOutputPort());
+                    vtkSmartPointer<vtkDataSetSurfaceFilter> gf = vtkSmartPointer<vtkDataSetSurfaceFilter>::New();
+                    gf->UseStripsOn();
+                    gf->SetInputConnection(_cutter[i]->GetOutputPort());
+                    _mapper[i]->SetInputConnection(gf->GetOutputPort());
+                }
+#else
+                if (_splatter == NULL) {
+                    _splatter = vtkSmartPointer<vtkGaussianSplatter>::New();
+                }
+#ifdef USE_VTK6
+                _splatter->SetInputData(pd);
+#else
+                _splatter->SetInput(pd);
+#endif
+                int dims[3];
+                dims[0] = dims[1] = dims[2] = 64;
+                TRACE("Generating volume with dims (%d,%d,%d) from point cloud",
+                      dims[0], dims[1], dims[2]);
+                _splatter->SetSampleDimensions(dims);
+                for (int i = 0; i < 3; i++) {
+                    _cutter[i]->SetInputConnection(_splatter->GetOutputPort());
+                    vtkSmartPointer<vtkDataSetSurfaceFilter> gf = vtkSmartPointer<vtkDataSetSurfaceFilter>::New();
+                    gf->UseStripsOn();
+                    gf->SetInputConnection(_cutter[i]->GetOutputPort());
+                    _mapper[i]->SetInputConnection(gf->GetOutputPort());
+                }
+#endif
+            }
+        } else {
+            // DataSet can be: image/volume/uniform grid, structured grid, unstructured grid, rectilinear grid, or
+            // PolyData with cells other than points
+            PrincipalPlane plane;
+            double offset;
+            if (!_dataSet->is2D(&plane, &offset)) {
+                // Sample a plane within the grid bounding box
+                for (int i = 0; i < 3; i++) {
+#ifdef USE_VTK6
+                    _cutter[i]->SetInputData(ds);
+#else
+                    _cutter[i]->SetInput(ds);
+#endif
+                    vtkSmartPointer<vtkDataSetSurfaceFilter> gf = vtkSmartPointer<vtkDataSetSurfaceFilter>::New();
+                    gf->UseStripsOn();
+                    gf->SetInputConnection(_cutter[i]->GetOutputPort());
+                    _mapper[i]->SetInputConnection(gf->GetOutputPort());
+                }
+            } else {
+                // 2D data
+                if (plane == PLANE_ZY) {
+                    _actor[1]->VisibilityOff();
+                    _actor[2]->VisibilityOff();
+                } else if (plane == PLANE_XZ) {
+                    _actor[0]->VisibilityOff();
+                    _actor[2]->VisibilityOff();
+                } else if (offset != 0.0) {
+                    // XY with Z offset
+                    _actor[0]->VisibilityOff();
+                    _actor[1]->VisibilityOff();
+                }
+                for (int i = 0; i < 3; i++) {
+                    vtkSmartPointer<vtkDataSetSurfaceFilter> gf = vtkSmartPointer<vtkDataSetSurfaceFilter>::New();
+                    gf->UseStripsOn();
+#ifdef USE_VTK6
+                    gf->SetInputData(ds);
+#else
+                    gf->SetInput(ds);
+#endif
+                    _mapper[i]->SetInputConnection(gf->GetOutputPort());
+                }
+            }
+        }
+    }
+
+    _pipelineInitialized = true;
+
+    for (int i = 0; i < 3; i++) {
+        if (_mapper[i] != NULL && _borderMapper[i] == NULL) {
+            _borderMapper[i] = vtkSmartPointer<vtkPolyDataMapper>::New();
+#ifdef CUTPLANE_TIGHT_OUTLINE
+            _outlineFilter[i] = vtkSmartPointer<vtkOutlineFilter>::New();
+            _outlineFilter[i]->SetInputConnection(_mapper[i]->GetInputConnection(0, 0));
+            _borderMapper[i]->SetInputConnection(_outlineFilter[i]->GetOutputPort());
+#else
+            _outlineSource[i] = vtkSmartPointer<vtkOutlineSource>::New();
+            switch (i) {
+            case 0:
+                _outlineSource[i]->SetBounds(bounds[0] + (bounds[1]-bounds[0])/2.,
+                                             bounds[0] + (bounds[1]-bounds[0])/2.,
+                                             bounds[2], bounds[3],
+                                             bounds[4], bounds[5]);
+                break;
+            case 1:
+                _outlineSource[i]->SetBounds(bounds[0], bounds[1],
+                                             bounds[2] + (bounds[3]-bounds[2])/2.,
+                                             bounds[2] + (bounds[3]-bounds[2])/2.,
+                                             bounds[4], bounds[5]);
+                break;
+            case 2:
+                _outlineSource[i]->SetBounds(bounds[0], bounds[1],
+                                             bounds[2], bounds[3],
+                                             bounds[4] + (bounds[5]-bounds[4])/2.,
+                                             bounds[4] + (bounds[5]-bounds[4])/2.);
+                break;
+            default:
+                ;
+            }
+            _borderMapper[i]->SetInputConnection(_outlineSource[i]->GetOutputPort());
+#endif
+            _borderMapper[i]->SetResolveCoincidentTopologyToPolygonOffset();
+        }
+    }
+
+    setInterpolateBeforeMapping(true);
+
+    if (_lut == NULL) {
+        setColorMap(ColorMap::getDefault());
+        setColorMode(_colorMode);
+    }
+
+    for (int i = 0; i < 3; i++) {
+        if (_mapper[i] != NULL) {
+            _actor[i]->SetMapper(_mapper[i]);
+            _mapper[i]->Update();
+        }
+        if (_borderMapper[i] != NULL) {
+            _borderActor[i]->SetMapper(_borderMapper[i]);
+            _borderMapper[i]->Update();
+        }
+        // Only add cutter actor to assembly if geometry was
+        // produced, in order to prevent messing up assembly bounds
+        double bounds[6];
+        _actor[i]->GetBounds(bounds);
+        if (bounds[0] <= bounds[1]) {
+            getAssembly()->AddPart(_actor[i]);
+        }
+    }
+}
+
+void Cutplane::setInterpolateBeforeMapping(bool state)
+{
+    for (int i = 0; i < 3; i++) {
+        if (_mapper[i] != NULL) {
+            _mapper[i]->SetInterpolateScalarsBeforeMapping((state ? 1 : 0));
+        }
+    }
+}
+
+/**
+ * \brief Select a 2D slice plane from a 3D DataSet
+ *
+ * \param[in] axis Axis of slice plane
+ * \param[in] ratio Position [0,1] of slice plane along axis
+ */
+void Cutplane::selectVolumeSlice(Axis axis, double ratio)
+{
+    if (_dataSet->is2D()) {
+        WARN("DataSet not 3D, returning");
+        return;
+    }
+
+    if ((axis == X_AXIS &&_cutPlane[0] == NULL) ||
+        (axis == Y_AXIS &&_cutPlane[1] == NULL) ||
+        (axis == Z_AXIS &&_cutPlane[2] == NULL)) {
+        WARN("Called before update() or DataSet is not a volume");
+        return;
+    }
+
+    double bounds[6];
+    _dataSet->getBounds(bounds);
+#if 0
+    if (ratio == 0.0)
+        ratio = 0.001;
+    if (ratio == 1.0)
+        ratio = 0.999;
+#endif
+    switch (axis) {
+    case X_AXIS:
+        _cutPlane[0]->SetOrigin(bounds[0] + (bounds[1]-bounds[0]) * ratio,
+                                0,
+                                0);
+#ifndef CUTPLANE_TIGHT_OUTLINE
+        _outlineSource[0]->SetBounds(bounds[0] + (bounds[1]-bounds[0]) * ratio,
+                                     bounds[0] + (bounds[1]-bounds[0]) * ratio,
+                                     bounds[2], bounds[3],
+                                     bounds[4], bounds[5]);
+#endif
+        break;
+    case Y_AXIS:
+        _cutPlane[1]->SetOrigin(0,
+                                bounds[2] + (bounds[3]-bounds[2]) * ratio,
+                                0);
+#ifndef CUTPLANE_TIGHT_OUTLINE
+        _outlineSource[1]->SetBounds(bounds[0], bounds[1],
+                                     bounds[2] + (bounds[3]-bounds[2]) * ratio,
+                                     bounds[2] + (bounds[3]-bounds[2]) * ratio,
+                                     bounds[4], bounds[5]);
+#endif
+        break;
+    case Z_AXIS:
+        _cutPlane[2]->SetOrigin(0,
+                                0,
+                                bounds[4] + (bounds[5]-bounds[4]) * ratio);
+#ifndef CUTPLANE_TIGHT_OUTLINE
+        _outlineSource[2]->SetBounds(bounds[0], bounds[1],
+                                     bounds[2], bounds[3],
+                                     bounds[4] + (bounds[5]-bounds[4]) * ratio,
+                                     bounds[4] + (bounds[5]-bounds[4]) * ratio);
+#endif
+        break;
+    default:
+        ERROR("Invalid Axis");
+        return;
+    }
+    update();
+}
+
+void Cutplane::updateRanges(Renderer *renderer)
+{
+    if (_dataSet == NULL) {
+        ERROR("called before setDataSet");
+        return;
+    }
+
+    if (renderer->getUseCumulativeRange()) {
+        renderer->getCumulativeDataRange(_dataRange,
+                                         _dataSet->getActiveScalarsName(),
+                                         1);
+        renderer->getCumulativeDataRange(_vectorMagnitudeRange,
+                                         _dataSet->getActiveVectorsName(),
+                                         3);
+        for (int i = 0; i < 3; i++) {
+            renderer->getCumulativeDataRange(_vectorComponentRange[i],
+                                             _dataSet->getActiveVectorsName(),
+                                             3, i);
+        }
+    } else {
+        _dataSet->getScalarRange(_dataRange);
+        _dataSet->getVectorRange(_vectorMagnitudeRange);
+        for (int i = 0; i < 3; i++) {
+            _dataSet->getVectorRange(_vectorComponentRange[i], i);
+        }
+    }
+
+    // Need to update color map ranges
+    double *rangePtr = _colorFieldRange;
+    if (_colorFieldRange[0] > _colorFieldRange[1]) {
+        rangePtr = NULL;
+    }
+    setColorMode(_colorMode, _colorFieldType, _colorFieldName.c_str(), rangePtr);
+}
+
+void Cutplane::setColorMode(ColorMode mode)
+{
+    _colorMode = mode;
+    if (_dataSet == NULL)
+        return;
+
+    switch (mode) {
+    case COLOR_BY_SCALAR:
+        setColorMode(mode,
+                     _dataSet->getActiveScalarsType(),
+                     _dataSet->getActiveScalarsName(),
+                     _dataRange);
+        break;
+    case COLOR_BY_VECTOR_MAGNITUDE:
+        setColorMode(mode,
+                     _dataSet->getActiveVectorsType(),
+                     _dataSet->getActiveVectorsName(),
+                     _vectorMagnitudeRange);
+        break;
+    case COLOR_BY_VECTOR_X:
+        setColorMode(mode,
+                     _dataSet->getActiveVectorsType(),
+                     _dataSet->getActiveVectorsName(),
+                     _vectorComponentRange[0]);
+        break;
+    case COLOR_BY_VECTOR_Y:
+        setColorMode(mode,
+                     _dataSet->getActiveVectorsType(),
+                     _dataSet->getActiveVectorsName(),
+                     _vectorComponentRange[1]);
+        break;
+    case COLOR_BY_VECTOR_Z:
+        setColorMode(mode,
+                     _dataSet->getActiveVectorsType(),
+                     _dataSet->getActiveVectorsName(),
+                     _vectorComponentRange[2]);
+        break;
+    default:
+        ;
+    }
+}
+
+void Cutplane::setColorMode(ColorMode mode,
+                            const char *name, double range[2])
+{
+    if (_dataSet == NULL)
+        return;
+    DataSet::DataAttributeType type;
+    int numComponents;
+    if (!_dataSet->getFieldInfo(name, &type, &numComponents)) {
+        ERROR("Field not found: %s", name);
+        return;
+    }
+    setColorMode(mode, type, name, range);
+}
+
+void Cutplane::setColorMode(ColorMode mode,
+                            DataSet::DataAttributeType type,
+                            const char *name, double range[2])
+{
+    _colorMode = mode;
+    _colorFieldType = type;
+    if (name == NULL)
+        _colorFieldName.clear();
+    else
+        _colorFieldName = name;
+    if (range == NULL) {
+        _colorFieldRange[0] = DBL_MAX;
+        _colorFieldRange[1] = -DBL_MAX;
+    } else {
+        memcpy(_colorFieldRange, range, sizeof(double)*2);
+    }
+
+    if (_dataSet == NULL ||
+        _mapper[0] == NULL ||
+        _mapper[1] == NULL ||
+        _mapper[2] == NULL)
+        return;
+
+    switch (type) {
+    case DataSet::POINT_DATA:
+        for (int i = 0; i < 3; i++) {
+            _mapper[i]->SetScalarModeToUsePointFieldData();
+        }
+        break;
+    case DataSet::CELL_DATA:
+        for (int i = 0; i < 3; i++) {
+            _mapper[i]->SetScalarModeToUseCellFieldData();
+        }
+        break;
+    default:
+        ERROR("Unsupported DataAttributeType: %d", type);
+        return;
+    }
+
+    if (_splatter != NULL) {
+        for (int i = 0; i < 3; i++) {
+            _mapper[i]->SelectColorArray("SplatterValues");
+        }
+    } else if (name != NULL && strlen(name) > 0) {
+        for (int i = 0; i < 3; i++) {
+            _mapper[i]->SelectColorArray(name);
+        }
+    } else {
+        for (int i = 0; i < 3; i++) {
+            _mapper[i]->SetScalarModeToDefault();
+        }
+    }
+
+    if (_lut != NULL) {
+        if (range != NULL) {
+            _lut->SetRange(range);
+        } else if (name != NULL && strlen(name) > 0) {
+            double r[2];
+            int comp = -1;
+            if (mode == COLOR_BY_VECTOR_X)
+                comp = 0;
+            else if (mode == COLOR_BY_VECTOR_Y)
+                comp = 1;
+            else if (mode == COLOR_BY_VECTOR_Z)
+                comp = 2;
+
+            if (_renderer->getUseCumulativeRange()) {
+                int numComponents;
+                if  (!_dataSet->getFieldInfo(name, type, &numComponents)) {
+                    ERROR("Field not found: %s, type: %d", name, type);
+                    return;
+                } else if (numComponents < comp+1) {
+                    ERROR("Request for component %d in field with %d components",
+                          comp, numComponents);
+                    return;
+                }
+                _renderer->getCumulativeDataRange(r, name, type, numComponents, comp);
+            } else {
+                _dataSet->getDataRange(r, name, type, comp);
+            }
+            _lut->SetRange(r);
+        }
+    }
+
+
+    switch (mode) {
+    case COLOR_BY_SCALAR:
+        for (int i = 0; i < 3; i++) {
+            _mapper[i]->ScalarVisibilityOn();
+        }
+        break;
+    case COLOR_BY_VECTOR_MAGNITUDE:
+        for (int i = 0; i < 3; i++) {
+            _mapper[i]->ScalarVisibilityOn();
+        }
+        if (_lut != NULL) {
+            _lut->SetVectorModeToMagnitude();
+        }
+        break;
+    case COLOR_BY_VECTOR_X:
+        for (int i = 0; i < 3; i++) {
+            _mapper[i]->ScalarVisibilityOn();
+        }
+        if (_lut != NULL) {
+            _lut->SetVectorModeToComponent();
+            _lut->SetVectorComponent(0);
+        }
+        break;
+    case COLOR_BY_VECTOR_Y:
+        for (int i = 0; i < 3; i++) {
+            _mapper[i]->ScalarVisibilityOn();
+        }
+        if (_lut != NULL) {
+            _lut->SetVectorModeToComponent();
+            _lut->SetVectorComponent(1);
+        }
+        break;
+    case COLOR_BY_VECTOR_Z:
+        for (int i = 0; i < 3; i++) {
+            _mapper[i]->ScalarVisibilityOn();
+        }
+        if (_lut != NULL) {
+            _lut->SetVectorModeToComponent();
+            _lut->SetVectorComponent(2);
+        }
+        break;
+    default:
+        for (int i = 0; i < 3; i++) {
+            _mapper[i]->ScalarVisibilityOff();
+        }
+        break;
+    }
+}
+
+/**
+ * \brief Called when the color map has been edited
+ */
+void Cutplane::updateColorMap()
+{
+    setColorMap(_colorMap);
+}
+
+/**
+ * \brief Associate a colormap lookup table with the DataSet
+ */
+void Cutplane::setColorMap(ColorMap *cmap)
+{
+    if (cmap == NULL)
+        return;
+
+    _colorMap = cmap;
+ 
+    if (_lut == NULL) {
+        _lut = vtkSmartPointer<vtkLookupTable>::New();
+        for (int i = 0; i < 3; i++) {
+            if (_mapper[i] != NULL) {
+                _mapper[i]->UseLookupTableScalarRangeOn();
+                _mapper[i]->SetLookupTable(_lut);
+            }
+        }
+        _lut->DeepCopy(cmap->getLookupTable());
+        switch (_colorMode) {
+        case COLOR_BY_SCALAR:
+            _lut->SetRange(_dataRange);
+            break;
+        case COLOR_BY_VECTOR_MAGNITUDE:
+            _lut->SetRange(_vectorMagnitudeRange);
+            break;
+        case COLOR_BY_VECTOR_X:
+            _lut->SetRange(_vectorComponentRange[0]);
+            break;
+        case COLOR_BY_VECTOR_Y:
+            _lut->SetRange(_vectorComponentRange[1]);
+            break;
+        case COLOR_BY_VECTOR_Z:
+            _lut->SetRange(_vectorComponentRange[2]);
+            break;
+        default:
+            break;
+        }
+    } else {
+        double range[2];
+        _lut->GetTableRange(range);
+        _lut->DeepCopy(cmap->getLookupTable());
+        _lut->SetRange(range);
+        _lut->Modified();
+    }
+
+    switch (_colorMode) {
+    case COLOR_BY_VECTOR_MAGNITUDE:
+        _lut->SetVectorModeToMagnitude();
+        break;
+    case COLOR_BY_VECTOR_X:
+        _lut->SetVectorModeToComponent();
+        _lut->SetVectorComponent(0);
+        break;
+    case COLOR_BY_VECTOR_Y:
+        _lut->SetVectorModeToComponent();
+        _lut->SetVectorComponent(1);
+        break;
+    case COLOR_BY_VECTOR_Z:
+        _lut->SetVectorModeToComponent();
+        _lut->SetVectorComponent(2);
+        break;
+    default:
+         break;
+    }
+}
+
+/**
+ * \brief Turn on/off lighting of this object
+ */
+void Cutplane::setLighting(bool state)
+{
+    _lighting = state;
+    for (int i = 0; i < 3; i++) {
+        if (_actor[i] != NULL)
+            _actor[i]->GetProperty()->SetLighting((state ? 1 : 0));
+    }
+}
+
+/**
+ * \brief Turn on/off rendering of mesh edges
+ */
+void Cutplane::setEdgeVisibility(bool state)
+{
+    for (int i = 0; i < 3; i++) {
+        if (_actor[i] != NULL) {
+            _actor[i]->GetProperty()->SetEdgeVisibility((state ? 1 : 0));
+        }
+    }
+}
+
+/**
+ * \brief Turn on/off rendering of outlines
+ */
+void Cutplane::setOutlineVisibility(bool state)
+{
+    for (int i = 0; i < 3; i++) {
+        if (_borderActor[i] != NULL) {
+            _borderActor[i]->SetVisibility((state ? 1 : 0));
+        }
+    }
+}
+
+/**
+ * \brief Set visibility of cutplane on specified axis
+ */
+void Cutplane::setSliceVisibility(Axis axis, bool state)
+{
+    switch (axis) {
+    case X_AXIS:
+        if (_actor[0] != NULL)
+            _actor[0]->SetVisibility((state ? 1 : 0));
+        if (_borderActor[0] != NULL)
+            _borderActor[0]->SetVisibility((state ? 1 : 0));
+        break;
+    case Y_AXIS:
+        if (_actor[1] != NULL)
+            _actor[1]->SetVisibility((state ? 1 : 0));
+        if (_borderActor[1] != NULL)
+            _borderActor[1]->SetVisibility((state ? 1 : 0));
+        break;
+    case Z_AXIS:
+    default:
+        if (_actor[2] != NULL)
+            _actor[2]->SetVisibility((state ? 1 : 0));
+        if (_borderActor[2] != NULL)
+            _borderActor[2]->SetVisibility((state ? 1 : 0));
+        break;
+    }
+}
+
+/**
+ * \brief Set a group of world coordinate planes to clip rendering
+ *
+ * Passing NULL for planes will remove all cliping planes
+ */
+void Cutplane::setClippingPlanes(vtkPlaneCollection *planes)
+{
+    for (int i = 0; i < 3; i++) {
+        if (_mapper[i] != NULL) {
+            _mapper[i]->SetClippingPlanes(planes);
+        }
+        if (_borderMapper[i] != NULL) {
+            _borderMapper[i]->SetClippingPlanes(planes);
+        }
+    }
+}
Index: /trunk/packages/vizservers/vtkvis/Cutplane.h
===================================================================
--- /trunk/packages/vizservers/vtkvis/Cutplane.h	(revision 3616)
+++ /trunk/packages/vizservers/vtkvis/Cutplane.h	(revision 3616)
@@ -0,0 +1,126 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (C) 2004-2012  HUBzero Foundation, LLC
+ *
+ * Author: Leif Delgass <ldelgass@purdue.edu>
+ */
+
+#ifndef VTKVIS_CUTPLANE_H
+#define VTKVIS_CUTPLANE_H
+
+#include <vtkSmartPointer.h>
+#include <vtkLookupTable.h>
+#include <vtkDataSetMapper.h>
+#include <vtkActor.h>
+#include <vtkPlaneCollection.h>
+#include <vtkCutter.h>
+#include <vtkPlane.h>
+#include <vtkOutlineFilter.h>
+#include <vtkOutlineSource.h>
+#include <vtkGaussianSplatter.h>
+
+#include "ColorMap.h"
+#include "Types.h"
+#include "VtkGraphicsObject.h"
+
+namespace VtkVis {
+
+//#define CUTPLANE_TIGHT_OUTLINE
+
+/**
+ * \brief Color-mapped plot of slice through a data set
+ * 
+ * Currently the DataSet must be image data (2D uniform grid)
+ */
+class Cutplane : public VtkGraphicsObject {
+public:
+    enum ColorMode {
+        COLOR_BY_SCALAR,
+        COLOR_BY_VECTOR_MAGNITUDE,
+        COLOR_BY_VECTOR_X,
+        COLOR_BY_VECTOR_Y,
+        COLOR_BY_VECTOR_Z
+    };
+
+    Cutplane();
+    virtual ~Cutplane();
+
+    virtual const char *getClassName() const
+    {
+        return "Cutplane";
+    }
+
+    virtual void setDataSet(DataSet *dataSet,
+                            Renderer *renderer);
+
+    virtual void setColor(float color[3]);
+
+    virtual void setLighting(bool state);
+
+    virtual void setEdgeVisibility(bool state);
+
+    virtual void setClippingPlanes(vtkPlaneCollection *planes);
+
+    void setOutlineVisibility(bool state);
+
+    void selectVolumeSlice(Axis axis, double ratio);
+
+    void setSliceVisibility(Axis axis, bool state);
+
+    void setInterpolateBeforeMapping(bool state);
+
+    void setColorMode(ColorMode mode, DataSet::DataAttributeType type,
+                      const char *name, double range[2] = NULL);
+
+    void setColorMode(ColorMode mode,
+                      const char *name, double range[2] = NULL);
+
+    void setColorMode(ColorMode mode);
+
+    void setColorMap(ColorMap *colorMap);
+
+    /**
+     * \brief Return the ColorMap in use
+     */
+    ColorMap *getColorMap()
+    {
+        return _colorMap;
+    }
+
+    void updateColorMap();
+
+    virtual void updateRanges(Renderer *renderer);
+
+private:
+    virtual void initProp();
+    virtual void update();
+
+    bool _pipelineInitialized;
+
+    ColorMap *_colorMap;
+    ColorMode _colorMode;
+    std::string _colorFieldName;
+    DataSet::DataAttributeType _colorFieldType;
+    double _colorFieldRange[2];
+    double _vectorMagnitudeRange[2];
+    double _vectorComponentRange[3][2];
+    Renderer *_renderer;
+
+    vtkSmartPointer<vtkLookupTable> _lut;
+    vtkSmartPointer<vtkActor> _actor[3];
+    vtkSmartPointer<vtkActor> _borderActor[3];
+    vtkSmartPointer<vtkDataSetMapper> _mapper[3];
+    vtkSmartPointer<vtkPolyDataMapper> _borderMapper[3];
+    vtkSmartPointer<vtkCutter> _cutter[3];
+    vtkSmartPointer<vtkPlane> _cutPlane[3];
+#ifdef CUTPLANE_TIGHT_OUTLINE
+    vtkSmartPointer<vtkOutlineFilter> _outlineFilter[3];
+#else
+    vtkSmartPointer<vtkOutlineSource> _outlineSource[3];
+#endif
+    vtkSmartPointer<vtkGaussianSplatter> _splatter;
+};
+
+}
+
+#endif
Index: /trunk/packages/vizservers/vtkvis/Cylinder.cpp
===================================================================
--- /trunk/packages/vizservers/vtkvis/Cylinder.cpp	(revision 3616)
+++ /trunk/packages/vizservers/vtkvis/Cylinder.cpp	(revision 3616)
@@ -0,0 +1,45 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (C) 2004-2012  HUBzero Foundation, LLC
+ *
+ * Author: Leif Delgass <ldelgass@purdue.edu>
+ */
+
+#include <vtkPolyDataMapper.h>
+#include <vtkActor.h>
+#include <vtkCylinderSource.h>
+
+#include "Cylinder.h"
+#include "Trace.h"
+
+using namespace VtkVis;
+
+Cylinder::Cylinder() :
+    Shape()
+{
+}
+
+Cylinder::~Cylinder()
+{
+    TRACE("Deleting Cylinder");
+}
+
+void Cylinder::update()
+{
+    if (_cylinder == NULL) {
+	_cylinder = vtkSmartPointer<vtkCylinderSource>::New();
+    }
+
+    if (_pdMapper == NULL) {
+        _pdMapper = vtkSmartPointer<vtkPolyDataMapper>::New();
+        _pdMapper->SetResolveCoincidentTopologyToPolygonOffset();
+        _pdMapper->ScalarVisibilityOff();
+    }
+
+    _pdMapper->SetInputConnection(_cylinder->GetOutputPort());
+
+    initProp();
+
+    getActor()->SetMapper(_pdMapper);
+    _pdMapper->Update();
+}
Index: /trunk/packages/vizservers/vtkvis/Cylinder.h
===================================================================
--- /trunk/packages/vizservers/vtkvis/Cylinder.h	(revision 3616)
+++ /trunk/packages/vizservers/vtkvis/Cylinder.h	(revision 3616)
@@ -0,0 +1,80 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (C) 2004-2012  HUBzero Foundation, LLC
+ *
+ * Author: Leif Delgass <ldelgass@purdue.edu>
+ */
+
+#ifndef VTKVIS_CYLINDER_H
+#define VTKVIS_CYLINDER_H
+
+#include <vtkSmartPointer.h>
+#include <vtkPolyDataMapper.h>
+#include <vtkActor.h>
+#include <vtkCylinderSource.h>
+
+#include "Shape.h"
+#include "VtkDataSet.h"
+
+namespace VtkVis {
+
+/**
+ * \brief VTK PolyData cylinder
+ *
+ * This class creates a mesh cylinder
+ */
+class Cylinder : public Shape
+{
+public:
+    Cylinder();
+    virtual ~Cylinder();
+
+    virtual const char *getClassName() const
+    {
+        return "Cylinder";
+    }
+
+    void setCenter(double center[3])
+    {
+        if (_cylinder != NULL) {
+            _cylinder->SetCenter(center);
+	}
+    }
+
+    void setHeight(double height)
+    {
+        if (_cylinder != NULL) {
+            _cylinder->SetHeight(height);
+	}
+    }
+
+    void setRadius(double radius)
+    {
+        if (_cylinder != NULL) {
+            _cylinder->SetRadius(radius);
+	}
+    }
+
+    void setResolution(int res)
+    {
+        if (_cylinder != NULL) {
+            _cylinder->SetResolution(res);
+	}
+    }
+
+    void setCapping(bool state)
+    {
+        if (_cylinder != NULL) {
+            _cylinder->SetCapping(state ? 1 : 0);
+	}
+    }
+
+private:
+    virtual void update();
+
+    vtkSmartPointer<vtkCylinderSource> _cylinder;
+};
+
+}
+
+#endif
Index: /trunk/packages/vizservers/vtkvis/Disk.cpp
===================================================================
--- /trunk/packages/vizservers/vtkvis/Disk.cpp	(revision 3616)
+++ /trunk/packages/vizservers/vtkvis/Disk.cpp	(revision 3616)
@@ -0,0 +1,45 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (C) 2004-2012  HUBzero Foundation, LLC
+ *
+ * Author: Leif Delgass <ldelgass@purdue.edu>
+ */
+
+#include <vtkPolyDataMapper.h>
+#include <vtkActor.h>
+#include <vtkDiskSource.h>
+
+#include "Disk.h"
+#include "Trace.h"
+
+using namespace VtkVis;
+
+Disk::Disk() :
+    Shape()
+{
+}
+
+Disk::~Disk()
+{
+    TRACE("Deleting Disk");
+}
+
+void Disk::update()
+{
+    if (_disk == NULL) {
+	_disk = vtkSmartPointer<vtkDiskSource>::New();
+    }
+
+    if (_pdMapper == NULL) {
+        _pdMapper = vtkSmartPointer<vtkPolyDataMapper>::New();
+        _pdMapper->SetResolveCoincidentTopologyToPolygonOffset();
+        _pdMapper->ScalarVisibilityOff();
+    }
+
+    _pdMapper->SetInputConnection(_disk->GetOutputPort());
+
+    initProp();
+
+    getActor()->SetMapper(_pdMapper);
+    _pdMapper->Update();
+}
Index: /trunk/packages/vizservers/vtkvis/Disk.h
===================================================================
--- /trunk/packages/vizservers/vtkvis/Disk.h	(revision 3616)
+++ /trunk/packages/vizservers/vtkvis/Disk.h	(revision 3616)
@@ -0,0 +1,61 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (C) 2004-2012  HUBzero Foundation, LLC
+ *
+ * Author: Leif Delgass <ldelgass@purdue.edu>
+ */
+
+#ifndef VTKVIS_DISK_H
+#define VTKVIS_DISK_H
+
+#include <vtkSmartPointer.h>
+#include <vtkPolyDataMapper.h>
+#include <vtkActor.h>
+#include <vtkDiskSource.h>
+
+#include "Shape.h"
+#include "VtkDataSet.h"
+
+namespace VtkVis {
+
+/**
+ * \brief VTK PolyData disk
+ *
+ * This class creates a mesh disk
+ */
+class Disk : public Shape
+{
+public:
+    Disk();
+    virtual ~Disk();
+
+    virtual const char *getClassName() const
+    {
+        return "Disk";
+    }
+
+    void setRadii(double inner, double outer)
+    {
+        if (_disk != NULL) {
+            _disk->SetInnerRadius(inner);
+	    _disk->SetOuterRadius(outer);
+	}
+    }
+
+    void setResolution(int radialRes, int circumRes)
+    {
+        if (_disk != NULL) {
+            _disk->SetRadialResolution(radialRes);
+	    _disk->SetCircumferentialResolution(circumRes);
+	}
+    }
+
+private:
+    virtual void update();
+
+    vtkSmartPointer<vtkDiskSource> _disk;
+};
+
+}
+
+#endif
Index: /trunk/packages/vizservers/vtkvis/Glyphs.cpp
===================================================================
--- /trunk/packages/vizservers/vtkvis/Glyphs.cpp	(revision 3616)
+++ /trunk/packages/vizservers/vtkvis/Glyphs.cpp	(revision 3616)
@@ -0,0 +1,750 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (C) 2004-2012  HUBzero Foundation, LLC
+ *
+ * Author: Leif Delgass <ldelgass@purdue.edu>
+ */
+
+#include <cstring>
+#include <cfloat>
+
+#include <vtkDataSet.h>
+#include <vtkPointData.h>
+#include <vtkCellData.h>
+#include <vtkCellDataToPointData.h>
+#include <vtkProp.h>
+#include <vtkActor.h>
+#include <vtkProperty.h>
+#include <vtkGlyph3D.h>
+#include <vtkLineSource.h>
+#include <vtkArrowSource.h>
+#include <vtkConeSource.h>
+#include <vtkCylinderSource.h>
+#include <vtkPlatonicSolidSource.h>
+#include <vtkSphereSource.h>
+#include <vtkTransform.h>
+#include <vtkPolyDataMapper.h>
+#include <vtkTransformPolyDataFilter.h>
+
+#include "Glyphs.h"
+#include "VtkRenderer.h"
+#include "Trace.h"
+
+using namespace VtkVis;
+
+Glyphs::Glyphs(GlyphShape shape) :
+    VtkGraphicsObject(),
+    _glyphShape(shape),
+    _scalingMode(SCALE_BY_VECTOR_MAGNITUDE),
+    _dataScale(1.0),
+    _scaleFactor(1.0),
+    _normalizeScale(true),
+    _colorMap(NULL),
+    _colorMode(COLOR_BY_SCALAR)
+{
+    _faceCulling = true;
+    _scalingFieldRange[0] = DBL_MAX;
+    _scalingFieldRange[1] = -DBL_MAX;
+    _colorFieldRange[0] = DBL_MAX;
+    _colorFieldRange[1] = -DBL_MAX;
+}
+
+Glyphs::~Glyphs()
+{
+#ifdef WANT_TRACE
+    if (_dataSet != NULL)
+        TRACE("Deleting Glyphs for %s", _dataSet->getName().c_str());
+    else
+        TRACE("Deleting Glyphs with NULL DataSet");
+#endif
+}
+
+void Glyphs::setDataSet(DataSet *dataSet,
+                        Renderer *renderer)
+{
+    if (_dataSet != dataSet) {
+        _dataSet = dataSet;
+
+        _renderer = renderer;
+
+        if (renderer->getUseCumulativeRange()) {
+            renderer->getCumulativeDataRange(_dataRange,
+                                             _dataSet->getActiveScalarsName(),
+                                             1);
+            renderer->getCumulativeDataRange(_vectorMagnitudeRange,
+                                             _dataSet->getActiveVectorsName(),
+                                             3);
+            for (int i = 0; i < 3; i++) {
+                renderer->getCumulativeDataRange(_vectorComponentRange[i],
+                                                 _dataSet->getActiveVectorsName(),
+                                                 3, i);
+            }
+        } else {
+            _dataSet->getScalarRange(_dataRange);
+            _dataSet->getVectorRange(_vectorMagnitudeRange);
+            for (int i = 0; i < 3; i++) {
+                _dataSet->getVectorRange(_vectorComponentRange[i], i);
+            }
+        }
+
+        update();
+    }
+}
+
+/**
+ * \brief Set the shape of the glyphs
+ */
+void Glyphs::setGlyphShape(GlyphShape shape)
+{
+    _glyphShape = shape;
+
+    // Note: using vtkTransformPolyDataFilter instead of the vtkGlyph3D's 
+    // SourceTransform because of a bug: vtkGlyph3D doesn't transform normals
+    // by the SourceTransform, so the lighting would be wrong
+
+    switch (_glyphShape) {
+    case LINE:
+        _glyphSource = vtkSmartPointer<vtkLineSource>::New();
+        break;
+    case ARROW: {
+        _glyphSource = vtkSmartPointer<vtkArrowSource>::New();
+        vtkSmartPointer<vtkArrowSource> arrow = vtkArrowSource::SafeDownCast(_glyphSource);
+        arrow->SetTipResolution(8);
+        arrow->SetShaftResolution(8);
+    }
+        break;
+    case CONE: {
+        _glyphSource = vtkSmartPointer<vtkConeSource>::New();
+        vtkSmartPointer<vtkConeSource> cone = vtkConeSource::SafeDownCast(_glyphSource);
+        cone->SetResolution(8);
+    }
+        break;
+    case CUBE:
+        _glyphSource = vtkSmartPointer<vtkPlatonicSolidSource>::New();
+        vtkPlatonicSolidSource::SafeDownCast(_glyphSource)->SetSolidTypeToCube();
+        break;
+    case CYLINDER: {
+        vtkSmartPointer<vtkCylinderSource> csource = vtkSmartPointer<vtkCylinderSource>::New();
+        csource->SetResolution(8);
+        _glyphSource = vtkSmartPointer<vtkTransformPolyDataFilter>::New();
+        _glyphSource->SetInputConnection(csource->GetOutputPort());
+        vtkSmartPointer<vtkTransform> trans = vtkSmartPointer<vtkTransform>::New();
+        trans->RotateZ(-90.0);
+        vtkTransformPolyDataFilter::SafeDownCast(_glyphSource)->SetTransform(trans);
+      }
+        break;
+    case DODECAHEDRON:
+        _glyphSource = vtkSmartPointer<vtkPlatonicSolidSource>::New();
+        vtkPlatonicSolidSource::SafeDownCast(_glyphSource)->SetSolidTypeToDodecahedron();
+        break;
+    case ICOSAHEDRON:
+        _glyphSource = vtkSmartPointer<vtkPlatonicSolidSource>::New();
+        vtkPlatonicSolidSource::SafeDownCast(_glyphSource)->SetSolidTypeToIcosahedron();
+        break;
+    case OCTAHEDRON:
+        _glyphSource = vtkSmartPointer<vtkPlatonicSolidSource>::New();
+        vtkPlatonicSolidSource::SafeDownCast(_glyphSource)->SetSolidTypeToOctahedron();
+        break;
+    case SPHERE: {
+        _glyphSource = vtkSmartPointer<vtkSphereSource>::New();
+        vtkSmartPointer<vtkSphereSource> sphere = vtkSphereSource::SafeDownCast(_glyphSource);
+        sphere->SetThetaResolution(14);
+        sphere->SetPhiResolution(14);
+    }
+        break;
+    case TETRAHEDRON:
+        // FIXME: need to rotate inital orientation
+        _glyphSource = vtkSmartPointer<vtkPlatonicSolidSource>::New();
+        vtkPlatonicSolidSource::SafeDownCast(_glyphSource)->SetSolidTypeToTetrahedron();
+        break;
+    default:
+        ERROR("Unknown glyph shape: %d", _glyphShape);
+        return;
+    }
+
+    if (_glyphShape == ICOSAHEDRON ||
+        _glyphShape == TETRAHEDRON) {
+        // These shapes are created with front faces pointing inside
+        setCullFace(CULL_FRONT);
+    } else {
+        setCullFace(CULL_BACK);
+    }
+
+    if (_glyphMapper != NULL) {
+        _glyphMapper->SetSourceConnection(_glyphSource->GetOutputPort());
+    }
+
+    //setQuality(0.8);
+}
+
+void Glyphs::setQuality(double quality)
+{
+    switch (_glyphShape) {
+    case ARROW: {
+        vtkSmartPointer<vtkArrowSource> arrow = vtkArrowSource::SafeDownCast(_glyphSource);
+        int res = (int)(quality * 25);
+        if (res < 5) res = 5;
+        arrow->SetTipResolution(res);
+        arrow->SetShaftResolution(res);
+    }
+        break;
+    case CONE: {
+        vtkSmartPointer<vtkConeSource> cone = vtkConeSource::SafeDownCast(_glyphSource);
+        int res = (int)(quality * 25);
+        if (res < 5) res = 5;
+        cone->SetResolution(res);
+    }
+        break;
+    case SPHERE: {
+        vtkSmartPointer<vtkSphereSource> sphere = vtkSphereSource::SafeDownCast(_glyphSource);
+        int res = (int)(quality * 50);
+        if (res < 5) res = 5;
+        sphere->SetThetaResolution(res);
+        sphere->SetPhiResolution(res);
+    }
+        break;
+    case CYLINDER: {
+        assert(vtkTransformPolyDataFilter::SafeDownCast(_glyphSource) != NULL);
+        assert(vtkTransformPolyDataFilter::SafeDownCast(_glyphSource)->GetInputConnection(0, 0) != NULL);
+        vtkSmartPointer<vtkCylinderSource> csource = vtkCylinderSource::SafeDownCast(vtkTransformPolyDataFilter::SafeDownCast(_glyphSource)->GetInputConnection(0, 0));
+        int res = (int)(quality * 25);
+        if (res < 5) res = 5;
+        csource->SetResolution(res);
+    }
+        break;
+    default:
+        break;
+    }
+}
+
+/**
+ * \brief Internal method to set up pipeline after a state change
+ */
+void Glyphs::update()
+{
+    if (_dataSet == NULL) {
+        return;
+    }
+
+    vtkDataSet *ds = _dataSet->getVtkDataSet();
+
+    if (_glyphMapper == NULL) {
+        _glyphMapper = vtkSmartPointer<vtkGlyph3DMapper>::New();
+        _glyphMapper->SetResolveCoincidentTopologyToPolygonOffset();
+        _glyphMapper->ScalarVisibilityOn();
+    }
+
+    initProp();
+
+    setGlyphShape(_glyphShape);
+
+    vtkSmartPointer<vtkCellDataToPointData> cellToPtData;
+
+    if (ds->GetPointData() == NULL ||
+        ds->GetPointData()->GetScalars() == NULL) {
+        if (ds->GetCellData() != NULL &&
+            ds->GetCellData()->GetScalars() != NULL) {
+            TRACE("Generating point data scalars from cell data for: %s", _dataSet->getName().c_str());
+            cellToPtData = 
+                vtkSmartPointer<vtkCellDataToPointData>::New();
+#ifdef USE_VTK6
+            cellToPtData->SetInputData(ds);
+#else
+            cellToPtData->SetInput(ds);
+#endif
+            //cellToPtData->PassCellDataOn();
+            cellToPtData->Update();
+            ds = cellToPtData->GetOutput();
+        } else {
+            TRACE("No scalar data in dataset %s", _dataSet->getName().c_str());
+        }
+    }
+
+#ifdef USE_VTK6
+    _glyphMapper->SetInputData(ds);
+#else
+    _glyphMapper->SetInputConnection(ds->GetProducerPort());
+#endif
+
+    if (ds->GetPointData()->GetVectors() != NULL) {
+        TRACE("Setting scale mode to vector magnitude");
+        setScalingMode(SCALE_BY_VECTOR_MAGNITUDE);
+    } else {
+        TRACE("Setting scale mode to scalar");
+        setScalingMode(SCALE_BY_SCALAR);
+    }
+
+    double cellSizeRange[2];
+    double avgSize;
+    _dataSet->getCellSizeRange(cellSizeRange, &avgSize);
+    //_dataScale = cellSizeRange[0] + (cellSizeRange[1] - cellSizeRange[0])/2.;
+    _dataScale = avgSize;
+
+    TRACE("Cell size range: %g,%g, Data scale factor: %g",
+          cellSizeRange[0], cellSizeRange[1], _dataScale);
+
+    // Normalize sizes to [0,1] * ScaleFactor
+    _glyphMapper->SetClamping(_normalizeScale ? 1 : 0);
+    _glyphMapper->SetScaleFactor(_scaleFactor * _dataScale);
+    _glyphMapper->ScalingOn();
+
+    if (_lut == NULL) {
+        setColorMap(ColorMap::getDefault());
+    }
+
+    if (ds->GetPointData()->GetScalars() == NULL) {
+        TRACE("Setting color mode to vector magnitude");
+        setColorMode(COLOR_BY_VECTOR_MAGNITUDE);
+    } else {
+        TRACE("Setting color mode to scalar");
+        setColorMode(COLOR_BY_SCALAR);
+    }
+
+    getActor()->SetMapper(_glyphMapper);
+    _glyphMapper->Update();
+}
+
+/** 
+ * \brief Control if field data range is normalized to [0,1] before
+ * applying scale factor
+ */
+void Glyphs::setNormalizeScale(bool normalize)
+{
+    if (_normalizeScale != normalize) {
+        _normalizeScale = normalize;
+        if (_glyphMapper != NULL) {
+            _glyphMapper->SetClamping(_normalizeScale ? 1 : 0);
+        }
+    }
+}
+
+/**
+ * \brief Turn on/off orienting glyphs from a vector field
+ */
+void Glyphs::setOrientMode(bool mode, const char *name)
+{
+    if (_glyphMapper != NULL) {
+        _glyphMapper->SetOrient(mode ? 1 : 0);
+        if (name != NULL && strlen(name) > 0) {
+            _glyphMapper->SetOrientationArray(name);
+        } else {
+            _glyphMapper->SetOrientationArray(vtkDataSetAttributes::VECTORS);
+        }
+    }
+}
+
+/**
+ * \brief Control how glyphs are scaled
+ */
+void Glyphs::setScalingMode(ScalingMode mode, const char *name, double range[2])
+{
+    _scalingMode = mode;
+
+    if (_dataSet == NULL || _glyphMapper == NULL)
+        return;
+
+    if (name != NULL && strlen(name) > 0) {
+        if (!_dataSet->hasField(name, DataSet::POINT_DATA)) {
+            ERROR("Field not found: %s", name);
+            return;
+        }
+        _scalingFieldName = name;
+    } else
+        _scalingFieldName.clear();
+    if (range == NULL) {
+        _scalingFieldRange[0] = DBL_MAX;
+        _scalingFieldRange[1] = -DBL_MAX;
+    } else {
+        memcpy(_scalingFieldRange, range, sizeof(double)*2);
+    }
+
+    if (name != NULL && strlen(name) > 0) {
+        _glyphMapper->SetScaleArray(name);
+    } else {
+        if (mode == SCALE_BY_SCALAR) {
+            _glyphMapper->SetScaleArray(vtkDataSetAttributes::SCALARS);
+        } else {
+            _glyphMapper->SetScaleArray(vtkDataSetAttributes::VECTORS);
+        }
+    }
+
+    if (range != NULL) {
+        TRACE("Setting size range to: %g,%g", range[0], range[1]);
+        _glyphMapper->SetRange(range);
+    } else if (name != NULL && strlen(name) > 0) {
+        double r[2];
+        DataSet::DataAttributeType type = DataSet::POINT_DATA;
+        int comp = -1;
+
+        if (_renderer->getUseCumulativeRange()) {
+            int numComponents;
+            if  (!_dataSet->getFieldInfo(name, type, &numComponents)) {
+                ERROR("Field not found: %s, type: %d", name, type);
+                return;
+            } else if (mode == SCALE_BY_VECTOR_COMPONENTS && numComponents < 3) {
+                ERROR("Field %s needs 3 components but has only %d components",
+                      name, numComponents);
+                return;
+            }
+            if (mode == SCALE_BY_VECTOR_COMPONENTS) {
+                double tmpR[2];
+                _renderer->getCumulativeDataRange(tmpR, name, type, numComponents, 0);
+                r[0] = tmpR[0];
+                r[1] = tmpR[1];
+                _renderer->getCumulativeDataRange(tmpR, name, type, numComponents, 1);
+                r[0] = min2(r[0], tmpR[0]);
+                r[1] = max2(r[1], tmpR[1]);
+                _renderer->getCumulativeDataRange(tmpR, name, type, numComponents, 2);
+                r[0] = min2(r[0], tmpR[0]);
+                r[1] = max2(r[1], tmpR[1]);
+            } else {
+                _renderer->getCumulativeDataRange(r, name, type, numComponents, comp);
+            }
+        } else {
+            if (mode == SCALE_BY_VECTOR_COMPONENTS) {
+                double tmpR[2];
+                _dataSet->getDataRange(tmpR, name, type, 0);
+                r[0] = tmpR[0];
+                r[1] = tmpR[1];
+                _dataSet->getDataRange(tmpR, name, type, 1);
+                r[0] = min2(r[0], tmpR[0]);
+                r[1] = max2(r[1], tmpR[1]);
+                _dataSet->getDataRange(tmpR, name, type, 2);
+                r[0] = min2(r[0], tmpR[0]);
+                r[1] = max2(r[1], tmpR[1]);
+            } else {
+                _dataSet->getDataRange(r, name, type, comp);
+            }
+        }
+        TRACE("Setting size range to: %g,%g", r[0], r[1]);
+        _glyphMapper->SetRange(r);
+    } else {
+        switch (mode) {
+        case SCALE_BY_SCALAR:
+            TRACE("Setting size range to: %g,%g", _dataRange[0], _dataRange[1]);
+            _glyphMapper->SetRange(_dataRange);
+            break;
+        case SCALE_BY_VECTOR_MAGNITUDE:
+            TRACE("Setting size range to: %g,%g", _vectorMagnitudeRange[0], _vectorMagnitudeRange[1]);
+            _glyphMapper->SetRange(_vectorMagnitudeRange);
+            break;
+        case SCALE_BY_VECTOR_COMPONENTS: {
+            double sizeRange[2];
+            sizeRange[0] = _vectorComponentRange[0][0];
+            sizeRange[1] = _vectorComponentRange[0][1];
+            sizeRange[0] = min2(sizeRange[0], _vectorComponentRange[1][0]);
+            sizeRange[1] = max2(sizeRange[1], _vectorComponentRange[1][1]);
+            sizeRange[0] = min2(sizeRange[0], _vectorComponentRange[2][0]);
+            sizeRange[1] = max2(sizeRange[1], _vectorComponentRange[2][1]);
+            TRACE("Setting size range to: %g,%g", sizeRange[0], sizeRange[1]);
+            _glyphMapper->SetRange(sizeRange);
+        }
+            break;
+        case SCALING_OFF:
+        default:
+            ;
+        }
+    }
+
+    switch (mode) {
+    case SCALE_BY_SCALAR:
+    case SCALE_BY_VECTOR_MAGNITUDE:
+        _glyphMapper->SetScaleModeToScaleByMagnitude();
+        break;
+    case SCALE_BY_VECTOR_COMPONENTS:
+        _glyphMapper->SetScaleModeToScaleByVectorComponents();
+        break;
+    case SCALING_OFF:
+    default:
+        _glyphMapper->SetScaleModeToNoDataScaling();
+    }
+}
+
+void Glyphs::setScalingMode(ScalingMode mode)
+{
+    setScalingMode(mode, NULL, NULL);
+}
+
+void Glyphs::setColorMode(ColorMode mode,
+                          const char *name, double range[2])
+{
+    _colorMode = mode;
+    if (name == NULL)
+        _colorFieldName.clear();
+    else
+        _colorFieldName = name;
+    if (range == NULL) {
+        _colorFieldRange[0] = DBL_MAX;
+        _colorFieldRange[1] = -DBL_MAX;
+    } else {
+        memcpy(_colorFieldRange, range, sizeof(double)*2);
+    }
+
+    if (_dataSet == NULL || _glyphMapper == NULL)
+        return;
+
+    if (name != NULL && strlen(name) > 0) {
+        _glyphMapper->SetScalarModeToUsePointFieldData();
+        _glyphMapper->SelectColorArray(name);
+    } else {
+        _glyphMapper->SetScalarModeToDefault();
+    }
+
+    if (_lut != NULL) {
+        if (range != NULL) {
+            _lut->SetRange(range);
+        } else if (name != NULL && strlen(name) > 0) {
+            double r[2];
+            int comp = -1;
+            if (mode == COLOR_BY_VECTOR_X)
+                comp = 0;
+            else if (mode == COLOR_BY_VECTOR_Y)
+                comp = 1;
+            else if (mode == COLOR_BY_VECTOR_Z)
+                comp = 2;
+
+            DataSet::DataAttributeType type = DataSet::POINT_DATA;
+
+            if (_renderer->getUseCumulativeRange()) {
+                int numComponents;
+                if  (!_dataSet->getFieldInfo(name, type, &numComponents)) {
+                    ERROR("Field not found: %s, type: %d", name, type);
+                    return;
+                } else if (numComponents < comp+1) {
+                    ERROR("Request for component %d in field with %d components",
+                          comp, numComponents);
+                    return;
+                }
+                _renderer->getCumulativeDataRange(r, name, type, numComponents, comp);
+            } else {
+                _dataSet->getDataRange(r, name, type, comp);
+            }
+            TRACE("Setting lut range to: %g,%g", r[0], r[1]);
+            _lut->SetRange(r);
+        }
+    }
+
+    switch (mode) {
+    case COLOR_BY_SCALAR:
+        _glyphMapper->ScalarVisibilityOn();
+        break;
+    case COLOR_BY_VECTOR_MAGNITUDE:
+        _glyphMapper->ScalarVisibilityOn();
+        if (_lut != NULL) {
+            _lut->SetVectorModeToMagnitude();
+        }
+        break;
+    case COLOR_BY_VECTOR_X:
+        _glyphMapper->ScalarVisibilityOn();
+        if (_lut != NULL) {
+            _lut->SetVectorModeToComponent();
+            _lut->SetVectorComponent(0);
+        }
+        break;
+    case COLOR_BY_VECTOR_Y:
+        _glyphMapper->ScalarVisibilityOn();
+        if (_lut != NULL) {
+            _lut->SetVectorModeToComponent();
+            _lut->SetVectorComponent(1);
+        }
+        break;
+    case COLOR_BY_VECTOR_Z:
+        _glyphMapper->ScalarVisibilityOn();
+        if (_lut != NULL) {
+            _lut->SetVectorModeToComponent();
+            _lut->SetVectorComponent(2);
+        }
+        break;
+    case COLOR_CONSTANT:
+    default:
+        _glyphMapper->ScalarVisibilityOff();
+        break;
+    }
+}
+
+void Glyphs::setColorMode(ColorMode mode)
+{
+    _colorMode = mode;
+    if (_dataSet == NULL)
+        return;
+
+    switch (mode) {
+    case COLOR_BY_SCALAR:
+        setColorMode(mode,
+                     _dataSet->getActiveScalarsName(),
+                     _dataRange);
+        break;
+    case COLOR_BY_VECTOR_MAGNITUDE:
+        setColorMode(mode,
+                     _dataSet->getActiveVectorsName(),
+                     _vectorMagnitudeRange);
+        break;
+    case COLOR_BY_VECTOR_X:
+        setColorMode(mode,
+                     _dataSet->getActiveVectorsName(),
+                     _vectorComponentRange[0]);
+        break;
+    case COLOR_BY_VECTOR_Y:
+        setColorMode(mode,
+                     _dataSet->getActiveVectorsName(),
+                     _vectorComponentRange[1]);
+        break;
+    case COLOR_BY_VECTOR_Z:
+        setColorMode(mode,
+                     _dataSet->getActiveVectorsName(),
+                     _vectorComponentRange[2]);
+        break;
+    case COLOR_CONSTANT:
+    default:
+        setColorMode(mode, NULL, NULL);
+        break;
+    }
+}
+
+/**
+ * \brief Turn on/off orienting glyphs from a vector field
+ */
+void Glyphs::setOrient(bool state)
+{
+    if (_glyphMapper != NULL) {
+        _glyphMapper->SetOrient(state ? 1 : 0);
+    }
+}
+
+/**
+ * \brief Controls relative scaling of glyphs
+ */
+void Glyphs::setScaleFactor(double scale)
+{
+    _scaleFactor = scale;
+    if (_glyphMapper != NULL) {
+        _glyphMapper->SetScaleFactor(_scaleFactor * _dataScale);
+    }
+}
+
+void Glyphs::updateRanges(Renderer *renderer)
+{
+    if (_dataSet == NULL) {
+        ERROR("called before setDataSet");
+        return;
+    }
+
+    if (renderer->getUseCumulativeRange()) {
+        renderer->getCumulativeDataRange(_dataRange,
+                                         _dataSet->getActiveScalarsName(),
+                                         1);
+        renderer->getCumulativeDataRange(_vectorMagnitudeRange,
+                                         _dataSet->getActiveVectorsName(),
+                                         3);
+        for (int i = 0; i < 3; i++) {
+            renderer->getCumulativeDataRange(_vectorComponentRange[i],
+                                             _dataSet->getActiveVectorsName(),
+                                             3, i);
+        }
+    } else {
+        _dataSet->getScalarRange(_dataRange);
+        _dataSet->getVectorRange(_vectorMagnitudeRange);
+        for (int i = 0; i < 3; i++) {
+            _dataSet->getVectorRange(_vectorComponentRange[i], i);
+        }
+    }
+
+    // Need to update color map ranges and/or active vector field
+    double *rangePtr = _colorFieldRange;
+    if (_colorFieldRange[0] > _colorFieldRange[1]) {
+        rangePtr = NULL;
+    }
+    setColorMode(_colorMode, _colorFieldName.c_str(), rangePtr);
+
+    rangePtr = _scalingFieldRange;
+    if (_scalingFieldRange[0] > _scalingFieldRange[1]) {
+        rangePtr = NULL;
+    }
+    setScalingMode(_scalingMode, _scalingFieldName.c_str(), rangePtr);
+}
+
+/**
+ * \brief Called when the color map has been edited
+ */
+void Glyphs::updateColorMap()
+{
+    setColorMap(_colorMap);
+}
+
+/**
+ * \brief Associate a colormap lookup table with the DataSet
+ */
+void Glyphs::setColorMap(ColorMap *cmap)
+{
+    if (cmap == NULL)
+        return;
+
+    _colorMap = cmap;
+ 
+    if (_lut == NULL) {
+        _lut = vtkSmartPointer<vtkLookupTable>::New();
+        if (_glyphMapper != NULL) {
+            _glyphMapper->UseLookupTableScalarRangeOn();
+            _glyphMapper->SetLookupTable(_lut);
+        }
+        _lut->DeepCopy(cmap->getLookupTable());
+        switch (_colorMode) {
+        case COLOR_CONSTANT:
+        case COLOR_BY_SCALAR:
+            _lut->SetRange(_dataRange);
+            break;
+        case COLOR_BY_VECTOR_MAGNITUDE:
+            _lut->SetRange(_vectorMagnitudeRange);
+            break;
+        case COLOR_BY_VECTOR_X:
+            _lut->SetRange(_vectorComponentRange[0]);
+            break;
+        case COLOR_BY_VECTOR_Y:
+            _lut->SetRange(_vectorComponentRange[1]);
+            break;
+        case COLOR_BY_VECTOR_Z:
+            _lut->SetRange(_vectorComponentRange[2]);
+            break;
+        default:
+            break;
+        }
+    } else {
+        double range[2];
+        _lut->GetTableRange(range);
+        _lut->DeepCopy(cmap->getLookupTable());
+        _lut->SetRange(range);
+        _lut->Modified();
+    }
+
+    switch (_colorMode) {
+    case COLOR_BY_VECTOR_MAGNITUDE:
+        _lut->SetVectorModeToMagnitude();
+        break;
+    case COLOR_BY_VECTOR_X:
+        _lut->SetVectorModeToComponent();
+        _lut->SetVectorComponent(0);
+        break;
+    case COLOR_BY_VECTOR_Y:
+        _lut->SetVectorModeToComponent();
+        _lut->SetVectorComponent(1);
+        break;
+    case COLOR_BY_VECTOR_Z:
+        _lut->SetVectorModeToComponent();
+        _lut->SetVectorComponent(2);
+        break;
+    default:
+        break;
+    }
+}
+
+/**
+ * \brief Set a group of world coordinate planes to clip rendering
+ *
+ * Passing NULL for planes will remove all cliping planes
+ */
+void Glyphs::setClippingPlanes(vtkPlaneCollection *planes)
+{
+    if (_glyphMapper != NULL) {
+        _glyphMapper->SetClippingPlanes(planes);
+    }
+}
Index: /trunk/packages/vizservers/vtkvis/Glyphs.h
===================================================================
--- /trunk/packages/vizservers/vtkvis/Glyphs.h	(revision 3616)
+++ /trunk/packages/vizservers/vtkvis/Glyphs.h	(revision 3616)
@@ -0,0 +1,141 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (C) 2004-2012  HUBzero Foundation, LLC
+ *
+ * Author: Leif Delgass <ldelgass@purdue.edu>
+ */
+
+#ifndef VTKVIS_GLYPHS_H
+#define VTKVIS_GLYPHS_H
+
+#include <vector>
+
+#include <vtkSmartPointer.h>
+#include <vtkProp.h>
+#include <vtkActor.h>
+#include <vtkVersion.h>
+#include <vtkGlyph3DMapper.h>
+#include <vtkLookupTable.h>
+#include <vtkPlaneCollection.h>
+
+#include "VtkGraphicsObject.h"
+#include "ColorMap.h"
+
+namespace VtkVis {
+
+/**
+ * \brief Oriented and scaled 3D glyph shapes
+ *
+ * The DataSet must have vectors and/or scalars
+ */
+class Glyphs : public VtkGraphicsObject {
+public:
+    enum GlyphShape {
+        ARROW,
+        CONE,
+        CUBE,
+        CYLINDER,
+        DODECAHEDRON,
+        ICOSAHEDRON,
+        LINE,
+        OCTAHEDRON,
+        SPHERE,
+        TETRAHEDRON
+    };
+    enum ScalingMode {
+        SCALE_BY_SCALAR,
+        SCALE_BY_VECTOR_MAGNITUDE,
+        SCALE_BY_VECTOR_COMPONENTS,
+        SCALING_OFF
+    };
+    enum ColorMode {
+        COLOR_BY_SCALAR,
+        COLOR_BY_VECTOR_MAGNITUDE,
+        COLOR_BY_VECTOR_X,
+        COLOR_BY_VECTOR_Y,
+        COLOR_BY_VECTOR_Z,
+        COLOR_CONSTANT
+    };
+
+    Glyphs(GlyphShape shape);
+    virtual ~Glyphs();
+
+    virtual const char *getClassName() const
+    {
+        return "Glyphs";
+    }
+
+    virtual void setDataSet(DataSet *dataSet,
+                            Renderer *renderer);
+
+    virtual void setClippingPlanes(vtkPlaneCollection *planes);
+
+    void setQuality(double quality);
+
+    void setOrient(bool state);
+
+    void setOrientMode(bool mode, const char *name);
+
+    void setScalingMode(ScalingMode mode, const char *name, double range[2]);
+
+    void setColorMode(ColorMode mode, const char *name, double range[2]);
+
+    void setScalingMode(ScalingMode mode);
+
+    void setNormalizeScale(bool normalize);
+
+    void setColorMode(ColorMode mode);
+
+    void setGlyphShape(GlyphShape shape);
+
+    void setScaleFactor(double scale);
+
+    void setColorMap(ColorMap *colorMap);
+
+    /**
+     * \brief Return the ColorMap in use
+     */
+    ColorMap *getColorMap()
+    {
+        return _colorMap;
+    }
+
+    void updateColorMap();
+
+    virtual void updateRanges(Renderer *renderer);
+
+private:
+    Glyphs();
+    virtual void update();
+    static inline double min2(double a, double b)
+    {
+        return ((a < b) ? a : b);
+    }
+    static inline double max2(double a, double b)
+    {
+        return ((a > b) ? a : b);
+    }
+
+    GlyphShape _glyphShape;
+    ScalingMode _scalingMode;
+    std::string _scalingFieldName;
+    double _scalingFieldRange[2];
+    double _dataScale;
+    double _scaleFactor;
+    bool _normalizeScale;
+    ColorMap *_colorMap;
+    ColorMode _colorMode;
+    std::string _colorFieldName;
+    double _colorFieldRange[2];
+    double _vectorMagnitudeRange[2];
+    double _vectorComponentRange[3][2];
+    Renderer *_renderer;
+
+    vtkSmartPointer<vtkLookupTable> _lut;
+    vtkSmartPointer<vtkPolyDataAlgorithm> _glyphSource;
+    vtkSmartPointer<vtkGlyph3DMapper> _glyphMapper;
+};
+
+}
+
+#endif
Index: /trunk/packages/vizservers/vtkvis/Group.cpp
===================================================================
--- /trunk/packages/vizservers/vtkvis/Group.cpp	(revision 3616)
+++ /trunk/packages/vizservers/vtkvis/Group.cpp	(revision 3616)
@@ -0,0 +1,81 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (C) 2004-2012  HUBzero Foundation, LLC
+ *
+ * Author: Leif Delgass <ldelgass@purdue.edu>
+ */
+
+#include "Group.h"
+#include "Trace.h"
+
+using namespace VtkVis;
+
+Group::Group()
+{
+}
+
+Group::~Group()
+{
+}
+
+/**
+ * \brief Create and initialize VTK Props to render the Group
+ */
+void Group::initProp()
+{
+    if (_prop == NULL) {
+        _prop = vtkSmartPointer<vtkAssembly>::New();
+    }
+}
+
+void Group::update()
+{
+    initProp();
+}
+
+void Group::addChild(const NodeId& name, VtkGraphicsObject *obj)
+{
+    if (obj == NULL)
+        return;
+    if (obj->getProp3D() != NULL) {
+        getAssembly()->AddPart(obj->getProp3D());
+    }
+    _nodes[name] = obj;
+}
+
+VtkGraphicsObject *Group::getChild(const NodeId& name)
+{
+    NodeHashmap::iterator itr = _nodes.find(name);
+    if (itr == _nodes.end()) {
+        return NULL;
+    } else {
+        return itr->second;
+    }
+}
+
+void Group::removeChild(const NodeId& name)
+{
+    NodeHashmap::iterator itr = _nodes.find(name);
+    if (itr == _nodes.end()) {
+        ERROR("Node not found: '%s'", name.c_str());
+        return;
+    }
+    VtkGraphicsObject *obj = itr->second;
+    if (obj->getProp3D() != NULL) {
+        getAssembly()->RemovePart(obj->getProp3D());
+    }
+    _nodes.erase(itr);
+}
+
+/**
+ * \brief Set a group of world coordinate planes to clip rendering
+ *
+ * Passing NULL for planes will remove all cliping planes
+ */
+void Group::setClippingPlanes(vtkPlaneCollection *planes)
+{
+    for (NodeHashmap::iterator itr = _nodes.begin();
+         itr != _nodes.end(); ++itr) {
+        itr->second->setClippingPlanes(planes);
+    }
+}
Index: /trunk/packages/vizservers/vtkvis/Group.h
===================================================================
--- /trunk/packages/vizservers/vtkvis/Group.h	(revision 3616)
+++ /trunk/packages/vizservers/vtkvis/Group.h	(revision 3616)
@@ -0,0 +1,68 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (C) 2004-2012  HUBzero Foundation, LLC
+ *
+ * Author: Leif Delgass <ldelgass@purdue.edu>
+ */
+
+#ifndef VTKVIS_GROUP_H
+#define VTKVIS_GROUP_H
+
+#include <tr1/unordered_map>
+
+#include <vtkProp3D.h>
+
+#include "VtkGraphicsObject.h"
+
+namespace VtkVis {
+
+/**
+ * \brief Collection of shapes with grouping
+ */
+class Group : public VtkGraphicsObject {
+public:
+    typedef std::string NodeId;
+    typedef std::tr1::unordered_map<NodeId, VtkGraphicsObject *> NodeHashmap;
+
+    Group();
+    virtual ~Group();
+
+    virtual const char *getClassName() const 
+    {
+        return "Group";
+    }
+
+    virtual void setDataSet(DataSet *dataSet,
+                            Renderer *renderer)
+    {
+        assert(dataSet == NULL);
+        update();
+    }
+
+    virtual void setClippingPlanes(vtkPlaneCollection *planes);
+
+    void addChild(const NodeId& name, VtkGraphicsObject *obj);
+
+    VtkGraphicsObject *getChild(const NodeId& name);
+
+    void getChildren(std::vector<VtkGraphicsObject *>& children)
+    {
+        for (NodeHashmap::iterator itr = _nodes.begin();
+             itr != _nodes.end(); ++itr) {
+            children.push_back(itr->second);
+        }
+    }
+
+    void removeChild(const NodeId& name);
+
+private:
+    virtual void initProp();
+
+    virtual void update();
+
+    NodeHashmap _nodes;
+};
+
+}
+
+#endif
Index: /trunk/packages/vizservers/vtkvis/HeightMap.cpp
===================================================================
--- /trunk/packages/vizservers/vtkvis/HeightMap.cpp	(revision 3616)
+++ /trunk/packages/vizservers/vtkvis/HeightMap.cpp	(revision 3616)
@@ -0,0 +1,1345 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (C) 2004-2012  HUBzero Foundation, LLC
+ *
+ * Author: Leif Delgass <ldelgass@purdue.edu>
+ */
+
+#include <cassert>
+
+#include <vtkDataSet.h>
+#include <vtkPointData.h>
+#include <vtkCellData.h>
+#include <vtkCellDataToPointData.h>
+#include <vtkDataSetMapper.h>
+#include <vtkPolyDataMapper.h>
+#include <vtkUnstructuredGrid.h>
+#include <vtkProperty.h>
+#include <vtkImageData.h>
+#include <vtkLookupTable.h>
+#include <vtkTransform.h>
+#include <vtkDelaunay2D.h>
+#include <vtkDelaunay3D.h>
+#include <vtkGaussianSplatter.h>
+#include <vtkExtractVOI.h>
+#include <vtkDataSetSurfaceFilter.h>
+#include <vtkContourFilter.h>
+#include <vtkStripper.h>
+#include <vtkWarpScalar.h>
+#include <vtkPropAssembly.h>
+#include <vtkCutter.h>
+#include <vtkPlane.h>
+
+#include "HeightMap.h"
+#include "VtkRenderer.h"
+#include "Trace.h"
+
+using namespace VtkVis;
+
+#define MESH_POINT_CLOUDS
+#define TRANSLATE_TO_ZORIGIN
+
+HeightMap::HeightMap(int numContours, double heightScale) :
+    VtkGraphicsObject(),
+    _numContours(numContours),
+    _contourColorMap(false),
+    _contourEdgeWidth(1.0),
+    _warpScale(heightScale),
+    _sliceAxis(Z_AXIS),
+    _pipelineInitialized(false),
+    _colorMap(NULL),
+    _colorMode(COLOR_BY_SCALAR),
+    _colorFieldType(DataSet::POINT_DATA),
+    _renderer(NULL)
+{
+    _contourEdgeColor[0] = 0.0f;
+    _contourEdgeColor[1] = 0.0f;
+    _contourEdgeColor[2] = 0.0f;
+    _colorFieldRange[0] = DBL_MAX;
+    _colorFieldRange[1] = -DBL_MAX;
+}
+
+HeightMap::HeightMap(const std::vector<double>& contours, double heightScale) :
+    VtkGraphicsObject(),
+    _numContours(contours.size()),
+    _contours(contours),
+    _contourColorMap(false),
+    _contourEdgeWidth(1.0),
+    _warpScale(heightScale),
+    _sliceAxis(Z_AXIS),
+    _pipelineInitialized(false),
+    _colorMap(NULL),
+    _colorMode(COLOR_BY_SCALAR),
+    _colorFieldType(DataSet::POINT_DATA),
+    _renderer(NULL)
+{
+    _contourEdgeColor[0] = 0.0f;
+    _contourEdgeColor[1] = 0.0f;
+    _contourEdgeColor[2] = 0.0f;
+    _colorFieldRange[0] = DBL_MAX;
+    _colorFieldRange[1] = -DBL_MAX;
+}
+
+HeightMap::~HeightMap()
+{
+#ifdef WANT_TRACE
+    if (_dataSet != NULL)
+        TRACE("Deleting HeightMap for %s", _dataSet->getName().c_str());
+    else
+        TRACE("Deleting HeightMap with NULL DataSet");
+#endif
+}
+
+void HeightMap::setDataSet(DataSet *dataSet,
+                           Renderer *renderer)
+{
+    if (_dataSet != dataSet) {
+        _dataSet = dataSet;
+        _renderer = renderer;
+
+        if (_dataSet != NULL) {
+            TRACE("DataSet name: '%s' type: %s",
+                  _dataSet->getName().c_str(),
+                  _dataSet->getVtkType());
+
+            if (renderer->getUseCumulativeRange()) {
+                renderer->getCumulativeDataRange(_dataRange,
+                                                 _dataSet->getActiveScalarsName(),
+                                                 1);
+                const char *activeVectors = _dataSet->getActiveVectorsName();
+                if (activeVectors != NULL) {
+                    renderer->getCumulativeDataRange(_vectorMagnitudeRange,
+                                                     activeVectors,
+                                                     3);
+                    for (int i = 0; i < 3; i++) {
+                        renderer->getCumulativeDataRange(_vectorComponentRange[i],
+                                                         activeVectors,
+                                                         3, i);
+                    }
+                }
+            } else {
+                _dataSet->getScalarRange(_dataRange);
+                _dataSet->getVectorRange(_vectorMagnitudeRange);
+                for (int i = 0; i < 3; i++) {
+                    _dataSet->getVectorRange(_vectorComponentRange[i], i);
+                }
+            }
+        }
+
+        update();
+    }
+}
+
+/**
+ * Compute a data scaling factor to make maximum height (at default _warpScale) 
+ * equivalent to largest dimension of data set
+ */
+void HeightMap::computeDataScale()
+{
+    if (_dataSet == NULL)
+        return;
+
+    double bounds[6];
+    double boundsRange = 0.0;
+    _dataSet->getBounds(bounds);
+    for (int i = 0; i < 6; i+=2) {
+        double r = bounds[i+1] - bounds[i];
+        if (r > boundsRange)
+            boundsRange = r;
+    }
+    double datRange = _dataRange[1] - _dataRange[0];
+    if (datRange < 1.0e-17) {
+        _dataScale = 1.0;
+    } else {
+        _dataScale = boundsRange / datRange;
+    }
+    TRACE("Bounds range: %g data range: %g scaling: %g",
+          boundsRange, datRange, _dataScale);
+}
+
+/**
+ * \brief Create and initialize VTK Props to render the colormapped dataset
+ */
+void HeightMap::initProp()
+{
+    if (_dsActor == NULL) {
+        _dsActor = vtkSmartPointer<vtkActor>::New();
+        _dsActor->GetProperty()->SetOpacity(_opacity);
+        _dsActor->GetProperty()->SetColor(_color[0],
+                                          _color[1],
+                                          _color[2]);
+        _dsActor->GetProperty()->SetEdgeColor(_edgeColor[0],
+                                              _edgeColor[1],
+                                              _edgeColor[2]);
+        _dsActor->GetProperty()->SetLineWidth(_edgeWidth);
+        _dsActor->GetProperty()->EdgeVisibilityOff();
+        _dsActor->GetProperty()->SetAmbient(0.2);
+        _dsActor->GetProperty()->LightingOn();
+    }
+    if (_contourActor == NULL) {
+        _contourActor = vtkSmartPointer<vtkActor>::New();
+        _contourActor->GetProperty()->SetOpacity(_opacity);
+        _contourActor->GetProperty()->SetColor(_contourEdgeColor[0],
+                                               _contourEdgeColor[1],
+                                               _contourEdgeColor[2]);
+        _contourActor->GetProperty()->SetEdgeColor(_contourEdgeColor[0],
+                                                   _contourEdgeColor[1],
+                                                   _contourEdgeColor[2]);
+        _contourActor->GetProperty()->SetLineWidth(_contourEdgeWidth);
+        _contourActor->GetProperty()->EdgeVisibilityOff();
+        _contourActor->GetProperty()->SetAmbient(1.0);
+        _contourActor->GetProperty()->LightingOff();
+    }
+    // Contour actor is added in update() if contours are produced
+    if (_prop == NULL) {
+        _prop = vtkSmartPointer<vtkAssembly>::New();
+        getAssembly()->AddPart(_dsActor);
+    } else {
+        getAssembly()->RemovePart(_contourActor);
+    }
+}
+
+/**
+ * \brief Internal method to set up pipeline after a state change
+ */
+void HeightMap::update()
+{
+    if (_dataSet == NULL)
+        return;
+
+    TRACE("DataSet: %s", _dataSet->getName().c_str());
+
+    vtkDataSet *ds = _dataSet->getVtkDataSet();
+
+    computeDataScale();
+
+    // Contour filter to generate isolines
+    if (_contourFilter == NULL) {
+        _contourFilter = vtkSmartPointer<vtkContourFilter>::New();
+    }
+
+    // Mapper, actor to render color-mapped data set
+    if (_dsMapper == NULL) {
+        _dsMapper = vtkSmartPointer<vtkDataSetMapper>::New();
+        // Map scalars through lookup table regardless of type
+        _dsMapper->SetColorModeToMapScalars();
+    }
+
+    if (!_pipelineInitialized) {
+        vtkSmartPointer<vtkCellDataToPointData> cellToPtData;
+
+        if (ds->GetPointData() == NULL ||
+            ds->GetPointData()->GetScalars() == NULL) {
+            TRACE("No scalar point data in dataset %s", _dataSet->getName().c_str());
+            if (ds->GetCellData() != NULL &&
+                ds->GetCellData()->GetScalars() != NULL) {
+                cellToPtData = 
+                    vtkSmartPointer<vtkCellDataToPointData>::New();
+#ifdef USE_VTK6
+                cellToPtData->SetInputData(ds);
+#else
+                cellToPtData->SetInput(ds);
+#endif
+                //cellToPtData->PassCellDataOn();
+                cellToPtData->Update();
+                ds = cellToPtData->GetOutput();
+            } else {
+                USER_ERROR("No scalar field was found in the data set.");
+                return;
+            }
+        }
+
+        vtkPolyData *pd = vtkPolyData::SafeDownCast(ds);
+        if (pd != NULL) {
+            // DataSet is a vtkPolyData
+            if (pd->GetNumberOfLines() == 0 &&
+                pd->GetNumberOfPolys() == 0 &&
+                pd->GetNumberOfStrips() == 0) {
+                // DataSet is a point cloud
+                PrincipalPlane plane;
+                double offset;
+                if (_dataSet->is2D(&plane, &offset)) {
+#ifdef MESH_POINT_CLOUDS
+                    // Result of Delaunay2D is a PolyData
+                    vtkSmartPointer<vtkDelaunay2D> mesher = vtkSmartPointer<vtkDelaunay2D>::New();
+                    if (plane == PLANE_ZY) {
+                        vtkSmartPointer<vtkTransform> trans = vtkSmartPointer<vtkTransform>::New();
+                        trans->RotateWXYZ(90, 0, 1, 0);
+                        if (offset != 0.0) {
+                            trans->Translate(-offset, 0, 0);
+                        }
+                        mesher->SetTransform(trans);
+                        _sliceAxis = X_AXIS;
+                    } else if (plane == PLANE_XZ) {
+                        vtkSmartPointer<vtkTransform> trans = vtkSmartPointer<vtkTransform>::New();
+                        trans->RotateWXYZ(-90, 1, 0, 0);
+                        if (offset != 0.0) {
+                            trans->Translate(0, -offset, 0);
+                        }
+                        mesher->SetTransform(trans);
+                        _sliceAxis = Y_AXIS;
+                    } else if (offset != 0.0) {
+                        // XY with Z offset
+                        vtkSmartPointer<vtkTransform> trans = vtkSmartPointer<vtkTransform>::New();
+                        trans->Translate(0, 0, -offset);
+                        mesher->SetTransform(trans);
+                    }
+#ifdef USE_VTK6
+                    mesher->SetInputData(pd);
+#else
+                    mesher->SetInput(pd);
+#endif
+                    vtkAlgorithmOutput *warpOutput = initWarp(mesher->GetOutputPort());
+                    _dsMapper->SetInputConnection(warpOutput);
+                    _contourFilter->SetInputConnection(warpOutput);
+#else
+                    if (_pointSplatter == NULL)
+                        _pointSplatter = vtkSmartPointer<vtkGaussianSplatter>::New();
+                    if (_volumeSlicer == NULL)
+                        _volumeSlicer = vtkSmartPointer<vtkExtractVOI>::New();
+#ifdef USE_VTK6
+                    _pointSplatter->SetInputData(pd);
+#else
+                    _pointSplatter->SetInput(pd);
+#endif
+                    int dims[3];
+                    _pointSplatter->GetSampleDimensions(dims);
+                    TRACE("Sample dims: %d %d %d", dims[0], dims[1], dims[2]);
+                    if (plane == PLANE_ZY) {
+                        dims[0] = 3;
+                        _volumeSlicer->SetVOI(1, 1, 0, dims[1]-1, 0, dims[1]-1);
+                        _sliceAxis = X_AXIS;
+                    } else if (plane == PLANE_XZ) {
+                        dims[1] = 3;
+                        _volumeSlicer->SetVOI(0, dims[0]-1, 1, 1, 0, dims[2]-1);
+                        _sliceAxis = Y_AXIS;
+                    } else {
+                        dims[2] = 3;
+                        _volumeSlicer->SetVOI(0, dims[0]-1, 0, dims[1]-1, 1, 1);
+                    }
+                    _pointSplatter->SetSampleDimensions(dims);
+                    double bounds[6];
+                    _pointSplatter->Update();
+                    _pointSplatter->GetModelBounds(bounds);
+                    TRACE("Model bounds: %g %g %g %g %g %g",
+                          bounds[0], bounds[1],
+                          bounds[2], bounds[3],
+                          bounds[4], bounds[5]);
+                    _volumeSlicer->SetInputConnection(_pointSplatter->GetOutputPort());
+                    _volumeSlicer->SetSampleRate(1, 1, 1);
+                    vtkSmartPointer<vtkDataSetSurfaceFilter> gf = vtkSmartPointer<vtkDataSetSurfaceFilter>::New();
+                    gf->UseStripsOn();
+                    gf->SetInputConnection(_volumeSlicer->GetOutputPort());
+                    vtkAlgorithmOutput *warpOutput = initWarp(gf->GetOutputPort());
+                    _dsMapper->SetInputConnection(warpOutput);
+                    _contourFilter->SetInputConnection(warpOutput);
+#endif
+                } else {
+#ifdef MESH_POINT_CLOUDS
+                    // Data Set is a 3D point cloud
+                    // Result of Delaunay3D mesher is unstructured grid
+                    vtkSmartPointer<vtkDelaunay3D> mesher = vtkSmartPointer<vtkDelaunay3D>::New();
+#ifdef USE_VTK6
+                    mesher->SetInputData(pd);
+#else
+                    mesher->SetInput(pd);
+#endif
+                    // Run the mesher
+                    mesher->Update();
+                    // Get bounds of resulting grid
+                    double bounds[6];
+                    mesher->GetOutput()->GetBounds(bounds);
+                    // Sample a plane within the grid bounding box
+                    vtkSmartPointer<vtkCutter> cutter = vtkSmartPointer<vtkCutter>::New();
+                    cutter->SetInputConnection(mesher->GetOutputPort());
+                    if (_cutPlane == NULL) {
+                        _cutPlane = vtkSmartPointer<vtkPlane>::New();
+                    }
+                    _cutPlane->SetNormal(0, 0, 1);
+                    _cutPlane->SetOrigin(0,
+                                         0,
+                                         bounds[4] + (bounds[5]-bounds[4])/2.);
+                    cutter->SetCutFunction(_cutPlane);
+                    vtkSmartPointer<vtkDataSetSurfaceFilter> gf = vtkSmartPointer<vtkDataSetSurfaceFilter>::New();
+                    gf->UseStripsOn();
+                    gf->SetInputConnection(cutter->GetOutputPort());
+#else
+                    if (_pointSplatter == NULL)
+                        _pointSplatter = vtkSmartPointer<vtkGaussianSplatter>::New();
+#ifdef USE_VTK6
+                    _pointSplatter->SetInputData(pd);
+#else
+                    _pointSplatter->SetInput(pd);
+#endif
+                    int dims[3];
+                    _pointSplatter->GetSampleDimensions(dims);
+                    TRACE("Sample dims: %d %d %d", dims[0], dims[1], dims[2]);
+                    dims[2] = 3;
+                    _pointSplatter->SetSampleDimensions(dims);
+                    double bounds[6];
+                    _pointSplatter->Update();
+                    _pointSplatter->GetModelBounds(bounds);
+                    TRACE("Model bounds: %g %g %g %g %g %g",
+                          bounds[0], bounds[1],
+                          bounds[2], bounds[3],
+                          bounds[4], bounds[5]);
+                    if (_volumeSlicer == NULL)
+                        _volumeSlicer = vtkSmartPointer<vtkExtractVOI>::New();
+                    _volumeSlicer->SetInputConnection(_pointSplatter->GetOutputPort());
+                    _volumeSlicer->SetVOI(0, dims[0]-1, 0, dims[1]-1, 1, 1);
+                    _volumeSlicer->SetSampleRate(1, 1, 1);
+                    vtkSmartPointer<vtkDataSetSurfaceFilter> gf = vtkSmartPointer<vtkDataSetSurfaceFilter>::New();
+                    gf->UseStripsOn();
+                    gf->SetInputConnection(_volumeSlicer->GetOutputPort());
+#endif
+                    vtkAlgorithmOutput *warpOutput = initWarp(gf->GetOutputPort());
+                    _dsMapper->SetInputConnection(warpOutput);
+                    _contourFilter->SetInputConnection(warpOutput);
+                }
+            } else {
+                // DataSet is a vtkPolyData with lines and/or polygons
+                vtkAlgorithmOutput *warpOutput = initWarp(pd);
+                if (warpOutput != NULL) {
+                    _dsMapper->SetInputConnection(warpOutput);
+                    _contourFilter->SetInputConnection(warpOutput);
+                } else {
+#ifdef USE_VTK6
+                    _dsMapper->SetInputData(pd);
+                    _contourFilter->SetInputData(pd);
+#else
+                    _dsMapper->SetInput(pd);
+                    _contourFilter->SetInput(pd);
+#endif
+
+                }
+            }
+        } else {
+            // DataSet is NOT a vtkPolyData
+            // Can be: image/volume/uniform grid, structured grid, unstructured grid, rectilinear grid
+            vtkSmartPointer<vtkDataSetSurfaceFilter> gf = vtkSmartPointer<vtkDataSetSurfaceFilter>::New();
+            gf->UseStripsOn();
+            vtkImageData *imageData = vtkImageData::SafeDownCast(ds);
+            if (!_dataSet->is2D() && imageData != NULL) {
+                // 3D image/volume/uniform grid
+                if (_volumeSlicer == NULL)
+                    _volumeSlicer = vtkSmartPointer<vtkExtractVOI>::New();
+                int dims[3];
+                imageData->GetDimensions(dims);
+                TRACE("Image data dimensions: %d %d %d", dims[0], dims[1], dims[2]);
+#ifdef USE_VTK6
+                _volumeSlicer->SetInputData(ds);
+#else
+                _volumeSlicer->SetInput(ds);
+#endif
+                _volumeSlicer->SetVOI(0, dims[0]-1, 0, dims[1]-1, (dims[2]-1)/2, (dims[2]-1)/2);
+                _volumeSlicer->SetSampleRate(1, 1, 1);
+                gf->SetInputConnection(_volumeSlicer->GetOutputPort());
+            } else if (!_dataSet->is2D() && imageData == NULL) {
+                // 3D structured grid, unstructured grid, or rectilinear grid
+                double bounds[6];
+                ds->GetBounds(bounds);
+                // Sample a plane within the grid bounding box
+                vtkSmartPointer<vtkCutter> cutter = vtkSmartPointer<vtkCutter>::New();
+#ifdef USE_VTK6
+                cutter->SetInputData(ds);
+#else
+                cutter->SetInput(ds);
+#endif
+                if (_cutPlane == NULL) {
+                    _cutPlane = vtkSmartPointer<vtkPlane>::New();
+                }
+                _cutPlane->SetNormal(0, 0, 1);
+                _cutPlane->SetOrigin(0,
+                                     0,
+                                     bounds[4] + (bounds[5]-bounds[4])/2.);
+                cutter->SetCutFunction(_cutPlane);
+                gf->SetInputConnection(cutter->GetOutputPort());
+            } else {
+                // 2D data
+#ifdef USE_VTK6
+                gf->SetInputData(ds);
+#else
+                gf->SetInput(ds);
+#endif
+            }
+            vtkAlgorithmOutput *warpOutput = initWarp(gf->GetOutputPort());
+            _dsMapper->SetInputConnection(warpOutput);
+            _contourFilter->SetInputConnection(warpOutput);
+        }
+    }
+
+    _pipelineInitialized = true;
+
+    _contourFilter->ComputeNormalsOff();
+    _contourFilter->ComputeGradientsOff();
+
+    // Speed up multiple contour computation at cost of extra memory use
+    if (_numContours > 1) {
+        _contourFilter->UseScalarTreeOn();
+    } else {
+        _contourFilter->UseScalarTreeOff();
+    }
+
+    _contourFilter->SetNumberOfContours(_numContours);
+
+    if (_contours.empty()) {
+        // Evenly spaced isovalues
+        _contourFilter->GenerateValues(_numContours, _dataRange[0], _dataRange[1]);
+    } else {
+        // User-supplied isovalues
+        for (int i = 0; i < _numContours; i++) {
+            _contourFilter->SetValue(i, _contours[i]);
+        }
+    }
+
+    initProp();
+
+    if (_contourMapper == NULL) {
+        _contourMapper = vtkSmartPointer<vtkPolyDataMapper>::New();
+        _contourMapper->ScalarVisibilityOff();
+        _contourMapper->SetResolveCoincidentTopologyToPolygonOffset();
+        vtkSmartPointer<vtkStripper> stripper = vtkSmartPointer<vtkStripper>::New();
+        stripper->SetInputConnection(_contourFilter->GetOutputPort());
+        _contourMapper->SetInputConnection(stripper->GetOutputPort());
+        _contourActor->SetMapper(_contourMapper);
+        //_contourActor->InterpolateScalarsBeforeMappingOn();
+    }
+
+    setInterpolateBeforeMapping(true);
+
+    if (_lut == NULL) {
+        setColorMap(ColorMap::getDefault());
+        setColorMode(_colorMode);
+    }
+
+    // Ensure updated dataScale is applied
+    if (_warp != NULL) {
+        _warp->SetScaleFactor(_warpScale * _dataScale);
+    }
+#ifdef TRANSLATE_TO_ZORIGIN
+    double pos[3];
+    pos[0] = 0;
+    pos[1] = 0;
+    pos[2] = - _warpScale * _dataScale * _dataRange[0];
+    setPosition(pos);
+    TRACE("Z_POS: %g", pos[2]);
+#endif
+    _dsActor->SetMapper(_dsMapper);
+
+    _dsMapper->Update();
+    _contourMapper->Update();
+
+    // Only add contour actor to assembly if contours were
+    // produced, in order to prevent messing up assembly bounds
+    double bounds[6];
+    _contourActor->GetBounds(bounds);
+    if (bounds[0] <= bounds[1]) {
+        getAssembly()->AddPart(_contourActor);
+    }
+}
+
+void HeightMap::setInterpolateBeforeMapping(bool state)
+{
+    if (_dsMapper != NULL) {
+        _dsMapper->SetInterpolateScalarsBeforeMapping((state ? 1 : 0));
+    }
+}
+
+void HeightMap::setAspect(double aspect)
+{
+    double bounds[6];
+    vtkDataSet *ds = _dataSet->getVtkDataSet();
+    ds->GetBounds(bounds);
+    double size[3];
+    size[0] = bounds[1] - bounds[0];
+    size[1] = bounds[3] - bounds[2];
+    size[2] = bounds[5] - bounds[4];
+    double scale[3];
+    scale[0] = scale[1] = scale[2] = 1.;
+
+    if (aspect == 1.0) {
+        // Square
+        switch (_sliceAxis) {
+        case X_AXIS: {
+            if (size[1] > size[2] && size[2] > 1.0e-6) {
+                scale[2] = size[1] / size[2];
+            } else if (size[2] > size[1] && size[1] > 1.0e-6) {
+                scale[1] = size[2] / size[1];
+            }
+        }
+            break;
+        case Y_AXIS: {
+            if (size[0] > size[2] && size[2] > 1.0e-6) {
+                scale[2] = size[0] / size[2];
+            } else if (size[2] > size[0] && size[0] > 1.0e-6) {
+                scale[0] = size[2] / size[0];
+            }
+        }
+            break;
+        case Z_AXIS: {
+            if (size[0] > size[1] && size[1] > 1.0e-6) {
+                scale[1] = size[0] / size[1];
+            } else if (size[1] > size[0] && size[0] > 1.0e-6) {
+                scale[0] = size[1] / size[0];
+            }
+        }
+            break;
+        }
+    } else if (aspect != 0.0) {
+        switch (_sliceAxis) {
+        case X_AXIS: {
+            if (aspect > 1.0) {
+                if (size[2] > size[1]) {
+                    scale[1] = (size[2] / aspect) / size[1];
+                } else {
+                    scale[2] = (size[1] * aspect) / size[2];
+                }
+            } else {
+                if (size[1] > size[2]) {
+                    scale[2] = (size[1] * aspect) / size[2];
+                } else {
+                    scale[1] = (size[2] / aspect) / size[1];
+                }
+            }
+        }
+            break;
+        case Y_AXIS: {
+            if (aspect > 1.0) {
+                if (size[0] > size[2]) {
+                    scale[2] = (size[0] / aspect) / size[2];
+                } else {
+                    scale[0] = (size[2] * aspect) / size[0];
+                }
+            } else {
+                if (size[2] > size[0]) {
+                    scale[0] = (size[2] * aspect) / size[0];
+                } else {
+                    scale[2] = (size[0] / aspect) / size[2];
+                }
+            }
+        }
+            break;
+        case Z_AXIS: {
+            if (aspect > 1.0) {
+                if (size[0] > size[1]) {
+                    scale[1] = (size[0] / aspect) / size[1];
+                } else {
+                    scale[0] = (size[1] * aspect) / size[0];
+                }
+            } else {
+                if (size[1] > size[0]) {
+                    scale[0] = (size[1] * aspect) / size[0];
+                } else {
+                    scale[1] = (size[0] / aspect) / size[1];
+                }
+            }
+        }
+            break;
+        }
+    }
+
+    TRACE("%s dims %g,%g,%g", _dataSet->getName().c_str(),
+          size[0], size[1], size[2]);
+    TRACE("Setting scale to %g,%g,%g", scale[0], scale[1], scale[2]);
+    setScale(scale);
+}
+
+vtkAlgorithmOutput *HeightMap::initWarp(vtkAlgorithmOutput *input)
+{
+    TRACE("Warp scale: %g", _warpScale);
+    if (_warpScale == 0.0) {
+        _warp = NULL;
+        _normalsGenerator = NULL;
+        return input;
+    } else if (input == NULL) {
+        ERROR("NULL input");
+        return input;
+    } else {
+        if (_warp == NULL)
+            _warp = vtkSmartPointer<vtkWarpScalar>::New();
+        if (_normalsGenerator == NULL)
+            _normalsGenerator = vtkSmartPointer<vtkPolyDataNormals>::New();
+        switch (_sliceAxis) {
+        case X_AXIS:
+            _warp->SetNormal(1, 0, 0);
+            break;
+        case Y_AXIS:
+            _warp->SetNormal(0, 1, 0);
+            break;
+        default:
+            _warp->SetNormal(0, 0, 1);
+        }
+        _warp->UseNormalOn();
+        _warp->SetScaleFactor(_warpScale * _dataScale);
+        _warp->SetInputConnection(input);
+        _normalsGenerator->SetInputConnection(_warp->GetOutputPort());
+        _normalsGenerator->SetFeatureAngle(90.);
+        _normalsGenerator->AutoOrientNormalsOff();
+        _normalsGenerator->ComputePointNormalsOn();
+        return _normalsGenerator->GetOutputPort();
+    }
+}
+
+vtkAlgorithmOutput *HeightMap::initWarp(vtkPolyData *pdInput)
+{
+    TRACE("Warp scale: %g", _warpScale);
+    if (_warpScale == 0.0) {
+        _warp = NULL;
+        _normalsGenerator = NULL;
+        return NULL;
+    } else if (pdInput == NULL) {
+        ERROR("NULL input");
+        return NULL;
+    } else {
+        if (_warp == NULL)
+            _warp = vtkSmartPointer<vtkWarpScalar>::New();
+        if (_normalsGenerator == NULL)
+            _normalsGenerator = vtkSmartPointer<vtkPolyDataNormals>::New();
+        switch (_sliceAxis) {
+        case X_AXIS:
+            _warp->SetNormal(1, 0, 0);
+            break;
+        case Y_AXIS:
+            _warp->SetNormal(0, 1, 0);
+            break;
+        default:
+            _warp->SetNormal(0, 0, 1);
+        }
+        _warp->UseNormalOn();
+        _warp->SetScaleFactor(_warpScale * _dataScale);
+#ifdef USE_VTK6
+        _warp->SetInputData(pdInput);
+#else
+        _warp->SetInput(pdInput);
+#endif
+        _normalsGenerator->SetInputConnection(_warp->GetOutputPort());
+        _normalsGenerator->SetFeatureAngle(90.);
+        _normalsGenerator->AutoOrientNormalsOff();
+        _normalsGenerator->ComputePointNormalsOn();
+        return _normalsGenerator->GetOutputPort();
+    }
+}
+
+/**
+ * \brief Controls relative scaling of height of mountain plot
+ */
+void HeightMap::setHeightScale(double scale)
+{
+    if (_warpScale == scale)
+        return;
+
+    _warpScale = scale;
+    if (_warp == NULL) {
+        vtkAlgorithmOutput *warpOutput = initWarp(_dsMapper->GetInputConnection(0, 0));
+        _dsMapper->SetInputConnection(warpOutput);
+        _contourFilter->SetInputConnection(warpOutput);
+    } else if (scale == 0.0) {
+        vtkAlgorithmOutput *warpInput = _warp->GetInputConnection(0, 0);
+        _dsMapper->SetInputConnection(warpInput);
+        _contourFilter->SetInputConnection(warpInput);
+        _warp = NULL;
+    } else {
+        _warp->SetScaleFactor(_warpScale * _dataScale);
+    }
+#ifdef TRANSLATE_TO_ZORIGIN
+    double pos[3];
+    pos[0] = 0;
+    pos[1] = 0;
+    pos[2] = - _warpScale * _dataScale * _dataRange[0];
+    setPosition(pos);
+    TRACE("Z_POS: %g", pos[2]);
+#endif
+    if (_dsMapper != NULL)
+        _dsMapper->Update();
+    if (_contourMapper != NULL)
+        _contourMapper->Update();
+}
+
+/**
+ * \brief Select a 2D slice plane from a 3D DataSet
+ *
+ * \param[in] axis Axis of slice plane
+ * \param[in] ratio Position [0,1] of slice plane along axis
+ */
+void HeightMap::selectVolumeSlice(Axis axis, double ratio)
+{
+    if (_dataSet->is2D()) {
+        WARN("DataSet not 3D, returning");
+        return;
+    }
+
+    if (_volumeSlicer == NULL &&
+        _cutPlane == NULL) {
+        WARN("Called before update() or DataSet is not a volume");
+        return;
+    }
+
+    _sliceAxis = axis;
+    if (_warp != NULL) {
+        switch (axis) {
+        case X_AXIS:
+            _warp->SetNormal(1, 0, 0);
+            break;
+        case Y_AXIS:
+            _warp->SetNormal(0, 1, 0);
+            break;
+        case Z_AXIS:
+            _warp->SetNormal(0, 0, 1);
+            break;
+        default:
+            ERROR("Invalid Axis");
+            return;
+        }
+    }
+
+    if (_cutPlane != NULL) {
+        double bounds[6];
+        _dataSet->getBounds(bounds);
+        switch (axis) {
+        case X_AXIS:
+            _cutPlane->SetNormal(1, 0, 0);
+            _cutPlane->SetOrigin(bounds[0] + (bounds[1]-bounds[0]) * ratio,
+                                 0,
+                                 0);
+            break;
+        case Y_AXIS:
+            _cutPlane->SetNormal(0, 1, 0);
+            _cutPlane->SetOrigin(0,
+                                 bounds[2] + (bounds[3]-bounds[2]) * ratio,
+                                 0);
+            break;
+        case Z_AXIS:
+            _cutPlane->SetNormal(0, 0, 1);
+            _cutPlane->SetOrigin(0,
+                                 0,
+                                 bounds[4] + (bounds[5]-bounds[4]) * ratio);
+            break;
+        default:
+            ERROR("Invalid Axis");
+            return;
+        }
+    } else {
+        int dims[3];
+        if (_pointSplatter != NULL) {
+            _pointSplatter->GetSampleDimensions(dims);
+        } else {
+            vtkImageData *imageData = vtkImageData::SafeDownCast(_dataSet->getVtkDataSet());
+            if (imageData == NULL) {
+                ERROR("Not a volume data set");
+                return;
+            }
+            imageData->GetDimensions(dims);
+        }
+        int voi[6];
+
+        switch (axis) {
+        case X_AXIS:
+            voi[0] = voi[1] = (int)((dims[0]-1) * ratio);
+            voi[2] = 0;
+            voi[3] = dims[1]-1;
+            voi[4] = 0;
+            voi[5] = dims[2]-1;
+            break;
+        case Y_AXIS:
+            voi[0] = 0;
+            voi[1] = dims[0]-1;
+            voi[2] = voi[3] = (int)((dims[1]-1) * ratio);
+            voi[4] = 0;
+            voi[5] = dims[2]-1;
+            break;
+        case Z_AXIS:
+            voi[0] = 0;
+            voi[1] = dims[0]-1;
+            voi[2] = 0;
+            voi[3] = dims[1]-1;
+            voi[4] = voi[5] = (int)((dims[2]-1) * ratio);
+            break;
+        default:
+            ERROR("Invalid Axis");
+            return;
+        }
+
+        _volumeSlicer->SetVOI(voi);
+    }
+
+    if (_dsMapper != NULL)
+        _dsMapper->Update();
+    if (_contourMapper != NULL)
+        _contourMapper->Update();
+}
+
+void HeightMap::updateRanges(Renderer *renderer)
+{
+    TRACE("Enter");
+
+    if (_dataSet == NULL) {
+        ERROR("called before setDataSet");
+        return;
+    }
+
+    if (renderer->getUseCumulativeRange()) {
+        renderer->getCumulativeDataRange(_dataRange,
+                                         _dataSet->getActiveScalarsName(),
+                                         1);
+        const char *activeVectors = _dataSet->getActiveVectorsName();
+        if (activeVectors != NULL) {
+            renderer->getCumulativeDataRange(_vectorMagnitudeRange,
+                                             activeVectors,
+                                             3);
+            for (int i = 0; i < 3; i++) {
+                renderer->getCumulativeDataRange(_vectorComponentRange[i],
+                                                 activeVectors,
+                                                 3, i);
+            }
+        }
+    } else {
+        _dataSet->getScalarRange(_dataRange);
+        _dataSet->getVectorRange(_vectorMagnitudeRange);
+        for (int i = 0; i < 3; i++) {
+            _dataSet->getVectorRange(_vectorComponentRange[i], i);
+        }
+    }
+ 
+    // Need to update color map ranges
+    double *rangePtr = _colorFieldRange;
+    if (_colorFieldRange[0] > _colorFieldRange[1]) {
+        rangePtr = NULL;
+    }
+    setColorMode(_colorMode, _colorFieldType, _colorFieldName.c_str(), rangePtr);
+
+    if ((_contours.empty() && _numContours > 0) ||
+        _warpScale > 0.0) {
+        // Contour isovalues and/or warp need to be recomputed
+        update();
+    }
+
+    TRACE("Leave");
+}
+
+void HeightMap::setContourLineColorMapEnabled(bool mode)
+{
+    _contourColorMap = mode;
+
+    double *rangePtr = _colorFieldRange;
+    if (_colorFieldRange[0] > _colorFieldRange[1]) {
+        rangePtr = NULL;
+    }
+    setColorMode(_colorMode, _colorFieldType, _colorFieldName.c_str(), rangePtr);
+}
+
+void HeightMap::setColorMode(ColorMode mode)
+{
+    _colorMode = mode;
+    if (_dataSet == NULL)
+        return;
+
+    switch (mode) {
+    case COLOR_BY_SCALAR:
+        setColorMode(mode,
+                     _dataSet->getActiveScalarsType(),
+                     _dataSet->getActiveScalarsName(),
+                     _dataRange);
+        break;
+    case COLOR_BY_VECTOR_MAGNITUDE:
+        setColorMode(mode,
+                     _dataSet->getActiveVectorsType(),
+                     _dataSet->getActiveVectorsName(),
+                     _vectorMagnitudeRange);
+        break;
+    case COLOR_BY_VECTOR_X:
+        setColorMode(mode,
+                     _dataSet->getActiveVectorsType(),
+                     _dataSet->getActiveVectorsName(),
+                     _vectorComponentRange[0]);
+        break;
+    case COLOR_BY_VECTOR_Y:
+        setColorMode(mode,
+                     _dataSet->getActiveVectorsType(),
+                     _dataSet->getActiveVectorsName(),
+                     _vectorComponentRange[1]);
+        break;
+    case COLOR_BY_VECTOR_Z:
+        setColorMode(mode,
+                     _dataSet->getActiveVectorsType(),
+                     _dataSet->getActiveVectorsName(),
+                     _vectorComponentRange[2]);
+        break;
+    case COLOR_CONSTANT:
+    default:
+        setColorMode(mode, DataSet::POINT_DATA, NULL, NULL);
+        break;
+    }
+}
+
+void HeightMap::setColorMode(ColorMode mode,
+                             const char *name, double range[2])
+{
+    if (_dataSet == NULL)
+        return;
+    DataSet::DataAttributeType type = DataSet::POINT_DATA;
+    int numComponents = 1;
+    if (name != NULL && strlen(name) > 0 &&
+        !_dataSet->getFieldInfo(name, &type, &numComponents)) {
+        ERROR("Field not found: %s", name);
+        return;
+    }
+    setColorMode(mode, type, name, range);
+}
+
+void HeightMap::setColorMode(ColorMode mode, DataSet::DataAttributeType type,
+                             const char *name, double range[2])
+{
+    _colorMode = mode;
+    _colorFieldType = type;
+    if (name == NULL)
+        _colorFieldName.clear();
+    else
+        _colorFieldName = name;
+    if (range == NULL) {
+        _colorFieldRange[0] = DBL_MAX;
+        _colorFieldRange[1] = -DBL_MAX;
+    } else {
+        memcpy(_colorFieldRange, range, sizeof(double)*2);
+    }
+
+    if (_dataSet == NULL || _dsMapper == NULL)
+        return;
+
+    switch (type) {
+    case DataSet::POINT_DATA:
+        _dsMapper->SetScalarModeToUsePointFieldData();
+        _contourMapper->SetScalarModeToUsePointFieldData();
+        break;
+    case DataSet::CELL_DATA:
+        _dsMapper->SetScalarModeToUseCellFieldData();
+        _contourMapper->SetScalarModeToUseCellFieldData();
+        break;
+    default:
+        ERROR("Unsupported DataAttributeType: %d", type);
+        return;
+    }
+
+    if (name != NULL && strlen(name) > 0) {
+        _dsMapper->SelectColorArray(name);
+        _contourMapper->SelectColorArray(name);
+    } else {
+        _dsMapper->SetScalarModeToDefault();
+        _contourMapper->SetScalarModeToDefault();
+    }
+
+    if (_lut != NULL) {
+        if (range != NULL) {
+            _lut->SetRange(range);
+            TRACE("range %g, %g", range[0], range[1]);
+        } else if (name != NULL && strlen(name) > 0) {
+            double r[2];
+            int comp = -1;
+            if (mode == COLOR_BY_VECTOR_X)
+                comp = 0;
+            else if (mode == COLOR_BY_VECTOR_Y)
+                comp = 1;
+            else if (mode == COLOR_BY_VECTOR_Z)
+                comp = 2;
+
+            if (_renderer->getUseCumulativeRange()) {
+                int numComponents;
+                if  (!_dataSet->getFieldInfo(name, type, &numComponents)) {
+                    ERROR("Field not found: %s, type: %d", name, type);
+                    return;
+                } else if (numComponents < comp+1) {
+                    ERROR("Request for component %d in field with %d components",
+                          comp, numComponents);
+                    return;
+                }
+                _renderer->getCumulativeDataRange(r, name, type, numComponents, comp);
+            } else {
+                _dataSet->getDataRange(r, name, type, comp);
+            }
+            _lut->SetRange(r);
+            TRACE("%s range %g, %g", name, r[0], r[1]);
+        }
+        _lut->Modified();
+    }
+
+    if (_contourColorMap) {
+        _contourMapper->ScalarVisibilityOn();
+    } else {
+        _contourMapper->ScalarVisibilityOff();
+    }
+
+    switch (mode) {
+    case COLOR_BY_SCALAR:
+        _dsMapper->ScalarVisibilityOn();
+        break;
+    case COLOR_BY_VECTOR_MAGNITUDE:
+        _dsMapper->ScalarVisibilityOn();
+        if (_lut != NULL) {
+            _lut->SetVectorModeToMagnitude();
+        }
+        break;
+    case COLOR_BY_VECTOR_X:
+        _dsMapper->ScalarVisibilityOn();
+        if (_lut != NULL) {
+            _lut->SetVectorModeToComponent();
+            _lut->SetVectorComponent(0);
+        }
+        break;
+    case COLOR_BY_VECTOR_Y:
+        _dsMapper->ScalarVisibilityOn();
+        if (_lut != NULL) {
+            _lut->SetVectorModeToComponent();
+            _lut->SetVectorComponent(1);
+        }
+        break;
+    case COLOR_BY_VECTOR_Z:
+        _dsMapper->ScalarVisibilityOn();
+        if (_lut != NULL) {
+            _lut->SetVectorModeToComponent();
+            _lut->SetVectorComponent(2);
+        }
+        break;
+    case COLOR_CONSTANT:
+    default:
+        _dsMapper->ScalarVisibilityOff();
+        break;
+    }
+}
+
+/**
+ * \brief Called when the color map has been edited
+ */
+void HeightMap::updateColorMap()
+{
+    setColorMap(_colorMap);
+}
+
+/**
+ * \brief Associate a colormap lookup table with the DataSet
+ */
+void HeightMap::setColorMap(ColorMap *cmap)
+{
+    if (cmap == NULL)
+        return;
+
+    _colorMap = cmap;
+
+    if (_lut == NULL) {
+        _lut = vtkSmartPointer<vtkLookupTable>::New();
+        if (_dsMapper != NULL) {
+            _dsMapper->UseLookupTableScalarRangeOn();
+            _dsMapper->SetLookupTable(_lut);
+        }
+        if (_contourMapper != NULL) {
+            _contourMapper->UseLookupTableScalarRangeOn();
+            _contourMapper->SetLookupTable(_lut);
+        }
+        _lut->DeepCopy(cmap->getLookupTable());
+        switch (_colorMode) {
+        case COLOR_CONSTANT:
+        case COLOR_BY_SCALAR:
+            _lut->SetRange(_dataRange);
+            break;
+        case COLOR_BY_VECTOR_MAGNITUDE:
+            _lut->SetRange(_vectorMagnitudeRange);
+            break;
+        case COLOR_BY_VECTOR_X:
+            _lut->SetRange(_vectorComponentRange[0]);
+            break;
+        case COLOR_BY_VECTOR_Y:
+            _lut->SetRange(_vectorComponentRange[1]);
+            break;
+        case COLOR_BY_VECTOR_Z:
+            _lut->SetRange(_vectorComponentRange[2]);
+            break;
+        default:
+            break;
+        }
+    } else {
+        double range[2];
+        _lut->GetTableRange(range);
+        _lut->DeepCopy(cmap->getLookupTable());
+        _lut->SetRange(range);
+        _lut->Modified();
+    }
+
+    switch (_colorMode) {
+    case COLOR_BY_VECTOR_MAGNITUDE:
+        _lut->SetVectorModeToMagnitude();
+        break;
+    case COLOR_BY_VECTOR_X:
+        _lut->SetVectorModeToComponent();
+        _lut->SetVectorComponent(0);
+        break;
+    case COLOR_BY_VECTOR_Y:
+        _lut->SetVectorModeToComponent();
+        _lut->SetVectorComponent(1);
+        break;
+    case COLOR_BY_VECTOR_Z:
+        _lut->SetVectorModeToComponent();
+        _lut->SetVectorComponent(2);
+        break;
+    default:
+         break;
+    }
+}
+
+/**
+ * \brief Specify number of evenly spaced contour lines to render
+ *
+ * Will override any existing contours
+ */
+void HeightMap::setNumContours(int numContours)
+{
+    _contours.clear();
+    _numContours = numContours;
+
+    update();
+}
+
+/**
+ * \brief Specify an explicit list of contour isovalues
+ *
+ * Will override any existing contours
+ */
+void HeightMap::setContourList(const std::vector<double>& contours)
+{
+    _contours = contours;
+    _numContours = (int)_contours.size();
+
+    update();
+}
+
+/**
+ * \brief Get the number of contours
+ */
+int HeightMap::getNumContours() const
+{
+    return _numContours;
+}
+
+/**
+ * \brief Get the contour list (may be empty if number of contours
+ * was specified in place of a list)
+ */
+const std::vector<double>& HeightMap::getContourList() const
+{
+    return _contours;
+}
+
+/**
+ * \brief Turn on/off lighting of this object
+ */
+void HeightMap::setLighting(bool state)
+{
+    _lighting = state;
+    if (_dsActor != NULL)
+        _dsActor->GetProperty()->SetLighting((state ? 1 : 0));
+}
+
+/**
+ * \brief Turn on/off rendering of mesh edges
+ */
+void HeightMap::setEdgeVisibility(bool state)
+{
+    if (_dsActor != NULL) {
+        _dsActor->GetProperty()->SetEdgeVisibility((state ? 1 : 0));
+    }
+}
+
+/**
+ * \brief Turn on/off rendering of colormaped surface
+ */
+void HeightMap::setContourSurfaceVisibility(bool state)
+{
+    if (_dsActor != NULL) {
+        _dsActor->SetVisibility((state ? 1 : 0));
+    }
+}
+
+/**
+ * \brief Turn on/off rendering of contour isolines
+ */
+void HeightMap::setContourLineVisibility(bool state)
+{
+    if (_contourActor != NULL) {
+        _contourActor->SetVisibility((state ? 1 : 0));
+    }
+}
+
+/**
+ * \brief Set RGB color of mesh
+ */
+void HeightMap::setColor(float color[3])
+{
+    _color[0] = color[0];
+    _color[1] = color[1];
+    _color[2] = color[2];
+    if (_dsActor != NULL)
+        _dsActor->GetProperty()->SetColor(_color[0], _color[1], _color[2]);
+}
+
+/**
+ * \brief Set RGB color of polygon edges
+ */
+void HeightMap::setEdgeColor(float color[3])
+{
+    _edgeColor[0] = color[0];
+    _edgeColor[1] = color[1];
+    _edgeColor[2] = color[2];
+    if (_dsActor != NULL)
+        _dsActor->GetProperty()->SetEdgeColor(_edgeColor[0], _edgeColor[1], _edgeColor[2]);
+}
+
+/**
+ * \brief Set pixel width of polygon edges (may be a no-op)
+ */
+void HeightMap::setEdgeWidth(float edgeWidth)
+{
+    _edgeWidth = edgeWidth;
+    if (_dsActor != NULL)
+        _dsActor->GetProperty()->SetLineWidth(_edgeWidth);
+}
+
+/**
+ * \brief Set RGB color of contour isolines
+ */
+void HeightMap::setContourEdgeColor(float color[3])
+{
+    _contourEdgeColor[0] = color[0];
+    _contourEdgeColor[1] = color[1];
+    _contourEdgeColor[2] = color[2];
+    if (_contourActor != NULL) {
+        _contourActor->GetProperty()->SetColor(_contourEdgeColor[0],
+                                               _contourEdgeColor[1],
+                                               _contourEdgeColor[2]);
+        _contourActor->GetProperty()->SetEdgeColor(_contourEdgeColor[0],
+                                                   _contourEdgeColor[1],
+                                                   _contourEdgeColor[2]);
+    }
+}
+
+/**
+ * \brief Set pixel width of contour isolines (may be a no-op)
+ */
+void HeightMap::setContourEdgeWidth(float edgeWidth)
+{
+    _contourEdgeWidth = edgeWidth;
+    if (_contourActor != NULL)
+        _contourActor->GetProperty()->SetLineWidth(_contourEdgeWidth);
+}
+
+/**
+ * \brief Set a group of world coordinate planes to clip rendering
+ *
+ * Passing NULL for planes will remove all cliping planes
+ */
+void HeightMap::setClippingPlanes(vtkPlaneCollection *planes)
+{
+    if (_dsMapper != NULL) {
+        _dsMapper->SetClippingPlanes(planes);
+    }
+    if (_contourMapper != NULL) {
+        _contourMapper->SetClippingPlanes(planes);
+    }
+}
+
Index: /trunk/packages/vizservers/vtkvis/HeightMap.h
===================================================================
--- /trunk/packages/vizservers/vtkvis/HeightMap.h	(revision 3616)
+++ /trunk/packages/vizservers/vtkvis/HeightMap.h	(revision 3616)
@@ -0,0 +1,173 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (C) 2004-2012  HUBzero Foundation, LLC
+ *
+ * Author: Leif Delgass <ldelgass@purdue.edu>
+ */
+
+#ifndef VTKVIS_HEIGHTMAP_H
+#define VTKVIS_HEIGHTMAP_H
+
+#include <vtkSmartPointer.h>
+#include <vtkAlgorithmOutput.h>
+#include <vtkContourFilter.h>
+#include <vtkLookupTable.h>
+#include <vtkDataSetMapper.h>
+#include <vtkActor.h>
+#include <vtkPlaneCollection.h>
+#include <vtkGaussianSplatter.h>
+#include <vtkExtractVOI.h>
+#include <vtkWarpScalar.h>
+#include <vtkPolyDataNormals.h>
+#include <vtkAssembly.h>
+#include <vtkPolyData.h>
+#include <vtkPlane.h>
+
+#include <vector>
+
+#include "ColorMap.h"
+#include "Types.h"
+#include "VtkGraphicsObject.h"
+
+namespace VtkVis {
+
+/**
+ * \brief Color-mapped plot of data set
+ */
+class HeightMap : public VtkGraphicsObject {
+public:
+    enum ColorMode {
+        COLOR_BY_SCALAR,
+        COLOR_BY_VECTOR_MAGNITUDE,
+        COLOR_BY_VECTOR_X,
+        COLOR_BY_VECTOR_Y,
+        COLOR_BY_VECTOR_Z,
+        COLOR_CONSTANT
+    };
+
+    HeightMap(int numContours, double heightScale = 1.0);
+
+    HeightMap(const std::vector<double>& contours, double heightScale = 1.0);
+
+    virtual ~HeightMap();
+
+    virtual const char *getClassName() const
+    {
+        return "HeightMap";
+    }
+
+    virtual void setDataSet(DataSet *dataSet,
+                            Renderer *renderer);
+
+    virtual void setLighting(bool state);
+
+    virtual void setColor(float color[3]);
+
+    virtual void setEdgeVisibility(bool state);
+
+    virtual void setEdgeColor(float color[3]);
+
+    virtual void setEdgeWidth(float edgeWidth);
+
+    virtual void setClippingPlanes(vtkPlaneCollection *planes);
+
+    virtual void setAspect(double aspect);
+
+    void selectVolumeSlice(Axis axis, double ratio);
+
+    void setHeightScale(double scale);
+
+    double getHeightScale()
+    {
+        return _warpScale;
+    }
+
+    void setInterpolateBeforeMapping(bool state);
+
+    void setNumContours(int numContours);
+
+    void setContourList(const std::vector<double>& contours);
+
+    int getNumContours() const;
+
+    const std::vector<double>& getContourList() const;
+
+    void setContourLineColorMapEnabled(bool mode);
+
+    void setColorMode(ColorMode mode, DataSet::DataAttributeType type,
+                      const char *name, double range[2] = NULL);
+
+    void setColorMode(ColorMode mode,
+                      const char *name, double range[2] = NULL);
+
+    void setColorMode(ColorMode mode);
+
+    void setColorMap(ColorMap *colorMap);
+
+    /**
+     * \brief Return the ColorMap in use
+     */
+    ColorMap *getColorMap()
+    {
+        return _colorMap;
+    }
+
+    void updateColorMap();
+
+    virtual void updateRanges(Renderer *renderer);
+
+    void setContourLineVisibility(bool state);
+
+    void setContourSurfaceVisibility(bool state);
+
+    void setContourEdgeColor(float color[3]);
+
+    void setContourEdgeWidth(float edgeWidth);
+
+private:
+    HeightMap();
+
+    virtual void initProp();
+    virtual void update();
+
+    void computeDataScale();
+
+    vtkAlgorithmOutput *initWarp(vtkAlgorithmOutput *input);
+    vtkAlgorithmOutput *initWarp(vtkPolyData *input);
+
+    int _numContours;
+    std::vector<double> _contours;
+
+    bool _contourColorMap;
+    float _contourEdgeColor[3];
+    float _contourEdgeWidth;
+    double _warpScale;
+    double _dataScale;
+    Axis _sliceAxis;
+    bool _pipelineInitialized;
+
+    ColorMap *_colorMap;
+    ColorMode _colorMode;
+    std::string _colorFieldName;
+    DataSet::DataAttributeType _colorFieldType;
+    double _colorFieldRange[2];
+    double _vectorMagnitudeRange[2];
+    double _vectorComponentRange[3][2];
+    Renderer *_renderer;
+
+    vtkSmartPointer<vtkLookupTable> _lut;
+    vtkSmartPointer<vtkDataSetMapper> _dsMapper;
+    vtkSmartPointer<vtkContourFilter> _contourFilter;
+    vtkSmartPointer<vtkPolyDataMapper> _contourMapper;
+    vtkSmartPointer<vtkGaussianSplatter> _pointSplatter;
+    vtkSmartPointer<vtkExtractVOI> _volumeSlicer;
+    vtkSmartPointer<vtkPlane> _cutPlane;
+    vtkSmartPointer<vtkWarpScalar> _warp;
+    vtkSmartPointer<vtkPolyDataNormals> _normalsGenerator;
+    vtkSmartPointer<vtkActor> _dsActor;
+    vtkSmartPointer<vtkActor> _contourActor;
+};
+
+}
+
+#endif
Index: /trunk/packages/vizservers/vtkvis/LIC.cpp
===================================================================
--- /trunk/packages/vizservers/vtkvis/LIC.cpp	(revision 3616)
+++ /trunk/packages/vizservers/vtkvis/LIC.cpp	(revision 3616)
@@ -0,0 +1,460 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (C) 2004-2012  HUBzero Foundation, LLC
+ *
+ * Author: Leif Delgass <ldelgass@purdue.edu>
+ */
+
+#include <cassert>
+
+#include <vtkActor.h>
+#include <vtkProperty.h>
+#include <vtkPointData.h>
+#include <vtkCellData.h>
+#include <vtkCellDataToPointData.h>
+#include <vtkImageData.h>
+#include <vtkPolyData.h>
+#include <vtkDataSetMapper.h>
+#include <vtkPainterPolyDataMapper.h>
+#include <vtkDataSetSurfaceFilter.h>
+#include <vtkCutter.h>
+#include <vtkImageMask.h>
+#include <vtkImageCast.h>
+
+#include "LIC.h"
+#include "Trace.h"
+
+using namespace VtkVis;
+
+LIC::LIC() :
+    VtkGraphicsObject(),
+    _sliceAxis(Z_AXIS),
+    _colorMap(NULL)
+{
+}
+
+LIC::~LIC()
+{
+#ifdef WANT_TRACE
+    if (_dataSet != NULL)
+        TRACE("Deleting LIC for %s", _dataSet->getName().c_str());
+    else
+        TRACE("Deleting LIC with NULL DataSet");
+#endif
+}
+
+void LIC::initProp()
+{
+    if (_prop == NULL) {
+        _prop = vtkSmartPointer<vtkActor>::New();
+        vtkProperty *property = getActor()->GetProperty();
+        property->SetOpacity(_opacity);
+        property->SetEdgeColor(_edgeColor[0], _edgeColor[1], _edgeColor[2]);
+        property->SetLineWidth(_edgeWidth);
+        property->EdgeVisibilityOff();
+        property->SetAmbient(.2);
+        if (!_lighting)
+            property->LightingOff();
+    }
+}
+
+void LIC::update()
+{
+    if (_dataSet == NULL)
+        return;
+
+    vtkDataSet *ds = _dataSet->getVtkDataSet();
+
+    vtkSmartPointer<vtkCellDataToPointData> cellToPtData;
+    if (ds->GetPointData() == NULL ||
+        ds->GetPointData()->GetVectors() == NULL) {
+         TRACE("No vector point data in dataset %s", _dataSet->getName().c_str());
+         if (ds->GetCellData() != NULL &&
+             ds->GetCellData()->GetVectors() != NULL) {
+             cellToPtData = 
+                 vtkSmartPointer<vtkCellDataToPointData>::New();
+#ifdef USE_VTK6
+             cellToPtData->SetInputData(ds);
+#else
+             cellToPtData->SetInput(ds);
+#endif
+             //cellToPtData->PassCellDataOn();
+             cellToPtData->Update();
+             ds = cellToPtData->GetOutput();
+         } else {
+             USER_ERROR("No vector field was found in the data set");
+             return;
+         }
+    }
+
+    vtkImageData *imageData = vtkImageData::SafeDownCast(ds);
+    if (imageData != NULL) {
+        if (_lic == NULL) {
+            _lic = vtkSmartPointer<vtkImageDataLIC2D>::New();
+        }
+        if (!_dataSet->is2D()) {
+            // 3D image/volume/uniform grid
+            if (_volumeSlicer == NULL)
+                _volumeSlicer = vtkSmartPointer<vtkExtractVOI>::New();
+            int dims[3];
+            imageData->GetDimensions(dims);
+            TRACE("Image data dimensions: %d %d %d", dims[0], dims[1], dims[2]);
+#ifdef USE_VTK6
+            _volumeSlicer->SetInputData(ds);
+#else
+            _volumeSlicer->SetInput(ds);
+#endif
+            _volumeSlicer->SetVOI(0, dims[0]-1, 0, dims[1]-1, (dims[2]-1)/2, (dims[2]-1)/2);
+            _volumeSlicer->SetSampleRate(1, 1, 1);
+            _lic->SetInputConnection(_volumeSlicer->GetOutputPort());
+        } else {
+            // 2D image/volume/uniform grid
+#ifdef USE_VTK6
+            _lic->SetInputData(ds);
+#else
+            _lic->SetInput(ds);
+#endif
+        }
+        if (_mapper == NULL) {
+            _mapper = vtkSmartPointer<vtkDataSetMapper>::New();
+        }
+        _mapper->SetInputConnection(_lic->GetOutputPort());
+    } else if (vtkPolyData::SafeDownCast(ds) == NULL) {
+        // structured grid, unstructured grid, or rectilinear grid
+        if (_lic == NULL) {
+            _lic = vtkSmartPointer<vtkImageDataLIC2D>::New();
+        }
+
+        // Need to convert to vtkImageData
+        double bounds[6];
+        ds->GetBounds(bounds);
+        double xSize = bounds[1] - bounds[0];
+        double ySize = bounds[3] - bounds[2];
+        double zSize = bounds[5] - bounds[4];
+        int minDir = 2;
+        if (xSize < ySize && xSize < zSize)
+            minDir = 0;
+        if (ySize < xSize && ySize < zSize)
+            minDir = 1;
+        if (_probeFilter == NULL)
+            _probeFilter = vtkSmartPointer<vtkProbeFilter>::New();
+
+        if (!_dataSet->is2D()) {
+            // Sample a plane within the grid bounding box
+            vtkSmartPointer<vtkCutter> cutter = vtkSmartPointer<vtkCutter>::New();
+            if (_cutPlane == NULL) {
+                _cutPlane = vtkSmartPointer<vtkPlane>::New();
+            }
+            if (minDir == 0) {
+                _cutPlane->SetNormal(1, 0, 0);
+                _cutPlane->SetOrigin(bounds[0] + (bounds[1]-bounds[0])/2.,
+                                     0,
+                                     0);
+            } else if (minDir == 1) {
+                _cutPlane->SetNormal(0, 1, 0);
+                _cutPlane->SetOrigin(0,
+                                     bounds[2] + (bounds[3]-bounds[2])/2.,
+                                     0);
+            } else {
+                _cutPlane->SetNormal(0, 0, 1);
+                _cutPlane->SetOrigin(0,
+                                     0,
+                                     bounds[4] + (bounds[5]-bounds[4])/2.);
+            }
+#ifdef USE_VTK6
+            cutter->SetInputData(ds);
+#else
+            cutter->SetInput(ds);
+#endif
+            cutter->SetCutFunction(_cutPlane);
+            _probeFilter->SetSourceConnection(cutter->GetOutputPort());
+        } else {
+#ifdef USE_VTK6
+            _probeFilter->SetSourceData(ds);
+#else
+            _probeFilter->SetSource(ds);
+#endif
+        }
+
+        vtkSmartPointer<vtkImageData> imageData = vtkSmartPointer<vtkImageData>::New();
+        int xdim, ydim, zdim;
+        double origin[3], spacing[3];
+        if (minDir == 0) {
+            xdim = 1;
+            ydim = 128;
+            zdim = 128;
+            origin[0] = bounds[0] + xSize/2.;
+            origin[1] = bounds[2];
+            origin[2] = bounds[4];
+            spacing[0] = 0;
+            spacing[1] = ySize/((double)(ydim-1));
+            spacing[2] = zSize/((double)(zdim-1));
+            _sliceAxis = X_AXIS;
+        } else if (minDir == 1) {
+            xdim = 128;
+            ydim = 1;
+            zdim = 128;
+            origin[0] = bounds[0];
+            origin[1] = bounds[2] + ySize/2.;
+            origin[2] = bounds[4];
+            spacing[0] = xSize/((double)(xdim-1));
+            spacing[1] = 0;
+            spacing[2] = zSize/((double)(zdim-1));
+            _sliceAxis = Y_AXIS;
+        } else {
+            xdim = 128;
+            ydim = 128;
+            zdim = 1;
+            origin[0] = bounds[0];
+            origin[1] = bounds[2];
+            origin[2] = bounds[4] + zSize/2.;
+            spacing[0] = xSize/((double)(xdim-1));
+            spacing[1] = ySize/((double)(ydim-1));
+            spacing[2] = 0;
+            _sliceAxis = Z_AXIS;
+        }
+        imageData->SetDimensions(xdim, ydim, zdim);
+        imageData->SetOrigin(origin);
+        imageData->SetSpacing(spacing);
+#ifdef USE_VTK6
+        _probeFilter->SetInputData(imageData);
+#else
+        _probeFilter->SetInput(imageData);
+#endif
+        _lic->SetInputConnection(_probeFilter->GetOutputPort());
+
+        if (_mapper == NULL) {
+            _mapper = vtkSmartPointer<vtkDataSetMapper>::New();
+            _mapper->SetColorModeToMapScalars();
+        }
+        _lic->Update();
+        vtkSmartPointer<vtkImageCast> cast = vtkSmartPointer<vtkImageCast>::New();
+        cast->SetInputConnection(_probeFilter->GetOutputPort());
+        cast->SetInputArrayToProcess(0, 0, 0, vtkDataObject::FIELD_ASSOCIATION_POINTS,
+                                     _probeFilter->GetValidPointMaskArrayName());
+        cast->SetOutputScalarTypeToUnsignedChar();
+        vtkSmartPointer<vtkImageMask> mask = vtkSmartPointer<vtkImageMask>::New();
+        mask->SetInputConnection(0, _lic->GetOutputPort());
+        mask->SetInputConnection(1, cast->GetOutputPort());
+        _mapper->SetInputConnection(mask->GetOutputPort());
+    } else {
+        // DataSet is a PolyData
+        vtkPolyData *pd = vtkPolyData::SafeDownCast(ds);
+        assert(pd != NULL);
+
+        // XXX: This mapper seems to conflict with offscreen rendering, so the main
+        // renderer needs to be set not to use FBOs for this to work
+        _mapper = vtkSmartPointer<vtkPainterPolyDataMapper>::New();
+        vtkPainterPolyDataMapper *ppdmapper = vtkPainterPolyDataMapper::SafeDownCast(_mapper);
+        if (_painter == NULL) {
+            _painter = vtkSmartPointer<vtkSurfaceLICPainter>::New();
+            _painter->SetDelegatePainter(ppdmapper->GetPainter());
+         }
+        ppdmapper->SetPainter(_painter);
+#ifdef USE_VTK6
+        ppdmapper->SetInputData(pd);
+#else
+        ppdmapper->SetInput(pd);
+#endif
+    }
+
+    setInterpolateBeforeMapping(true);
+
+    if (_lut == NULL) {
+        setColorMap(ColorMap::getGrayDefault());
+    }
+
+    initProp();
+    getActor()->SetMapper(_mapper);
+
+    _mapper->Update();
+#ifdef WANT_TRACE
+    if (_lic != NULL) {
+        TRACE("FBO status: %d LIC status: %d", _lic->GetFBOSuccess(), _lic->GetLICSuccess());
+    } else if (_painter != NULL) {
+        TRACE("LIC status: %d", _painter->GetLICSuccess());
+    }
+#endif
+}
+
+void LIC::setInterpolateBeforeMapping(bool state)
+{
+    if (_mapper != NULL) {
+        _mapper->SetInterpolateScalarsBeforeMapping((state ? 1 : 0));
+    }
+}
+
+/**
+ * \brief Select a 2D slice plane from a 3D DataSet
+ *
+ * \param[in] axis Axis of slice plane
+ * \param[in] ratio Position [0,1] of slice plane along axis
+ */
+void LIC::selectVolumeSlice(Axis axis, double ratio)
+{
+    if (_dataSet->is2D()) {
+        WARN("DataSet not 3D, returning");
+        return;
+    }
+
+    if (_volumeSlicer == NULL &&
+        _probeFilter == NULL) {
+        WARN("Called before update() or DataSet is not a volume");
+        return;
+    }
+
+    int dims[3];
+
+    vtkImageData *imageData = vtkImageData::SafeDownCast(_dataSet->getVtkDataSet());
+    if (imageData == NULL) {
+        if (_probeFilter != NULL) {
+            imageData = vtkImageData::SafeDownCast(_probeFilter->GetInput());
+            if (imageData == NULL) {
+                ERROR("Couldn't get probe filter input image");
+                return;
+            }
+        } else {
+            ERROR("Not a volume data set");
+            return;
+        }
+    }
+    imageData->GetDimensions(dims);
+
+    _sliceAxis = axis;
+
+    if (_probeFilter != NULL) {
+        vtkImageData *imageData = vtkImageData::SafeDownCast(_probeFilter->GetInput());
+        double bounds[6];
+        assert(vtkDataSet::SafeDownCast(_probeFilter->GetSource()) != NULL);
+        _dataSet->getBounds(bounds);
+        int dim = 128;
+
+        switch (axis) {
+        case X_AXIS:
+            imageData->SetDimensions(1, dim, dim);
+            imageData->SetOrigin(bounds[0] + (bounds[1]-bounds[0])*ratio, bounds[2], bounds[4]);
+            imageData->SetSpacing(0,
+                                  (bounds[3]-bounds[2])/((double)(dim-1)), 
+                                  (bounds[5]-bounds[4])/((double)(dim-1)));
+            if (_cutPlane != NULL) {
+                _cutPlane->SetNormal(1, 0, 0);
+                _cutPlane->SetOrigin(bounds[0] + (bounds[1]-bounds[0])*ratio, 0, 0);
+            }
+            break;
+        case Y_AXIS:
+            imageData->SetDimensions(dim, 1, dim);
+            imageData->SetOrigin(bounds[0], bounds[2] + (bounds[3]-bounds[2])*ratio, bounds[4]);
+            imageData->SetSpacing((bounds[1]-bounds[0])/((double)(dim-1)), 
+                                  0,
+                                  (bounds[5]-bounds[4])/((double)(dim-1)));
+            if (_cutPlane != NULL) {
+                _cutPlane->SetNormal(0, 1, 0);
+                _cutPlane->SetOrigin(0, bounds[2] + (bounds[3]-bounds[2])*ratio, 0);
+            }
+            break;
+        case Z_AXIS:
+            imageData->SetDimensions(dim, dim, 1);
+            imageData->SetOrigin(bounds[0], bounds[2], bounds[4] + (bounds[5]-bounds[4])*ratio);
+            imageData->SetSpacing((bounds[1]-bounds[0])/((double)(dim-1)), 
+                                  (bounds[3]-bounds[2])/((double)(dim-1)),
+                                  0);
+            if (_cutPlane != NULL) {
+                _cutPlane->SetNormal(0, 0, 1);
+                _cutPlane->SetOrigin(0, 0, bounds[4] + (bounds[5]-bounds[4])*ratio);
+            }
+            break;
+        default:
+            ERROR("Invalid Axis");
+            return;
+        }
+    } else {
+        int voi[6];
+
+        switch (axis) {
+        case X_AXIS:
+            voi[0] = voi[1] = (int)((dims[0]-1) * ratio);
+            voi[2] = 0;
+            voi[3] = dims[1]-1;
+            voi[4] = 0;
+            voi[5] = dims[2]-1;
+            break;
+        case Y_AXIS:
+            voi[2] = voi[3] = (int)((dims[1]-1) * ratio);
+            voi[0] = 0;
+            voi[1] = dims[0]-1;
+            voi[4] = 0;
+            voi[5] = dims[2]-1;
+            break;
+        case Z_AXIS:
+            voi[4] = voi[5] = (int)((dims[2]-1) * ratio);
+            voi[0] = 0;
+            voi[1] = dims[0]-1;
+            voi[2] = 0;
+            voi[3] = dims[1]-1;
+            break;
+        default:
+            ERROR("Invalid Axis");
+            return;
+        }
+
+        _volumeSlicer->SetVOI(voi);
+    }
+
+    if (_lic != NULL)
+        _lic->Update();
+
+    if (_mapper != NULL)
+        _mapper->Update();
+}
+
+/**
+ * \brief Called when the color map has been edited
+ */
+void LIC::updateColorMap()
+{
+    setColorMap(_colorMap);
+}
+
+/**
+ * \brief Associate a colormap lookup table with the DataSet
+ */
+void LIC::setColorMap(ColorMap *cmap)
+{
+    if (cmap == NULL)
+        return;
+
+    _colorMap = cmap;
+ 
+    if (_lut == NULL) {
+        _lut = vtkSmartPointer<vtkLookupTable>::New();
+        if (_mapper != NULL) {
+            _mapper->UseLookupTableScalarRangeOff();
+            _mapper->SetLookupTable(_lut);
+        }
+    }
+
+    _lut->DeepCopy(cmap->getLookupTable());
+    _lut->SetRange(_dataRange);
+    _lut->Modified();
+}
+
+void LIC::updateRanges(Renderer *renderer)
+{
+    VtkGraphicsObject::updateRanges(renderer);
+
+    if (_lut != NULL) {
+        _lut->SetRange(_dataRange);
+    }
+}
+
+/**
+ * \brief Set a group of world coordinate planes to clip rendering
+ *
+ * Passing NULL for planes will remove all cliping planes
+ */
+void LIC::setClippingPlanes(vtkPlaneCollection *planes)
+{
+    if (_mapper != NULL) {
+        _mapper->SetClippingPlanes(planes);
+    }
+}
Index: /trunk/packages/vizservers/vtkvis/LIC.h
===================================================================
--- /trunk/packages/vizservers/vtkvis/LIC.h	(revision 3616)
+++ /trunk/packages/vizservers/vtkvis/LIC.h	(revision 3616)
@@ -0,0 +1,81 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (C) 2004-2012  HUBzero Foundation, LLC
+ *
+ * Author: Leif Delgass <ldelgass@purdue.edu>
+ */
+
+#ifndef VTKVIS_LIC_H
+#define VTKVIS_LIC_H
+
+#include <vtkSmartPointer.h>
+#include <vtkProp.h>
+#include <vtkPlaneCollection.h>
+#include <vtkExtractVOI.h>
+#include <vtkProbeFilter.h>
+#include <vtkImageDataLIC2D.h>
+#include <vtkSurfaceLICPainter.h>
+#include <vtkMapper.h>
+#include <vtkLookupTable.h>
+#include <vtkPlane.h>
+
+#include "ColorMap.h"
+#include "Types.h"
+#include "VtkGraphicsObject.h"
+
+namespace VtkVis {
+
+/**
+ * \brief Line Integral Convolution visualization of vector fields
+ *
+ *  The DataSet must contain vectors
+ */
+class LIC : public VtkGraphicsObject {
+public:
+    LIC();
+    virtual ~LIC();
+
+    virtual const char *getClassName() const
+    {
+        return "LIC";
+    }
+    
+    virtual void setClippingPlanes(vtkPlaneCollection *planes);
+
+    void selectVolumeSlice(Axis axis, double ratio);
+
+    void setInterpolateBeforeMapping(bool state);
+
+    void setColorMap(ColorMap *colorMap);
+
+    /**
+     * \brief Return the ColorMap in use
+     */
+    ColorMap *getColorMap()
+    {
+        return _colorMap;
+    }
+
+    void updateColorMap();
+
+    virtual void updateRanges(Renderer *renderer);
+
+private:
+    virtual void initProp();
+    virtual void update();
+
+    Axis _sliceAxis;
+    ColorMap *_colorMap;
+
+    vtkSmartPointer<vtkLookupTable> _lut;
+    vtkSmartPointer<vtkExtractVOI> _volumeSlicer;
+    vtkSmartPointer<vtkProbeFilter> _probeFilter;
+    vtkSmartPointer<vtkPlane> _cutPlane;
+    vtkSmartPointer<vtkImageDataLIC2D> _lic;
+    vtkSmartPointer<vtkSurfaceLICPainter> _painter;
+    vtkSmartPointer<vtkMapper> _mapper;
+};
+
+}
+
+#endif
Index: /trunk/packages/vizservers/vtkvis/Line.cpp
===================================================================
--- /trunk/packages/vizservers/vtkvis/Line.cpp	(revision 3616)
+++ /trunk/packages/vizservers/vtkvis/Line.cpp	(revision 3616)
@@ -0,0 +1,45 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (C) 2004-2012  HUBzero Foundation, LLC
+ *
+ * Author: Leif Delgass <ldelgass@purdue.edu>
+ */
+
+#include <vtkPolyDataMapper.h>
+#include <vtkActor.h>
+#include <vtkLineSource.h>
+
+#include "Line.h"
+#include "Trace.h"
+
+using namespace VtkVis;
+
+Line::Line() :
+    Shape()
+{
+}
+
+Line::~Line()
+{
+    TRACE("Deleting Line");
+}
+
+void Line::update()
+{
+    if (_line == NULL) {
+	_line = vtkSmartPointer<vtkLineSource>::New();
+    }
+
+    if (_pdMapper == NULL) {
+        _pdMapper = vtkSmartPointer<vtkPolyDataMapper>::New();
+        _pdMapper->SetResolveCoincidentTopologyToPolygonOffset();
+        _pdMapper->ScalarVisibilityOff();
+    }
+
+    _pdMapper->SetInputConnection(_line->GetOutputPort());
+
+    initProp();
+
+    getActor()->SetMapper(_pdMapper);
+    _pdMapper->Update();
+}
Index: /trunk/packages/vizservers/vtkvis/Line.h
===================================================================
--- /trunk/packages/vizservers/vtkvis/Line.h	(revision 3616)
+++ /trunk/packages/vizservers/vtkvis/Line.h	(revision 3616)
@@ -0,0 +1,53 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (C) 2004-2012  HUBzero Foundation, LLC
+ *
+ * Author: Leif Delgass <ldelgass@purdue.edu>
+ */
+
+#ifndef VTKVIS_LINE_H
+#define VTKVIS_LINE_H
+
+#include <vtkSmartPointer.h>
+#include <vtkPolyDataMapper.h>
+#include <vtkActor.h>
+#include <vtkLineSource.h>
+
+#include "Shape.h"
+#include "VtkDataSet.h"
+
+namespace VtkVis {
+
+/**
+ * \brief VTK PolyData Line
+ *
+ * This class creates a line
+ */
+class Line : public Shape
+{
+public:
+    Line();
+    virtual ~Line();
+
+    virtual const char *getClassName() const
+    {
+        return "Line";
+    }
+
+    void setEndPoints(double pt1[3], double pt2[3])
+    {
+        if (_line != NULL) {
+            _line->SetPoint1(pt1);
+	    _line->SetPoint2(pt2);
+	}
+    }
+
+private:
+    virtual void update();
+
+    vtkSmartPointer<vtkLineSource> _line;
+};
+
+}
+
+#endif
Index: /trunk/packages/vizservers/vtkvis/Makefile.in
===================================================================
--- /trunk/packages/vizservers/vtkvis/Makefile.in	(revision 3615)
+++ /trunk/packages/vizservers/vtkvis/Makefile.in	(revision 3616)
@@ -137,40 +137,40 @@
 
 SERVER_SRCS	= \
+		Arc.cpp \
+		Arrow.cpp \
+		Box.cpp \
 		CmdProc.cpp \
 		ColorMap.cpp \
+		Cone.cpp \
+		Contour2D.cpp \
+		Contour3D.cpp \
+		Cutplane.cpp \
+		Cylinder.cpp \
+		Disk.cpp \
+		Glyphs.cpp \
+		Group.cpp \
+		HeightMap.cpp \
+		LIC.cpp \
+		Line.cpp \
+		Molecule.cpp \
+		Outline.cpp \
+		PolyData.cpp \
+		Polygon.cpp \
 		PPMWriter.cpp \
+		PseudoColor.cpp \
 		ReadBuffer.cpp \
-		RpArc.cpp \
-		RpArrow.cpp \
-		RpBox.cpp \
-		RpCone.cpp \
-		RpContour2D.cpp \
-		RpContour3D.cpp \
-		RpCutplane.cpp \
-		RpCylinder.cpp \
-		RpDisk.cpp \
-		RpGlyphs.cpp \
-		RpGroup.cpp \
-		RpHeightMap.cpp \
-		RpLine.cpp \
-		RpLIC.cpp \
-		RpMolecule.cpp \
-		RpOutline.cpp \
-		RpPolyData.cpp \
-		RpPolygon.cpp \
-		RpPseudoColor.cpp \
-		RpShape.cpp \
-		RpSphere.cpp \
-		RpStreamlines.cpp \
-		RpVolume.cpp \
-		RpVtkDataSet.cpp \
-		RpVtkGraphicsObject.cpp \
-		RpVtkRenderer.cpp \
-		RpVtkRendererCmd.cpp \
-		RpVtkRendererGraphicsObjs.cpp \
-		RpVtkRenderServer.cpp \
-		RpWarp.cpp \
+		Shape.cpp \
+		Sphere.cpp \
+		Streamlines.cpp \
 		TGAWriter.cpp \
-		Trace.cpp 
+		Trace.cpp \
+		Volume.cpp \
+		VtkDataSet.cpp \
+		VtkGraphicsObject.cpp \
+		VtkRenderer.cpp \
+		VtkRendererCmd.cpp \
+		VtkRendererGraphicsObjs.cpp \
+		VtkRenderServer.cpp \
+		Warp.cpp
 
 ifdef USE_CUSTOM_AXES
@@ -217,44 +217,43 @@
 	$(RM) Makefile Doxyfile
 
+Arc.o: Arc.h Shape.h VtkGraphicsObject.h VtkDataSet.h VtkRenderer.h Trace.h
+Arrow.o: Arrow.h Shape.h VtkGraphicsObject.h VtkDataSet.h VtkRenderer.h Trace.h
+Box.o: Box.h Shape.h VtkGraphicsObject.h VtkDataSet.h VtkRenderer.h Trace.h
 CmdProc.o: CmdProc.h
-ColorMap.o: ColorMap.h RpMolecule.h Trace.h
+ColorMap.o: ColorMap.h Molecule.h Trace.h
+Cone.o: Cone.h Shape.h VtkGraphicsObject.h VtkDataSet.h VtkRenderer.h Trace.h
+Contour2D.o: Contour2D.h VtkGraphicsObject.h VtkDataSet.h VtkRenderer.h Trace.h
+Contour3D.o: Contour3D.h VtkGraphicsObject.h VtkDataSet.h VtkRenderer.h ColorMap.h Trace.h
+Cutplane.o: Cutplane.h VtkGraphicsObject.h VtkDataSet.h VtkRenderer.h ColorMap.h Trace.h
+Cylinder.o: Cylinder.h Shape.h VtkGraphicsObject.h VtkDataSet.h VtkRenderer.h Trace.h
+Disk.o: Disk.h Shape.h VtkGraphicsObject.h VtkDataSet.h VtkRenderer.h Trace.h
+Glyphs.o: Glyphs.h VtkGraphicsObject.h VtkDataSet.h VtkRenderer.h ColorMap.h Trace.h
+Group.o: Group.h VtkGraphicsObject.h VtkDataSet.h VtkRenderer.h Trace.h
+HeightMap.o: HeightMap.h VtkGraphicsObject.h VtkDataSet.h VtkRenderer.h ColorMap.h Trace.h
+LIC.o: LIC.h VtkGraphicsObject.h VtkDataSet.h VtkRenderer.h ColorMap.h Trace.h VtkRenderServer.h
+Line.o: Line.h Shape.h VtkGraphicsObject.h VtkDataSet.h VtkRenderer.h Trace.h
+md5.o: md5.h
+Molecule.o: Molecule.h MoleculeData.h VtkGraphicsObject.h VtkDataSet.h VtkRenderer.h ColorMap.h Trace.h
+Outline.o: Outline.h VtkGraphicsObject.h VtkDataSet.h Trace.h
+PolyData.o: PolyData.h VtkGraphicsObject.h VtkDataSet.h VtkRenderer.h Trace.h
+Polygon.o: Polygon.h Shape.h VtkGraphicsObject.h VtkDataSet.h VtkRenderer.h Trace.h
 PPMWriter.o: PPMWriter.h ResponseQueue.h Trace.h
+PseudoColor.o: PseudoColor.h VtkGraphicsObject.h VtkDataSet.h VtkRenderer.h ColorMap.h Trace.h
 ReadBuffer.o: ReadBuffer.h Trace.h
 ResponseQueue.o: ResponseQueue.h Trace.h
-RpArc.o: RpArc.h RpShape.h RpVtkGraphicsObject.h RpVtkDataSet.h RpVtkRenderer.h Trace.h
-RpArrow.o: RpArrow.h RpShape.h RpVtkGraphicsObject.h RpVtkDataSet.h RpVtkRenderer.h Trace.h
-RpBox.o: RpBox.h RpShape.h RpVtkGraphicsObject.h RpVtkDataSet.h RpVtkRenderer.h Trace.h
-RpCone.o: RpCone.h RpShape.h RpVtkGraphicsObject.h RpVtkDataSet.h RpVtkRenderer.h Trace.h
-RpContour2D.o: RpContour2D.h RpVtkGraphicsObject.h RpVtkDataSet.h RpVtkRenderer.h Trace.h
-RpContour3D.o: RpContour3D.h RpVtkGraphicsObject.h RpVtkDataSet.h RpVtkRenderer.h ColorMap.h Trace.h
-RpCutplane.o: RpCutplane.h RpVtkGraphicsObject.h RpVtkDataSet.h RpVtkRenderer.h ColorMap.h Trace.h
-RpCylinder.o: RpCylinder.h RpShape.h RpVtkGraphicsObject.h RpVtkDataSet.h RpVtkRenderer.h Trace.h
-RpDisk.o: RpDisk.h RpShape.h RpVtkGraphicsObject.h RpVtkDataSet.h RpVtkRenderer.h Trace.h
-RpGlyphs.o: RpGlyphs.h RpVtkGraphicsObject.h RpVtkDataSet.h RpVtkRenderer.h ColorMap.h Trace.h
-RpGroup.o: RpGroup.h RpVtkGraphicsObject.h RpVtkDataSet.h RpVtkRenderer.h Trace.h
-RpHeightMap.o: RpHeightMap.h RpVtkGraphicsObject.h RpVtkDataSet.h RpVtkRenderer.h ColorMap.h Trace.h
-RpLine.o: RpLine.h RpShape.h RpVtkGraphicsObject.h RpVtkDataSet.h RpVtkRenderer.h Trace.h
-RpLIC.o: RpLIC.h RpVtkGraphicsObject.h RpVtkDataSet.h RpVtkRenderer.h ColorMap.h Trace.h RpVtkRenderServer.h
-RpMolecule.o: RpMolecule.h RpMoleculeData.h RpVtkGraphicsObject.h RpVtkDataSet.h RpVtkRenderer.h ColorMap.h Trace.h
-RpMolecule2.o: RpMolecule2.h RpMoleculeData.h RpVtkGraphicsObject.h RpVtkDataSet.h RpVtkRenderer.h ColorMap.h Trace.h
-RpOutline.o: RpOutline.h RpVtkGraphicsObject.h RpVtkDataSet.h Trace.h
-RpPolyData.o: RpPolyData.h RpVtkGraphicsObject.h RpVtkDataSet.h RpVtkRenderer.h Trace.h
-RpPolygon.o: RpPolygon.h RpShape.h RpVtkGraphicsObject.h RpVtkDataSet.h RpVtkRenderer.h Trace.h
-RpPseudoColor.o: RpPseudoColor.h RpVtkGraphicsObject.h RpVtkDataSet.h RpVtkRenderer.h ColorMap.h Trace.h
-RpShape.o: RpShape.h RpVtkGraphicsObject.h RpVtkDataSet.h RpVtkRenderer.h Trace.h
-RpSphere.o: RpSphere.h RpShape.h RpVtkGraphicsObject.h RpVtkDataSet.h RpVtkRenderer.h Trace.h
-RpStreamlines.o: RpStreamlines.h RpVtkGraphicsObject.h RpVtkDataSet.h RpVtkRenderer.h ColorMap.h Trace.h
-RpVolume.o: RpVolume.h RpVtkGraphicsObject.h RpVtkDataSet.h RpVtkRenderer.h ColorMap.h Trace.h
-RpVtkDataSet.o: RpVtkDataSet.h Trace.h
-RpVtkGraphicsObject.o: RpVtkGraphicsObject.h RpVtkRenderer.h RpVtkDataSet.h ColorMap.h Trace.h
-RpVtkRenderer.o: RpVtkRenderer.h RpVtkRendererGraphicsObjs.h vtkRpCubeAxesActor.h vtkRpAxisFollower.h vtkRpAxisActor.h RpMath.h RpVtkDataSet.h RpArc.h RpArrow.h RpBox.h RpCone.h RpContour2D.h RpContour3D.h RpCutplane.h RpCylinder.h RpDisk.h RpGlyphs.h RpGroup.h RpHeightMap.h RpLIC.h RpLine.h RpMolecule.h RpOutline.h RpPolyData.h RpPolygon.h RpPseudoColor.h RpSphere.h RpStreamlines.h RpVolume.h ColorMap.h Trace.h
-RpVtkRendererCmd.o: RpVtkRenderer.h RpVtkRendererGraphicsObjs.h vtkRpCubeAxesActor.h vtkRpAxisFollower.h vtkRpAxisActor.h RpVtkDataSet.h RpArc.h RpArrow.h RpBox.h RpCone.h RpContour2D.h RpContour3D.h RpCutplane.h RpCylinder.h RpDisk.h RpGlyphs.h RpGroup.h RpHeightMap.h RpLIC.h RpLine.h RpMolecule.h RpOutline.h RpPolyData.h RpPolygon.h RpPseudoColor.h RpSphere.h RpStreamlines.h RpVolume.h ColorMap.h ReadBuffer.h ResponseQueue.h Trace.h CmdProc.h PPMWriter.h TGAWriter.h
-RpVtkRendererGraphicsObjs.o: RpVtkRenderer.h RpVtkRendererGraphicsObjs.h RpVtkDataSet.h RpArc.h RpArrow.h RpBox.h RpCone.h RpContour2D.h RpContour3D.h RpCutplane.h RpCylinder.h RpDisk.h RpGlyphs.h RpGroup.h RpHeightMap.h RpLIC.h RpLine.h RpMolecule.h RpOutline.h RpPolyData.h RpPolygon.h RpPseudoColor.h RpSphere.h RpStreamlines.h RpVolume.h ColorMap.h Trace.h
-RpVtkRenderServer.o: RpVtkRenderServer.h RpVtkRendererCmd.h RpVtkRenderer.h vtkRpCubeAxesActor.h vtkRpAxisFollower.h vtkRpAxisActor.h ReadBuffer.h ResponseQueue.h Trace.h PPMWriter.h TGAWriter.h
-RpWarp.o: RpWarp.h RpVtkGraphicsObject.h RpVtkDataSet.h RpVtkRenderer.h ColorMap.h Trace.h
+Shape.o: Shape.h VtkGraphicsObject.h VtkDataSet.h VtkRenderer.h Trace.h
+Sphere.o: Sphere.h Shape.h VtkGraphicsObject.h VtkDataSet.h VtkRenderer.h Trace.h
+Streamlines.o: Streamlines.h VtkGraphicsObject.h VtkDataSet.h VtkRenderer.h ColorMap.h Trace.h
+TGAWriter.o: TGAWriter.h ResponseQueue.h Trace.h
 Trace.o: Trace.h
-TGAWriter.o: TGAWriter.h ResponseQueue.h Trace.h
+Volume.o: Volume.h VtkGraphicsObject.h VtkDataSet.h VtkRenderer.h ColorMap.h Trace.h
+VtkDataSet.o: VtkDataSet.h Trace.h
+VtkGraphicsObject.o: VtkGraphicsObject.h VtkRenderer.h VtkDataSet.h ColorMap.h Trace.h
+VtkRenderer.o: VtkRenderer.h VtkRendererGraphicsObjs.h vtkRpCubeAxesActor.h vtkRpAxisFollower.h vtkRpAxisActor.h Math.h VtkDataSet.h Arc.h Arrow.h Box.h Cone.h Contour2D.h Contour3D.h Cutplane.h Cylinder.h Disk.h Glyphs.h Group.h HeightMap.h LIC.h Line.h Molecule.h Outline.h PolyData.h Polygon.h PseudoColor.h Sphere.h Streamlines.h Volume.h ColorMap.h Trace.h
+VtkRendererCmd.o: VtkRenderer.h VtkRendererGraphicsObjs.h vtkRpCubeAxesActor.h vtkRpAxisFollower.h vtkRpAxisActor.h VtkDataSet.h Arc.h Arrow.h Box.h Cone.h Contour2D.h Contour3D.h Cutplane.h Cylinder.h Disk.h Glyphs.h Group.h HeightMap.h LIC.h Line.h Molecule.h Outline.h PolyData.h Polygon.h PseudoColor.h Sphere.h Streamlines.h Volume.h ColorMap.h ReadBuffer.h ResponseQueue.h Trace.h CmdProc.h PPMWriter.h TGAWriter.h
+VtkRendererGraphicsObjs.o: VtkRenderer.h VtkRendererGraphicsObjs.h VtkDataSet.h Arc.h Arrow.h Box.h Cone.h Contour2D.h Contour3D.h Cutplane.h Cylinder.h Disk.h Glyphs.h Group.h HeightMap.h LIC.h Line.h Molecule.h Outline.h PolyData.h Polygon.h PseudoColor.h Sphere.h Streamlines.h Volume.h ColorMap.h Trace.h
+VtkRenderServer.o: VtkRenderServer.h VtkRendererCmd.h VtkRenderer.h vtkRpCubeAxesActor.h vtkRpAxisFollower.h vtkRpAxisActor.h ReadBuffer.h ResponseQueue.h Trace.h PPMWriter.h TGAWriter.h
 vtkRpAxisActor.o: vtkRpAxisActor.h
 vtkRpAxisFollower.o: vtkRpAxisFollower.h vtkRpAxisActor.h
 vtkRpCubeAxesActor.o: vtkRpCubeAxesActor.h vtkRpAxisFollower.h vtkRpAxisActor.h
-md5.o: md5.h
+Warp.o: Warp.h VtkGraphicsObject.h VtkDataSet.h VtkRenderer.h ColorMap.h Trace.h
Index: /trunk/packages/vizservers/vtkvis/Math.h
===================================================================
--- /trunk/packages/vizservers/vtkvis/Math.h	(revision 3616)
+++ /trunk/packages/vizservers/vtkvis/Math.h	(revision 3616)
@@ -0,0 +1,221 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (C) 2004-2012  HUBzero Foundation, LLC
+ *
+ * Author: Leif Delgass <ldelgass@purdue.edu>
+ */
+
+#ifndef VTKVIS_MATH_H
+#define VTKVIS_MATH_H
+
+#include <cmath>
+#include <cstring>
+
+#include <vtkMath.h>
+#include <vtkMatrix4x4.h>
+
+namespace VtkVis {
+
+/**
+ * \brief Convert a quaternion to an axis/angle rotation
+ * 
+ * \param[in] quat Quaternion with scalar first: wxyz
+ * \param[out] angleAxis axis/angle rotation with angle in degrees first
+ */
+inline void quatToAngleAxis(const double quat[4], double angleAxis[4])
+{
+    angleAxis[0] = vtkMath::DegreesFromRadians(2.0 * acos(quat[0]));
+    if (angleAxis[0] < 1.0e-6) {
+        angleAxis[1] = 1;
+        angleAxis[2] = 0;
+        angleAxis[3] = 0;
+    } else {
+        double denom = sqrt(1. - quat[0] * quat[0]);
+        angleAxis[1] = quat[1] / denom;
+        angleAxis[2] = quat[2] / denom;
+        angleAxis[3] = quat[3] / denom;
+    }
+}
+
+/**
+ * \brief Convert an axis/angle rotation to a quaternion
+ * 
+ * \param[in] angleAxis axis/angle rotation with angle in degrees first
+ * \param[out] quat Quaternion with scalar first: wxyz
+ */
+inline void angleAxisToQuat(const double angleAxis[4], double quat[4])
+{
+    quat[0] = cos(vtkMath::RadiansFromDegrees(angleAxis[0]) / 2.0);
+    double sinHalfAngle = sin(vtkMath::RadiansFromDegrees(angleAxis[0]) / 2.0);
+    quat[1] = angleAxis[1] * sinHalfAngle;
+    quat[2] = angleAxis[2] * sinHalfAngle;
+    quat[3] = angleAxis[3] * sinHalfAngle;
+}
+
+/**
+ * \brief Fill a vtkMatrix4x4 from a quaternion
+ *
+ * \param[in] quat Quaternion with scalar first: wxyz
+ * \param[out] mat Matrix to be filled in
+ */
+inline void quaternionToMatrix4x4(const double quat[4], vtkMatrix4x4& mat)
+{
+    double ww = quat[0]*quat[0];
+    double wx = quat[0]*quat[1];
+    double wy = quat[0]*quat[2];
+    double wz = quat[0]*quat[3];
+
+    double xx = quat[1]*quat[1];
+    double yy = quat[2]*quat[2];
+    double zz = quat[3]*quat[3];
+
+    double xy = quat[1]*quat[2];
+    double xz = quat[1]*quat[3];
+    double yz = quat[2]*quat[3];
+
+    double rr = xx + yy + zz;
+    // normalization factor, just in case quaternion was not normalized
+    double f = double(1)/double(sqrt(ww + rr));
+    double s = (ww - rr)*f;
+    f *= 2;
+
+    mat[0][0] = xx*f + s;
+    mat[1][0] = (xy + wz)*f;
+    mat[2][0] = (xz - wy)*f;
+
+    mat[0][1] = (xy - wz)*f;
+    mat[1][1] = yy*f + s;
+    mat[2][1] = (yz + wx)*f;
+
+    mat[0][2] = (xz + wy)*f;
+    mat[1][2] = (yz - wx)*f;
+    mat[2][2] = zz*f + s;
+}
+
+/**
+ * \brief Fill a vtkMatrix4x4 from a quaternion, but with the matrix
+ * transposed.
+ *
+ * \param[in] quat Quaternion with scalar first: wxyz
+ * \param[out] mat Matrix to be filled in
+ */
+inline void quaternionToTransposeMatrix4x4(const double quat[4], vtkMatrix4x4& mat)
+{
+    double ww = quat[0]*quat[0];
+    double wx = quat[0]*quat[1];
+    double wy = quat[0]*quat[2];
+    double wz = quat[0]*quat[3];
+
+    double xx = quat[1]*quat[1];
+    double yy = quat[2]*quat[2];
+    double zz = quat[3]*quat[3];
+
+    double xy = quat[1]*quat[2];
+    double xz = quat[1]*quat[3];
+    double yz = quat[2]*quat[3];
+
+    double rr = xx + yy + zz;
+    // normalization factor, just in case quaternion was not normalized
+    double f = double(1)/double(sqrt(ww + rr));
+    double s = (ww - rr)*f;
+    f *= 2;
+
+    mat[0][0] = xx*f + s;
+    mat[0][1] = (xy + wz)*f;
+    mat[0][2] = (xz - wy)*f;
+
+    mat[1][0] = (xy - wz)*f;
+    mat[1][1] = yy*f + s;
+    mat[1][2] = (yz + wx)*f;
+
+    mat[2][0] = (xz + wy)*f;
+    mat[2][1] = (yz - wx)*f;
+    mat[2][2] = zz*f + s;
+}
+
+/**
+ * \brief Multiply two quaternions and return the result
+ *
+ * Note: result can be the same memory location as one of the
+ * inputs
+ */
+inline double *quatMult(const double q1[4], const double q2[4], double result[4])
+{
+    double q1w = q1[0];
+    double q1x = q1[1];
+    double q1y = q1[2];
+    double q1z = q1[3];
+    double q2w = q2[0];
+    double q2x = q2[1];
+    double q2y = q2[2];
+    double q2z = q2[3];
+    result[0] = (q1w*q2w) - (q1x*q2x) - (q1y*q2y) - (q1z*q2z);
+    result[1] = (q1w*q2x) + (q1x*q2w) + (q1y*q2z) - (q1z*q2y);
+    result[2] = (q1w*q2y) + (q1y*q2w) + (q1z*q2x) - (q1x*q2z);
+    result[3] = (q1w*q2z) + (q1z*q2w) + (q1x*q2y) - (q1y*q2x);
+    return result;
+}
+
+/**
+ * \brief Compute the conjugate of a quaternion
+ *
+ * Note: result can be the same memory location as the input
+ */
+inline double *quatConjugate(const double quat[4], double result[4])
+{
+    if (result != quat)
+        result[0] = quat[0];
+    result[1] = -quat[1];
+    result[2] = -quat[2];
+    result[3] = -quat[3];
+    return result;
+}
+
+/**
+ * \brief Compute the reciprocal of a quaternion
+ *
+ * Note: result can be the same memory location as the input
+ */
+inline double *quatReciprocal(const double quat[4], double result[4])
+{
+    double denom = 
+        quat[0]*quat[0] + 
+        quat[1]*quat[1] + 
+        quat[2]*quat[2] + 
+        quat[3]*quat[3];
+    VtkVis::quatConjugate(quat, result);
+    for (int i = 0; i < 4; i++) {
+        result[i] /= denom;
+    }
+    return result;
+}
+
+/**
+ * \brief Compute the reciprocal of a quaternion in place
+ */
+inline double *quatReciprocal(double quat[4])
+{
+    return VtkVis::quatReciprocal(quat, quat);
+}
+
+/**
+ * \brief Deep copy a quaternion
+ */
+inline void copyQuat(const double quat[4], double result[4])
+{
+    memcpy(result, quat, sizeof(double)*4);
+}
+
+inline double min2(double a, double b)
+{
+    return ((a < b) ? a : b);
+}
+
+inline double max2(double a, double b)
+{
+    return ((a > b) ? a : b);
+}
+
+}
+
+#endif
Index: /trunk/packages/vizservers/vtkvis/Molecule.cpp
===================================================================
--- /trunk/packages/vizservers/vtkvis/Molecule.cpp	(revision 3616)
+++ /trunk/packages/vizservers/vtkvis/Molecule.cpp	(revision 3616)
@@ -0,0 +1,968 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (C) 2004-2012  HUBzero Foundation, LLC
+ *
+ * Author: Leif Delgass <ldelgass@purdue.edu>
+ */
+
+#include <cstdio>
+#include <cfloat>
+#include <cassert>
+
+#include <vtkDataSet.h>
+#include <vtkCellArray.h>
+#include <vtkPointData.h>
+#include <vtkFloatArray.h>
+#include <vtkDoubleArray.h>
+#include <vtkIntArray.h>
+#include <vtkStringArray.h>
+#include <vtkPolyData.h>
+#include <vtkPolyDataMapper.h>
+#include <vtkActor.h>
+#include <vtkProperty.h>
+#include <vtkSphereSource.h>
+#include <vtkCylinderSource.h>
+#include <vtkTransform.h>
+#include <vtkTransformPolyDataFilter.h>
+#include <vtkGlyph3DMapper.h>
+#include <vtkPointSetToLabelHierarchy.h>
+#include <vtkLabelPlacementMapper.h>
+#include <vtkTextProperty.h>
+
+#include "Molecule.h"
+#include "MoleculeData.h"
+#include "VtkRenderer.h"
+#include "Trace.h"
+
+using namespace VtkVis;
+
+Molecule::Molecule() :
+    VtkGraphicsObject(),
+    _radiusScale(0.3),
+    _atomScaling(COVALENT_RADIUS),
+    _labelsOn(false),
+    _colorMap(NULL),
+    _colorMode(COLOR_BY_ELEMENTS),
+    _colorFieldType(DataSet::POINT_DATA)
+{
+    _bondColor[0] = _bondColor[1] = _bondColor[2] = 1.0f;
+    _colorFieldRange[0] = DBL_MAX;
+    _colorFieldRange[1] = -DBL_MAX;
+    _faceCulling = true;
+}
+
+Molecule::~Molecule()
+{
+#ifdef WANT_TRACE
+    if (_dataSet != NULL)
+        TRACE("Deleting Molecule for %s", _dataSet->getName().c_str());
+    else
+        TRACE("Deleting Molecule with NULL DataSet");
+#endif
+}
+
+void Molecule::setDataSet(DataSet *dataSet,
+                          Renderer *renderer)
+{
+    if (_dataSet != dataSet) {
+        _dataSet = dataSet;
+
+        _renderer = renderer;
+
+        if (renderer->getUseCumulativeRange()) {
+            renderer->getCumulativeDataRange(_dataRange,
+                                             _dataSet->getActiveScalarsName(),
+                                             1);
+            renderer->getCumulativeDataRange(_vectorMagnitudeRange,
+                                             _dataSet->getActiveVectorsName(),
+                                             3);
+            for (int i = 0; i < 3; i++) {
+                renderer->getCumulativeDataRange(_vectorComponentRange[i],
+                                                 _dataSet->getActiveVectorsName(),
+                                                 3, i);
+            }
+        } else {
+            _dataSet->getScalarRange(_dataRange);
+            _dataSet->getVectorRange(_vectorMagnitudeRange);
+            for (int i = 0; i < 3; i++) {
+                _dataSet->getVectorRange(_vectorComponentRange[i], i);
+            }
+        }
+
+        update();
+    }
+}
+
+/**
+ * \brief Create and initialize VTK Props to render a Molecule
+ */
+void Molecule::initProp()
+{
+    if (_atomProp == NULL) {
+        _atomProp = vtkSmartPointer<vtkActor>::New();
+        if (_faceCulling && _opacity == 1.0)
+            setCulling(_atomProp->GetProperty(), true);
+        _atomProp->GetProperty()->EdgeVisibilityOff();
+        _atomProp->GetProperty()->SetEdgeColor(_edgeColor[0], _edgeColor[1], _edgeColor[2]);
+        _atomProp->GetProperty()->SetLineWidth(_edgeWidth);
+        _atomProp->GetProperty()->SetOpacity(_opacity);
+        _atomProp->GetProperty()->SetAmbient(.2);
+        if (!_lighting)
+            _atomProp->GetProperty()->LightingOff();
+    }
+    if (_bondProp == NULL) {
+        _bondProp = vtkSmartPointer<vtkActor>::New();
+        if (_faceCulling && _opacity == 1.0)
+            setCulling(_bondProp->GetProperty(), true);
+        _bondProp->GetProperty()->EdgeVisibilityOff();
+        _bondProp->GetProperty()->SetColor(_bondColor[0], _bondColor[1], _bondColor[2]);
+        _bondProp->GetProperty()->SetEdgeColor(_edgeColor[0], _edgeColor[1], _edgeColor[2]);
+        _bondProp->GetProperty()->SetLineWidth(_edgeWidth);
+        _bondProp->GetProperty()->SetOpacity(_opacity);
+        _bondProp->GetProperty()->SetAmbient(.2);
+        if (!_lighting)
+            _bondProp->GetProperty()->LightingOff();
+    }
+    if (_labelProp == NULL) {
+        _labelProp = vtkSmartPointer<vtkActor2D>::New();
+    }
+    if (_prop == NULL) {
+        _prop = vtkSmartPointer<vtkAssembly>::New();
+    }
+}
+
+/**
+ * \brief Internal method to set up pipeline after a state change
+ */
+void Molecule::update()
+{
+    if (_dataSet == NULL) {
+        return;
+    }
+    vtkDataSet *ds = _dataSet->getVtkDataSet();
+
+    if (_atomMapper == NULL) {
+        _atomMapper = vtkSmartPointer<vtkGlyph3DMapper>::New();
+        _atomMapper->SetResolveCoincidentTopologyToPolygonOffset();
+        _atomMapper->ScalarVisibilityOn();
+    }
+    if (_bondMapper == NULL) {
+        _bondMapper = vtkSmartPointer<vtkGlyph3DMapper>::New();
+        _bondMapper->SetResolveCoincidentTopologyToPolygonOffset();
+        _bondMapper->ScalarVisibilityOn();
+    }
+    if (_labelMapper == NULL) {
+        _labelMapper = vtkSmartPointer<vtkLabelPlacementMapper>::New();
+        _labelMapper->SetShapeToRoundedRect();
+        _labelMapper->SetBackgroundColor(1.0, 1.0, 0.7);
+        _labelMapper->SetBackgroundOpacity(0.8);
+        _labelMapper->SetMargin(3);
+    }
+
+    if (_lut == NULL) {
+        if (ds->GetPointData() == NULL ||
+            ds->GetPointData()->GetScalars() == NULL ||
+            strcmp(ds->GetPointData()->GetScalars()->GetName(), "element") != 0) {
+            WARN("No element array in dataset %s", _dataSet->getName().c_str());
+            setColorMap(ColorMap::getDefault());
+            if (_atomScaling != NO_ATOM_SCALING)
+                _atomScaling = NO_ATOM_SCALING;
+        } else {
+            TRACE("Using element default colormap");
+            setColorMap(ColorMap::getElementDefault());
+        }
+    }
+
+    initProp();
+
+    addLabelArray(ds);
+    addRadiusArray(ds, _atomScaling, _radiusScale);
+
+    vtkPolyData *pd = vtkPolyData::SafeDownCast(ds);
+    if (pd) {
+        TRACE("Verts: %d Lines: %d Polys: %d Strips: %d",
+                  pd->GetNumberOfVerts(),
+                  pd->GetNumberOfLines(),
+                  pd->GetNumberOfPolys(),
+                  pd->GetNumberOfStrips());
+        // DataSet is a vtkPolyData
+        if (pd->GetNumberOfLines() > 0) {
+            // Bonds
+            setupBondPolyData();
+
+            if (_cylinderSource == NULL) {
+                _cylinderSource = vtkSmartPointer<vtkCylinderSource>::New();
+                _cylinderSource->SetRadius(0.075);
+                _cylinderSource->SetHeight(1.0);
+                _cylinderSource->SetResolution(12);
+                _cylinderSource->CappingOff();
+                _cylinderTrans = vtkSmartPointer<vtkTransformPolyDataFilter>::New();
+                _cylinderTrans->SetInputConnection(_cylinderSource->GetOutputPort());
+                vtkSmartPointer<vtkTransform> trans = vtkSmartPointer<vtkTransform>::New();
+                trans->RotateZ(-90.0);
+                _cylinderTrans->SetTransform(trans);
+            }
+            if (_lineSource == NULL) {
+                _lineSource = vtkSmartPointer<vtkLineSource>::New();
+                _lineSource->SetPoint1(-0.5, 0, 0);
+                _lineSource->SetPoint2(0.5, 0, 0);
+            }
+
+            _bondMapper->SetSourceConnection(_cylinderTrans->GetOutputPort());
+#ifdef USE_VTK6
+            _bondMapper->SetInputData(_bondPD);
+#else
+            _bondMapper->SetInputConnection(_bondPD->GetProducerPort());
+#endif
+            _bondMapper->SetOrientationArray("bond_orientations");
+            _bondMapper->SetOrientationModeToDirection();
+            _bondMapper->OrientOn();
+            _bondMapper->SetScaleArray("bond_scales");
+            _bondMapper->SetScaleModeToScaleByVectorComponents();
+            _bondMapper->ScalingOn();
+            _bondMapper->ClampingOff();
+
+            _bondProp->SetMapper(_bondMapper);
+            getAssembly()->AddPart(_bondProp);
+        }
+        if (pd->GetNumberOfVerts() > 0) {
+            vtkSmartPointer<vtkPointSetToLabelHierarchy> hier = vtkSmartPointer<vtkPointSetToLabelHierarchy>::New();
+#ifdef USE_VTK6
+            hier->SetInputData(pd);
+#else
+            hier->SetInput(pd);
+#endif
+            hier->SetLabelArrayName("labels");
+            hier->GetTextProperty()->SetColor(0, 0, 0);
+            _labelMapper->SetInputConnection(hier->GetOutputPort());
+            _labelProp->SetMapper(_labelMapper);
+
+            // Atoms
+            vtkSmartPointer<vtkSphereSource> sphereSource = vtkSmartPointer<vtkSphereSource>::New();
+            sphereSource->SetRadius(1.0);
+            sphereSource->SetThetaResolution(14);
+            sphereSource->SetPhiResolution(14);
+
+            _atomMapper->SetSourceConnection(sphereSource->GetOutputPort());
+#ifdef USE_VTK6
+            _atomMapper->SetInputData(pd);
+#else
+            _atomMapper->SetInputConnection(pd->GetProducerPort());
+#endif
+            if (ds->GetPointData() != NULL &&
+                ds->GetPointData()->GetVectors() != NULL) {
+                _atomMapper->SetScaleArray(vtkDataSetAttributes::VECTORS);
+                _atomMapper->SetScaleModeToScaleByMagnitude();
+                _atomMapper->ScalingOn();
+            } else {
+                _atomMapper->SetScaleModeToNoDataScaling();
+                _atomMapper->ScalingOff();
+            }
+            _atomMapper->OrientOff();
+
+            _atomProp->SetMapper(_atomMapper);
+            getAssembly()->AddPart(_atomProp);
+        }
+    } else {
+        // DataSet is NOT a vtkPolyData
+        ERROR("DataSet is not a PolyData");
+        return;
+    }
+
+    setAtomLabelVisibility(_labelsOn);
+
+    _atomMapper->Update();
+    _bondMapper->Update();
+    _labelMapper->Update();
+}
+
+void Molecule::updateRanges(Renderer *renderer)
+{
+    if (_dataSet == NULL) {
+        ERROR("called before setDataSet");
+        return;
+    }
+
+    if (renderer->getUseCumulativeRange()) {
+        renderer->getCumulativeDataRange(_dataRange,
+                                         _dataSet->getActiveScalarsName(),
+                                         1);
+        renderer->getCumulativeDataRange(_vectorMagnitudeRange,
+                                         _dataSet->getActiveVectorsName(),
+                                         3);
+        for (int i = 0; i < 3; i++) {
+            renderer->getCumulativeDataRange(_vectorComponentRange[i],
+                                             _dataSet->getActiveVectorsName(),
+                                             3, i);
+        }
+    } else {
+        _dataSet->getScalarRange(_dataRange);
+        _dataSet->getVectorRange(_vectorMagnitudeRange);
+        for (int i = 0; i < 3; i++) {
+            _dataSet->getVectorRange(_vectorComponentRange[i], i);
+        }
+    }
+
+    // Need to update color map ranges
+    double *rangePtr = _colorFieldRange;
+    if (_colorFieldRange[0] > _colorFieldRange[1]) {
+        rangePtr = NULL;
+    }
+    setColorMode(_colorMode, _colorFieldType, _colorFieldName.c_str(), rangePtr);
+}
+
+void Molecule::setColorMode(ColorMode mode)
+{
+    _colorMode = mode;
+    if (_dataSet == NULL)
+        return;
+
+    switch (mode) {
+    case COLOR_BY_ELEMENTS: // Assume default scalar is "element" array
+        setColorMode(mode,
+                     DataSet::POINT_DATA,
+                     "element");
+        break;
+    case COLOR_BY_SCALAR:
+        setColorMode(mode,
+                     _dataSet->getActiveScalarsType(),
+                     _dataSet->getActiveScalarsName(),
+                     _dataRange);
+        break;
+    case COLOR_BY_VECTOR_MAGNITUDE:
+        setColorMode(mode,
+                     _dataSet->getActiveVectorsType(),
+                     _dataSet->getActiveVectorsName(),
+                     _vectorMagnitudeRange);
+        break;
+    case COLOR_BY_VECTOR_X:
+        setColorMode(mode,
+                     _dataSet->getActiveVectorsType(),
+                     _dataSet->getActiveVectorsName(),
+                     _vectorComponentRange[0]);
+        break;
+    case COLOR_BY_VECTOR_Y:
+        setColorMode(mode,
+                     _dataSet->getActiveVectorsType(),
+                     _dataSet->getActiveVectorsName(),
+                     _vectorComponentRange[1]);
+        break;
+    case COLOR_BY_VECTOR_Z:
+        setColorMode(mode,
+                     _dataSet->getActiveVectorsType(),
+                     _dataSet->getActiveVectorsName(),
+                     _vectorComponentRange[2]);
+        break;
+    case COLOR_CONSTANT:
+    default:
+        setColorMode(mode, DataSet::POINT_DATA, NULL, NULL);
+        break;
+    }
+}
+
+void Molecule::setColorMode(ColorMode mode,
+                            const char *name, double range[2])
+{
+    if (_dataSet == NULL)
+        return;
+    DataSet::DataAttributeType type = DataSet::POINT_DATA;
+    int numComponents = 1;
+    if (name != NULL && strlen(name) > 0 &&
+        !_dataSet->getFieldInfo(name, &type, &numComponents)) {
+        ERROR("Field not found: %s", name);
+        return;
+    }
+    setColorMode(mode, type, name, range);
+}
+
+void Molecule::setColorMode(ColorMode mode, DataSet::DataAttributeType type,
+                            const char *name, double range[2])
+{
+    _colorMode = mode;
+    _colorFieldType = type;
+    if (name == NULL)
+        _colorFieldName.clear();
+    else
+        _colorFieldName = name;
+    if (range == NULL) {
+        _colorFieldRange[0] = DBL_MAX;
+        _colorFieldRange[1] = -DBL_MAX;
+    } else {
+        memcpy(_colorFieldRange, range, sizeof(double)*2);
+    }
+
+    if (_dataSet == NULL || (_atomMapper == NULL && _bondMapper == NULL))
+        return;
+
+    switch (type) {
+    case DataSet::POINT_DATA:
+        if (_atomMapper != NULL)
+            _atomMapper->SetScalarModeToUsePointFieldData();
+        if (_bondMapper != NULL)
+            _bondMapper->SetScalarModeToUsePointFieldData();
+        break;
+    case DataSet::CELL_DATA:
+        if (_atomMapper != NULL)
+            _atomMapper->SetScalarModeToUseCellFieldData();
+        if (_bondMapper != NULL)
+            _bondMapper->SetScalarModeToUseCellFieldData();
+        break;
+    default:
+        ERROR("Unsupported DataAttributeType: %d", type);
+        return;
+    }
+
+    if (name != NULL && strlen(name) > 0) {
+        if (_atomMapper != NULL)
+            _atomMapper->SelectColorArray(name);
+        if (_bondMapper != NULL)
+            _bondMapper->SelectColorArray(name);
+    } else {
+        if (_atomMapper != NULL)
+            _atomMapper->SetScalarModeToDefault();
+        if (_bondMapper != NULL)
+            _bondMapper->SetScalarModeToDefault();
+    }
+
+    if (_lut != NULL) {
+        if (range != NULL) {
+            _lut->SetRange(range);
+        } else if (mode == COLOR_BY_ELEMENTS) {
+            double range[2];
+            range[0] = 0;
+            range[1] = NUM_ELEMENTS;
+            _lut->SetRange(range);
+        } else if (name != NULL && strlen(name) > 0) {
+            double r[2];
+            int comp = -1;
+            if (mode == COLOR_BY_VECTOR_X)
+                comp = 0;
+            else if (mode == COLOR_BY_VECTOR_Y)
+                comp = 1;
+            else if (mode == COLOR_BY_VECTOR_Z)
+                comp = 2;
+
+            if (_renderer->getUseCumulativeRange()) {
+                int numComponents;
+                if  (!_dataSet->getFieldInfo(name, type, &numComponents)) {
+                    ERROR("Field not found: %s, type: %d", name, type);
+                    return;
+                } else if (numComponents < comp+1) {
+                    ERROR("Request for component %d in field with %d components",
+                          comp, numComponents);
+                    return;
+                }
+                _renderer->getCumulativeDataRange(r, name, type, numComponents, comp);
+            } else {
+                _dataSet->getDataRange(r, name, type, comp);
+            }
+            _lut->SetRange(r);
+        }
+    }
+
+    switch (mode) {
+    case COLOR_BY_ELEMENTS:
+        if (_atomMapper != NULL)
+            _atomMapper->ScalarVisibilityOn();
+        if (_bondMapper != NULL)
+            _bondMapper->ScalarVisibilityOn();
+        break;
+    case COLOR_BY_SCALAR:
+        if (_atomMapper != NULL)
+            _atomMapper->ScalarVisibilityOn();
+        if (_bondMapper != NULL)
+            _bondMapper->ScalarVisibilityOn();
+        break;
+    case COLOR_BY_VECTOR_MAGNITUDE:
+        if (_atomMapper != NULL)
+            _atomMapper->ScalarVisibilityOn();
+        if (_bondMapper != NULL)
+            _bondMapper->ScalarVisibilityOn();
+        if (_lut != NULL) {
+            _lut->SetVectorModeToMagnitude();
+        }
+        break;
+    case COLOR_BY_VECTOR_X:
+        if (_atomMapper != NULL)
+            _atomMapper->ScalarVisibilityOn();
+        if (_bondMapper != NULL)
+            _bondMapper->ScalarVisibilityOn();
+        if (_lut != NULL) {
+            _lut->SetVectorModeToComponent();
+            _lut->SetVectorComponent(0);
+        }
+        break;
+    case COLOR_BY_VECTOR_Y:
+        if (_atomMapper != NULL)
+            _atomMapper->ScalarVisibilityOn();
+        if (_bondMapper != NULL)
+            _bondMapper->ScalarVisibilityOn();
+        if (_lut != NULL) {
+            _lut->SetVectorModeToComponent();
+            _lut->SetVectorComponent(1);
+        }
+        break;
+    case COLOR_BY_VECTOR_Z:
+        if (_atomMapper != NULL)
+            _atomMapper->ScalarVisibilityOn();
+        if (_bondMapper != NULL)
+            _bondMapper->ScalarVisibilityOn();
+        if (_lut != NULL) {
+            _lut->SetVectorModeToComponent();
+            _lut->SetVectorComponent(2);
+        }
+        break;
+    case COLOR_CONSTANT:
+    default:
+        if (_atomMapper != NULL)
+            _atomMapper->ScalarVisibilityOff();
+        if (_bondMapper != NULL)
+            _bondMapper->ScalarVisibilityOff();
+        break;
+    }
+}
+
+/**
+ * \brief Called when the color map has been edited
+ */
+void Molecule::updateColorMap()
+{
+    setColorMap(_colorMap);
+}
+
+/**
+ * \brief Associate a colormap lookup table with the DataSet
+ */
+void Molecule::setColorMap(ColorMap *cmap)
+{
+    if (cmap == NULL)
+        return;
+
+    _colorMap = cmap;
+ 
+    if (_lut == NULL) {
+        _lut = vtkSmartPointer<vtkLookupTable>::New();
+        if (_atomMapper != NULL) {
+            _atomMapper->UseLookupTableScalarRangeOn();
+            _atomMapper->SetLookupTable(_lut);
+        }
+        if (_bondMapper != NULL) {
+            _bondMapper->UseLookupTableScalarRangeOn();
+            _bondMapper->SetLookupTable(_lut);
+        }
+        _lut->DeepCopy(cmap->getLookupTable());
+        switch (_colorMode) {
+        case COLOR_BY_ELEMENTS: {
+            double range[2];
+            range[0] = 0;
+            range[1] = NUM_ELEMENTS;
+            _lut->SetRange(range);
+        }
+            break;
+        case COLOR_CONSTANT:
+        case COLOR_BY_SCALAR:
+            _lut->SetRange(_dataRange);
+            break;
+        case COLOR_BY_VECTOR_MAGNITUDE:
+            _lut->SetRange(_vectorMagnitudeRange);
+            break;
+        case COLOR_BY_VECTOR_X:
+            _lut->SetRange(_vectorComponentRange[0]);
+            break;
+        case COLOR_BY_VECTOR_Y:
+            _lut->SetRange(_vectorComponentRange[1]);
+            break;
+        case COLOR_BY_VECTOR_Z:
+            _lut->SetRange(_vectorComponentRange[2]);
+            break;
+        default:
+            break;
+        }
+    } else {
+        double range[2];
+        _lut->GetTableRange(range);
+        _lut->DeepCopy(cmap->getLookupTable());
+        _lut->SetRange(range);
+        _lut->Modified();
+    }
+}
+
+/**
+ * \brief Turn on/off rendering of atom labels
+ */
+void Molecule::setAtomLabelVisibility(bool state)
+{
+    _labelsOn = state;
+    if (_labelProp != NULL) {
+        _labelProp->SetVisibility((state ? 1 : 0));
+    }
+}
+
+/**
+ * \brief Turn on/off rendering of the atoms
+ */
+void Molecule::setAtomVisibility(bool state)
+{
+    if (_atomProp != NULL) {
+        _atomProp->SetVisibility((state ? 1 : 0));
+    }
+}
+
+/**
+ * \brief Turn on/off rendering of the bonds
+ */
+void Molecule::setBondVisibility(bool state)
+{
+    if (_bondProp != NULL) {
+        _bondProp->SetVisibility((state ? 1 : 0));
+    }
+}
+
+/**
+ * \brief Toggle visibility of the prop
+ */
+void Molecule::setVisibility(bool state)
+{
+    VtkGraphicsObject::setVisibility(state);
+    if (_labelProp != NULL) {
+        if (!state)
+            _labelProp->SetVisibility(0);
+        else
+            setAtomLabelVisibility(_labelsOn);
+    }
+}
+
+/**
+ * \brief Set opacity of molecule
+ */
+void Molecule::setOpacity(double opacity)
+{
+    VtkGraphicsObject::setOpacity(opacity);
+    if (_labelMapper != NULL) {
+        _labelMapper->SetBackgroundOpacity(opacity);
+    }
+}
+
+void Molecule::setBondStyle(BondStyle style)
+{
+    switch (style) {
+    case BOND_STYLE_CYLINDER:
+        if (_bondProp != NULL) {
+            _bondProp->GetProperty()->SetLineWidth(_edgeWidth);
+            _bondProp->GetProperty()->SetLighting(_lighting ? 1 : 0);
+        }
+        if (_bondMapper != NULL && _cylinderTrans != NULL) {
+            _cylinderTrans->Modified();
+            _bondMapper->SetSourceConnection(_cylinderTrans->GetOutputPort());
+            _bondMapper->Modified();
+        }
+        break;
+    case BOND_STYLE_LINE:
+        if (_bondProp != NULL) {
+            _bondProp->GetProperty()->LightingOff();
+        }
+        if (_bondMapper != NULL && _lineSource != NULL) {
+            _lineSource->Modified();
+            _bondMapper->SetSourceConnection(_lineSource->GetOutputPort());
+            _bondMapper->Modified();
+        }
+         break;
+    default:
+        WARN("Unknown bond style");    
+    }
+}
+
+/**
+ * \brief Set constant bond color
+ */
+void Molecule::setBondColor(float color[3])
+{
+    _bondColor[0] = color[0];
+    _bondColor[1] = color[1];
+    _bondColor[2] = color[2];
+    if (_bondProp != NULL) {
+        _bondProp->GetProperty()->SetColor(_bondColor[0], _bondColor[1], _bondColor[2]);
+    }
+}
+
+/**
+ * \brief Set mode to determine how bonds are colored
+ */
+void Molecule::setBondColorMode(BondColorMode mode)
+{
+    if (_bondMapper == NULL) return;
+
+    switch (mode) {
+    case BOND_COLOR_BY_ELEMENTS:
+        _bondMapper->ScalarVisibilityOn();
+        break;
+    case BOND_COLOR_CONSTANT:
+        _bondMapper->ScalarVisibilityOff();
+        break;
+    default:
+        WARN("Unknown bond color mode");
+    }
+}
+
+/**
+ * \brief Set a group of world coordinate planes to clip rendering
+ *
+ * Passing NULL for planes will remove all cliping planes
+ */
+void Molecule::setClippingPlanes(vtkPlaneCollection *planes)
+{
+    if (_atomMapper != NULL) {
+        _atomMapper->SetClippingPlanes(planes);
+    }
+    if (_bondMapper != NULL) {
+        _bondMapper->SetClippingPlanes(planes);
+    }
+}
+
+/**
+ * \brief Set the radius type used for scaling atoms
+ */
+void Molecule::setAtomScaling(AtomScaling state)
+{
+    _atomScaling = state;
+    if (_dataSet != NULL) {
+        vtkDataSet *ds = _dataSet->getVtkDataSet();
+        addRadiusArray(ds, _atomScaling, _radiusScale);
+        if (_atomMapper != NULL) {
+             assert(ds->GetPointData() != NULL &&
+                    ds->GetPointData()->GetVectors() != NULL);
+            _atomMapper->SetScaleModeToScaleByMagnitude();
+            _atomMapper->SetScaleArray(vtkDataSetAttributes::VECTORS);
+            _atomMapper->ScalingOn();
+        }
+    }
+}
+
+/**
+ * \brief Set the constant radius scaling factor for atoms.  This
+ * can be used to convert from Angstroms to atom coordinates units.
+ */
+void Molecule::setAtomRadiusScale(double scale)
+{
+    _radiusScale = scale;
+    if (_dataSet != NULL) {
+        vtkDataSet *ds = _dataSet->getVtkDataSet();
+        addRadiusArray(ds, _atomScaling, _radiusScale);
+    }
+}
+
+/**
+ * \brief Set the constant radius scaling factor for bonds.
+ */
+void Molecule::setBondRadiusScale(double scale)
+{
+    if (_cylinderSource != NULL) {
+        _cylinderSource->SetRadius(scale);
+        // Workaround bug with source modification not causing
+        // mapper to be updated
+        if (_bondMapper != NULL) {
+            _bondMapper->Modified();
+        }
+    }
+}
+
+void Molecule::setupBondPolyData()
+{
+    if (_dataSet == NULL)
+        return;
+    if (_bondPD == NULL) {
+        _bondPD = vtkSmartPointer<vtkPolyData>::New();
+    } else {
+        _bondPD->Initialize();
+    }
+    vtkPolyData *pd = vtkPolyData::SafeDownCast(_dataSet->getVtkDataSet());
+    if (pd == NULL)
+        return;
+    vtkCellArray *lines = pd->GetLines();
+    lines->InitTraversal();
+    vtkIdType npts, *pts;
+    vtkSmartPointer<vtkPoints> bondPoints = vtkSmartPointer<vtkPoints>::New();
+    vtkSmartPointer<vtkIntArray> bondElements = vtkSmartPointer<vtkIntArray>::New();
+    vtkSmartPointer<vtkDoubleArray> bondVectors = vtkSmartPointer<vtkDoubleArray>::New();
+    vtkSmartPointer<vtkDoubleArray> bondScales = vtkSmartPointer<vtkDoubleArray>::New();
+    bondElements->SetName("element");
+    bondVectors->SetName("bond_orientations");
+    bondVectors->SetNumberOfComponents(3);
+    bondScales->SetName("bond_scales");
+    bondScales->SetNumberOfComponents(3);
+    vtkDataArray *elements = NULL;
+    if (pd->GetPointData() != NULL &&
+        pd->GetPointData()->GetScalars() != NULL &&
+        strcmp(pd->GetPointData()->GetScalars()->GetName(), "element") == 0) {
+        elements = pd->GetPointData()->GetScalars();
+    }
+    for (int i = 0; lines->GetNextCell(npts, pts); i++) {
+        assert(npts == 2);
+        double pt0[3], pt1[3];
+        double newPt0[3], newPt1[3];
+        //double *pt0 = pd->GetPoint(pts[0]);
+        //double *pt1 = pd->GetPoint(pts[1]);
+        pd->GetPoint(pts[0], pt0);
+        pd->GetPoint(pts[1], pt1);
+        double center[3];
+
+        for (int j = 0; j < 3; j++)
+            center[j] = pt0[j] + (pt1[j] - pt0[j]) * 0.5;
+        for (int j = 0; j < 3; j++)
+            newPt0[j] = pt0[j] + (pt1[j] - pt0[j]) * 0.25;
+        for (int j = 0; j < 3; j++)
+            newPt1[j] = pt0[j] + (pt1[j] - pt0[j]) * 0.75;
+
+        bondPoints->InsertNextPoint(newPt0);
+        bondPoints->InsertNextPoint(newPt1);
+
+        TRACE("Bond %d: (%g,%g,%g)-(%g,%g,%g)-(%g,%g,%g)", i,
+              pt0[0], pt0[1], pt0[2], 
+              center[0], center[1], center[2],
+              pt1[0], pt1[1], pt1[2]);
+
+        double vec[3];
+        for (int j = 0; j < 3; j++)
+            vec[j] = center[j] - pt0[j];
+
+        bondVectors->InsertNextTupleValue(vec);
+        bondVectors->InsertNextTupleValue(vec);
+        TRACE("Bond %d, vec: %g,%g,%g", i, vec[0], vec[1], vec[2]);
+
+        double scale[3];
+        scale[0] = sqrt(vec[0]*vec[0] + vec[1]*vec[1] + vec[2]*vec[2]);
+        scale[1] = 1.0;
+        scale[2] = 1.0;
+
+        bondScales->InsertNextTupleValue(scale);
+        bondScales->InsertNextTupleValue(scale);
+
+        if (elements != NULL) {
+            int element = (int)elements->GetComponent(pts[0], 0);
+            TRACE("Bond %d, elt 0: %d", i, element);
+            bondElements->InsertNextValue(element);
+            element = (int)elements->GetComponent(pts[1], 0);
+            TRACE("Bond %d, elt 1: %d", i, element);
+            bondElements->InsertNextValue(element);
+        }
+    }
+    _bondPD->SetPoints(bondPoints);
+    if (elements != NULL)
+        _bondPD->GetPointData()->SetScalars(bondElements);
+    _bondPD->GetPointData()->AddArray(bondVectors);
+    _bondPD->GetPointData()->AddArray(bondScales);
+}
+
+void Molecule::addLabelArray(vtkDataSet *dataSet)
+{
+    vtkDataArray *elements = NULL;
+    if (dataSet->GetPointData() != NULL &&
+        dataSet->GetPointData()->GetScalars() != NULL &&
+        strcmp(dataSet->GetPointData()->GetScalars()->GetName(), "element") == 0) {
+        elements = dataSet->GetPointData()->GetScalars();
+    } else {
+        WARN("Can't label atoms without an element array");
+    }
+
+    vtkSmartPointer<vtkStringArray> labelArray = vtkSmartPointer<vtkStringArray>::New();
+    labelArray->SetName("labels");
+    vtkPolyData *pd = vtkPolyData::SafeDownCast(dataSet);
+    if (pd == NULL) {
+        ERROR("DataSet not a PolyData");
+        return;
+    }
+    for (int i = 0; i < pd->GetNumberOfVerts(); i++) {
+        char buf[32];
+        if (elements != NULL) {
+            int elt = (int)elements->GetComponent(i, 0);
+            sprintf(buf, "%s%d", g_elementNames[elt], i);
+        } else {
+            sprintf(buf, "%d", i);
+        }
+        labelArray->InsertNextValue(buf);
+    }
+    dataSet->GetPointData()->AddArray(labelArray);
+}
+
+/**
+ * \brief Add a scalar array to dataSet with sizes for the elements
+ * specified in the "element" scalar array
+ */
+void Molecule::addRadiusArray(vtkDataSet *dataSet, AtomScaling scaling, double scaleFactor)
+{
+    vtkDataArray *elements = NULL;
+    if (dataSet->GetPointData() != NULL &&
+        dataSet->GetPointData()->GetScalars() != NULL &&
+        strcmp(dataSet->GetPointData()->GetScalars()->GetName(), "element") == 0) {
+        elements = dataSet->GetPointData()->GetScalars();
+    } else if (scaling != NO_ATOM_SCALING) {
+        WARN("Can't use non-constant scaling without an element array");
+    }
+    const float *radiusSource = NULL;
+    switch (scaling) {
+    case VAN_DER_WAALS_RADIUS:
+        radiusSource = g_vdwRadii;
+        break;
+    case COVALENT_RADIUS:
+        radiusSource = g_covalentRadii;
+        break;
+    case ATOMIC_RADIUS:
+        radiusSource = g_atomicRadii;
+        break;
+    case NO_ATOM_SCALING:
+    default:
+        ;
+    }
+    vtkSmartPointer<vtkFloatArray> radii = vtkSmartPointer<vtkFloatArray>::New();
+    radii->SetName("radius");
+    radii->SetNumberOfComponents(3);
+    vtkPolyData *pd = vtkPolyData::SafeDownCast(dataSet);
+    if (pd == NULL) {
+        ERROR("DataSet not a PolyData");
+        return;
+    }
+    for (int i = 0; i < pd->GetNumberOfVerts(); i++) {
+        float tuple[3];
+        tuple[1] = tuple[2] = 0;
+        if (elements != NULL && radiusSource != NULL) {
+            int elt = (int)elements->GetComponent(i, 0);
+            tuple[0] = radiusSource[elt] * scaleFactor;
+        } else {
+            tuple[0] = scaleFactor;
+        }
+        radii->InsertNextTupleValue(tuple);
+    }
+    dataSet->GetPointData()->SetVectors(radii);
+}
+
+/**
+ * \brief Create a color map to map atomic numbers to element colors
+ */
+ColorMap *Molecule::createElementColorMap()
+{
+    ColorMap *elementCmap = new ColorMap("elementDefault");
+    ColorMap::ControlPoint cp[NUM_ELEMENTS+1];
+
+    elementCmap->setNumberOfTableEntries(NUM_ELEMENTS+1);
+    for (int i = 0; i <= NUM_ELEMENTS; i++) {
+        cp[i].value = i/((double)NUM_ELEMENTS);
+        for (int c = 0; c < 3; c++) {
+            cp[i].color[c] = ((double)g_elementColors[i][c])/255.;
+        }
+        elementCmap->addControlPoint(cp[i]);
+    }
+    ColorMap::OpacityControlPoint ocp[2];
+    ocp[0].value = 0;
+    ocp[0].alpha = 1.0;
+    ocp[1].value = 1.0;
+    ocp[1].alpha = 1.0;
+    elementCmap->addOpacityControlPoint(ocp[0]);
+    elementCmap->addOpacityControlPoint(ocp[1]);
+    elementCmap->build();
+    double range[2];
+    range[0] = 0;
+    range[1] = NUM_ELEMENTS;
+    elementCmap->getLookupTable()->SetRange(range);
+
+    return elementCmap;
+}
Index: /trunk/packages/vizservers/vtkvis/Molecule.h
===================================================================
--- /trunk/packages/vizservers/vtkvis/Molecule.h	(revision 3616)
+++ /trunk/packages/vizservers/vtkvis/Molecule.h	(revision 3616)
@@ -0,0 +1,167 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (C) 2004-2012  HUBzero Foundation, LLC
+ *
+ * Author: Leif Delgass <ldelgass@purdue.edu>
+ */
+
+#ifndef VTKVIS_MOLECULE_H
+#define VTKVIS_MOLECULE_H
+
+#include <vtkSmartPointer.h>
+#include <vtkLookupTable.h>
+#include <vtkPolyDataMapper.h>
+#include <vtkActor.h>
+#include <vtkActor2D.h>
+#include <vtkAssembly.h>
+#include <vtkGlyph3DMapper.h>
+#include <vtkTransformPolyDataFilter.h>
+#include <vtkCylinderSource.h>
+#include <vtkLineSource.h>
+#include <vtkLabelPlacementMapper.h>
+
+#include "ColorMap.h"
+#include "VtkGraphicsObject.h"
+
+namespace VtkVis {
+
+/**
+ * \brief Ball and stick Molecule
+ *
+ * The data format for this class is based on the VisIt Molecule
+ * plot.  It consists of a vtkPolyData with atom coordinates as
+ * points and vertices and bonds as lines.  A scalar array named
+ * "element" can be included as point data to specify atomic 
+ * numbers to use in coloring (via the "elementDefault" ColorMap)
+ * and scaling atoms.  If the scalar array is not named 
+ * "element," it will be color-mapped as a standard scalar field.
+ */
+class Molecule : public VtkGraphicsObject {
+public:
+    enum AtomScaling {
+        NO_ATOM_SCALING,
+        VAN_DER_WAALS_RADIUS,
+        COVALENT_RADIUS,
+        ATOMIC_RADIUS
+    };
+    enum BondStyle {
+        BOND_STYLE_CYLINDER,
+        BOND_STYLE_LINE
+    };
+    enum ColorMode {
+        COLOR_BY_ELEMENTS,
+        COLOR_BY_SCALAR,
+        COLOR_BY_VECTOR_MAGNITUDE,
+        COLOR_BY_VECTOR_X,
+        COLOR_BY_VECTOR_Y,
+        COLOR_BY_VECTOR_Z,
+        COLOR_CONSTANT
+    };
+    enum BondColorMode {
+        BOND_COLOR_BY_ELEMENTS,
+        BOND_COLOR_CONSTANT
+    };
+
+    Molecule();
+    virtual ~Molecule();
+
+    virtual const char *getClassName() const
+    {
+        return "Molecule";
+    }
+
+    virtual vtkProp *getOverlayProp()
+    {
+        return _labelProp;
+    }
+
+    virtual void setDataSet(DataSet *dataSet,
+                            Renderer *renderer);
+
+    virtual void setClippingPlanes(vtkPlaneCollection *planes);
+
+    void setColorMode(ColorMode mode, DataSet::DataAttributeType type,
+                      const char *name, double range[2] = NULL);
+
+    void setColorMode(ColorMode mode,
+                      const char *name, double range[2] = NULL);
+
+    void setColorMode(ColorMode mode);
+
+    void setColorMap(ColorMap *colorMap);
+
+    /**
+     * \brief Return the ColorMap in use
+     */
+    ColorMap *getColorMap()
+    {
+        return _colorMap;
+    }
+
+    void updateColorMap();
+
+    virtual void updateRanges(Renderer *renderer);
+
+    void setAtomScaling(AtomScaling state);
+
+    void setAtomRadiusScale(double scale);
+
+    void setBondRadiusScale(double scale);
+
+    virtual void setVisibility(bool state);
+
+    virtual void setOpacity(double opacity);
+
+    void setAtomVisibility(bool state);
+
+    void setAtomLabelVisibility(bool state);
+
+    void setBondVisibility(bool state);
+
+    void setBondStyle(BondStyle style);
+
+    void setBondColor(float color[3]);
+
+    void setBondColorMode(BondColorMode mode);
+
+    static ColorMap *createElementColorMap();
+
+private:
+    virtual void initProp();
+    virtual void update();
+
+    void setupBondPolyData();
+
+    static void addLabelArray(vtkDataSet *dataSet);
+
+    static void addRadiusArray(vtkDataSet *dataSet, AtomScaling scaling, double scaleFactor);
+
+    float _bondColor[3];
+    double _radiusScale;
+    AtomScaling _atomScaling;
+    bool _labelsOn;
+    ColorMap *_colorMap;
+    ColorMode _colorMode;
+    std::string _colorFieldName;
+    DataSet::DataAttributeType _colorFieldType;
+    double _colorFieldRange[2];
+    double _vectorMagnitudeRange[2];
+    double _vectorComponentRange[3][2];
+    Renderer *_renderer;
+
+    vtkSmartPointer<vtkLookupTable> _lut;
+    vtkSmartPointer<vtkActor> _atomProp;
+    vtkSmartPointer<vtkActor> _bondProp;
+    vtkSmartPointer<vtkActor2D> _labelProp;
+    vtkSmartPointer<vtkPolyData> _bondPD;
+    vtkSmartPointer<vtkCylinderSource> _cylinderSource;
+    vtkSmartPointer<vtkTransformPolyDataFilter>_cylinderTrans;
+    vtkSmartPointer<vtkLineSource> _lineSource;
+    vtkSmartPointer<vtkGlyph3DMapper> _atomMapper;
+    vtkSmartPointer<vtkGlyph3DMapper> _bondMapper;
+    vtkSmartPointer<vtkLabelPlacementMapper> _labelMapper;
+};
+
+}
+
+#endif
Index: /trunk/packages/vizservers/vtkvis/MoleculeData.h
===================================================================
--- /trunk/packages/vizservers/vtkvis/MoleculeData.h	(revision 3616)
+++ /trunk/packages/vizservers/vtkvis/MoleculeData.h	(revision 3616)
@@ -0,0 +1,578 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (C) 2004-2012  HUBzero Foundation, LLC
+ *
+ * Author: Leif Delgass <ldelgass@purdue.edu>
+ */
+
+#define NUM_ELEMENTS 109
+
+// jmol colors (taken from VisIt)
+const unsigned char g_elementColors[NUM_ELEMENTS+1][3] = {
+    { 0x20, 0x20, 0x20 }, // ?
+    { 0xFF, 0xFF, 0xFF }, // H
+    { 0xD9, 0xFF, 0xFF }, // He
+    { 0xCC, 0x80, 0xFF }, // Li
+    { 0xC2, 0xFF, 0x00 }, // Be
+    { 0xFF, 0xB5, 0xB5 }, // B
+    { 0x90, 0x90, 0x90 }, // C
+    { 0x30, 0x50, 0xF8 }, // N
+    { 0xFF, 0x0D, 0x0D }, // O
+    { 0x90, 0xE0, 0x50 }, // F
+    { 0xB3, 0xE3, 0xF5 }, // Ne
+    { 0xAB, 0x5C, 0xF2 }, // Na
+    { 0x8A, 0xFF, 0x00 }, // Mg
+    { 0xBF, 0xA6, 0xA6 }, // Al
+    { 0xF0, 0xC8, 0xA0 }, // Si
+    { 0xFF, 0x80, 0x00 }, // P
+    { 0xFF, 0xFF, 0x30 }, // S
+    { 0x1F, 0xF0, 0x1F }, // Cl
+    { 0x80, 0xD1, 0xE3 }, // Ar
+    { 0x8F, 0x40, 0xD4 }, // K
+    { 0x3D, 0xFF, 0x00 }, // Ca
+    { 0xE6, 0xE6, 0xE6 }, // Sc
+    { 0xBF, 0xC2, 0xC7 }, // Ti
+    { 0xA6, 0xA6, 0xAB }, // V
+    { 0x8A, 0x99, 0xC7 }, // Cr
+    { 0x9C, 0x7A, 0xC7 }, // Mn
+    { 0xE0, 0x66, 0x33 }, // Fe
+    { 0xF0, 0x90, 0xA0 }, // Co
+    { 0x50, 0xD0, 0x50 }, // Ni
+    { 0xC8, 0x80, 0x33 }, // Cu
+    { 0x7D, 0x80, 0xB0 }, // Zn
+    { 0xC2, 0x8F, 0x8F }, // Ga
+    { 0x66, 0x8F, 0x8F }, // Ge
+    { 0xBD, 0x80, 0xE3 }, // As
+    { 0xFF, 0xA1, 0x00 }, // Se
+    { 0xA6, 0x29, 0x29 }, // Br
+    { 0x5C, 0xB8, 0xD1 }, // Kr
+    { 0x70, 0x2E, 0xB0 }, // Rb
+    { 0x00, 0xFF, 0x00 }, // Sr
+    { 0x94, 0xFF, 0xFF }, // Y
+    { 0x94, 0xE0, 0xE0 }, // Zr
+    { 0x73, 0xC2, 0xC9 }, // Nb
+    { 0x54, 0xB5, 0xB5 }, // Mo
+    { 0x3B, 0x9E, 0x9E }, // Tc
+    { 0x24, 0x8F, 0x8F }, // Ru
+    { 0x0A, 0x7D, 0x8C }, // Rh
+    { 0x00, 0x69, 0x85 }, // Pd
+    { 0xC0, 0xC0, 0xC0 }, // Ag
+    { 0xFF, 0xD9, 0x8F }, // Cd
+    { 0xA6, 0x75, 0x73 }, // In
+    { 0x66, 0x80, 0x80 }, // Sn
+    { 0x9E, 0x63, 0xB5 }, // Sb
+    { 0xD4, 0x7A, 0x00 }, // Te
+    { 0x94, 0x00, 0x94 }, // I
+    { 0x42, 0x9E, 0xB0 }, // Xe
+    { 0x57, 0x17, 0x8F }, // Cs
+    { 0x00, 0xC9, 0x00 }, // Ba
+    { 0x70, 0xD4, 0xFF }, // La
+    { 0xFF, 0xFF, 0xC7 }, // Ce
+    { 0xD9, 0xFF, 0xC7 }, // Pr
+    { 0xC7, 0xFF, 0xC7 }, // Nd
+    { 0xA3, 0xFF, 0xC7 }, // Pm
+    { 0x8F, 0xFF, 0xC7 }, // Sm
+    { 0x61, 0xFF, 0xC7 }, // Eu
+    { 0x45, 0xFF, 0xC7 }, // Gd
+    { 0x30, 0xFF, 0xC7 }, // Tb
+    { 0x1F, 0xFF, 0xC7 }, // Dy
+    { 0x00, 0xFF, 0x9C }, // Ho
+    { 0x00, 0xE6, 0x75 }, // Er
+    { 0x00, 0xD4, 0x52 }, // Tm
+    { 0x00, 0xBF, 0x38 }, // Yb
+    { 0x00, 0xAB, 0x24 }, // Lu
+    { 0x4D, 0xC2, 0xFF }, // Hf
+    { 0x4D, 0xA6, 0xFF }, // Ta
+    { 0x21, 0x94, 0xD6 }, // W
+    { 0x26, 0x7D, 0xAB }, // Re
+    { 0x26, 0x66, 0x96 }, // Os
+    { 0x17, 0x54, 0x87 }, // Ir
+    { 0xD0, 0xD0, 0xE0 }, // Pt
+    { 0xFF, 0xD1, 0x23 }, // Au
+    { 0xB8, 0xB8, 0xD0 }, // Hg
+    { 0xA6, 0x54, 0x4D }, // Tl
+    { 0x57, 0x59, 0x61 }, // Pb
+    { 0x9E, 0x4F, 0xB5 }, // Bi
+    { 0xAB, 0x5C, 0x00 }, // Po
+    { 0x75, 0x4F, 0x45 }, // At
+    { 0x42, 0x82, 0x96 }, // Rn
+    { 0x42, 0x00, 0x66 }, // Fr
+    { 0x00, 0x7D, 0x00 }, // Ra
+    { 0x70, 0xAB, 0xFA }, // Ac
+    { 0x00, 0xBA, 0xFF }, // Th
+    { 0x00, 0xA1, 0xFF }, // Pa
+    { 0x00, 0x8F, 0xFF }, // U
+    { 0x00, 0x80, 0xFF }, // Np
+    { 0x00, 0x6B, 0xFF }, // Pu
+    { 0x54, 0x5C, 0xF2 }, // Am
+    { 0x78, 0x5C, 0xE3 }, // Cm
+    { 0x8A, 0x4F, 0xE3 }, // Bk
+    { 0xA1, 0x36, 0xD4 }, // Cf
+    { 0xB3, 0x1F, 0xD4 }, // Es
+    { 0xB3, 0x1F, 0xBA }, // Fm
+    { 0xB3, 0x0D, 0xA6 }, // Md
+    { 0xBD, 0x0D, 0x87 }, // No
+    { 0xC7, 0x00, 0x66 }, // Lr
+    { 0xCC, 0x00, 0x59 }, // Rf
+    { 0xD1, 0x00, 0x4F }, // Db
+    { 0xD9, 0x00, 0x45 }, // Sg
+    { 0xE0, 0x00, 0x38 }, // Bh
+    { 0xE6, 0x00, 0x2E }, // Hs
+    { 0xEB, 0x00, 0x26 }  // Mt
+};
+
+// Covalent radii in Angstroms from VisIt
+const float g_covalentRadii[NUM_ELEMENTS+1] = {
+     .1f,  // ?  0
+    0.32f, // H  1
+    0.93f, // He 2
+    1.23f, // Li 3
+    0.90f, // Be 4
+    0.82f, // B  5
+    0.77f, // C  6
+    0.75f, // N  7
+    0.73f, // O  8
+    0.72f, // F  9
+    0.71f, // Ne 10
+    1.54f, // Na 11
+    1.36f, // Mg 12
+    1.18f, // Al 13
+    1.11f, // Si 14
+    1.06f, // P  15
+    1.02f, // S  16
+    0.99f, // Cl 17
+    0.98f, // Ar 18
+    2.03f, // K  19
+    1.74f, // Ca 20
+    1.44f, // Sc 21
+    1.32f, // Ti 22
+    1.22f, // V  23
+    1.18f, // Cr 24
+    1.17f, // Mn 25
+    1.17f, // Fe 26
+    1.16f, // Co 27
+    1.15f, // Ni 28
+    1.17f, // Cu 29
+    1.25f, // Zn 30
+    1.26f, // Ga 31
+    1.22f, // Ge 32
+    1.20f, // As 33
+    1.16f, // Se 34
+    1.14f, // Br 35
+    1.12f, // Kr 36
+    2.16f, // Rb 37
+    1.91f, // Sr 38
+    1.62f, // Y  39
+    1.45f, // Zr 40
+    1.34f, // Nb 41
+    1.30f, // Mo 42
+    1.27f, // Tc 43
+    1.25f, // Ru 44
+    1.25f, // Rh 45
+    1.28f, // Pd 46
+    1.34f, // Ag 47
+    1.48f, // Cd 48
+    1.44f, // In 49
+    1.41f, // Sn 50
+    1.40f, // Sb 51
+    1.36f, // Te 52
+    1.33f, // I  53
+    1.31f, // Xe 54
+    2.35f, // Cs 55
+    1.98f, // Ba 56
+    1.69f, // La 57
+    1.65f, // Ce 58
+    1.65f, // Pr 59
+    1.64f, // Nd 60
+    1.63f, // Pm 61
+    1.62f, // Sm 62
+    1.85f, // Eu 63
+    1.61f, // Gd 64
+    1.59f, // Tb 65
+    1.59f, // Dy 66
+    1.58f, // Ho 67
+    1.57f, // Er 68
+    1.56f, // Tm 69
+    1.74f, // Yb 70
+    1.56f, // Lu 71
+    1.44f, // Hf 72
+    1.34f, // Ta 73
+    1.30f, // W  74
+    1.28f, // Re 75
+    1.26f, // Os 76
+    1.27f, // Ir 77
+    1.30f, // Pt 78
+    1.34f, // Au 79
+    1.49f, // Hg 80
+    1.48f, // Tl 81
+    1.47f, // Pb 82
+    1.46f, // Bi 83
+    1.46f, // Po 84
+    1.45f, // At 85
+    1.50f, // Rn 86 // 86-96 from en.wikipedia.org/wiki/Covalent_radius 10/6/09
+    2.60f, // Fr 87
+    2.21f, // Ra 88
+    2.15f, // Ac 89
+    2.06f, // Th 90
+    2.00f, // Pa 91
+    1.96f, // U  92
+    1.90f, // Np 93
+    1.87f, // Pu 94
+    1.80f, // Am 95
+    1.69f, // Cm 96
+    .1f,
+    .1f,
+    .1f,
+    .1f,
+    .1f,
+    .1f,
+    .1f,
+    .1f,
+    .1f,
+    .1f,
+    .1f,
+    .1f,
+    .1f
+};
+
+// Atomic radii in Angstroms from VisIt
+const float g_atomicRadii[NUM_ELEMENTS+1] = {
+     .1f,  // ?  0
+    0.79f, // H  1
+    0.49f, // He 2
+    2.05f, // Li 3
+    1.40f, // Be 4
+    1.17f, // B  5
+    0.91f, // C  6
+    0.75f, // N  7
+    0.65f, // O  8
+    0.57f, // F  9
+    0.51f, // Ne 10
+    2.23f, // Na 11
+    1.72f, // Mg 12
+    1.82f, // Al 13
+    1.46f, // Si 14
+    1.23f, // P  15
+    1.09f, // S  16
+    0.97f, // Cl 17
+    0.88f, // Ar 18
+    2.77f, // K  19
+    2.23f, // Ca 20
+    2.09f, // Sc 21
+    2.00f, // Ti 22
+    1.92f, // V  23
+    1.85f, // Cr 24
+    1.79f, // Mn 25
+    1.72f, // Fe 26
+    1.67f, // Co 27
+    1.62f, // Ni 28
+    1.57f, // Cu 29
+    1.53f, // Zn 30
+    1.81f, // Ga 31
+    1.52f, // Ge 32
+    1.33f, // As 33
+    1.22f, // Se 34
+    1.12f, // Br 35
+    1.03f, // Kr 36
+    2.98f, // Rb 37
+    2.45f, // Sr 38
+    2.27f, // Y  39
+    2.16f, // Zr 40
+    2.08f, // Nb 41
+    2.01f, // Mo 42
+    1.95f, // Tc 43
+    1.89f, // Ru 44
+    1.83f, // Rh 45
+    1.79f, // Pd 46
+    1.75f, // Ag 47
+    1.71f, // Cd 48
+    2.00f, // In 49
+    1.72f, // Sn 50
+    1.53f, // Sb 51
+    1.42f, // Te 52
+    1.32f, // I  53
+    1.24f, // Xe 54
+    3.34f, // Cs 55
+    2.78f, // Ba 56
+    2.74f, // La 57
+    2.70f, // Ce 58
+    2.67f, // Pr 59
+    2.64f, // Nd 60
+    2.62f, // Pm 61
+    2.59f, // Sm 62
+    2.56f, // Eu 63
+    2.54f, // Gd 64
+    2.51f, // Tb 65
+    2.49f, // Dy 66
+    2.47f, // Ho 67
+    2.45f, // Er 68
+    2.42f, // Tm 69
+    2.40f, // Yb 70
+    2.25f, // Lu 71
+    2.16f, // Hf 72
+    2.09f, // Ta 73
+    2.02f, // W  74
+    1.97f, // Re 75
+    1.92f, // Os 76
+    1.87f, // Ir 77
+    1.83f, // Pt 78
+    1.79f, // Au 79
+    1.76f, // Hg 80
+    2.08f, // Tl 81
+    1.81f, // Pb 82
+    1.63f, // Bi 83
+    1.53f, // Po 84
+    1.43f, // At 85
+    1.34f, // Rn 86
+    2.60f, // Fr 87 (using covalent radius just to get a number here)
+    2.15f, // Ra 88 (88-99 from "http://en.wikipedia.org/wiki/Atomic_radii_of_the_elements_(data_page)", which references J.C. Slater, J. Chem. Phys. 1964, 41, 3199.)
+    1.95f, // Ac 89
+    1.80f, // Th 90
+    1.80f, // Pa 91
+    1.75f, // U  92
+    1.75f, // Np 93
+    1.75f, // Pu 94
+    1.75f, // Am 95
+    1.74f, // Cm 96 (96-99 use metallic radius to just get a number)
+    1.70f, // Bk 97
+    1.86f, // Cf 98
+    1.86f, // Es 99
+    .1f,
+    .1f,
+    .1f,
+    .1f,
+    .1f,
+    .1f,
+    .1f,
+    .1f,
+    .1f,
+    .1f
+};
+
+// From JMol / OpenBabel
+/// van der Waals radii in Angstroms
+const float g_vdwRadii[NUM_ELEMENTS+1] = {
+    1.0,    //   0  ?
+    1.200f, //   1  H
+    1.400f, //   2  He
+    1.820f, //   3  Li
+    1.700f, //   4  Be
+    2.080f, //   5  B
+    1.950f, //   6  C
+    1.850f, //   7  N
+    1.700f, //   8  O
+    1.730f, //   9  F
+    1.540f, //  10  Ne
+    2.270f, //  11  Na
+    1.730f, //  12  Mg
+    2.050f, //  13  Al
+    2.100f, //  14  Si
+    2.080f, //  15  P
+    2.000f, //  16  S
+    1.970f, //  17  Cl
+    1.880f, //  18  Ar
+    2.750f, //  19  K
+    1.973f, //  20  Ca
+    1.700f, //  21  Sc
+    1.700f, //  22  Ti
+    1.700f, //  23  V
+    1.700f, //  24  Cr
+    1.700f, //  25  Mn
+    1.700f, //  26  Fe
+    1.700f, //  27  Co
+    1.630f, //  28  Ni
+    1.400f, //  29  Cu
+    1.390f, //  30  Zn
+    1.870f, //  31  Ga
+    1.700f, //  32  Ge
+    1.850f, //  33  As
+    1.900f, //  34  Se
+    2.100f, //  35  Br
+    2.020f, //  36  Kr
+    1.700f, //  37  Rb
+    1.700f, //  38  Sr
+    1.700f, //  39  Y
+    1.700f, //  40  Zr
+    1.700f, //  41  Nb
+    1.700f, //  42  Mo
+    1.700f, //  43  Tc
+    1.700f, //  44  Ru
+    1.700f, //  45  Rh
+    1.630f, //  46  Pd
+    1.720f, //  47  Ag
+    1.580f, //  48  Cd
+    1.930f, //  49  In
+    2.170f, //  50  Sn
+    2.200f, //  51  Sb
+    2.060f, //  52  Te
+    2.150f, //  53  I
+    2.160f, //  54  Xe
+    1.700f, //  55  Cs
+    1.700f, //  56  Ba
+    1.700f, //  57  La
+    1.700f, //  58  Ce
+    1.700f, //  59  Pr
+    1.700f, //  60  Nd
+    1.700f, //  61  Pm
+    1.700f, //  62  Sm
+    1.700f, //  63  Eu
+    1.700f, //  64  Gd
+    1.700f, //  65  Tb
+    1.700f, //  66  Dy
+    1.700f, //  67  Ho
+    1.700f, //  68  Er
+    1.700f, //  69  Tm
+    1.700f, //  70  Yb
+    1.700f, //  71  Lu
+    1.700f, //  72  Hf
+    1.700f, //  73  Ta
+    1.700f, //  74  W
+    1.700f, //  75  Re
+    1.700f, //  76  Os
+    1.700f, //  77  Ir
+    1.720f, //  78  Pt
+    1.660f, //  79  Au
+    1.550f, //  80  Hg
+    1.960f, //  81  Tl
+    2.020f, //  82  Pb
+    1.700f, //  83  Bi
+    1.700f, //  84  Po
+    1.700f, //  85  At
+    1.700f, //  86  Rn
+    1.700f, //  87  Fr
+    1.700f, //  88  Ra
+    1.700f, //  89  Ac
+    1.700f, //  90  Th
+    1.700f, //  91  Pa
+    1.860f, //  92  U
+    1.700f, //  93  Np
+    1.700f, //  94  Pu
+    1.700f, //  95  Am
+    1.700f, //  96  Cm
+    1.700f, //  97  Bk
+    1.700f, //  98  Cf
+    1.700f, //  99  Es
+    1.700f, // 100  Fm
+    1.700f, // 101  Md
+    1.700f, // 102  No
+    1.700f, // 103  Lr
+    1.700f, // 104  Rf
+    1.700f, // 105  Db
+    1.700f, // 106  Sg
+    1.700f, // 107  Bh
+    1.700f, // 108  Hs
+    1.700f, // 109  Mt
+};
+
+const char * g_elementNames[NUM_ELEMENTS+1] = {
+    "?",    //   0  ?
+    "H",    //   1  H
+    "He",   //   2  He
+    "Li",   //   3  Li
+    "Be",   //   4  Be
+    "B",    //   5  B
+    "C",    //   6  C
+    "N",    //   7  N
+    "O",    //   8  O
+    "F",    //   9  F
+    "Ne",   //  10  Ne
+    "Na",   //  11  Na
+    "Mg",   //  12  Mg
+    "Al",   //  13  Al
+    "Si",   //  14  Si
+    "P",    //  15  P
+    "S",    //  16  S
+    "Cl",   //  17  Cl
+    "Ar",   //  18  Ar
+    "K",    //  19  K
+    "Ca",   //  20  Ca
+    "Sc",   //  21  Sc
+    "Ti",   //  22  Ti
+    "V",    //  23  V
+    "Cr",   //  24  Cr
+    "Mn",   //  25  Mn
+    "Fe",   //  26  Fe
+    "Co",   //  27  Co
+    "Ni",   //  28  Ni
+    "Cu",   //  29  Cu
+    "Zn",   //  30  Zn
+    "Ga",   //  31  Ga
+    "Ge",   //  32  Ge
+    "As",   //  33  As
+    "Se",   //  34  Se
+    "Br",   //  35  Br
+    "Kr",   //  36  Kr
+    "Rb",   //  37  Rb
+    "Sr",   //  38  Sr
+    "Y",    //  39  Y
+    "Zr",   //  40  Zr
+    "Nb",   //  41  Nb
+    "Mo",   //  42  Mo
+    "Tc",   //  43  Tc
+    "Ru",   //  44  Ru
+    "Rh",   //  45  Rh
+    "Pd",   //  46  Pd
+    "Ag",   //  47  Ag
+    "Cd",   //  48  Cd
+    "In",   //  49  In
+    "Sn",   //  50  Sn
+    "Sb",   //  51  Sb
+    "Te",   //  52  Te
+    "I",    //  53  I
+    "Xe",   //  54  Xe
+    "Cs",   //  55  Cs
+    "Ba",   //  56  Ba
+    "La",   //  57  La
+    "Ce",   //  58  Ce
+    "Pr",   //  59  Pr
+    "Nd",   //  60  Nd
+    "Pm",   //  61  Pm
+    "Sm",   //  62  Sm
+    "Eu",   //  63  Eu
+    "Gd",   //  64  Gd
+    "Tb",   //  65  Tb
+    "Dy",   //  66  Dy
+    "Ho",   //  67  Ho
+    "Er",   //  68  Er
+    "Tm",   //  69  Tm
+    "Yb",   //  70  Yb
+    "Lu",   //  71  Lu
+    "Hf",   //  72  Hf
+    "Ta",   //  73  Ta
+    "W",    //  74  W
+    "Re",   //  75  Re
+    "Os",   //  76  Os
+    "Ir",   //  77  Ir
+    "Pt",   //  78  Pt
+    "Au",   //  79  Au
+    "Hg",   //  80  Hg
+    "Tl",   //  81  Tl
+    "Pb",   //  82  Pb
+    "Bi",   //  83  Bi
+    "Po",   //  84  Po
+    "At",   //  85  At
+    "Rn",   //  86  Rn
+    "Fr",   //  87  Fr
+    "Ra",   //  88  Ra
+    "Ac",   //  89  Ac
+    "Th",   //  90  Th
+    "Pa",   //  91  Pa
+    "U",    //  92  U
+    "Np",   //  93  Np
+    "Pu",   //  94  Pu
+    "Am",   //  95  Am
+    "Cm",   //  96  Cm
+    "Bk",   //  97  Bk
+    "Cf",   //  98  Cf
+    "Es",   //  99  Es
+    "Fm",   // 100  Fm
+    "Md",   // 101  Md
+    "No",   // 102  No
+    "Lr",   // 103  Lr
+    "Rf",   // 104  Rf
+    "Db",   // 105  Db
+    "Sg",   // 106  Sg
+    "Bh",   // 107  Bh
+    "Hs",   // 108  Hs
+    "Mt",   // 109  Mt
+};
Index: /trunk/packages/vizservers/vtkvis/Outline.cpp
===================================================================
--- /trunk/packages/vizservers/vtkvis/Outline.cpp	(revision 3616)
+++ /trunk/packages/vizservers/vtkvis/Outline.cpp	(revision 3616)
@@ -0,0 +1,104 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (C) 2004-2013  HUBzero Foundation, LLC
+ *
+ * Author: Leif Delgass <ldelgass@purdue.edu>
+ */
+
+#include <cassert>
+
+#include <vtkDataSet.h>
+#include <vtkStructuredGrid.h>
+#include <vtkPolyData.h>
+#include <vtkOutlineFilter.h>
+#include <vtkStructuredGridOutlineFilter.h>
+
+#include "Outline.h"
+#include "Trace.h"
+
+using namespace VtkVis;
+
+Outline::Outline() :
+    VtkGraphicsObject()
+{
+}
+
+Outline::~Outline()
+{
+#ifdef WANT_TRACE
+    if (_dataSet != NULL)
+        TRACE("Deleting Outline for %s", _dataSet->getName().c_str());
+    else
+        TRACE("Deleting Outline with NULL DataSet");
+#endif
+}
+
+/**
+ * \brief Create and initialize a VTK Prop to render a mesh
+ */
+void Outline::initProp()
+{
+    VtkGraphicsObject::initProp();
+}
+
+/**
+ * \brief Internal method to set up pipeline after a state change
+ */
+void Outline::update()
+{
+    if (_dataSet == NULL) {
+        return;
+    }
+
+    if (_pdMapper == NULL) {
+        _pdMapper = vtkSmartPointer<vtkPolyDataMapper>::New();
+        _pdMapper->SetResolveCoincidentTopologyToPolygonOffset();
+        _pdMapper->ScalarVisibilityOff();
+    }
+
+    vtkDataSet *ds = _dataSet->getVtkDataSet();
+    vtkStructuredGrid *sg = vtkStructuredGrid::SafeDownCast(ds);
+    if (sg != NULL) {
+        vtkSmartPointer<vtkStructuredGridOutlineFilter> ofilter = vtkSmartPointer<vtkStructuredGridOutlineFilter>::New();
+#ifdef USE_VTK6
+        ofilter->SetInputData(ds);
+#else
+        ofilter->SetInput(ds);
+#endif
+        ofilter->ReleaseDataFlagOn();
+        _pdMapper->SetInputConnection(ofilter->GetOutputPort());
+    } else {
+        vtkSmartPointer<vtkOutlineFilter> ofilter = vtkSmartPointer<vtkOutlineFilter>::New();
+#ifdef USE_VTK6
+        ofilter->SetInputData(ds);
+#else
+        ofilter->SetInput(ds);
+#endif
+        ofilter->ReleaseDataFlagOn();
+        _pdMapper->SetInputConnection(ofilter->GetOutputPort());
+    }
+
+    initProp();
+
+    setVisibility(_dataSet->getVisibility());
+
+    getActor()->SetMapper(_pdMapper);
+    _pdMapper->Update();
+
+#ifdef WANT_TRACE
+    double *b = getBounds();
+    TRACE("bounds: %g %g %g %g %g %g", b[0], b[1], b[2], b[3], b[4], b[5]);
+#endif
+}
+
+/**
+ * \brief Set a group of world coordinate planes to clip rendering
+ *
+ * Passing NULL for planes will remove all cliping planes
+ */
+void Outline::setClippingPlanes(vtkPlaneCollection *planes)
+{
+    if (_pdMapper != NULL) {
+        _pdMapper->SetClippingPlanes(planes);
+    }
+}
Index: /trunk/packages/vizservers/vtkvis/Outline.h
===================================================================
--- /trunk/packages/vizservers/vtkvis/Outline.h	(revision 3616)
+++ /trunk/packages/vizservers/vtkvis/Outline.h	(revision 3616)
@@ -0,0 +1,46 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (C) 2004-2013  HUBzero Foundation, LLC
+ *
+ * Author: Leif Delgass <ldelgass@purdue.edu>
+ */
+
+#ifndef VTKVIS_OUTLINE_H
+#define VTKVIS_OUTLINE_H
+
+#include <vtkSmartPointer.h>
+#include <vtkPolyDataMapper.h>
+#include <vtkActor.h>
+
+#include "VtkGraphicsObject.h"
+#include "VtkDataSet.h"
+
+namespace VtkVis {
+
+/**
+ * \brief VTK Wire outline of DataSet
+ *
+ * This class creates a wireframe box around the DataSet bounds
+ */
+class Outline : public VtkGraphicsObject {
+public:
+    Outline();
+    virtual ~Outline();
+
+    virtual const char *getClassName() const
+    {
+        return "Outline";
+    }
+
+    virtual void setClippingPlanes(vtkPlaneCollection *planes);
+
+private:
+    virtual void initProp();
+    virtual void update();
+
+    vtkSmartPointer<vtkPolyDataMapper> _pdMapper;
+};
+
+}
+
+#endif
Index: /trunk/packages/vizservers/vtkvis/PolyData.cpp
===================================================================
--- /trunk/packages/vizservers/vtkvis/PolyData.cpp	(revision 3616)
+++ /trunk/packages/vizservers/vtkvis/PolyData.cpp	(revision 3616)
@@ -0,0 +1,205 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (C) 2004-2012  HUBzero Foundation, LLC
+ *
+ * Author: Leif Delgass <ldelgass@purdue.edu>
+ */
+
+#include <cassert>
+
+#include <vtkDataSet.h>
+#include <vtkPolyData.h>
+#include <vtkUnstructuredGrid.h>
+#include <vtkPolyDataMapper.h>
+#include <vtkActor.h>
+#include <vtkProperty.h>
+#include <vtkTransform.h>
+#include <vtkDelaunay2D.h>
+#include <vtkDelaunay3D.h>
+#include <vtkDataSetSurfaceFilter.h>
+
+#include "PolyData.h"
+#include "Trace.h"
+
+using namespace VtkVis;
+
+PolyData::PolyData() :
+    VtkGraphicsObject()
+{
+}
+
+PolyData::~PolyData()
+{
+#ifdef WANT_TRACE
+    if (_dataSet != NULL)
+        TRACE("Deleting PolyData for %s", _dataSet->getName().c_str());
+    else
+        TRACE("Deleting PolyData with NULL DataSet");
+#endif
+}
+
+/**
+ * \brief Create and initialize a VTK Prop to render a mesh
+ */
+void PolyData::initProp()
+{
+    VtkGraphicsObject::initProp();
+}
+
+/**
+ * \brief Internal method to set up pipeline after a state change
+ */
+void PolyData::update()
+{
+    if (_dataSet == NULL) {
+        return;
+    }
+
+    if (_pdMapper == NULL) {
+        _pdMapper = vtkSmartPointer<vtkPolyDataMapper>::New();
+        _pdMapper->SetResolveCoincidentTopologyToPolygonOffset();
+        _pdMapper->ScalarVisibilityOff();
+    }
+
+    vtkDataSet *ds = _dataSet->getVtkDataSet();
+    vtkPolyData *pd = vtkPolyData::SafeDownCast(ds);
+    if (pd) {
+        TRACE("Points: %d Verts: %d Lines: %d Polys: %d Strips: %d",
+              pd->GetNumberOfPoints(),
+              pd->GetNumberOfVerts(),
+              pd->GetNumberOfLines(),
+              pd->GetNumberOfPolys(),
+              pd->GetNumberOfStrips());
+        // DataSet is a vtkPolyData
+        if (pd->GetNumberOfLines() == 0 &&
+            pd->GetNumberOfPolys() == 0 &&
+            pd->GetNumberOfStrips() == 0) {
+            // DataSet is a point cloud
+            PrincipalPlane plane;
+            double offset;
+            if (_dataSet->numDimensions() < 2 || pd->GetNumberOfPoints() < 3) {
+                // 0D or 1D or not enough points to mesh
+#ifdef USE_VTK6
+                _pdMapper->SetInputData(pd);
+#else
+                _pdMapper->SetInput(pd);
+#endif
+            } else if (_dataSet->is2D(&plane, &offset)) {
+                vtkSmartPointer<vtkDelaunay2D> mesher = vtkSmartPointer<vtkDelaunay2D>::New();
+                if (plane == PLANE_ZY) {
+                    vtkSmartPointer<vtkTransform> trans = vtkSmartPointer<vtkTransform>::New();
+                    trans->RotateWXYZ(90, 0, 1, 0);
+                    if (offset != 0.0) {
+                        trans->Translate(-offset, 0, 0);
+                    }
+                    mesher->SetTransform(trans);
+                } else if (plane == PLANE_XZ) {
+                     vtkSmartPointer<vtkTransform> trans = vtkSmartPointer<vtkTransform>::New();
+                    trans->RotateWXYZ(-90, 1, 0, 0);
+                    if (offset != 0.0) {
+                        trans->Translate(0, -offset, 0);
+                    }
+                    mesher->SetTransform(trans);
+                } else if (offset != 0.0) {
+                    // XY with Z offset
+                    vtkSmartPointer<vtkTransform> trans = vtkSmartPointer<vtkTransform>::New();
+                    trans->Translate(0, 0, -offset);
+                    mesher->SetTransform(trans);
+                }
+#ifdef USE_VTK6
+                mesher->SetInputData(pd);
+#else
+                mesher->SetInput(pd);
+#endif
+                mesher->ReleaseDataFlagOn();
+                mesher->Update();
+                vtkPolyData *outpd = mesher->GetOutput();
+                TRACE("Delaunay2D Verts: %d Lines: %d Polys: %d Strips: %d",
+                      outpd->GetNumberOfVerts(),
+                      outpd->GetNumberOfLines(),
+                      outpd->GetNumberOfPolys(),
+                      outpd->GetNumberOfStrips());
+                if (outpd->GetNumberOfPolys() == 0) {
+                    WARN("Delaunay2D mesher failed");
+#ifdef USE_VTK6
+                    _pdMapper->SetInputData(pd);
+#else
+                    _pdMapper->SetInput(pd);
+#endif
+                } else {
+                    _pdMapper->SetInputConnection(mesher->GetOutputPort());
+                }
+            } else {
+                vtkSmartPointer<vtkDelaunay3D> mesher = vtkSmartPointer<vtkDelaunay3D>::New();
+#ifdef USE_VTK6
+                mesher->SetInputData(pd);
+#else
+                mesher->SetInput(pd);
+#endif
+                mesher->ReleaseDataFlagOn();
+                mesher->Update();
+                vtkUnstructuredGrid *grid = mesher->GetOutput();
+                TRACE("Delaunay3D Cells: %d",
+                      grid->GetNumberOfCells());
+                if (grid->GetNumberOfCells() == 0) {
+                    WARN("Delaunay3D mesher failed");
+#ifdef USE_VTK6
+                    _pdMapper->SetInputData(pd);
+#else
+                    _pdMapper->SetInput(pd);
+#endif
+                } else {
+                    // Delaunay3D returns an UnstructuredGrid, so feed it 
+                    // through a surface filter to get the grid boundary 
+                    // as a PolyData
+                    vtkSmartPointer<vtkDataSetSurfaceFilter> gf = vtkSmartPointer<vtkDataSetSurfaceFilter>::New();
+                    gf->UseStripsOn();
+                    gf->SetInputConnection(mesher->GetOutputPort());
+                    gf->ReleaseDataFlagOn();
+                    _pdMapper->SetInputConnection(gf->GetOutputPort());
+                }
+             }
+        } else {
+            // DataSet is a vtkPolyData with lines and/or polygons
+#ifdef USE_VTK6
+            _pdMapper->SetInputData(pd);
+#else
+            _pdMapper->SetInput(pd);
+#endif
+        }
+    } else {
+        // DataSet is NOT a vtkPolyData
+        TRACE("DataSet is not a PolyData");
+        vtkSmartPointer<vtkDataSetSurfaceFilter> gf = vtkSmartPointer<vtkDataSetSurfaceFilter>::New();
+        gf->UseStripsOn();
+#ifdef USE_VTK6
+        gf->SetInputData(ds);
+#else
+        gf->SetInput(ds);
+#endif
+        gf->ReleaseDataFlagOn();
+        _pdMapper->SetInputConnection(gf->GetOutputPort());
+    }
+
+    initProp();
+    setVisibility(_dataSet->getVisibility());
+    getActor()->SetMapper(_pdMapper);
+    _pdMapper->Update();
+#ifdef WANT_TRACE
+    double *b = getBounds();
+    TRACE("bounds: %g %g %g %g %g %g", b[0], b[1], b[2], b[3], b[4], b[5]);
+#endif
+}
+
+/**
+ * \brief Set a group of world coordinate planes to clip rendering
+ *
+ * Passing NULL for planes will remove all cliping planes
+ */
+void PolyData::setClippingPlanes(vtkPlaneCollection *planes)
+{
+    if (_pdMapper != NULL) {
+        _pdMapper->SetClippingPlanes(planes);
+    }
+}
+
Index: /trunk/packages/vizservers/vtkvis/PolyData.h
===================================================================
--- /trunk/packages/vizservers/vtkvis/PolyData.h	(revision 3616)
+++ /trunk/packages/vizservers/vtkvis/PolyData.h	(revision 3616)
@@ -0,0 +1,46 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (C) 2004-2012  HUBzero Foundation, LLC
+ *
+ * Author: Leif Delgass <ldelgass@purdue.edu>
+ */
+
+#ifndef VTKVIS_POLYDATA_H
+#define VTKVIS_POLYDATA_H
+
+#include <vtkSmartPointer.h>
+#include <vtkPolyDataMapper.h>
+#include <vtkActor.h>
+
+#include "VtkGraphicsObject.h"
+#include "VtkDataSet.h"
+
+namespace VtkVis {
+
+/**
+ * \brief VTK Mesh (Polygon data)
+ *
+ * This class creates a boundary mesh of a DataSet
+ */
+class PolyData : public VtkGraphicsObject {
+public:
+    PolyData();
+    virtual ~PolyData();
+
+    virtual const char *getClassName() const
+    {
+        return "PolyData";
+    }
+
+    virtual void setClippingPlanes(vtkPlaneCollection *planes);
+
+private:
+    virtual void initProp();
+    virtual void update();
+
+    vtkSmartPointer<vtkPolyDataMapper> _pdMapper;
+};
+
+}
+
+#endif
Index: /trunk/packages/vizservers/vtkvis/Polygon.cpp
===================================================================
--- /trunk/packages/vizservers/vtkvis/Polygon.cpp	(revision 3616)
+++ /trunk/packages/vizservers/vtkvis/Polygon.cpp	(revision 3616)
@@ -0,0 +1,45 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (C) 2004-2012  HUBzero Foundation, LLC
+ *
+ * Author: Leif Delgass <ldelgass@purdue.edu>
+ */
+
+#include <vtkPolyDataMapper.h>
+#include <vtkActor.h>
+#include <vtkRegularPolygonSource.h>
+
+#include "Polygon.h"
+#include "Trace.h"
+
+using namespace VtkVis;
+
+Polygon::Polygon() :
+    Shape()
+{
+}
+
+Polygon::~Polygon()
+{
+    TRACE("Deleting Polygon");
+}
+
+void Polygon::update()
+{
+    if (_polygon == NULL) {
+	_polygon = vtkSmartPointer<vtkRegularPolygonSource>::New();
+    }
+
+    if (_pdMapper == NULL) {
+        _pdMapper = vtkSmartPointer<vtkPolyDataMapper>::New();
+        _pdMapper->SetResolveCoincidentTopologyToPolygonOffset();
+        _pdMapper->ScalarVisibilityOff();
+    }
+
+    _pdMapper->SetInputConnection(_polygon->GetOutputPort());
+
+    initProp();
+
+    getActor()->SetMapper(_pdMapper);
+    _pdMapper->Update();
+}
Index: /trunk/packages/vizservers/vtkvis/Polygon.h
===================================================================
--- /trunk/packages/vizservers/vtkvis/Polygon.h	(revision 3616)
+++ /trunk/packages/vizservers/vtkvis/Polygon.h	(revision 3616)
@@ -0,0 +1,73 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (C) 2004-2012  HUBzero Foundation, LLC
+ *
+ * Author: Leif Delgass <ldelgass@purdue.edu>
+ */
+
+#ifndef VTKVIS_POLYGON_H
+#define VTKVIS_POLYGON_H_
+
+#include <vtkSmartPointer.h>
+#include <vtkPolyDataMapper.h>
+#include <vtkActor.h>
+#include <vtkRegularPolygonSource.h>
+
+#include "Shape.h"
+#include "VtkDataSet.h"
+
+namespace VtkVis {
+
+/**
+ * \brief VTK PolyData regular n-sided polygon
+ *
+ * This class creates a regular n-sided polygon
+ */
+class Polygon : public Shape
+{
+public:
+    Polygon();
+    virtual ~Polygon();
+
+    virtual const char *getClassName() const
+    {
+        return "Polygon";
+    }
+
+    void setNumberOfSides(int numSides)
+    {
+        if (_polygon != NULL) {
+            _polygon->SetNumberOfSides(numSides);
+	}
+    }
+
+    void setCenter(double center[3])
+    {
+        if (_polygon != NULL) {
+            _polygon->SetCenter(center);
+	}
+    }
+
+    void setNormal(double normal[3])
+    {
+        if (_polygon != NULL) {
+            _polygon->SetNormal(normal);
+	}
+    }
+
+    void setRadius(double radius)
+    {
+        if (_polygon != NULL) {
+            _polygon->SetRadius(radius);
+	}
+    }
+
+private:
+    virtual void update();
+
+    vtkSmartPointer<vtkRegularPolygonSource> _polygon;
+};
+
+}
+
+#endif
Index: /trunk/packages/vizservers/vtkvis/PseudoColor.cpp
===================================================================
--- /trunk/packages/vizservers/vtkvis/PseudoColor.cpp	(revision 3616)
+++ /trunk/packages/vizservers/vtkvis/PseudoColor.cpp	(revision 3616)
@@ -0,0 +1,514 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (C) 2004-2012  HUBzero Foundation, LLC
+ *
+ * Author: Leif Delgass <ldelgass@purdue.edu>
+ */
+
+#include <cassert>
+#include <cfloat>
+#include <cstring>
+
+#include <vtkDataSet.h>
+#include <vtkPointData.h>
+#include <vtkCellData.h>
+#include <vtkDataSetMapper.h>
+#include <vtkUnstructuredGrid.h>
+#include <vtkProperty.h>
+#include <vtkImageData.h>
+#include <vtkLookupTable.h>
+#include <vtkTransform.h>
+#include <vtkDelaunay2D.h>
+#include <vtkDelaunay3D.h>
+#include <vtkGaussianSplatter.h>
+#include <vtkExtractVOI.h>
+#include <vtkDataSetSurfaceFilter.h>
+
+#include "PseudoColor.h"
+#include "VtkRenderer.h"
+#include "Trace.h"
+
+#define MESH_POINT_CLOUDS
+
+using namespace VtkVis;
+
+PseudoColor::PseudoColor() :
+    VtkGraphicsObject(),
+    _colorMap(NULL),
+    _colorMode(COLOR_BY_SCALAR),
+    _colorFieldType(DataSet::POINT_DATA),
+    _renderer(NULL)
+{
+    _colorFieldRange[0] = DBL_MAX;
+    _colorFieldRange[1] = -DBL_MAX;
+}
+
+PseudoColor::~PseudoColor()
+{
+#ifdef WANT_TRACE
+    if (_dataSet != NULL)
+        TRACE("Deleting PseudoColor for %s", _dataSet->getName().c_str());
+    else
+        TRACE("Deleting PseudoColor with NULL DataSet");
+#endif
+}
+
+void PseudoColor::setDataSet(DataSet *dataSet,
+                             Renderer *renderer)
+{
+    if (_dataSet != dataSet) {
+        _dataSet = dataSet;
+
+        _renderer = renderer;
+
+        if (renderer->getUseCumulativeRange()) {
+            renderer->getCumulativeDataRange(_dataRange,
+                                             _dataSet->getActiveScalarsName(),
+                                             1);
+            renderer->getCumulativeDataRange(_vectorMagnitudeRange,
+                                             _dataSet->getActiveVectorsName(),
+                                             3);
+            for (int i = 0; i < 3; i++) {
+                renderer->getCumulativeDataRange(_vectorComponentRange[i],
+                                                 _dataSet->getActiveVectorsName(),
+                                                 3, i);
+            }
+        } else {
+            _dataSet->getScalarRange(_dataRange);
+            _dataSet->getVectorRange(_vectorMagnitudeRange);
+            for (int i = 0; i < 3; i++) {
+                _dataSet->getVectorRange(_vectorComponentRange[i], i);
+            }
+        }
+
+        update();
+    }
+}
+
+/**
+ * \brief Internal method to set up pipeline after a state change
+ */
+void PseudoColor::update()
+{
+    if (_dataSet == NULL)
+        return;
+
+    vtkDataSet *ds = _dataSet->getVtkDataSet();
+
+    // Mapper, actor to render color-mapped data set
+    if (_dsMapper == NULL) {
+        _dsMapper = vtkSmartPointer<vtkDataSetMapper>::New();
+        // Map scalars through lookup table regardless of type
+        _dsMapper->SetColorModeToMapScalars();
+    }
+
+    vtkPolyData *pd = vtkPolyData::SafeDownCast(ds);
+    if (pd) {
+        // DataSet is a vtkPolyData
+        if (pd->GetNumberOfLines() == 0 &&
+            pd->GetNumberOfPolys() == 0 &&
+            pd->GetNumberOfStrips() == 0) {
+            // DataSet is a point cloud
+            PrincipalPlane plane;
+            double offset;
+            if (_dataSet->is2D(&plane, &offset)) {
+#ifdef MESH_POINT_CLOUDS
+                vtkSmartPointer<vtkDelaunay2D> mesher = vtkSmartPointer<vtkDelaunay2D>::New();
+                if (plane == PLANE_ZY) {
+                    vtkSmartPointer<vtkTransform> trans = vtkSmartPointer<vtkTransform>::New();
+                    trans->RotateWXYZ(90, 0, 1, 0);
+                    if (offset != 0.0) {
+                        trans->Translate(-offset, 0, 0);
+                    }
+                    mesher->SetTransform(trans);
+                } else if (plane == PLANE_XZ) {
+                    vtkSmartPointer<vtkTransform> trans = vtkSmartPointer<vtkTransform>::New();
+                    trans->RotateWXYZ(-90, 1, 0, 0);
+                    if (offset != 0.0) {
+                        trans->Translate(0, -offset, 0);
+                    }
+                    mesher->SetTransform(trans);
+                } else if (offset != 0.0) {
+                    // XY with Z offset
+                    vtkSmartPointer<vtkTransform> trans = vtkSmartPointer<vtkTransform>::New();
+                    trans->Translate(0, 0, -offset);
+                    mesher->SetTransform(trans);
+                }
+#ifdef USE_VTK6
+                mesher->SetInputData(pd);
+#else
+                mesher->SetInput(pd);
+#endif
+                _dsMapper->SetInputConnection(mesher->GetOutputPort());
+#else
+                vtkSmartPointer<vtkGaussianSplatter> splatter = vtkSmartPointer<vtkGaussianSplatter>::New();
+                vtkSmartPointer<vtkExtractVOI> slicer = vtkSmartPointer<vtkExtractVOI>::New();
+#ifdef USE_VTK6
+                splatter->SetInputData(pd);
+#else
+                splatter->SetInput(pd);
+#endif
+                int dims[3];
+                splatter->GetSampleDimensions(dims);
+                TRACE("Sample dims: %d %d %d", dims[0], dims[1], dims[2]);
+                if (plane == PLANE_ZY) {
+                    dims[0] = 3;
+                    slicer->SetVOI(1, 1, 0, dims[1]-1, 0, dims[1]-1);
+                } else if (plane == PLANE_XZ) {
+                    dims[1] = 3;
+                    slicer->SetVOI(0, dims[0]-1, 1, 1, 0, dims[2]-1);
+                } else {
+                    dims[2] = 3;
+                    slicer->SetVOI(0, dims[0]-1, 0, dims[1]-1, 1, 1);
+                }
+                splatter->SetSampleDimensions(dims);
+                double bounds[6];
+                splatter->Update();
+                splatter->GetModelBounds(bounds);
+                TRACE("Model bounds: %g %g %g %g %g %g",
+                      bounds[0], bounds[1],
+                      bounds[2], bounds[3],
+                      bounds[4], bounds[5]);
+                slicer->SetInputConnection(splatter->GetOutputPort());
+                slicer->SetSampleRate(1, 1, 1);
+                vtkSmartPointer<vtkDataSetSurfaceFilter> gf = vtkSmartPointer<vtkDataSetSurfaceFilter>::New();
+                gf->UseStripsOn();
+                gf->SetInputConnection(slicer->GetOutputPort());
+                _dsMapper->SetInputConnection(gf->GetOutputPort());
+#endif
+            } else {
+                vtkSmartPointer<vtkDelaunay3D> mesher = vtkSmartPointer<vtkDelaunay3D>::New();
+#ifdef USE_VTK6
+                mesher->SetInputData(pd);
+#else
+                mesher->SetInput(pd);
+#endif
+                vtkSmartPointer<vtkDataSetSurfaceFilter> gf = vtkSmartPointer<vtkDataSetSurfaceFilter>::New();
+                gf->SetInputConnection(mesher->GetOutputPort());
+                _dsMapper->SetInputConnection(gf->GetOutputPort());
+             }
+        } else {
+            // DataSet is a vtkPolyData with lines and/or polygons
+#ifdef USE_VTK6
+            _dsMapper->SetInputData(ds);
+#else
+            _dsMapper->SetInput(ds);
+#endif
+        }
+    } else {
+        TRACE("Generating surface for data set");
+        // DataSet is NOT a vtkPolyData
+        vtkSmartPointer<vtkDataSetSurfaceFilter> gf = vtkSmartPointer<vtkDataSetSurfaceFilter>::New();
+#ifdef USE_VTK6
+        gf->SetInputData(ds);
+#else
+        gf->SetInput(ds);
+#endif
+        _dsMapper->SetInputConnection(gf->GetOutputPort());
+    }
+
+    setInterpolateBeforeMapping(true);
+
+    if (_lut == NULL) {
+        setColorMap(ColorMap::getDefault());
+    }
+
+    setColorMode(_colorMode);
+
+    initProp();
+    getActor()->SetMapper(_dsMapper);
+    _dsMapper->Update();
+}
+
+void PseudoColor::setInterpolateBeforeMapping(bool state)
+{
+    if (_dsMapper != NULL) {
+        _dsMapper->SetInterpolateScalarsBeforeMapping((state ? 1 : 0));
+    }
+}
+
+void PseudoColor::updateRanges(Renderer *renderer)
+{
+    if (_dataSet == NULL) {
+        ERROR("called before setDataSet");
+        return;
+    }
+
+    if (renderer->getUseCumulativeRange()) {
+        renderer->getCumulativeDataRange(_dataRange,
+                                         _dataSet->getActiveScalarsName(),
+                                         1);
+        renderer->getCumulativeDataRange(_vectorMagnitudeRange,
+                                         _dataSet->getActiveVectorsName(),
+                                         3);
+        for (int i = 0; i < 3; i++) {
+            renderer->getCumulativeDataRange(_vectorComponentRange[i],
+                                             _dataSet->getActiveVectorsName(),
+                                             3, i);
+        }
+    } else {
+        _dataSet->getScalarRange(_dataRange);
+        _dataSet->getVectorRange(_vectorMagnitudeRange);
+        for (int i = 0; i < 3; i++) {
+            _dataSet->getVectorRange(_vectorComponentRange[i], i);
+        }
+    }
+
+    // Need to update color map ranges
+    double *rangePtr = _colorFieldRange;
+    if (_colorFieldRange[0] > _colorFieldRange[1]) {
+        rangePtr = NULL;
+    }
+    setColorMode(_colorMode, _colorFieldType, _colorFieldName.c_str(), rangePtr);
+}
+
+void PseudoColor::setColorMode(ColorMode mode)
+{
+    _colorMode = mode;
+    if (_dataSet == NULL)
+        return;
+
+    switch (mode) {
+    case COLOR_BY_SCALAR:
+        setColorMode(mode,
+                     _dataSet->getActiveScalarsType(),
+                     _dataSet->getActiveScalarsName(),
+                     _dataRange);
+        break;
+    case COLOR_BY_VECTOR_MAGNITUDE:
+        setColorMode(mode,
+                     _dataSet->getActiveVectorsType(),
+                     _dataSet->getActiveVectorsName(),
+                     _vectorMagnitudeRange);
+        break;
+    case COLOR_BY_VECTOR_X:
+        setColorMode(mode,
+                     _dataSet->getActiveVectorsType(),
+                     _dataSet->getActiveVectorsName(),
+                     _vectorComponentRange[0]);
+        break;
+    case COLOR_BY_VECTOR_Y:
+        setColorMode(mode,
+                     _dataSet->getActiveVectorsType(),
+                     _dataSet->getActiveVectorsName(),
+                     _vectorComponentRange[1]);
+        break;
+    case COLOR_BY_VECTOR_Z:
+        setColorMode(mode,
+                     _dataSet->getActiveVectorsType(),
+                     _dataSet->getActiveVectorsName(),
+                     _vectorComponentRange[2]);
+        break;
+    case COLOR_CONSTANT:
+    default:
+        setColorMode(mode, DataSet::POINT_DATA, NULL, NULL);
+        break;
+    }
+}
+
+void PseudoColor::setColorMode(ColorMode mode,
+                               const char *name, double range[2])
+{
+    if (_dataSet == NULL)
+        return;
+    DataSet::DataAttributeType type = DataSet::POINT_DATA;
+    int numComponents = 1;
+    if (name != NULL && strlen(name) > 0 &&
+        !_dataSet->getFieldInfo(name, &type, &numComponents)) {
+        ERROR("Field not found: %s", name);
+        return;
+    }
+    setColorMode(mode, type, name, range);
+}
+
+void PseudoColor::setColorMode(ColorMode mode, DataSet::DataAttributeType type,
+                               const char *name, double range[2])
+{
+    _colorMode = mode;
+    _colorFieldType = type;
+    if (name == NULL)
+        _colorFieldName.clear();
+    else
+        _colorFieldName = name;
+    if (range == NULL) {
+        _colorFieldRange[0] = DBL_MAX;
+        _colorFieldRange[1] = -DBL_MAX;
+    } else {
+        memcpy(_colorFieldRange, range, sizeof(double)*2);
+    }
+
+    if (_dataSet == NULL || _dsMapper == NULL)
+        return;
+
+    switch (type) {
+    case DataSet::POINT_DATA:
+        _dsMapper->SetScalarModeToUsePointFieldData();
+        break;
+    case DataSet::CELL_DATA:
+        _dsMapper->SetScalarModeToUseCellFieldData();
+        break;
+    default:
+        ERROR("Unsupported DataAttributeType: %d", type);
+        return;
+    }
+
+    if (name != NULL && strlen(name) > 0) {
+        _dsMapper->SelectColorArray(name);
+    } else {
+        _dsMapper->SetScalarModeToDefault();
+    }
+
+    if (_lut != NULL) {
+        if (range != NULL) {
+            _lut->SetRange(range);
+        } else if (name != NULL && strlen(name) > 0) {
+            double r[2];
+            int comp = -1;
+            if (mode == COLOR_BY_VECTOR_X)
+                comp = 0;
+            else if (mode == COLOR_BY_VECTOR_Y)
+                comp = 1;
+            else if (mode == COLOR_BY_VECTOR_Z)
+                comp = 2;
+
+            if (_renderer->getUseCumulativeRange()) {
+                int numComponents;
+                if  (!_dataSet->getFieldInfo(name, type, &numComponents)) {
+                    ERROR("Field not found: %s, type: %d", name, type);
+                    return;
+                } else if (numComponents < comp+1) {
+                    ERROR("Request for component %d in field with %d components",
+                          comp, numComponents);
+                    return;
+                }
+                _renderer->getCumulativeDataRange(r, name, type, numComponents, comp);
+            } else {
+                _dataSet->getDataRange(r, name, type, comp);
+            }
+            _lut->SetRange(r);
+        }
+    }
+
+    switch (mode) {
+    case COLOR_BY_SCALAR:
+        _dsMapper->ScalarVisibilityOn();
+        break;
+    case COLOR_BY_VECTOR_MAGNITUDE:
+        _dsMapper->ScalarVisibilityOn();
+        if (_lut != NULL) {
+            _lut->SetVectorModeToMagnitude();
+        }
+        break;
+    case COLOR_BY_VECTOR_X:
+        _dsMapper->ScalarVisibilityOn();
+        if (_lut != NULL) {
+            _lut->SetVectorModeToComponent();
+            _lut->SetVectorComponent(0);
+        }
+        break;
+    case COLOR_BY_VECTOR_Y:
+        _dsMapper->ScalarVisibilityOn();
+        if (_lut != NULL) {
+            _lut->SetVectorModeToComponent();
+            _lut->SetVectorComponent(1);
+        }
+        break;
+    case COLOR_BY_VECTOR_Z:
+        _dsMapper->ScalarVisibilityOn();
+        if (_lut != NULL) {
+            _lut->SetVectorModeToComponent();
+            _lut->SetVectorComponent(2);
+        }
+        break;
+    case COLOR_CONSTANT:
+    default:
+        _dsMapper->ScalarVisibilityOff();
+        break;
+    }
+}
+
+/**
+ * \brief Called when the color map has been edited
+ */
+void PseudoColor::updateColorMap()
+{
+    setColorMap(_colorMap);
+}
+
+/**
+ * \brief Associate a colormap lookup table with the DataSet
+ */
+void PseudoColor::setColorMap(ColorMap *cmap)
+{
+    if (cmap == NULL)
+        return;
+
+    _colorMap = cmap;
+ 
+    if (_lut == NULL) {
+        _lut = vtkSmartPointer<vtkLookupTable>::New();
+        if (_dsMapper != NULL) {
+            _dsMapper->UseLookupTableScalarRangeOn();
+            _dsMapper->SetLookupTable(_lut);
+        }
+        _lut->DeepCopy(cmap->getLookupTable());
+        switch (_colorMode) {
+        case COLOR_CONSTANT:
+        case COLOR_BY_SCALAR:
+            _lut->SetRange(_dataRange);
+            break;
+        case COLOR_BY_VECTOR_MAGNITUDE:
+            _lut->SetRange(_vectorMagnitudeRange);
+            break;
+        case COLOR_BY_VECTOR_X:
+            _lut->SetRange(_vectorComponentRange[0]);
+            break;
+        case COLOR_BY_VECTOR_Y:
+            _lut->SetRange(_vectorComponentRange[1]);
+            break;
+        case COLOR_BY_VECTOR_Z:
+            _lut->SetRange(_vectorComponentRange[2]);
+            break;
+        default:
+            break;
+        }
+    } else {
+        double range[2];
+        _lut->GetTableRange(range);
+        _lut->DeepCopy(cmap->getLookupTable());
+        _lut->SetRange(range);
+        _lut->Modified();
+    }
+
+    switch (_colorMode) {
+    case COLOR_BY_VECTOR_MAGNITUDE:
+        _lut->SetVectorModeToMagnitude();
+        break;
+    case COLOR_BY_VECTOR_X:
+        _lut->SetVectorModeToComponent();
+        _lut->SetVectorComponent(0);
+        break;
+    case COLOR_BY_VECTOR_Y:
+        _lut->SetVectorModeToComponent();
+        _lut->SetVectorComponent(1);
+        break;
+    case COLOR_BY_VECTOR_Z:
+        _lut->SetVectorModeToComponent();
+        _lut->SetVectorComponent(2);
+        break;
+    default:
+         break;
+    }
+}
+
+/**
+ * \brief Set a group of world coordinate planes to clip rendering
+ *
+ * Passing NULL for planes will remove all cliping planes
+ */
+void PseudoColor::setClippingPlanes(vtkPlaneCollection *planes)
+{
+    if (_dsMapper != NULL) {
+        _dsMapper->SetClippingPlanes(planes);
+    }
+}
Index: /trunk/packages/vizservers/vtkvis/PseudoColor.h
===================================================================
--- /trunk/packages/vizservers/vtkvis/PseudoColor.h	(revision 3616)
+++ /trunk/packages/vizservers/vtkvis/PseudoColor.h	(revision 3616)
@@ -0,0 +1,91 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (C) 2004-2012  HUBzero Foundation, LLC
+ *
+ * Author: Leif Delgass <ldelgass@purdue.edu>
+ */
+
+#ifndef VTKVIS_PSEUDOCOLOR_H
+#define VTKVIS_PSEUDOCOLOR_H
+
+#include <vtkSmartPointer.h>
+#include <vtkLookupTable.h>
+#include <vtkDataSetMapper.h>
+#include <vtkActor.h>
+#include <vtkPlaneCollection.h>
+
+#include "ColorMap.h"
+#include "VtkGraphicsObject.h"
+
+namespace VtkVis {
+
+/**
+ * \brief Color-mapped plot of data set
+ */
+class PseudoColor : public VtkGraphicsObject {
+public:
+    enum ColorMode {
+        COLOR_BY_SCALAR,
+        COLOR_BY_VECTOR_MAGNITUDE,
+        COLOR_BY_VECTOR_X,
+        COLOR_BY_VECTOR_Y,
+        COLOR_BY_VECTOR_Z,
+        COLOR_CONSTANT
+    };
+
+    PseudoColor();
+    virtual ~PseudoColor();
+
+    virtual const char *getClassName() const
+    {
+        return "PseudoColor";
+    }
+
+    virtual void setDataSet(DataSet *dataSet,
+                            Renderer *renderer);
+
+    virtual void setClippingPlanes(vtkPlaneCollection *planes);
+
+    void setInterpolateBeforeMapping(bool state);
+
+    void setColorMode(ColorMode mode, DataSet::DataAttributeType type,
+                      const char *name, double range[2] = NULL);
+
+    void setColorMode(ColorMode mode,
+                      const char *name, double range[2] = NULL);
+
+    void setColorMode(ColorMode mode);
+
+    void setColorMap(ColorMap *colorMap);
+
+    /**
+     * \brief Return the ColorMap in use
+     */
+    ColorMap *getColorMap()
+    {
+        return _colorMap;
+    }
+
+    void updateColorMap();
+
+    virtual void updateRanges(Renderer *renderer);
+
+private:
+    virtual void update();
+
+    ColorMap *_colorMap;
+    ColorMode _colorMode;
+    std::string _colorFieldName;
+    DataSet::DataAttributeType _colorFieldType;
+    double _colorFieldRange[2];
+    double _vectorMagnitudeRange[2];
+    double _vectorComponentRange[3][2];
+    Renderer *_renderer;
+
+    vtkSmartPointer<vtkLookupTable> _lut;
+    vtkSmartPointer<vtkDataSetMapper> _dsMapper;
+};
+
+}
+
+#endif
Index: unk/packages/vizservers/vtkvis/RpArc.cpp
===================================================================
--- /trunk/packages/vizservers/vtkvis/RpArc.cpp	(revision 3615)
+++ 	(revision )
@@ -1,45 +1,0 @@
-/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
-/*
- * Copyright (C) 2004-2012  HUBzero Foundation, LLC
- *
- * Author: Leif Delgass <ldelgass@purdue.edu>
- */
-
-#include <vtkPolyDataMapper.h>
-#include <vtkActor.h>
-#include <vtkArcSource.h>
-
-#include "RpArc.h"
-#include "Trace.h"
-
-using namespace VtkVis;
-
-Arc::Arc() :
-    Shape()
-{
-}
-
-Arc::~Arc()
-{
-    TRACE("Deleting Arc");
-}
-
-void Arc::update()
-{
-    if (_arc == NULL) {
-	_arc = vtkSmartPointer<vtkArcSource>::New();
-    }
-
-    if (_pdMapper == NULL) {
-        _pdMapper = vtkSmartPointer<vtkPolyDataMapper>::New();
-        _pdMapper->SetResolveCoincidentTopologyToPolygonOffset();
-        _pdMapper->ScalarVisibilityOff();
-    }
-
-    _pdMapper->SetInputConnection(_arc->GetOutputPort());
-
-    initProp();
-
-    getActor()->SetMapper(_pdMapper);
-    _pdMapper->Update();
-}
Index: unk/packages/vizservers/vtkvis/RpArc.h
===================================================================
--- /trunk/packages/vizservers/vtkvis/RpArc.h	(revision 3615)
+++ 	(revision )
@@ -1,67 +1,0 @@
-/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
-/*
- * Copyright (C) 2004-2012  HUBzero Foundation, LLC
- *
- * Author: Leif Delgass <ldelgass@purdue.edu>
- */
-
-#ifndef VTKVIS_ARC_H
-#define VTKVIS_ARC_H
-
-#include <vtkSmartPointer.h>
-#include <vtkPolyDataMapper.h>
-#include <vtkActor.h>
-#include <vtkArcSource.h>
-
-#include "RpShape.h"
-#include "RpVtkDataSet.h"
-
-namespace VtkVis {
-
-/**
- * \brief VTK PolyData Arc
- *
- * This class creates a arc
- */
-class Arc : public Shape
-{
-public:
-    Arc();
-    virtual ~Arc();
-
-    virtual const char *getClassName() const
-    {
-        return "Arc";
-    }
-
-    void setCenter(double center[3])
-    {
-        if (_arc != NULL) {
-            _arc->SetCenter(center);
-	}
-    }
-
-    void setEndPoints(double pt1[3], double pt2[3])
-    {
-        if (_arc != NULL) {
-            _arc->SetPoint1(pt1);
-            _arc->SetPoint2(pt2);
-	}
-    }
-
-    void setResolution(int res)
-    {
-        if (_arc != NULL) {
-            _arc->SetResolution(res);
-	}
-    }
-
-private:
-    virtual void update();
-
-    vtkSmartPointer<vtkArcSource> _arc;
-};
-
-}
-
-#endif
Index: unk/packages/vizservers/vtkvis/RpArrow.cpp
===================================================================
--- /trunk/packages/vizservers/vtkvis/RpArrow.cpp	(revision 3615)
+++ 	(revision )
@@ -1,45 +1,0 @@
-/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
-/*
- * Copyright (C) 2004-2012  HUBzero Foundation, LLC
- *
- * Author: Leif Delgass <ldelgass@purdue.edu>
- */
-
-#include <vtkPolyDataMapper.h>
-#include <vtkActor.h>
-#include <vtkArrowSource.h>
-
-#include "RpArrow.h"
-#include "Trace.h"
-
-using namespace VtkVis;
-
-Arrow::Arrow() :
-    Shape()
-{
-}
-
-Arrow::~Arrow()
-{
-    TRACE("Deleting Arrow");
-}
-
-void Arrow::update()
-{
-    if (_arrow == NULL) {
-	_arrow = vtkSmartPointer<vtkArrowSource>::New();
-    }
-
-    if (_pdMapper == NULL) {
-        _pdMapper = vtkSmartPointer<vtkPolyDataMapper>::New();
-        _pdMapper->SetResolveCoincidentTopologyToPolygonOffset();
-        _pdMapper->ScalarVisibilityOff();
-    }
-
-    _pdMapper->SetInputConnection(_arrow->GetOutputPort());
-
-    initProp();
-
-    getActor()->SetMapper(_pdMapper);
-    _pdMapper->Update();
-}
Index: unk/packages/vizservers/vtkvis/RpArrow.h
===================================================================
--- /trunk/packages/vizservers/vtkvis/RpArrow.h	(revision 3615)
+++ 	(revision )
@@ -1,75 +1,0 @@
-/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
-/*
- * Copyright (C) 2004-2012  HUBzero Foundation, LLC
- *
- * Author: Leif Delgass <ldelgass@purdue.edu>
- */
-
-#ifndef VTKVIS_ARROW_H
-#define VTKVIS_ARROW_H
-
-#include <vtkSmartPointer.h>
-#include <vtkPolyDataMapper.h>
-#include <vtkActor.h>
-#include <vtkArrowSource.h>
-
-#include "RpShape.h"
-#include "RpVtkDataSet.h"
-
-namespace VtkVis {
-
-/**
- * \brief VTK PolyData 3D Arrow
- *
- * This class creates a mesh arrow
- */
-class Arrow : public Shape
-{
-public:
-    Arrow();
-    virtual ~Arrow();
-
-    virtual const char *getClassName() const
-    {
-        return "Arrow";
-    }
-
-    void setTipLength(double len)
-    {
-        if (_arrow != NULL) {
-            _arrow->SetTipLength(len);
-	}
-    }
-
-    void setRadii(double tipRadius, double shaftRadius)
-    {
-        if (_arrow != NULL) {
-            _arrow->SetTipRadius(tipRadius);
-            _arrow->SetShaftRadius(shaftRadius);
-	}
-    }
-
-    void setResolution(int tipRes, int shaftRes)
-    {
-        if (_arrow != NULL) {
-            _arrow->SetTipResolution(tipRes);
-            _arrow->SetShaftResolution(shaftRes);
-	}
-    }
-
-    void setInvert(bool state)
-    {
-        if (_arrow != NULL) {
-            _arrow->SetInvert(state);
-	}
-    }
-
-private:
-    virtual void update();
-
-    vtkSmartPointer<vtkArrowSource> _arrow;
-};
-
-}
-
-#endif
Index: unk/packages/vizservers/vtkvis/RpBox.cpp
===================================================================
--- /trunk/packages/vizservers/vtkvis/RpBox.cpp	(revision 3615)
+++ 	(revision )
@@ -1,51 +1,0 @@
-/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
-/*
- * Copyright (C) 2004-2012  HUBzero Foundation, LLC
- *
- * Author: Leif Delgass <ldelgass@purdue.edu>
- */
-
-#include <cassert>
-
-#include <vtkDataSet.h>
-#include <vtkPolyData.h>
-#include <vtkPolyDataMapper.h>
-#include <vtkActor.h>
-#include <vtkProperty.h>
-#include <vtkTransform.h>
-#include <vtkCubeSource.h>
-
-#include "RpBox.h"
-#include "Trace.h"
-
-using namespace VtkVis;
-
-Box::Box() :
-    Shape()
-{
-}
-
-Box::~Box()
-{
-    TRACE("Deleting Box");
-}
-
-void Box::update()
-{
-    if (_box == NULL) {
-	_box = vtkSmartPointer<vtkCubeSource>::New();
-    }
-
-    if (_pdMapper == NULL) {
-        _pdMapper = vtkSmartPointer<vtkPolyDataMapper>::New();
-        _pdMapper->SetResolveCoincidentTopologyToPolygonOffset();
-        _pdMapper->ScalarVisibilityOff();
-    }
-
-    _pdMapper->SetInputConnection(_box->GetOutputPort());
-
-    initProp();
-
-    getActor()->SetMapper(_pdMapper);
-    _pdMapper->Update();
-}
Index: unk/packages/vizservers/vtkvis/RpBox.h
===================================================================
--- /trunk/packages/vizservers/vtkvis/RpBox.h	(revision 3615)
+++ 	(revision )
@@ -1,54 +1,0 @@
-/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
-/*
- * Copyright (C) 2004-2012  HUBzero Foundation, LLC
- *
- * Author: Leif Delgass <ldelgass@purdue.edu>
- */
-
-#ifndef VTKVIS_BOX_H
-#define VTKVIS_BOX_H
-
-#include <vtkSmartPointer.h>
-#include <vtkPolyDataMapper.h>
-#include <vtkActor.h>
-#include <vtkCubeSource.h>
-
-#include "RpShape.h"
-#include "RpVtkDataSet.h"
-
-namespace VtkVis {
-
-/**
- * \brief VTK PolyData box
- *
- * This class creates a mesh box
- */
-class Box : public Shape
-{
-public:
-    Box();
-    virtual ~Box();
-
-    virtual const char *getClassName() const
-    {
-        return "Box";
-    }
-
-    void setSize(double xlen, double ylen, double zlen)
-    {
-        if (_box != NULL) {
-            _box->SetXLength(xlen);
-	    _box->SetYLength(ylen);
-	    _box->SetZLength(zlen);
-	}
-    }
-
-private:
-    virtual void update();
-
-    vtkSmartPointer<vtkCubeSource> _box;
-};
-
-}
-
-#endif
Index: unk/packages/vizservers/vtkvis/RpCone.cpp
===================================================================
--- /trunk/packages/vizservers/vtkvis/RpCone.cpp	(revision 3615)
+++ 	(revision )
@@ -1,45 +1,0 @@
-/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
-/*
- * Copyright (C) 2004-2012  HUBzero Foundation, LLC
- *
- * Author: Leif Delgass <ldelgass@purdue.edu>
- */
-
-#include <vtkPolyDataMapper.h>
-#include <vtkActor.h>
-#include <vtkConeSource.h>
-
-#include "RpCone.h"
-#include "Trace.h"
-
-using namespace VtkVis;
-
-Cone::Cone() :
-    Shape()
-{
-}
-
-Cone::~Cone()
-{
-    TRACE("Deleting Cone");
-}
-
-void Cone::update()
-{
-    if (_cone == NULL) {
-	_cone = vtkSmartPointer<vtkConeSource>::New();
-    }
-
-    if (_pdMapper == NULL) {
-        _pdMapper = vtkSmartPointer<vtkPolyDataMapper>::New();
-        _pdMapper->SetResolveCoincidentTopologyToPolygonOffset();
-        _pdMapper->ScalarVisibilityOff();
-    }
-
-    _pdMapper->SetInputConnection(_cone->GetOutputPort());
-
-    initProp();
-
-    getActor()->SetMapper(_pdMapper);
-    _pdMapper->Update();
-}
Index: unk/packages/vizservers/vtkvis/RpCone.h
===================================================================
--- /trunk/packages/vizservers/vtkvis/RpCone.h	(revision 3615)
+++ 	(revision )
@@ -1,87 +1,0 @@
-/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
-/*
- * Copyright (C) 2004-2012  HUBzero Foundation, LLC
- *
- * Author: Leif Delgass <ldelgass@purdue.edu>
- */
-
-#ifndef VTKVIS_CONE_H
-#define VTKVIS_CONE_H
-
-#include <vtkSmartPointer.h>
-#include <vtkPolyDataMapper.h>
-#include <vtkActor.h>
-#include <vtkConeSource.h>
-
-#include "RpShape.h"
-#include "RpVtkDataSet.h"
-
-namespace VtkVis {
-
-/**
- * \brief VTK PolyData cone
- *
- * This class creates a mesh cone
- */
-class Cone : public Shape
-{
-public:
-    Cone();
-    virtual ~Cone();
-
-    virtual const char *getClassName() const
-    {
-        return "Cone";
-    }
-
-    void setCenter(double center[3])
-    {
-        if (_cone != NULL) {
-            _cone->SetCenter(center);
-	}
-    }
-
-    void setHeight(double height)
-    {
-        if (_cone != NULL) {
-            _cone->SetHeight(height);
-	}
-    }
-
-    void setRadius(double radius)
-    {
-        if (_cone != NULL) {
-            _cone->SetRadius(radius);
-	}
-    }
-
-    void setDirection(double x, double y, double z)
-    {
-        if (_cone != NULL) {
-            _cone->SetDirection(x, y, z);
-	}
-    }
-
-    void setResolution(int res)
-    {
-        if (_cone != NULL) {
-            _cone->SetResolution(res);
-	}
-    }
-
-    void setCapping(bool state)
-    {
-        if (_cone != NULL) {
-            _cone->SetCapping(state ? 1 : 0);
-	}
-    }
-
-private:
-    virtual void update();
-
-    vtkSmartPointer<vtkConeSource> _cone;
-};
-
-}
-
-#endif
Index: unk/packages/vizservers/vtkvis/RpContour2D.cpp
===================================================================
--- /trunk/packages/vizservers/vtkvis/RpContour2D.cpp	(revision 3615)
+++ 	(revision )
@@ -1,604 +1,0 @@
-/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
-/*
- * Copyright (C) 2004-2012  HUBzero Foundation, LLC
- *
- * Author: Leif Delgass <ldelgass@purdue.edu>
- */
-
-#include <cfloat>
-
-#include <vtkVersion.h>
-#include <vtkDataSet.h>
-#include <vtkPointData.h>
-#include <vtkCellData.h>
-#include <vtkCellDataToPointData.h>
-#include <vtkContourFilter.h>
-#include <vtkStripper.h>
-#include <vtkPolyDataMapper.h>
-#include <vtkUnstructuredGrid.h>
-#include <vtkProperty.h>
-#include <vtkTransform.h>
-#include <vtkDelaunay2D.h>
-#include <vtkDelaunay3D.h>
-#include <vtkDataSetSurfaceFilter.h>
-
-#include "RpContour2D.h"
-#include "RpVtkRenderer.h"
-#include "Trace.h"
-
-using namespace VtkVis;
-
-Contour2D::Contour2D(int numContours) :
-    VtkGraphicsObject(),
-    _numContours(numContours),
-    _pipelineInitialized(false),
-    _colorMap(NULL),
-    _colorMode(COLOR_BY_SCALAR),
-    _colorFieldType(DataSet::POINT_DATA),
-    _renderer(NULL)
-{
-    _edgeColor[0] = _color[0];
-    _edgeColor[1] = _color[0];
-    _edgeColor[2] = _color[0];
-    _colorFieldRange[0] = DBL_MAX;
-    _colorFieldRange[1] = -DBL_MAX;
-    _lighting = false;
-}
-
-Contour2D::Contour2D(const std::vector<double>& contours) :
-    VtkGraphicsObject(),
-    _numContours(contours.size()),
-    _contours(contours),
-    _pipelineInitialized(false),
-    _colorMap(NULL),
-    _colorMode(COLOR_BY_SCALAR),
-    _colorFieldType(DataSet::POINT_DATA),
-    _renderer(NULL)
-{
-    _edgeColor[0] = _color[0];
-    _edgeColor[1] = _color[0];
-    _edgeColor[2] = _color[0];
-    _colorFieldRange[0] = DBL_MAX;
-    _colorFieldRange[1] = -DBL_MAX;
-    _lighting = false;
-}
-
-Contour2D::~Contour2D()
-{
-#ifdef WANT_TRACE
-    if (_dataSet != NULL)
-        TRACE("Deleting Contour2D for %s", _dataSet->getName().c_str());
-    else
-        TRACE("Deleting Contour2D with NULL DataSet");
-#endif
-}
-
-void Contour2D::setDataSet(DataSet *dataSet,
-                           Renderer *renderer)
-{
-    if (_dataSet != dataSet) {
-        _dataSet = dataSet;
-        _renderer = renderer;
-
-        if (renderer->getUseCumulativeRange()) {
-            renderer->getCumulativeDataRange(_dataRange,
-                                             _dataSet->getActiveScalarsName(),
-                                             1);
-            const char *activeVectors = _dataSet->getActiveVectorsName();
-            if (activeVectors != NULL) {
-                renderer->getCumulativeDataRange(_vectorMagnitudeRange,
-                                                 _dataSet->getActiveVectorsName(),
-                                                 3);
-                for (int i = 0; i < 3; i++) {
-                    renderer->getCumulativeDataRange(_vectorComponentRange[i],
-                                                     _dataSet->getActiveVectorsName(),
-                                                     3, i);
-                }
-            }
-        } else {
-            _dataSet->getScalarRange(_dataRange);
-            _dataSet->getVectorRange(_vectorMagnitudeRange);
-            for (int i = 0; i < 3; i++) {
-                _dataSet->getVectorRange(_vectorComponentRange[i], i);
-            }
-        }
-
-        update();
-    }
-}
-
-/**
- * \brief Internal method to re-compute contours after a state change
- */
-void Contour2D::update()
-{
-    if (_dataSet == NULL) {
-        return;
-    }
-    vtkDataSet *ds = _dataSet->getVtkDataSet();
-
-    // Contour filter to generate isolines
-    if (_contourFilter == NULL) {
-        _contourFilter = vtkSmartPointer<vtkContourFilter>::New();
-    }
-
-    if (!_pipelineInitialized) {
-        vtkSmartPointer<vtkCellDataToPointData> cellToPtData;
-
-        if (ds->GetPointData() == NULL ||
-            ds->GetPointData()->GetScalars() == NULL) {
-            TRACE("No scalar point data in dataset %s", _dataSet->getName().c_str());
-            if (ds->GetCellData() != NULL &&
-                ds->GetCellData()->GetScalars() != NULL) {
-                cellToPtData = 
-                    vtkSmartPointer<vtkCellDataToPointData>::New();
-#ifdef USE_VTK6
-                cellToPtData->SetInputData(ds);
-#else
-                cellToPtData->SetInput(ds);
-#endif
-                //cellToPtData->PassCellDataOn();
-                cellToPtData->Update();
-                ds = cellToPtData->GetOutput();
-            } else {
-                USER_ERROR("No scalar field was found in the data set");
-            }
-        }
-
-        vtkPolyData *pd = vtkPolyData::SafeDownCast(ds);
-        if (pd) {
-            // DataSet is a vtkPolyData
-            if (pd->GetNumberOfLines() == 0 &&
-                pd->GetNumberOfPolys() == 0 &&
-                pd->GetNumberOfStrips() == 0) {
-                // DataSet is a point cloud
-                PrincipalPlane plane;
-                double offset;
-                if (_dataSet->is2D(&plane, &offset)) {
-                    vtkSmartPointer<vtkDelaunay2D> mesher = vtkSmartPointer<vtkDelaunay2D>::New();
-                    if (plane == PLANE_ZY) {
-                        vtkSmartPointer<vtkTransform> trans = vtkSmartPointer<vtkTransform>::New();
-                        trans->RotateWXYZ(90, 0, 1, 0);
-                        if (offset != 0.0) {
-                            trans->Translate(-offset, 0, 0);
-                        }
-                        mesher->SetTransform(trans);
-                    } else if (plane == PLANE_XZ) {
-                        vtkSmartPointer<vtkTransform> trans = vtkSmartPointer<vtkTransform>::New();
-                        trans->RotateWXYZ(-90, 1, 0, 0);
-                        if (offset != 0.0) {
-                            trans->Translate(0, -offset, 0);
-                        }
-                        mesher->SetTransform(trans);
-                    } else if (offset != 0.0) {
-                        // XY with Z offset
-                        vtkSmartPointer<vtkTransform> trans = vtkSmartPointer<vtkTransform>::New();
-                        trans->Translate(0, 0, -offset);
-                        mesher->SetTransform(trans);
-                    }
-#ifdef USE_VTK6
-                    mesher->SetInputData(pd);
-#else
-                    mesher->SetInput(pd);
-#endif
-                    _contourFilter->SetInputConnection(mesher->GetOutputPort());
-                } else {
-                    vtkSmartPointer<vtkDelaunay3D> mesher = vtkSmartPointer<vtkDelaunay3D>::New();
-#ifdef USE_VTK6
-                    mesher->SetInputData(pd);
-#else
-                    mesher->SetInput(pd);
-#endif
-                    vtkSmartPointer<vtkDataSetSurfaceFilter> gf = vtkSmartPointer<vtkDataSetSurfaceFilter>::New();
-                    gf->SetInputConnection(mesher->GetOutputPort());
-                    _contourFilter->SetInputConnection(gf->GetOutputPort());
-                }
-            } else {
-                // DataSet is a vtkPolyData with lines and/or polygons
-#ifdef USE_VTK6
-                _contourFilter->SetInputData(ds);
-#else
-                _contourFilter->SetInput(ds);
-#endif
-            }
-        } else {
-            TRACE("Generating surface for data set");
-            // DataSet is NOT a vtkPolyData
-            vtkSmartPointer<vtkDataSetSurfaceFilter> gf = vtkSmartPointer<vtkDataSetSurfaceFilter>::New();
-#ifdef USE_VTK6
-            gf->SetInputData(ds);
-#else
-            gf->SetInput(ds);
-#endif
-            _contourFilter->SetInputConnection(gf->GetOutputPort());
-        }
-    }
-
-    _pipelineInitialized = true;
-
-    _contourFilter->ComputeNormalsOff();
-    _contourFilter->ComputeGradientsOff();
-
-    // Speed up multiple contour computation at cost of extra memory use
-    if (_numContours > 1) {
-        _contourFilter->UseScalarTreeOn();
-    } else {
-        _contourFilter->UseScalarTreeOff();
-    }
-
-    _contourFilter->SetNumberOfContours(_numContours);
-
-    if (_contours.empty()) {
-        // Evenly spaced isovalues
-        _contourFilter->GenerateValues(_numContours, _dataRange[0], _dataRange[1]);
-    } else {
-        // User-supplied isovalues
-        for (int i = 0; i < _numContours; i++) {
-            _contourFilter->SetValue(i, _contours[i]);
-        }
-    }
-
-    initProp();
-
-    if (_dsMapper == NULL) {
-        _dsMapper = vtkSmartPointer<vtkPolyDataMapper>::New();
-        _dsMapper->SetResolveCoincidentTopologyToPolygonOffset();
-        _dsMapper->ScalarVisibilityOff();
-        vtkSmartPointer<vtkStripper> stripper = vtkSmartPointer<vtkStripper>::New();
-        stripper->SetInputConnection(_contourFilter->GetOutputPort());
-        _dsMapper->SetInputConnection(stripper->GetOutputPort());
-        getActor()->SetMapper(_dsMapper);
-    }
-
-    if (_lut == NULL) {
-        setColorMap(ColorMap::getDefault());
-        setColorMode(_colorMode);
-    }
-
-    _dsMapper->Update();
-}
-
-void Contour2D::updateRanges(Renderer *renderer)
-{
-    if (_dataSet == NULL) {
-        ERROR("called before setDataSet");
-        return;
-    }
-
-    if (renderer->getUseCumulativeRange()) {
-        renderer->getCumulativeDataRange(_dataRange,
-                                         _dataSet->getActiveScalarsName(),
-                                         1);
-        const char *activeVectors = _dataSet->getActiveVectorsName();
-        if (activeVectors != NULL) {
-            renderer->getCumulativeDataRange(_vectorMagnitudeRange,
-                                             _dataSet->getActiveVectorsName(),
-                                             3);
-            for (int i = 0; i < 3; i++) {
-                renderer->getCumulativeDataRange(_vectorComponentRange[i],
-                                                 _dataSet->getActiveVectorsName(),
-                                                 3, i);
-            }
-        }
-    } else {
-        _dataSet->getScalarRange(_dataRange);
-        _dataSet->getVectorRange(_vectorMagnitudeRange);
-        for (int i = 0; i < 3; i++) {
-            _dataSet->getVectorRange(_vectorComponentRange[i], i);
-        }
-    }
- 
-    // Need to update color map ranges
-    double *rangePtr = _colorFieldRange;
-    if (_colorFieldRange[0] > _colorFieldRange[1]) {
-        rangePtr = NULL;
-    }
-    setColorMode(_colorMode, _colorFieldType, _colorFieldName.c_str(), rangePtr);
-
-    if (_contours.empty() && _numContours > 0) {
-        // Contour isovalues need to be recomputed
-        update();
-    }
-}
-
-void Contour2D::setContourField(const char *name)
-{
-    if (_contourFilter != NULL) {
-        _contourFilter->SetInputArrayToProcess(0, 0, 0, vtkDataObject::FIELD_ASSOCIATION_POINTS, name);
-        update();
-    }
-}
-
-void Contour2D::setColorMode(ColorMode mode)
-{
-    _colorMode = mode;
-    if (_dataSet == NULL)
-        return;
-
-    switch (mode) {
-    case COLOR_BY_SCALAR:
-        setColorMode(mode,
-                     _dataSet->getActiveScalarsType(),
-                     _dataSet->getActiveScalarsName(),
-                     _dataRange);
-        break;
-    case COLOR_BY_VECTOR_MAGNITUDE:
-        setColorMode(mode,
-                     _dataSet->getActiveVectorsType(),
-                     _dataSet->getActiveVectorsName(),
-                     _vectorMagnitudeRange);
-        break;
-    case COLOR_BY_VECTOR_X:
-        setColorMode(mode,
-                     _dataSet->getActiveVectorsType(),
-                     _dataSet->getActiveVectorsName(),
-                     _vectorComponentRange[0]);
-        break;
-    case COLOR_BY_VECTOR_Y:
-        setColorMode(mode,
-                     _dataSet->getActiveVectorsType(),
-                     _dataSet->getActiveVectorsName(),
-                     _vectorComponentRange[1]);
-        break;
-    case COLOR_BY_VECTOR_Z:
-        setColorMode(mode,
-                     _dataSet->getActiveVectorsType(),
-                     _dataSet->getActiveVectorsName(),
-                     _vectorComponentRange[2]);
-        break;
-    case COLOR_CONSTANT:
-    default:
-        setColorMode(mode, DataSet::POINT_DATA, NULL, NULL);
-        break;
-    }
-}
-
-void Contour2D::setColorMode(ColorMode mode,
-                             const char *name, double range[2])
-{
-    if (_dataSet == NULL)
-        return;
-    DataSet::DataAttributeType type = DataSet::POINT_DATA;
-    int numComponents = 1;
-    if (name != NULL && strlen(name) > 0 &&
-        !_dataSet->getFieldInfo(name, &type, &numComponents)) {
-        ERROR("Field not found: %s", name);
-        return;
-    }
-    setColorMode(mode, type, name, range);
-}
-
-void Contour2D::setColorMode(ColorMode mode, DataSet::DataAttributeType type,
-                             const char *name, double range[2])
-{
-    _colorMode = mode;
-    _colorFieldType = type;
-    if (name == NULL)
-        _colorFieldName.clear();
-    else
-        _colorFieldName = name;
-    if (range == NULL) {
-        _colorFieldRange[0] = DBL_MAX;
-        _colorFieldRange[1] = -DBL_MAX;
-    } else {
-        memcpy(_colorFieldRange, range, sizeof(double)*2);
-    }
-
-    if (_dataSet == NULL || _dsMapper == NULL)
-        return;
-
-    switch (type) {
-    case DataSet::POINT_DATA:
-        _dsMapper->SetScalarModeToUsePointFieldData();
-        break;
-    case DataSet::CELL_DATA:
-        _dsMapper->SetScalarModeToUseCellFieldData();
-        break;
-    default:
-        ERROR("Unsupported DataAttributeType: %d", type);
-        return;
-    }
-
-    if (name != NULL && strlen(name) > 0) {
-        _dsMapper->SelectColorArray(name);
-    } else {
-        _dsMapper->SetScalarModeToDefault();
-    }
-
-    if (_lut != NULL) {
-        if (range != NULL) {
-            _lut->SetRange(range);
-        } else if (name != NULL && strlen(name) > 0) {
-            double r[2];
-            int comp = -1;
-            if (mode == COLOR_BY_VECTOR_X)
-                comp = 0;
-            else if (mode == COLOR_BY_VECTOR_Y)
-                comp = 1;
-            else if (mode == COLOR_BY_VECTOR_Z)
-                comp = 2;
-
-            if (_renderer->getUseCumulativeRange()) {
-                int numComponents;
-                if  (!_dataSet->getFieldInfo(name, type, &numComponents)) {
-                    ERROR("Field not found: %s, type: %d", name, type);
-                    return;
-                } else if (numComponents < comp+1) {
-                    ERROR("Request for component %d in field with %d components",
-                          comp, numComponents);
-                    return;
-                }
-                _renderer->getCumulativeDataRange(r, name, type, numComponents, comp);
-            } else {
-                _dataSet->getDataRange(r, name, type, comp);
-            }
-            _lut->SetRange(r);
-        }
-    }
-
-    switch (mode) {
-    case COLOR_BY_SCALAR:
-        _dsMapper->ScalarVisibilityOn();
-        break;
-    case COLOR_BY_VECTOR_MAGNITUDE:
-        _dsMapper->ScalarVisibilityOn();
-        if (_lut != NULL) {
-            _lut->SetVectorModeToMagnitude();
-        }
-        break;
-    case COLOR_BY_VECTOR_X:
-        _dsMapper->ScalarVisibilityOn();
-        if (_lut != NULL) {
-            _lut->SetVectorModeToComponent();
-            _lut->SetVectorComponent(0);
-        }
-        break;
-    case COLOR_BY_VECTOR_Y:
-        _dsMapper->ScalarVisibilityOn();
-        if (_lut != NULL) {
-            _lut->SetVectorModeToComponent();
-            _lut->SetVectorComponent(1);
-        }
-        break;
-    case COLOR_BY_VECTOR_Z:
-        _dsMapper->ScalarVisibilityOn();
-        if (_lut != NULL) {
-            _lut->SetVectorModeToComponent();
-            _lut->SetVectorComponent(2);
-        }
-        break;
-    case COLOR_CONSTANT:
-    default:
-        _dsMapper->ScalarVisibilityOff();
-        break;
-    }
-}
-
-/**
- * \brief Called when the color map has been edited
- */
-void Contour2D::updateColorMap()
-{
-    setColorMap(_colorMap);
-}
-
-/**
- * \brief Associate a colormap lookup table with the DataSet
- */
-void Contour2D::setColorMap(ColorMap *cmap)
-{
-    if (cmap == NULL)
-        return;
-
-    _colorMap = cmap;
- 
-    if (_lut == NULL) {
-        _lut = vtkSmartPointer<vtkLookupTable>::New();
-        if (_dsMapper != NULL) {
-            _dsMapper->UseLookupTableScalarRangeOn();
-            _dsMapper->SetLookupTable(_lut);
-        }
-        _lut->DeepCopy(cmap->getLookupTable());
-        switch (_colorMode) {
-        case COLOR_CONSTANT:
-        case COLOR_BY_SCALAR:
-            _lut->SetRange(_dataRange);
-            break;
-        case COLOR_BY_VECTOR_MAGNITUDE:
-            _lut->SetRange(_vectorMagnitudeRange);
-            break;
-        case COLOR_BY_VECTOR_X:
-            _lut->SetRange(_vectorComponentRange[0]);
-            break;
-        case COLOR_BY_VECTOR_Y:
-            _lut->SetRange(_vectorComponentRange[1]);
-            break;
-        case COLOR_BY_VECTOR_Z:
-            _lut->SetRange(_vectorComponentRange[2]);
-            break;
-        default:
-            break;
-        }
-    } else {
-        double range[2];
-        _lut->GetTableRange(range);
-        _lut->DeepCopy(cmap->getLookupTable());
-        _lut->SetRange(range);
-        _lut->Modified();
-    }
-
-    switch (_colorMode) {
-    case COLOR_BY_VECTOR_MAGNITUDE:
-        _lut->SetVectorModeToMagnitude();
-        break;
-    case COLOR_BY_VECTOR_X:
-        _lut->SetVectorModeToComponent();
-        _lut->SetVectorComponent(0);
-        break;
-    case COLOR_BY_VECTOR_Y:
-        _lut->SetVectorModeToComponent();
-        _lut->SetVectorComponent(1);
-        break;
-    case COLOR_BY_VECTOR_Z:
-        _lut->SetVectorModeToComponent();
-        _lut->SetVectorComponent(2);
-        break;
-    default:
-         break;
-    }
-}
-
-/**
- * \brief Specify number of evenly spaced contour lines to render
- *
- * Will override any existing contours
- */
-void Contour2D::setNumContours(int numContours)
-{
-    _contours.clear();
-    _numContours = numContours;
-
-    update();
-}
-
-/**
- * \brief Specify an explicit list of contour isovalues
- *
- * Will override any existing contours
- */
-void Contour2D::setContourList(const std::vector<double>& contours)
-{
-    _contours = contours;
-    _numContours = (int)_contours.size();
-
-    update();
-}
-
-/**
- * \brief Get the number of contours
- */
-int Contour2D::getNumContours() const
-{
-    return _numContours;
-}
-
-/**
- * \brief Get the contour list (may be empty if number of contours
- * was specified in place of a list)
- */
-const std::vector<double>& Contour2D::getContourList() const
-{
-    return _contours;
-}
-
-/**
- * \brief Set a group of world coordinate planes to clip rendering
- *
- * Passing NULL for planes will remove all cliping planes
- */
-void Contour2D::setClippingPlanes(vtkPlaneCollection *planes)
-{
-    if (_dsMapper != NULL) {
-        _dsMapper->SetClippingPlanes(planes);
-    }
-}
Index: unk/packages/vizservers/vtkvis/RpContour2D.h
===================================================================
--- /trunk/packages/vizservers/vtkvis/RpContour2D.h	(revision 3615)
+++ 	(revision )
@@ -1,124 +1,0 @@
-/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
-/*
- * Copyright (C) 2004-2012  HUBzero Foundation, LLC
- *
- * Author: Leif Delgass <ldelgass@purdue.edu>
- */
-
-#ifndef VTKVIS_CONTOUR2D_H
-#define VTKVIS_CONTOUR2D_H
-
-#include <vtkSmartPointer.h>
-#include <vtkContourFilter.h>
-#include <vtkPolyDataMapper.h>
-#include <vtkActor.h>
-#include <vtkPlaneCollection.h>
-#include <vtkLookupTable.h>
-
-#include <vector>
-
-#include "ColorMap.h"
-#include "RpVtkGraphicsObject.h"
-
-namespace VtkVis {
-
-/**
- * \brief 2D Contour lines (isolines)
- */
-class Contour2D : public VtkGraphicsObject {
-public:
-    enum ColorMode {
-        COLOR_BY_SCALAR,
-        COLOR_BY_VECTOR_MAGNITUDE,
-        COLOR_BY_VECTOR_X,
-        COLOR_BY_VECTOR_Y,
-        COLOR_BY_VECTOR_Z,
-        COLOR_CONSTANT
-    };
-
-    Contour2D(int numContours);
-
-    Contour2D(const std::vector<double>& contours);
-
-    virtual ~Contour2D();
-
-    virtual const char *getClassName() const
-    {
-        return "Contour2D";
-    }
-
-    virtual void setDataSet(DataSet *dataSet,
-                            Renderer *renderer);
-
-    virtual void setClippingPlanes(vtkPlaneCollection *planes);
-
-    void setContourField(const char *name);
-
-    void setNumContours(int numContours);
-
-    void setContourList(const std::vector<double>& contours);
-
-    int getNumContours() const;
-
-    const std::vector<double>& getContourList() const;
-
-    void setColorMode(ColorMode mode, DataSet::DataAttributeType type,
-                      const char *name, double range[2] = NULL);
-
-    void setColorMode(ColorMode mode,
-                      const char *name, double range[2] = NULL);
-
-    void setColorMode(ColorMode mode);
-
-    void setColorMap(ColorMap *colorMap);
-
-    /**
-     * \brief Return the ColorMap in use
-     */
-    ColorMap *getColorMap()
-    {
-        return _colorMap;
-    }
-
-    void updateColorMap();
-
-    virtual void updateRanges(Renderer *renderer);
-
-    virtual void setColor(float color[3])
-    {
-        VtkGraphicsObject::setColor(color);
-        VtkGraphicsObject::setEdgeColor(color);
-    }
-
-    virtual void setEdgeColor(float color[3])
-    {
-        setColor(color);
-    }
-
-private:
-    Contour2D();
-
-    virtual void update();
-
-    int _numContours;
-    std::vector<double> _contours;
-
-    bool _pipelineInitialized;
-
-    ColorMap *_colorMap;
-    ColorMode _colorMode;
-    std::string _colorFieldName;
-    DataSet::DataAttributeType _colorFieldType;
-    double _colorFieldRange[2];
-    double _vectorMagnitudeRange[2];
-    double _vectorComponentRange[3][2];
-    Renderer *_renderer;
-
-    vtkSmartPointer<vtkLookupTable> _lut;
-    vtkSmartPointer<vtkContourFilter> _contourFilter;
-    vtkSmartPointer<vtkPolyDataMapper> _dsMapper;
-};
-
-}
-
-#endif
Index: unk/packages/vizservers/vtkvis/RpContour3D.cpp
===================================================================
--- /trunk/packages/vizservers/vtkvis/RpContour3D.cpp	(revision 3615)
+++ 	(revision )
@@ -1,571 +1,0 @@
-/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
-/*
- * Copyright (C) 2004-2012  HUBzero Foundation, LLC
- *
- * Author: Leif Delgass <ldelgass@purdue.edu>
- */
-
-#include <cassert>
-
-#include <vtkVersion.h>
-#include <vtkDataSet.h>
-#include <vtkPointData.h>
-#include <vtkCellData.h>
-#include <vtkCellDataToPointData.h>
-#include <vtkContourFilter.h>
-#include <vtkPolyDataMapper.h>
-#include <vtkUnstructuredGrid.h>
-#include <vtkProperty.h>
-#include <vtkDelaunay2D.h>
-#include <vtkDelaunay3D.h>
-#include <vtkDataSetSurfaceFilter.h>
-
-#include "RpContour3D.h"
-#include "RpVtkRenderer.h"
-#include "Trace.h"
-
-using namespace VtkVis;
-
-Contour3D::Contour3D(int numContours) :
-    VtkGraphicsObject(),
-    _numContours(numContours),
-    _pipelineInitialized(false),
-    _colorMap(NULL),
-    _colorMode(COLOR_BY_SCALAR),
-    _colorFieldType(DataSet::POINT_DATA),
-    _renderer(NULL)
-{
-    _colorFieldRange[0] = DBL_MAX;
-    _colorFieldRange[1] = -DBL_MAX;
-}
-
-Contour3D::Contour3D(const std::vector<double>& contours) :
-    VtkGraphicsObject(),
-    _numContours(contours.size()),
-    _contours(contours),
-    _pipelineInitialized(false),
-    _colorMap(NULL),
-    _colorMode(COLOR_BY_SCALAR),
-    _colorFieldType(DataSet::POINT_DATA),
-    _renderer(NULL)
-{
-    _colorFieldRange[0] = DBL_MAX;
-    _colorFieldRange[1] = -DBL_MAX;
-}
-
-Contour3D::~Contour3D()
-{
-#ifdef WANT_TRACE
-    if (_dataSet != NULL)
-        TRACE("Deleting Contour3D for %s", _dataSet->getName().c_str());
-    else
-        TRACE("Deleting Contour3D with NULL DataSet");
-#endif
-}
-
-void Contour3D::setDataSet(DataSet *dataSet,
-                           Renderer *renderer)
-{
-    if (_dataSet != dataSet) {
-        _dataSet = dataSet;
-        _renderer = renderer;
-
-        if (renderer->getUseCumulativeRange()) {
-            renderer->getCumulativeDataRange(_dataRange,
-                                             _dataSet->getActiveScalarsName(),
-                                             1);
-            const char *activeVectors = _dataSet->getActiveVectorsName();
-            if (activeVectors != NULL) {
-                renderer->getCumulativeDataRange(_vectorMagnitudeRange,
-                                                 _dataSet->getActiveVectorsName(),
-                                                 3);
-                for (int i = 0; i < 3; i++) {
-                    renderer->getCumulativeDataRange(_vectorComponentRange[i],
-                                                     _dataSet->getActiveVectorsName(),
-                                                     3, i);
-                }
-            }
-        } else {
-            _dataSet->getScalarRange(_dataRange);
-            _dataSet->getVectorRange(_vectorMagnitudeRange);
-            for (int i = 0; i < 3; i++) {
-                _dataSet->getVectorRange(_vectorComponentRange[i], i);
-            }
-        }
-
-        update();
-    }
-}
-
-/**
- * \brief Internal method to re-compute contours after a state change
- */
-void Contour3D::update()
-{
-    if (_dataSet == NULL) {
-        return;
-    }
-    vtkDataSet *ds = _dataSet->getVtkDataSet();
-
-    if (_dataSet->is2D()) {
-        USER_ERROR("Cannot create isosurface(s) since the data set is not 3D");
-        return;
-    }
-
-    // Contour filter to generate isosurfaces
-    if (_contourFilter == NULL) {
-        _contourFilter = vtkSmartPointer<vtkContourFilter>::New();
-    }
-
-    if (!_pipelineInitialized) {
-        vtkSmartPointer<vtkCellDataToPointData> cellToPtData;
-
-        if (ds->GetPointData() == NULL ||
-            ds->GetPointData()->GetScalars() == NULL) {
-            TRACE("No scalar point data in dataset %s", _dataSet->getName().c_str());
-            if (ds->GetCellData() != NULL &&
-                ds->GetCellData()->GetScalars() != NULL) {
-                cellToPtData = 
-                    vtkSmartPointer<vtkCellDataToPointData>::New();
-#ifdef USE_VTK6
-                cellToPtData->SetInputData(ds);
-#else
-                cellToPtData->SetInput(ds);
-#endif
-                //cellToPtData->PassCellDataOn();
-                cellToPtData->Update();
-                ds = cellToPtData->GetOutput();
-            } else {
-                USER_ERROR("No scalar field was found in the data set.");
-            }
-        }
-
-        vtkPolyData *pd = vtkPolyData::SafeDownCast(ds);
-        if (pd) {
-            // DataSet is a vtkPolyData
-            if (pd->GetNumberOfLines() == 0 &&
-                pd->GetNumberOfPolys() == 0 &&
-                pd->GetNumberOfStrips() == 0) {
-                // DataSet is a point cloud
-                // Generate a 3D unstructured grid
-                vtkSmartPointer<vtkDelaunay3D> mesher = vtkSmartPointer<vtkDelaunay3D>::New();
-#ifdef USE_VTK6
-                mesher->SetInputData(pd);
-#else
-                mesher->SetInput(pd);
-#endif
-                _contourFilter->SetInputConnection(mesher->GetOutputPort());
-            } else {
-                // DataSet is a vtkPolyData with lines and/or polygons
-                ERROR("Not a 3D DataSet");
-                return;
-            }
-        } else {
-            // DataSet is NOT a vtkPolyData
-#ifdef USE_VTK6
-            _contourFilter->SetInputData(ds);
-#else
-            _contourFilter->SetInput(ds);
-#endif
-        }
-    }
-
-    _pipelineInitialized = true;
-
-    _contourFilter->ComputeNormalsOff();
-    _contourFilter->ComputeGradientsOff();
-
-    // Speed up multiple contour computation at cost of extra memory use
-    if (_numContours > 1) {
-        _contourFilter->UseScalarTreeOn();
-    } else {
-        _contourFilter->UseScalarTreeOff();
-    }
-
-    _contourFilter->SetNumberOfContours(_numContours);
-
-    if (_contours.empty()) {
-        // Evenly spaced isovalues
-        TRACE("Setting %d contours between %g and %g", _numContours, _dataRange[0], _dataRange[1]);
-        _contourFilter->GenerateValues(_numContours, _dataRange[0], _dataRange[1]);
-    } else {
-        // User-supplied isovalues
-        for (int i = 0; i < _numContours; i++) {
-            _contourFilter->SetValue(i, _contours[i]);
-        }
-    }
-
-    initProp();
-
-    if (_normalsGenerator == NULL) {
-        _normalsGenerator = vtkSmartPointer<vtkPolyDataNormals>::New();
-        _normalsGenerator->SetInputConnection(_contourFilter->GetOutputPort());
-        _normalsGenerator->SetFeatureAngle(90.);
-        _normalsGenerator->AutoOrientNormalsOff();
-        _normalsGenerator->ComputePointNormalsOn();
-    }
-
-    if (_dsMapper == NULL) {
-        _dsMapper = vtkSmartPointer<vtkPolyDataMapper>::New();
-        _dsMapper->SetResolveCoincidentTopologyToPolygonOffset();
-        _dsMapper->SetInputConnection(_normalsGenerator->GetOutputPort());
-        _dsMapper->ScalarVisibilityOff();
-        //_dsMapper->SetColorModeToMapScalars();
-        getActor()->SetMapper(_dsMapper);
-    }
-
-    if (_lut == NULL) {
-        setColorMap(ColorMap::getDefault());
-        setColorMode(_colorMode);
-    }
-
-    _dsMapper->Update();
-    TRACE("Contour output %d polys, %d strips",
-          _contourFilter->GetOutput()->GetNumberOfPolys(),
-          _contourFilter->GetOutput()->GetNumberOfStrips());
-}
-
-void Contour3D::updateRanges(Renderer *renderer)
-{
-    if (_dataSet == NULL) {
-        ERROR("called before setDataSet");
-        return;
-    }
-
-    if (renderer->getUseCumulativeRange()) {
-        renderer->getCumulativeDataRange(_dataRange,
-                                         _dataSet->getActiveScalarsName(),
-                                         1);
-        const char *activeVectors = _dataSet->getActiveVectorsName();
-        if (activeVectors != NULL) {
-            renderer->getCumulativeDataRange(_vectorMagnitudeRange,
-                                             _dataSet->getActiveVectorsName(),
-                                             3);
-            for (int i = 0; i < 3; i++) {
-                renderer->getCumulativeDataRange(_vectorComponentRange[i],
-                                                 _dataSet->getActiveVectorsName(),
-                                                 3, i);
-            }
-        }
-    } else {
-        _dataSet->getScalarRange(_dataRange);
-        _dataSet->getVectorRange(_vectorMagnitudeRange);
-        for (int i = 0; i < 3; i++) {
-            _dataSet->getVectorRange(_vectorComponentRange[i], i);
-        }
-    }
- 
-    // Need to update color map ranges
-    double *rangePtr = _colorFieldRange;
-    if (_colorFieldRange[0] > _colorFieldRange[1]) {
-        rangePtr = NULL;
-    }
-    setColorMode(_colorMode, _colorFieldType, _colorFieldName.c_str(), rangePtr);
-
-    if (_contours.empty() && _numContours > 0) {
-        // Contour isovalues need to be recomputed
-        update();
-    }
-}
-
-void Contour3D::setContourField(const char *name)
-{
-    if (_contourFilter != NULL) {
-        _contourFilter->SetInputArrayToProcess(0, 0, 0, vtkDataObject::FIELD_ASSOCIATION_POINTS, name);
-        update();
-    }
-}
-
-void Contour3D::setColorMode(ColorMode mode)
-{
-    _colorMode = mode;
-    if (_dataSet == NULL)
-        return;
-
-    switch (mode) {
-    case COLOR_BY_SCALAR:
-        setColorMode(mode,
-                     _dataSet->getActiveScalarsType(),
-                     _dataSet->getActiveScalarsName(),
-                     _dataRange);
-        break;
-    case COLOR_BY_VECTOR_MAGNITUDE:
-        setColorMode(mode,
-                     _dataSet->getActiveVectorsType(),
-                     _dataSet->getActiveVectorsName(),
-                     _vectorMagnitudeRange);
-        break;
-    case COLOR_BY_VECTOR_X:
-        setColorMode(mode,
-                     _dataSet->getActiveVectorsType(),
-                     _dataSet->getActiveVectorsName(),
-                     _vectorComponentRange[0]);
-        break;
-    case COLOR_BY_VECTOR_Y:
-        setColorMode(mode,
-                     _dataSet->getActiveVectorsType(),
-                     _dataSet->getActiveVectorsName(),
-                     _vectorComponentRange[1]);
-        break;
-    case COLOR_BY_VECTOR_Z:
-        setColorMode(mode,
-                     _dataSet->getActiveVectorsType(),
-                     _dataSet->getActiveVectorsName(),
-                     _vectorComponentRange[2]);
-        break;
-    case COLOR_CONSTANT:
-    default:
-        setColorMode(mode, DataSet::POINT_DATA, NULL, NULL);
-        break;
-    }
-}
-
-void Contour3D::setColorMode(ColorMode mode,
-                             const char *name, double range[2])
-{
-    if (_dataSet == NULL)
-        return;
-    DataSet::DataAttributeType type = DataSet::POINT_DATA;
-    int numComponents = 1;
-    if (name != NULL && strlen(name) > 0 &&
-        !_dataSet->getFieldInfo(name, &type, &numComponents)) {
-        ERROR("Field not found: %s", name);
-        return;
-    }
-    setColorMode(mode, type, name, range);
-}
-
-void Contour3D::setColorMode(ColorMode mode, DataSet::DataAttributeType type,
-                             const char *name, double range[2])
-{
-    _colorMode = mode;
-    _colorFieldType = type;
-    if (name == NULL)
-        _colorFieldName.clear();
-    else
-        _colorFieldName = name;
-    if (range == NULL) {
-        _colorFieldRange[0] = DBL_MAX;
-        _colorFieldRange[1] = -DBL_MAX;
-    } else {
-        memcpy(_colorFieldRange, range, sizeof(double)*2);
-    }
-
-    if (_dataSet == NULL || _dsMapper == NULL)
-        return;
-
-    switch (type) {
-    case DataSet::POINT_DATA:
-        _dsMapper->SetScalarModeToUsePointFieldData();
-        break;
-    case DataSet::CELL_DATA:
-        _dsMapper->SetScalarModeToUseCellFieldData();
-        break;
-    default:
-        ERROR("Unsupported DataAttributeType: %d", type);
-        return;
-    }
-
-    if (name != NULL && strlen(name) > 0) {
-        _dsMapper->SelectColorArray(name);
-    } else {
-        _dsMapper->SetScalarModeToDefault();
-    }
-
-    if (_lut != NULL) {
-        if (range != NULL) {
-            _lut->SetRange(range);
-        } else if (name != NULL && strlen(name) > 0) {
-            double r[2];
-            int comp = -1;
-            if (mode == COLOR_BY_VECTOR_X)
-                comp = 0;
-            else if (mode == COLOR_BY_VECTOR_Y)
-                comp = 1;
-            else if (mode == COLOR_BY_VECTOR_Z)
-                comp = 2;
-
-            if (_renderer->getUseCumulativeRange()) {
-                int numComponents;
-                if  (!_dataSet->getFieldInfo(name, type, &numComponents)) {
-                    ERROR("Field not found: %s, type: %d", name, type);
-                    return;
-                } else if (numComponents < comp+1) {
-                    ERROR("Request for component %d in field with %d components",
-                          comp, numComponents);
-                    return;
-                }
-                _renderer->getCumulativeDataRange(r, name, type, numComponents, comp);
-            } else {
-                _dataSet->getDataRange(r, name, type, comp);
-            }
-            _lut->SetRange(r);
-        }
-    }
-
-    switch (mode) {
-    case COLOR_BY_SCALAR:
-        _dsMapper->ScalarVisibilityOn();
-        break;
-    case COLOR_BY_VECTOR_MAGNITUDE:
-        _dsMapper->ScalarVisibilityOn();
-        if (_lut != NULL) {
-            _lut->SetVectorModeToMagnitude();
-        }
-        break;
-    case COLOR_BY_VECTOR_X:
-        _dsMapper->ScalarVisibilityOn();
-        if (_lut != NULL) {
-            _lut->SetVectorModeToComponent();
-            _lut->SetVectorComponent(0);
-        }
-        break;
-    case COLOR_BY_VECTOR_Y:
-        _dsMapper->ScalarVisibilityOn();
-        if (_lut != NULL) {
-            _lut->SetVectorModeToComponent();
-            _lut->SetVectorComponent(1);
-        }
-        break;
-    case COLOR_BY_VECTOR_Z:
-        _dsMapper->ScalarVisibilityOn();
-        if (_lut != NULL) {
-            _lut->SetVectorModeToComponent();
-            _lut->SetVectorComponent(2);
-        }
-        break;
-    case COLOR_CONSTANT:
-    default:
-        _dsMapper->ScalarVisibilityOff();
-        break;
-    }
-}
-
-/**
- * \brief Called when the color map has been edited
- */
-void Contour3D::updateColorMap()
-{
-    setColorMap(_colorMap);
-}
-
-/**
- * \brief Associate a colormap lookup table with the DataSet
- */
-void Contour3D::setColorMap(ColorMap *cmap)
-{
-    if (cmap == NULL)
-        return;
-
-    _colorMap = cmap;
- 
-    if (_lut == NULL) {
-        _lut = vtkSmartPointer<vtkLookupTable>::New();
-        if (_dsMapper != NULL) {
-            _dsMapper->UseLookupTableScalarRangeOn();
-            _dsMapper->SetLookupTable(_lut);
-        }
-        _lut->DeepCopy(cmap->getLookupTable());
-        switch (_colorMode) {
-        case COLOR_CONSTANT:
-        case COLOR_BY_SCALAR:
-            _lut->SetRange(_dataRange);
-            break;
-        case COLOR_BY_VECTOR_MAGNITUDE:
-            _lut->SetRange(_vectorMagnitudeRange);
-            break;
-        case COLOR_BY_VECTOR_X:
-            _lut->SetRange(_vectorComponentRange[0]);
-            break;
-        case COLOR_BY_VECTOR_Y:
-            _lut->SetRange(_vectorComponentRange[1]);
-            break;
-        case COLOR_BY_VECTOR_Z:
-            _lut->SetRange(_vectorComponentRange[2]);
-            break;
-        default:
-            break;
-        }
-    } else {
-        double range[2];
-        _lut->GetTableRange(range);
-        _lut->DeepCopy(cmap->getLookupTable());
-        _lut->SetRange(range);
-        _lut->Modified();
-    }
-
-    switch (_colorMode) {
-    case COLOR_BY_VECTOR_MAGNITUDE:
-        _lut->SetVectorModeToMagnitude();
-        break;
-    case COLOR_BY_VECTOR_X:
-        _lut->SetVectorModeToComponent();
-        _lut->SetVectorComponent(0);
-        break;
-    case COLOR_BY_VECTOR_Y:
-        _lut->SetVectorModeToComponent();
-        _lut->SetVectorComponent(1);
-        break;
-    case COLOR_BY_VECTOR_Z:
-        _lut->SetVectorModeToComponent();
-        _lut->SetVectorComponent(2);
-        break;
-    default:
-         break;
-    }
-}
-
-/**
- * \brief Specify number of evenly spaced isosurfaces to render
- *
- * Will override any existing contours
- */
-void Contour3D::setNumContours(int numContours)
-{
-    _contours.clear();
-    _numContours = numContours;
-
-    update();
-}
-
-/**
- * \brief Specify an explicit list of contour isovalues
- *
- * Will override any existing contours
- */
-void Contour3D::setContourList(const std::vector<double>& contours)
-{
-    _contours = contours;
-    _numContours = (int)_contours.size();
-
-    update();
-}
-
-/**
- * \brief Get the number of contours
- */
-int Contour3D::getNumContours() const
-{
-    return _numContours;
-}
-
-/**
- * \brief Get the contour list (may be empty if number of contours
- * was specified in place of a list)
- */
-const std::vector<double>& Contour3D::getContourList() const
-{
-    return _contours;
-}
-
-/**
- * \brief Set a group of world coordinate planes to clip rendering
- *
- * Passing NULL for planes will remove all cliping planes
- */
-void Contour3D::setClippingPlanes(vtkPlaneCollection *planes)
-{
-    if (_dsMapper != NULL) {
-        _dsMapper->SetClippingPlanes(planes);
-    }
-}
Index: unk/packages/vizservers/vtkvis/RpContour3D.h
===================================================================
--- /trunk/packages/vizservers/vtkvis/RpContour3D.h	(revision 3615)
+++ 	(revision )
@@ -1,115 +1,0 @@
-/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
-/*
- * Copyright (C) 2004-2012  HUBzero Foundation, LLC
- *
- * Author: Leif Delgass <ldelgass@purdue.edu>
- */
-
-#ifndef VTKVIS_CONTOUR3D_H
-#define VTKVIS_CONTOUR3D_H
-
-#include <vtkSmartPointer.h>
-#include <vtkContourFilter.h>
-#include <vtkPolyDataNormals.h>
-#include <vtkLookupTable.h>
-#include <vtkPolyDataMapper.h>
-#include <vtkActor.h>
-#include <vtkPlaneCollection.h>
-
-#include <vector>
-
-#include "ColorMap.h"
-#include "RpVtkGraphicsObject.h"
-
-namespace VtkVis {
-
-/**
- * \brief 3D Contour isosurfaces (geometry)
- */
-class Contour3D : public VtkGraphicsObject {
-public:
-    enum ColorMode {
-        COLOR_BY_SCALAR,
-        COLOR_BY_VECTOR_MAGNITUDE,
-        COLOR_BY_VECTOR_X,
-        COLOR_BY_VECTOR_Y,
-        COLOR_BY_VECTOR_Z,
-        COLOR_CONSTANT
-    };
-
-    Contour3D(int numContours);
-
-    Contour3D(const std::vector<double>& contours);
-
-    virtual ~Contour3D();
-
-    virtual const char *getClassName() const
-    {
-        return "Contour3D";
-    }
-
-    virtual void setDataSet(DataSet *dataSet,
-                            Renderer *renderer);
-
-    virtual void setClippingPlanes(vtkPlaneCollection *planes);
-
-    void setNumContours(int numContours);
-
-    void setContourList(const std::vector<double>& contours);
-
-    int getNumContours() const;
-
-    const std::vector<double>& getContourList() const;
-
-    void setContourField(const char *name);
-
-    void setColorMode(ColorMode mode, DataSet::DataAttributeType type,
-                      const char *name, double range[2] = NULL);
-
-    void setColorMode(ColorMode mode,
-                      const char *name, double range[2] = NULL);
-
-    void setColorMode(ColorMode mode);
-
-    void setColorMap(ColorMap *colorMap);
-
-    /**
-     * \brief Return the ColorMap in use
-     */
-    ColorMap *getColorMap()
-    {
-        return _colorMap;
-    }
-
-    void updateColorMap();
-
-    virtual void updateRanges(Renderer *renderer);
-
-private:
-    Contour3D();
-
-    virtual void update();
-
-    int _numContours;
-    std::vector<double> _contours;
-
-    bool _pipelineInitialized;
-
-    ColorMap *_colorMap;
-    ColorMode _colorMode;
-    std::string _colorFieldName;
-    DataSet::DataAttributeType _colorFieldType;
-    double _colorFieldRange[2];
-    double _vectorMagnitudeRange[2];
-    double _vectorComponentRange[3][2];
-    Renderer *_renderer;
-
-    vtkSmartPointer<vtkLookupTable> _lut;
-    vtkSmartPointer<vtkContourFilter> _contourFilter;
-    vtkSmartPointer<vtkPolyDataNormals> _normalsGenerator;
-    vtkSmartPointer<vtkPolyDataMapper> _dsMapper;
-};
-
-}
-
-#endif
Index: unk/packages/vizservers/vtkvis/RpCutplane.cpp
===================================================================
--- /trunk/packages/vizservers/vtkvis/RpCutplane.cpp	(revision 3615)
+++ 	(revision )
@@ -1,880 +1,0 @@
-/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
-/*
- * Copyright (C) 2004-2012  HUBzero Foundation, LLC
- *
- * Author: Leif Delgass <ldelgass@purdue.edu>
- */
-
-#include <cassert>
-#include <cfloat>
-#include <cstring>
-
-#include <vtkDataSet.h>
-#include <vtkPointData.h>
-#include <vtkCellData.h>
-#include <vtkDataSetMapper.h>
-#include <vtkUnstructuredGrid.h>
-#include <vtkProperty.h>
-#include <vtkImageData.h>
-#include <vtkLookupTable.h>
-#include <vtkTransform.h>
-#include <vtkDelaunay2D.h>
-#include <vtkDelaunay3D.h>
-#include <vtkGaussianSplatter.h>
-#include <vtkExtractVOI.h>
-#include <vtkCutter.h>
-#include <vtkDataSetSurfaceFilter.h>
-
-#include "RpCutplane.h"
-#include "RpVtkRenderer.h"
-#include "Trace.h"
-
-#define MESH_POINT_CLOUDS
-
-using namespace VtkVis;
-
-Cutplane::Cutplane() :
-    VtkGraphicsObject(),
-    _pipelineInitialized(false),
-    _colorMap(NULL),
-    _colorMode(COLOR_BY_SCALAR),
-    _colorFieldType(DataSet::POINT_DATA),
-    _renderer(NULL)
-{
-    _colorFieldRange[0] = DBL_MAX;
-    _colorFieldRange[1] = -DBL_MAX;
-}
-
-Cutplane::~Cutplane()
-{
-#ifdef WANT_TRACE
-    if (_dataSet != NULL)
-        TRACE("Deleting Cutplane for %s", _dataSet->getName().c_str());
-    else
-        TRACE("Deleting Cutplane with NULL DataSet");
-#endif
-}
-
-void Cutplane::setDataSet(DataSet *dataSet,
-                          Renderer *renderer)
-{
-    if (_dataSet != dataSet) {
-        _dataSet = dataSet;
-
-        _renderer = renderer;
-
-        if (renderer->getUseCumulativeRange()) {
-            renderer->getCumulativeDataRange(_dataRange,
-                                             _dataSet->getActiveScalarsName(),
-                                             1);
-            renderer->getCumulativeDataRange(_vectorMagnitudeRange,
-                                             _dataSet->getActiveVectorsName(),
-                                             3);
-            for (int i = 0; i < 3; i++) {
-                renderer->getCumulativeDataRange(_vectorComponentRange[i],
-                                                 _dataSet->getActiveVectorsName(),
-                                                 3, i);
-            }
-        } else {
-            _dataSet->getScalarRange(_dataRange);
-            _dataSet->getVectorRange(_vectorMagnitudeRange);
-            for (int i = 0; i < 3; i++) {
-                _dataSet->getVectorRange(_vectorComponentRange[i], i);
-            }
-        }
-
-        update();
-    }
-}
-
-/**
- * \brief Create and initialize a VTK Prop to render the object
- */
-void Cutplane::initProp()
-{
-    if (_prop == NULL) {
-        _prop = vtkSmartPointer<vtkAssembly>::New();
-
-        for (int i = 0; i < 3; i++) {
-            _actor[i] = vtkSmartPointer<vtkActor>::New();
-            _borderActor[i] = vtkSmartPointer<vtkActor>::New();
-            //_actor[i]->VisibilityOff();
-            vtkProperty *property = _actor[i]->GetProperty();
-            property->SetColor(_color[0], _color[1], _color[2]);
-            property->SetEdgeColor(_edgeColor[0], _edgeColor[1], _edgeColor[2]);
-            property->SetLineWidth(_edgeWidth);
-            property->SetPointSize(_pointSize);
-            property->EdgeVisibilityOff();
-            property->SetOpacity(_opacity);
-            property->SetAmbient(.2);
-            if (!_lighting)
-                property->LightingOff();
-            if (_faceCulling && _opacity == 1.0) {
-                setCulling(property, true);
-            }
-            property = _borderActor[i]->GetProperty();
-            property->SetColor(_color[0], _color[1], _color[2]);
-            property->SetEdgeColor(_edgeColor[0], _edgeColor[1], _edgeColor[2]);
-            property->SetLineWidth(_edgeWidth);
-            property->SetPointSize(_pointSize);
-            property->EdgeVisibilityOff();
-            property->SetOpacity(_opacity);
-            property->SetAmbient(.2);
-            property->LightingOff();
-            
-            getAssembly()->AddPart(_borderActor[i]);
-        }
-    } else {
-        for (int i = 0; i < 3; i++) {
-            getAssembly()->RemovePart(_actor[i]);
-        }
-    }
-}
-
-/**
- * \brief Set the material color (sets ambient, diffuse, and specular)
- */
-void Cutplane::setColor(float color[3])
-{
-    for (int i = 0; i < 3; i++)
-        _color[i] = color[i];
-
-    for (int i = 0; i < 3; i++) {
-        if (_borderActor[i] != NULL) {
-            _borderActor[i]->GetProperty()->SetColor(color[0], color[1], color[2]);
-        }
-    }
-}
-
-void Cutplane::update()
-{
-    if (_dataSet == NULL)
-        return;
-
-    vtkDataSet *ds = _dataSet->getVtkDataSet();
-
-    double bounds[6];
-    _dataSet->getBounds(bounds);
-    // Mapper, actor to render color-mapped data set
-    for (int i = 0; i < 3; i++) {
-        if (_mapper[i] == NULL) {
-            _mapper[i] = vtkSmartPointer<vtkDataSetMapper>::New();
-            // Map scalars through lookup table regardless of type
-            _mapper[i]->SetColorModeToMapScalars();
-        }
-        if (_cutPlane[i] == NULL) {
-            _cutPlane[i] = vtkSmartPointer<vtkPlane>::New();
-            switch (i) {
-            case 0:
-                _cutPlane[i]->SetNormal(1, 0, 0);
-                _cutPlane[i]->SetOrigin(bounds[0] + (bounds[1]-bounds[0])/2.,
-                                        0,
-                                        0);
-                break;
-            case 1:
-                _cutPlane[i]->SetNormal(0, 1, 0);
-                _cutPlane[i]->SetOrigin(0,
-                                        bounds[2] + (bounds[3]-bounds[2])/2.,
-                                        0);
-                break;
-            case 2:
-            default:
-                _cutPlane[i]->SetNormal(0, 0, 1);
-                _cutPlane[i]->SetOrigin(0,
-                                        0,
-                                        bounds[4] + (bounds[5]-bounds[4])/2.);
-                break;
-            }
-        }
-        if (_cutter[i] == NULL) {
-            _cutter[i] = vtkSmartPointer<vtkCutter>::New();
-            _cutter[i]->SetCutFunction(_cutPlane[i]);
-        }
-    }
-
-    initProp();
-
-    if (!_pipelineInitialized) {
-        vtkPolyData *pd = vtkPolyData::SafeDownCast(ds);
-        if (pd && 
-            pd->GetNumberOfLines() == 0 &&
-            pd->GetNumberOfPolys() == 0 &&
-            pd->GetNumberOfStrips() == 0) {
-            // DataSet is a point cloud
-            PrincipalPlane plane;
-            double offset;
-            if (_dataSet->is2D(&plane, &offset)) {
-                // DataSet is a 2D point cloud
-#ifdef MESH_POINT_CLOUDS
-                vtkSmartPointer<vtkDelaunay2D> mesher = vtkSmartPointer<vtkDelaunay2D>::New();
-                if (plane == PLANE_ZY) {
-                    vtkSmartPointer<vtkTransform> trans = vtkSmartPointer<vtkTransform>::New();
-                    trans->RotateWXYZ(90, 0, 1, 0);
-                    if (offset != 0.0) {
-                        trans->Translate(-offset, 0, 0);
-                    }
-                    mesher->SetTransform(trans);
-                    _actor[1]->VisibilityOff();
-                    _actor[2]->VisibilityOff();
-                } else if (plane == PLANE_XZ) {
-                    vtkSmartPointer<vtkTransform> trans = vtkSmartPointer<vtkTransform>::New();
-                    trans->RotateWXYZ(-90, 1, 0, 0);
-                    if (offset != 0.0) {
-                        trans->Translate(0, -offset, 0);
-                    }
-                    mesher->SetTransform(trans);
-                    _actor[0]->VisibilityOff();
-                    _actor[2]->VisibilityOff();
-                } else if (offset != 0.0) {
-                    // XY with Z offset
-                    vtkSmartPointer<vtkTransform> trans = vtkSmartPointer<vtkTransform>::New();
-                    trans->Translate(0, 0, -offset);
-                    mesher->SetTransform(trans);
-                    _actor[0]->VisibilityOff();
-                    _actor[1]->VisibilityOff();
-                }
-#ifdef USE_VTK6
-                mesher->SetInputData(pd);
-#else
-                mesher->SetInput(pd);
-#endif
-                for (int i = 0; i < 3; i++) {
-                    _mapper[i]->SetInputConnection(mesher->GetOutputPort());
-                }
-#else
-                if (_splatter == NULL) {
-                    _splatter = vtkSmartPointer<vtkGaussianSplatter>::New();
-                }
-#ifdef USE_VTK6
-                _splatter->SetInputData(pd);
-#else
-                _splatter->SetInput(pd);
-#endif
-                int dims[3];
-                _splatter->GetSampleDimensions(dims);
-                TRACE("Sample dims: %d %d %d", dims[0], dims[1], dims[2]);
-                if (plane == PLANE_ZY) {
-                    dims[0] = 3;
-                } else if (plane == PLANE_XZ) {
-                    dims[1] = 3;
-                } else {
-                    dims[2] = 3;
-                }
-                _splatter->SetSampleDimensions(dims);
-                for (int i = 0; i < 3; i++) {
-                    _cutter[i]->SetInputConnection(_splatter->GetOutputPort());
-                    vtkSmartPointer<vtkDataSetSurfaceFilter> gf = vtkSmartPointer<vtkDataSetSurfaceFilter>::New();
-                    gf->UseStripsOn();
-                    gf->SetInputConnection(_cutter[i]->GetOutputPort());
-                    _mapper[i]->SetInputConnection(gf->GetOutputPort());
-                }
-#endif
-            } else {
-#ifdef MESH_POINT_CLOUDS
-                // Data Set is a 3D point cloud
-                // Result of Delaunay3D mesher is unstructured grid
-                vtkSmartPointer<vtkDelaunay3D> mesher = vtkSmartPointer<vtkDelaunay3D>::New();
-#ifdef USE_VTK6
-                mesher->SetInputData(pd);
-#else
-                mesher->SetInput(pd);
-#endif
-                // Sample a plane within the grid bounding box
-                for (int i = 0; i < 3; i++) {
-                    _cutter[i]->SetInputConnection(mesher->GetOutputPort());
-                    vtkSmartPointer<vtkDataSetSurfaceFilter> gf = vtkSmartPointer<vtkDataSetSurfaceFilter>::New();
-                    gf->UseStripsOn();
-                    gf->SetInputConnection(_cutter[i]->GetOutputPort());
-                    _mapper[i]->SetInputConnection(gf->GetOutputPort());
-                }
-#else
-                if (_splatter == NULL) {
-                    _splatter = vtkSmartPointer<vtkGaussianSplatter>::New();
-                }
-#ifdef USE_VTK6
-                _splatter->SetInputData(pd);
-#else
-                _splatter->SetInput(pd);
-#endif
-                int dims[3];
-                dims[0] = dims[1] = dims[2] = 64;
-                TRACE("Generating volume with dims (%d,%d,%d) from point cloud",
-                      dims[0], dims[1], dims[2]);
-                _splatter->SetSampleDimensions(dims);
-                for (int i = 0; i < 3; i++) {
-                    _cutter[i]->SetInputConnection(_splatter->GetOutputPort());
-                    vtkSmartPointer<vtkDataSetSurfaceFilter> gf = vtkSmartPointer<vtkDataSetSurfaceFilter>::New();
-                    gf->UseStripsOn();
-                    gf->SetInputConnection(_cutter[i]->GetOutputPort());
-                    _mapper[i]->SetInputConnection(gf->GetOutputPort());
-                }
-#endif
-            }
-        } else {
-            // DataSet can be: image/volume/uniform grid, structured grid, unstructured grid, rectilinear grid, or
-            // PolyData with cells other than points
-            PrincipalPlane plane;
-            double offset;
-            if (!_dataSet->is2D(&plane, &offset)) {
-                // Sample a plane within the grid bounding box
-                for (int i = 0; i < 3; i++) {
-#ifdef USE_VTK6
-                    _cutter[i]->SetInputData(ds);
-#else
-                    _cutter[i]->SetInput(ds);
-#endif
-                    vtkSmartPointer<vtkDataSetSurfaceFilter> gf = vtkSmartPointer<vtkDataSetSurfaceFilter>::New();
-                    gf->UseStripsOn();
-                    gf->SetInputConnection(_cutter[i]->GetOutputPort());
-                    _mapper[i]->SetInputConnection(gf->GetOutputPort());
-                }
-            } else {
-                // 2D data
-                if (plane == PLANE_ZY) {
-                    _actor[1]->VisibilityOff();
-                    _actor[2]->VisibilityOff();
-                } else if (plane == PLANE_XZ) {
-                    _actor[0]->VisibilityOff();
-                    _actor[2]->VisibilityOff();
-                } else if (offset != 0.0) {
-                    // XY with Z offset
-                    _actor[0]->VisibilityOff();
-                    _actor[1]->VisibilityOff();
-                }
-                for (int i = 0; i < 3; i++) {
-                    vtkSmartPointer<vtkDataSetSurfaceFilter> gf = vtkSmartPointer<vtkDataSetSurfaceFilter>::New();
-                    gf->UseStripsOn();
-#ifdef USE_VTK6
-                    gf->SetInputData(ds);
-#else
-                    gf->SetInput(ds);
-#endif
-                    _mapper[i]->SetInputConnection(gf->GetOutputPort());
-                }
-            }
-        }
-    }
-
-    _pipelineInitialized = true;
-
-    for (int i = 0; i < 3; i++) {
-        if (_mapper[i] != NULL && _borderMapper[i] == NULL) {
-            _borderMapper[i] = vtkSmartPointer<vtkPolyDataMapper>::New();
-#ifdef CUTPLANE_TIGHT_OUTLINE
-            _outlineFilter[i] = vtkSmartPointer<vtkOutlineFilter>::New();
-            _outlineFilter[i]->SetInputConnection(_mapper[i]->GetInputConnection(0, 0));
-            _borderMapper[i]->SetInputConnection(_outlineFilter[i]->GetOutputPort());
-#else
-            _outlineSource[i] = vtkSmartPointer<vtkOutlineSource>::New();
-            switch (i) {
-            case 0:
-                _outlineSource[i]->SetBounds(bounds[0] + (bounds[1]-bounds[0])/2.,
-                                             bounds[0] + (bounds[1]-bounds[0])/2.,
-                                             bounds[2], bounds[3],
-                                             bounds[4], bounds[5]);
-                break;
-            case 1:
-                _outlineSource[i]->SetBounds(bounds[0], bounds[1],
-                                             bounds[2] + (bounds[3]-bounds[2])/2.,
-                                             bounds[2] + (bounds[3]-bounds[2])/2.,
-                                             bounds[4], bounds[5]);
-                break;
-            case 2:
-                _outlineSource[i]->SetBounds(bounds[0], bounds[1],
-                                             bounds[2], bounds[3],
-                                             bounds[4] + (bounds[5]-bounds[4])/2.,
-                                             bounds[4] + (bounds[5]-bounds[4])/2.);
-                break;
-            default:
-                ;
-            }
-            _borderMapper[i]->SetInputConnection(_outlineSource[i]->GetOutputPort());
-#endif
-            _borderMapper[i]->SetResolveCoincidentTopologyToPolygonOffset();
-        }
-    }
-
-    setInterpolateBeforeMapping(true);
-
-    if (_lut == NULL) {
-        setColorMap(ColorMap::getDefault());
-        setColorMode(_colorMode);
-    }
-
-    for (int i = 0; i < 3; i++) {
-        if (_mapper[i] != NULL) {
-            _actor[i]->SetMapper(_mapper[i]);
-            _mapper[i]->Update();
-        }
-        if (_borderMapper[i] != NULL) {
-            _borderActor[i]->SetMapper(_borderMapper[i]);
-            _borderMapper[i]->Update();
-        }
-        // Only add cutter actor to assembly if geometry was
-        // produced, in order to prevent messing up assembly bounds
-        double bounds[6];
-        _actor[i]->GetBounds(bounds);
-        if (bounds[0] <= bounds[1]) {
-            getAssembly()->AddPart(_actor[i]);
-        }
-    }
-}
-
-void Cutplane::setInterpolateBeforeMapping(bool state)
-{
-    for (int i = 0; i < 3; i++) {
-        if (_mapper[i] != NULL) {
-            _mapper[i]->SetInterpolateScalarsBeforeMapping((state ? 1 : 0));
-        }
-    }
-}
-
-/**
- * \brief Select a 2D slice plane from a 3D DataSet
- *
- * \param[in] axis Axis of slice plane
- * \param[in] ratio Position [0,1] of slice plane along axis
- */
-void Cutplane::selectVolumeSlice(Axis axis, double ratio)
-{
-    if (_dataSet->is2D()) {
-        WARN("DataSet not 3D, returning");
-        return;
-    }
-
-    if ((axis == X_AXIS &&_cutPlane[0] == NULL) ||
-        (axis == Y_AXIS &&_cutPlane[1] == NULL) ||
-        (axis == Z_AXIS &&_cutPlane[2] == NULL)) {
-        WARN("Called before update() or DataSet is not a volume");
-        return;
-    }
-
-    double bounds[6];
-    _dataSet->getBounds(bounds);
-#if 0
-    if (ratio == 0.0)
-        ratio = 0.001;
-    if (ratio == 1.0)
-        ratio = 0.999;
-#endif
-    switch (axis) {
-    case X_AXIS:
-        _cutPlane[0]->SetOrigin(bounds[0] + (bounds[1]-bounds[0]) * ratio,
-                                0,
-                                0);
-#ifndef CUTPLANE_TIGHT_OUTLINE
-        _outlineSource[0]->SetBounds(bounds[0] + (bounds[1]-bounds[0]) * ratio,
-                                     bounds[0] + (bounds[1]-bounds[0]) * ratio,
-                                     bounds[2], bounds[3],
-                                     bounds[4], bounds[5]);
-#endif
-        break;
-    case Y_AXIS:
-        _cutPlane[1]->SetOrigin(0,
-                                bounds[2] + (bounds[3]-bounds[2]) * ratio,
-                                0);
-#ifndef CUTPLANE_TIGHT_OUTLINE
-        _outlineSource[1]->SetBounds(bounds[0], bounds[1],
-                                     bounds[2] + (bounds[3]-bounds[2]) * ratio,
-                                     bounds[2] + (bounds[3]-bounds[2]) * ratio,
-                                     bounds[4], bounds[5]);
-#endif
-        break;
-    case Z_AXIS:
-        _cutPlane[2]->SetOrigin(0,
-                                0,
-                                bounds[4] + (bounds[5]-bounds[4]) * ratio);
-#ifndef CUTPLANE_TIGHT_OUTLINE
-        _outlineSource[2]->SetBounds(bounds[0], bounds[1],
-                                     bounds[2], bounds[3],
-                                     bounds[4] + (bounds[5]-bounds[4]) * ratio,
-                                     bounds[4] + (bounds[5]-bounds[4]) * ratio);
-#endif
-        break;
-    default:
-        ERROR("Invalid Axis");
-        return;
-    }
-    update();
-}
-
-void Cutplane::updateRanges(Renderer *renderer)
-{
-    if (_dataSet == NULL) {
-        ERROR("called before setDataSet");
-        return;
-    }
-
-    if (renderer->getUseCumulativeRange()) {
-        renderer->getCumulativeDataRange(_dataRange,
-                                         _dataSet->getActiveScalarsName(),
-                                         1);
-        renderer->getCumulativeDataRange(_vectorMagnitudeRange,
-                                         _dataSet->getActiveVectorsName(),
-                                         3);
-        for (int i = 0; i < 3; i++) {
-            renderer->getCumulativeDataRange(_vectorComponentRange[i],
-                                             _dataSet->getActiveVectorsName(),
-                                             3, i);
-        }
-    } else {
-        _dataSet->getScalarRange(_dataRange);
-        _dataSet->getVectorRange(_vectorMagnitudeRange);
-        for (int i = 0; i < 3; i++) {
-            _dataSet->getVectorRange(_vectorComponentRange[i], i);
-        }
-    }
-
-    // Need to update color map ranges
-    double *rangePtr = _colorFieldRange;
-    if (_colorFieldRange[0] > _colorFieldRange[1]) {
-        rangePtr = NULL;
-    }
-    setColorMode(_colorMode, _colorFieldType, _colorFieldName.c_str(), rangePtr);
-}
-
-void Cutplane::setColorMode(ColorMode mode)
-{
-    _colorMode = mode;
-    if (_dataSet == NULL)
-        return;
-
-    switch (mode) {
-    case COLOR_BY_SCALAR:
-        setColorMode(mode,
-                     _dataSet->getActiveScalarsType(),
-                     _dataSet->getActiveScalarsName(),
-                     _dataRange);
-        break;
-    case COLOR_BY_VECTOR_MAGNITUDE:
-        setColorMode(mode,
-                     _dataSet->getActiveVectorsType(),
-                     _dataSet->getActiveVectorsName(),
-                     _vectorMagnitudeRange);
-        break;
-    case COLOR_BY_VECTOR_X:
-        setColorMode(mode,
-                     _dataSet->getActiveVectorsType(),
-                     _dataSet->getActiveVectorsName(),
-                     _vectorComponentRange[0]);
-        break;
-    case COLOR_BY_VECTOR_Y:
-        setColorMode(mode,
-                     _dataSet->getActiveVectorsType(),
-                     _dataSet->getActiveVectorsName(),
-                     _vectorComponentRange[1]);
-        break;
-    case COLOR_BY_VECTOR_Z:
-        setColorMode(mode,
-                     _dataSet->getActiveVectorsType(),
-                     _dataSet->getActiveVectorsName(),
-                     _vectorComponentRange[2]);
-        break;
-    default:
-        ;
-    }
-}
-
-void Cutplane::setColorMode(ColorMode mode,
-                            const char *name, double range[2])
-{
-    if (_dataSet == NULL)
-        return;
-    DataSet::DataAttributeType type;
-    int numComponents;
-    if (!_dataSet->getFieldInfo(name, &type, &numComponents)) {
-        ERROR("Field not found: %s", name);
-        return;
-    }
-    setColorMode(mode, type, name, range);
-}
-
-void Cutplane::setColorMode(ColorMode mode,
-                            DataSet::DataAttributeType type,
-                            const char *name, double range[2])
-{
-    _colorMode = mode;
-    _colorFieldType = type;
-    if (name == NULL)
-        _colorFieldName.clear();
-    else
-        _colorFieldName = name;
-    if (range == NULL) {
-        _colorFieldRange[0] = DBL_MAX;
-        _colorFieldRange[1] = -DBL_MAX;
-    } else {
-        memcpy(_colorFieldRange, range, sizeof(double)*2);
-    }
-
-    if (_dataSet == NULL ||
-        _mapper[0] == NULL ||
-        _mapper[1] == NULL ||
-        _mapper[2] == NULL)
-        return;
-
-    switch (type) {
-    case DataSet::POINT_DATA:
-        for (int i = 0; i < 3; i++) {
-            _mapper[i]->SetScalarModeToUsePointFieldData();
-        }
-        break;
-    case DataSet::CELL_DATA:
-        for (int i = 0; i < 3; i++) {
-            _mapper[i]->SetScalarModeToUseCellFieldData();
-        }
-        break;
-    default:
-        ERROR("Unsupported DataAttributeType: %d", type);
-        return;
-    }
-
-    if (_splatter != NULL) {
-        for (int i = 0; i < 3; i++) {
-            _mapper[i]->SelectColorArray("SplatterValues");
-        }
-    } else if (name != NULL && strlen(name) > 0) {
-        for (int i = 0; i < 3; i++) {
-            _mapper[i]->SelectColorArray(name);
-        }
-    } else {
-        for (int i = 0; i < 3; i++) {
-            _mapper[i]->SetScalarModeToDefault();
-        }
-    }
-
-    if (_lut != NULL) {
-        if (range != NULL) {
-            _lut->SetRange(range);
-        } else if (name != NULL && strlen(name) > 0) {
-            double r[2];
-            int comp = -1;
-            if (mode == COLOR_BY_VECTOR_X)
-                comp = 0;
-            else if (mode == COLOR_BY_VECTOR_Y)
-                comp = 1;
-            else if (mode == COLOR_BY_VECTOR_Z)
-                comp = 2;
-
-            if (_renderer->getUseCumulativeRange()) {
-                int numComponents;
-                if  (!_dataSet->getFieldInfo(name, type, &numComponents)) {
-                    ERROR("Field not found: %s, type: %d", name, type);
-                    return;
-                } else if (numComponents < comp+1) {
-                    ERROR("Request for component %d in field with %d components",
-                          comp, numComponents);
-                    return;
-                }
-                _renderer->getCumulativeDataRange(r, name, type, numComponents, comp);
-            } else {
-                _dataSet->getDataRange(r, name, type, comp);
-            }
-            _lut->SetRange(r);
-        }
-    }
-
-
-    switch (mode) {
-    case COLOR_BY_SCALAR:
-        for (int i = 0; i < 3; i++) {
-            _mapper[i]->ScalarVisibilityOn();
-        }
-        break;
-    case COLOR_BY_VECTOR_MAGNITUDE:
-        for (int i = 0; i < 3; i++) {
-            _mapper[i]->ScalarVisibilityOn();
-        }
-        if (_lut != NULL) {
-            _lut->SetVectorModeToMagnitude();
-        }
-        break;
-    case COLOR_BY_VECTOR_X:
-        for (int i = 0; i < 3; i++) {
-            _mapper[i]->ScalarVisibilityOn();
-        }
-        if (_lut != NULL) {
-            _lut->SetVectorModeToComponent();
-            _lut->SetVectorComponent(0);
-        }
-        break;
-    case COLOR_BY_VECTOR_Y:
-        for (int i = 0; i < 3; i++) {
-            _mapper[i]->ScalarVisibilityOn();
-        }
-        if (_lut != NULL) {
-            _lut->SetVectorModeToComponent();
-            _lut->SetVectorComponent(1);
-        }
-        break;
-    case COLOR_BY_VECTOR_Z:
-        for (int i = 0; i < 3; i++) {
-            _mapper[i]->ScalarVisibilityOn();
-        }
-        if (_lut != NULL) {
-            _lut->SetVectorModeToComponent();
-            _lut->SetVectorComponent(2);
-        }
-        break;
-    default:
-        for (int i = 0; i < 3; i++) {
-            _mapper[i]->ScalarVisibilityOff();
-        }
-        break;
-    }
-}
-
-/**
- * \brief Called when the color map has been edited
- */
-void Cutplane::updateColorMap()
-{
-    setColorMap(_colorMap);
-}
-
-/**
- * \brief Associate a colormap lookup table with the DataSet
- */
-void Cutplane::setColorMap(ColorMap *cmap)
-{
-    if (cmap == NULL)
-        return;
-
-    _colorMap = cmap;
- 
-    if (_lut == NULL) {
-        _lut = vtkSmartPointer<vtkLookupTable>::New();
-        for (int i = 0; i < 3; i++) {
-            if (_mapper[i] != NULL) {
-                _mapper[i]->UseLookupTableScalarRangeOn();
-                _mapper[i]->SetLookupTable(_lut);
-            }
-        }
-        _lut->DeepCopy(cmap->getLookupTable());
-        switch (_colorMode) {
-        case COLOR_BY_SCALAR:
-            _lut->SetRange(_dataRange);
-            break;
-        case COLOR_BY_VECTOR_MAGNITUDE:
-            _lut->SetRange(_vectorMagnitudeRange);
-            break;
-        case COLOR_BY_VECTOR_X:
-            _lut->SetRange(_vectorComponentRange[0]);
-            break;
-        case COLOR_BY_VECTOR_Y:
-            _lut->SetRange(_vectorComponentRange[1]);
-            break;
-        case COLOR_BY_VECTOR_Z:
-            _lut->SetRange(_vectorComponentRange[2]);
-            break;
-        default:
-            break;
-        }
-    } else {
-        double range[2];
-        _lut->GetTableRange(range);
-        _lut->DeepCopy(cmap->getLookupTable());
-        _lut->SetRange(range);
-        _lut->Modified();
-    }
-
-    switch (_colorMode) {
-    case COLOR_BY_VECTOR_MAGNITUDE:
-        _lut->SetVectorModeToMagnitude();
-        break;
-    case COLOR_BY_VECTOR_X:
-        _lut->SetVectorModeToComponent();
-        _lut->SetVectorComponent(0);
-        break;
-    case COLOR_BY_VECTOR_Y:
-        _lut->SetVectorModeToComponent();
-        _lut->SetVectorComponent(1);
-        break;
-    case COLOR_BY_VECTOR_Z:
-        _lut->SetVectorModeToComponent();
-        _lut->SetVectorComponent(2);
-        break;
-    default:
-         break;
-    }
-}
-
-/**
- * \brief Turn on/off lighting of this object
- */
-void Cutplane::setLighting(bool state)
-{
-    _lighting = state;
-    for (int i = 0; i < 3; i++) {
-        if (_actor[i] != NULL)
-            _actor[i]->GetProperty()->SetLighting((state ? 1 : 0));
-    }
-}
-
-/**
- * \brief Turn on/off rendering of mesh edges
- */
-void Cutplane::setEdgeVisibility(bool state)
-{
-    for (int i = 0; i < 3; i++) {
-        if (_actor[i] != NULL) {
-            _actor[i]->GetProperty()->SetEdgeVisibility((state ? 1 : 0));
-        }
-    }
-}
-
-/**
- * \brief Turn on/off rendering of outlines
- */
-void Cutplane::setOutlineVisibility(bool state)
-{
-    for (int i = 0; i < 3; i++) {
-        if (_borderActor[i] != NULL) {
-            _borderActor[i]->SetVisibility((state ? 1 : 0));
-        }
-    }
-}
-
-/**
- * \brief Set visibility of cutplane on specified axis
- */
-void Cutplane::setSliceVisibility(Axis axis, bool state)
-{
-    switch (axis) {
-    case X_AXIS:
-        if (_actor[0] != NULL)
-            _actor[0]->SetVisibility((state ? 1 : 0));
-        if (_borderActor[0] != NULL)
-            _borderActor[0]->SetVisibility((state ? 1 : 0));
-        break;
-    case Y_AXIS:
-        if (_actor[1] != NULL)
-            _actor[1]->SetVisibility((state ? 1 : 0));
-        if (_borderActor[1] != NULL)
-            _borderActor[1]->SetVisibility((state ? 1 : 0));
-        break;
-    case Z_AXIS:
-    default:
-        if (_actor[2] != NULL)
-            _actor[2]->SetVisibility((state ? 1 : 0));
-        if (_borderActor[2] != NULL)
-            _borderActor[2]->SetVisibility((state ? 1 : 0));
-        break;
-    }
-}
-
-/**
- * \brief Set a group of world coordinate planes to clip rendering
- *
- * Passing NULL for planes will remove all cliping planes
- */
-void Cutplane::setClippingPlanes(vtkPlaneCollection *planes)
-{
-    for (int i = 0; i < 3; i++) {
-        if (_mapper[i] != NULL) {
-            _mapper[i]->SetClippingPlanes(planes);
-        }
-        if (_borderMapper[i] != NULL) {
-            _borderMapper[i]->SetClippingPlanes(planes);
-        }
-    }
-}
Index: unk/packages/vizservers/vtkvis/RpCutplane.h
===================================================================
--- /trunk/packages/vizservers/vtkvis/RpCutplane.h	(revision 3615)
+++ 	(revision )
@@ -1,126 +1,0 @@
-/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
-/*
- * Copyright (C) 2004-2012  HUBzero Foundation, LLC
- *
- * Author: Leif Delgass <ldelgass@purdue.edu>
- */
-
-#ifndef VTKVIS_CUTPLANE_H
-#define VTKVIS_CUTPLANE_H
-
-#include <vtkSmartPointer.h>
-#include <vtkLookupTable.h>
-#include <vtkDataSetMapper.h>
-#include <vtkActor.h>
-#include <vtkPlaneCollection.h>
-#include <vtkCutter.h>
-#include <vtkPlane.h>
-#include <vtkOutlineFilter.h>
-#include <vtkOutlineSource.h>
-#include <vtkGaussianSplatter.h>
-
-#include "ColorMap.h"
-#include "RpTypes.h"
-#include "RpVtkGraphicsObject.h"
-
-namespace VtkVis {
-
-//#define CUTPLANE_TIGHT_OUTLINE
-
-/**
- * \brief Color-mapped plot of slice through a data set
- * 
- * Currently the DataSet must be image data (2D uniform grid)
- */
-class Cutplane : public VtkGraphicsObject {
-public:
-    enum ColorMode {
-        COLOR_BY_SCALAR,
-        COLOR_BY_VECTOR_MAGNITUDE,
-        COLOR_BY_VECTOR_X,
-        COLOR_BY_VECTOR_Y,
-        COLOR_BY_VECTOR_Z
-    };
-
-    Cutplane();
-    virtual ~Cutplane();
-
-    virtual const char *getClassName() const
-    {
-        return "Cutplane";
-    }
-
-    virtual void setDataSet(DataSet *dataSet,
-                            Renderer *renderer);
-
-    virtual void setColor(float color[3]);
-
-    virtual void setLighting(bool state);
-
-    virtual void setEdgeVisibility(bool state);
-
-    virtual void setClippingPlanes(vtkPlaneCollection *planes);
-
-    void setOutlineVisibility(bool state);
-
-    void selectVolumeSlice(Axis axis, double ratio);
-
-    void setSliceVisibility(Axis axis, bool state);
-
-    void setInterpolateBeforeMapping(bool state);
-
-    void setColorMode(ColorMode mode, DataSet::DataAttributeType type,
-                      const char *name, double range[2] = NULL);
-
-    void setColorMode(ColorMode mode,
-                      const char *name, double range[2] = NULL);
-
-    void setColorMode(ColorMode mode);
-
-    void setColorMap(ColorMap *colorMap);
-
-    /**
-     * \brief Return the ColorMap in use
-     */
-    ColorMap *getColorMap()
-    {
-        return _colorMap;
-    }
-
-    void updateColorMap();
-
-    virtual void updateRanges(Renderer *renderer);
-
-private:
-    virtual void initProp();
-    virtual void update();
-
-    bool _pipelineInitialized;
-
-    ColorMap *_colorMap;
-    ColorMode _colorMode;
-    std::string _colorFieldName;
-    DataSet::DataAttributeType _colorFieldType;
-    double _colorFieldRange[2];
-    double _vectorMagnitudeRange[2];
-    double _vectorComponentRange[3][2];
-    Renderer *_renderer;
-
-    vtkSmartPointer<vtkLookupTable> _lut;
-    vtkSmartPointer<vtkActor> _actor[3];
-    vtkSmartPointer<vtkActor> _borderActor[3];
-    vtkSmartPointer<vtkDataSetMapper> _mapper[3];
-    vtkSmartPointer<vtkPolyDataMapper> _borderMapper[3];
-    vtkSmartPointer<vtkCutter> _cutter[3];
-    vtkSmartPointer<vtkPlane> _cutPlane[3];
-#ifdef CUTPLANE_TIGHT_OUTLINE
-    vtkSmartPointer<vtkOutlineFilter> _outlineFilter[3];
-#else
-    vtkSmartPointer<vtkOutlineSource> _outlineSource[3];
-#endif
-    vtkSmartPointer<vtkGaussianSplatter> _splatter;
-};
-
-}
-
-#endif
Index: unk/packages/vizservers/vtkvis/RpCylinder.cpp
===================================================================
--- /trunk/packages/vizservers/vtkvis/RpCylinder.cpp	(revision 3615)
+++ 	(revision )
@@ -1,45 +1,0 @@
-/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
-/*
- * Copyright (C) 2004-2012  HUBzero Foundation, LLC
- *
- * Author: Leif Delgass <ldelgass@purdue.edu>
- */
-
-#include <vtkPolyDataMapper.h>
-#include <vtkActor.h>
-#include <vtkCylinderSource.h>
-
-#include "RpCylinder.h"
-#include "Trace.h"
-
-using namespace VtkVis;
-
-Cylinder::Cylinder() :
-    Shape()
-{
-}
-
-Cylinder::~Cylinder()
-{
-    TRACE("Deleting Cylinder");
-}
-
-void Cylinder::update()
-{
-    if (_cylinder == NULL) {
-	_cylinder = vtkSmartPointer<vtkCylinderSource>::New();
-    }
-
-    if (_pdMapper == NULL) {
-        _pdMapper = vtkSmartPointer<vtkPolyDataMapper>::New();
-        _pdMapper->SetResolveCoincidentTopologyToPolygonOffset();
-        _pdMapper->ScalarVisibilityOff();
-    }
-
-    _pdMapper->SetInputConnection(_cylinder->GetOutputPort());
-
-    initProp();
-
-    getActor()->SetMapper(_pdMapper);
-    _pdMapper->Update();
-}
Index: unk/packages/vizservers/vtkvis/RpCylinder.h
===================================================================
--- /trunk/packages/vizservers/vtkvis/RpCylinder.h	(revision 3615)
+++ 	(revision )
@@ -1,80 +1,0 @@
-/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
-/*
- * Copyright (C) 2004-2012  HUBzero Foundation, LLC
- *
- * Author: Leif Delgass <ldelgass@purdue.edu>
- */
-
-#ifndef VTKVIS_CYLINDER_H
-#define VTKVIS_CYLINDER_H
-
-#include <vtkSmartPointer.h>
-#include <vtkPolyDataMapper.h>
-#include <vtkActor.h>
-#include <vtkCylinderSource.h>
-
-#include "RpShape.h"
-#include "RpVtkDataSet.h"
-
-namespace VtkVis {
-
-/**
- * \brief VTK PolyData cylinder
- *
- * This class creates a mesh cylinder
- */
-class Cylinder : public Shape
-{
-public:
-    Cylinder();
-    virtual ~Cylinder();
-
-    virtual const char *getClassName() const
-    {
-        return "Cylinder";
-    }
-
-    void setCenter(double center[3])
-    {
-        if (_cylinder != NULL) {
-            _cylinder->SetCenter(center);
-	}
-    }
-
-    void setHeight(double height)
-    {
-        if (_cylinder != NULL) {
-            _cylinder->SetHeight(height);
-	}
-    }
-
-    void setRadius(double radius)
-    {
-        if (_cylinder != NULL) {
-            _cylinder->SetRadius(radius);
-	}
-    }
-
-    void setResolution(int res)
-    {
-        if (_cylinder != NULL) {
-            _cylinder->SetResolution(res);
-	}
-    }
-
-    void setCapping(bool state)
-    {
-        if (_cylinder != NULL) {
-            _cylinder->SetCapping(state ? 1 : 0);
-	}
-    }
-
-private:
-    virtual void update();
-
-    vtkSmartPointer<vtkCylinderSource> _cylinder;
-};
-
-}
-
-#endif
Index: unk/packages/vizservers/vtkvis/RpDisk.cpp
===================================================================
--- /trunk/packages/vizservers/vtkvis/RpDisk.cpp	(revision 3615)
+++ 	(revision )
@@ -1,45 +1,0 @@
-/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
-/*
- * Copyright (C) 2004-2012  HUBzero Foundation, LLC
- *
- * Author: Leif Delgass <ldelgass@purdue.edu>
- */
-
-#include <vtkPolyDataMapper.h>
-#include <vtkActor.h>
-#include <vtkDiskSource.h>
-
-#include "RpDisk.h"
-#include "Trace.h"
-
-using namespace VtkVis;
-
-Disk::Disk() :
-    Shape()
-{
-}
-
-Disk::~Disk()
-{
-    TRACE("Deleting Disk");
-}
-
-void Disk::update()
-{
-    if (_disk == NULL) {
-	_disk = vtkSmartPointer<vtkDiskSource>::New();
-    }
-
-    if (_pdMapper == NULL) {
-        _pdMapper = vtkSmartPointer<vtkPolyDataMapper>::New();
-        _pdMapper->SetResolveCoincidentTopologyToPolygonOffset();
-        _pdMapper->ScalarVisibilityOff();
-    }
-
-    _pdMapper->SetInputConnection(_disk->GetOutputPort());
-
-    initProp();
-
-    getActor()->SetMapper(_pdMapper);
-    _pdMapper->Update();
-}
Index: unk/packages/vizservers/vtkvis/RpDisk.h
===================================================================
--- /trunk/packages/vizservers/vtkvis/RpDisk.h	(revision 3615)
+++ 	(revision )
@@ -1,61 +1,0 @@
-/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
-/*
- * Copyright (C) 2004-2012  HUBzero Foundation, LLC
- *
- * Author: Leif Delgass <ldelgass@purdue.edu>
- */
-
-#ifndef VTKVIS_DISK_H
-#define VTKVIS_DISK_H
-
-#include <vtkSmartPointer.h>
-#include <vtkPolyDataMapper.h>
-#include <vtkActor.h>
-#include <vtkDiskSource.h>
-
-#include "RpShape.h"
-#include "RpVtkDataSet.h"
-
-namespace VtkVis {
-
-/**
- * \brief VTK PolyData disk
- *
- * This class creates a mesh disk
- */
-class Disk : public Shape
-{
-public:
-    Disk();
-    virtual ~Disk();
-
-    virtual const char *getClassName() const
-    {
-        return "Disk";
-    }
-
-    void setRadii(double inner, double outer)
-    {
-        if (_disk != NULL) {
-            _disk->SetInnerRadius(inner);
-	    _disk->SetOuterRadius(outer);
-	}
-    }
-
-    void setResolution(int radialRes, int circumRes)
-    {
-        if (_disk != NULL) {
-            _disk->SetRadialResolution(radialRes);
-	    _disk->SetCircumferentialResolution(circumRes);
-	}
-    }
-
-private:
-    virtual void update();
-
-    vtkSmartPointer<vtkDiskSource> _disk;
-};
-
-}
-
-#endif
Index: unk/packages/vizservers/vtkvis/RpGlyphs.cpp
===================================================================
--- /trunk/packages/vizservers/vtkvis/RpGlyphs.cpp	(revision 3615)
+++ 	(revision )
@@ -1,750 +1,0 @@
-/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
-/*
- * Copyright (C) 2004-2012  HUBzero Foundation, LLC
- *
- * Author: Leif Delgass <ldelgass@purdue.edu>
- */
-
-#include <cstring>
-#include <cfloat>
-
-#include <vtkDataSet.h>
-#include <vtkPointData.h>
-#include <vtkCellData.h>
-#include <vtkCellDataToPointData.h>
-#include <vtkProp.h>
-#include <vtkActor.h>
-#include <vtkProperty.h>
-#include <vtkGlyph3D.h>
-#include <vtkLineSource.h>
-#include <vtkArrowSource.h>
-#include <vtkConeSource.h>
-#include <vtkCylinderSource.h>
-#include <vtkPlatonicSolidSource.h>
-#include <vtkSphereSource.h>
-#include <vtkTransform.h>
-#include <vtkPolyDataMapper.h>
-#include <vtkTransformPolyDataFilter.h>
-
-#include "RpGlyphs.h"
-#include "RpVtkRenderer.h"
-#include "Trace.h"
-
-using namespace VtkVis;
-
-Glyphs::Glyphs(GlyphShape shape) :
-    VtkGraphicsObject(),
-    _glyphShape(shape),
-    _scalingMode(SCALE_BY_VECTOR_MAGNITUDE),
-    _dataScale(1.0),
-    _scaleFactor(1.0),
-    _normalizeScale(true),
-    _colorMap(NULL),
-    _colorMode(COLOR_BY_SCALAR)
-{
-    _faceCulling = true;
-    _scalingFieldRange[0] = DBL_MAX;
-    _scalingFieldRange[1] = -DBL_MAX;
-    _colorFieldRange[0] = DBL_MAX;
-    _colorFieldRange[1] = -DBL_MAX;
-}
-
-Glyphs::~Glyphs()
-{
-#ifdef WANT_TRACE
-    if (_dataSet != NULL)
-        TRACE("Deleting Glyphs for %s", _dataSet->getName().c_str());
-    else
-        TRACE("Deleting Glyphs with NULL DataSet");
-#endif
-}
-
-void Glyphs::setDataSet(DataSet *dataSet,
-                        Renderer *renderer)
-{
-    if (_dataSet != dataSet) {
-        _dataSet = dataSet;
-
-        _renderer = renderer;
-
-        if (renderer->getUseCumulativeRange()) {
-            renderer->getCumulativeDataRange(_dataRange,
-                                             _dataSet->getActiveScalarsName(),
-                                             1);
-            renderer->getCumulativeDataRange(_vectorMagnitudeRange,
-                                             _dataSet->getActiveVectorsName(),
-                                             3);
-            for (int i = 0; i < 3; i++) {
-                renderer->getCumulativeDataRange(_vectorComponentRange[i],
-                                                 _dataSet->getActiveVectorsName(),
-                                                 3, i);
-            }
-        } else {
-            _dataSet->getScalarRange(_dataRange);
-            _dataSet->getVectorRange(_vectorMagnitudeRange);
-            for (int i = 0; i < 3; i++) {
-                _dataSet->getVectorRange(_vectorComponentRange[i], i);
-            }
-        }
-
-        update();
-    }
-}
-
-/**
- * \brief Set the shape of the glyphs
- */
-void Glyphs::setGlyphShape(GlyphShape shape)
-{
-    _glyphShape = shape;
-
-    // Note: using vtkTransformPolyDataFilter instead of the vtkGlyph3D's 
-    // SourceTransform because of a bug: vtkGlyph3D doesn't transform normals
-    // by the SourceTransform, so the lighting would be wrong
-
-    switch (_glyphShape) {
-    case LINE:
-        _glyphSource = vtkSmartPointer<vtkLineSource>::New();
-        break;
-    case ARROW: {
-        _glyphSource = vtkSmartPointer<vtkArrowSource>::New();
-        vtkSmartPointer<vtkArrowSource> arrow = vtkArrowSource::SafeDownCast(_glyphSource);
-        arrow->SetTipResolution(8);
-        arrow->SetShaftResolution(8);
-    }
-        break;
-    case CONE: {
-        _glyphSource = vtkSmartPointer<vtkConeSource>::New();
-        vtkSmartPointer<vtkConeSource> cone = vtkConeSource::SafeDownCast(_glyphSource);
-        cone->SetResolution(8);
-    }
-        break;
-    case CUBE:
-        _glyphSource = vtkSmartPointer<vtkPlatonicSolidSource>::New();
-        vtkPlatonicSolidSource::SafeDownCast(_glyphSource)->SetSolidTypeToCube();
-        break;
-    case CYLINDER: {
-        vtkSmartPointer<vtkCylinderSource> csource = vtkSmartPointer<vtkCylinderSource>::New();
-        csource->SetResolution(8);
-        _glyphSource = vtkSmartPointer<vtkTransformPolyDataFilter>::New();
-        _glyphSource->SetInputConnection(csource->GetOutputPort());
-        vtkSmartPointer<vtkTransform> trans = vtkSmartPointer<vtkTransform>::New();
-        trans->RotateZ(-90.0);
-        vtkTransformPolyDataFilter::SafeDownCast(_glyphSource)->SetTransform(trans);
-      }
-        break;
-    case DODECAHEDRON:
-        _glyphSource = vtkSmartPointer<vtkPlatonicSolidSource>::New();
-        vtkPlatonicSolidSource::SafeDownCast(_glyphSource)->SetSolidTypeToDodecahedron();
-        break;
-    case ICOSAHEDRON:
-        _glyphSource = vtkSmartPointer<vtkPlatonicSolidSource>::New();
-        vtkPlatonicSolidSource::SafeDownCast(_glyphSource)->SetSolidTypeToIcosahedron();
-        break;
-    case OCTAHEDRON:
-        _glyphSource = vtkSmartPointer<vtkPlatonicSolidSource>::New();
-        vtkPlatonicSolidSource::SafeDownCast(_glyphSource)->SetSolidTypeToOctahedron();
-        break;
-    case SPHERE: {
-        _glyphSource = vtkSmartPointer<vtkSphereSource>::New();
-        vtkSmartPointer<vtkSphereSource> sphere = vtkSphereSource::SafeDownCast(_glyphSource);
-        sphere->SetThetaResolution(14);
-        sphere->SetPhiResolution(14);
-    }
-        break;
-    case TETRAHEDRON:
-        // FIXME: need to rotate inital orientation
-        _glyphSource = vtkSmartPointer<vtkPlatonicSolidSource>::New();
-        vtkPlatonicSolidSource::SafeDownCast(_glyphSource)->SetSolidTypeToTetrahedron();
-        break;
-    default:
-        ERROR("Unknown glyph shape: %d", _glyphShape);
-        return;
-    }
-
-    if (_glyphShape == ICOSAHEDRON ||
-        _glyphShape == TETRAHEDRON) {
-        // These shapes are created with front faces pointing inside
-        setCullFace(CULL_FRONT);
-    } else {
-        setCullFace(CULL_BACK);
-    }
-
-    if (_glyphMapper != NULL) {
-        _glyphMapper->SetSourceConnection(_glyphSource->GetOutputPort());
-    }
-
-    //setQuality(0.8);
-}
-
-void Glyphs::setQuality(double quality)
-{
-    switch (_glyphShape) {
-    case ARROW: {
-        vtkSmartPointer<vtkArrowSource> arrow = vtkArrowSource::SafeDownCast(_glyphSource);
-        int res = (int)(quality * 25);
-        if (res < 5) res = 5;
-        arrow->SetTipResolution(res);
-        arrow->SetShaftResolution(res);
-    }
-        break;
-    case CONE: {
-        vtkSmartPointer<vtkConeSource> cone = vtkConeSource::SafeDownCast(_glyphSource);
-        int res = (int)(quality * 25);
-        if (res < 5) res = 5;
-        cone->SetResolution(res);
-    }
-        break;
-    case SPHERE: {
-        vtkSmartPointer<vtkSphereSource> sphere = vtkSphereSource::SafeDownCast(_glyphSource);
-        int res = (int)(quality * 50);
-        if (res < 5) res = 5;
-        sphere->SetThetaResolution(res);
-        sphere->SetPhiResolution(res);
-    }
-        break;
-    case CYLINDER: {
-        assert(vtkTransformPolyDataFilter::SafeDownCast(_glyphSource) != NULL);
-        assert(vtkTransformPolyDataFilter::SafeDownCast(_glyphSource)->GetInputConnection(0, 0) != NULL);
-        vtkSmartPointer<vtkCylinderSource> csource = vtkCylinderSource::SafeDownCast(vtkTransformPolyDataFilter::SafeDownCast(_glyphSource)->GetInputConnection(0, 0));
-        int res = (int)(quality * 25);
-        if (res < 5) res = 5;
-        csource->SetResolution(res);
-    }
-        break;
-    default:
-        break;
-    }
-}
-
-/**
- * \brief Internal method to set up pipeline after a state change
- */
-void Glyphs::update()
-{
-    if (_dataSet == NULL) {
-        return;
-    }
-
-    vtkDataSet *ds = _dataSet->getVtkDataSet();
-
-    if (_glyphMapper == NULL) {
-        _glyphMapper = vtkSmartPointer<vtkGlyph3DMapper>::New();
-        _glyphMapper->SetResolveCoincidentTopologyToPolygonOffset();
-        _glyphMapper->ScalarVisibilityOn();
-    }
-
-    initProp();
-
-    setGlyphShape(_glyphShape);
-
-    vtkSmartPointer<vtkCellDataToPointData> cellToPtData;
-
-    if (ds->GetPointData() == NULL ||
-        ds->GetPointData()->GetScalars() == NULL) {
-        if (ds->GetCellData() != NULL &&
-            ds->GetCellData()->GetScalars() != NULL) {
-            TRACE("Generating point data scalars from cell data for: %s", _dataSet->getName().c_str());
-            cellToPtData = 
-                vtkSmartPointer<vtkCellDataToPointData>::New();
-#ifdef USE_VTK6
-            cellToPtData->SetInputData(ds);
-#else
-            cellToPtData->SetInput(ds);
-#endif
-            //cellToPtData->PassCellDataOn();
-            cellToPtData->Update();
-            ds = cellToPtData->GetOutput();
-        } else {
-            TRACE("No scalar data in dataset %s", _dataSet->getName().c_str());
-        }
-    }
-
-#ifdef USE_VTK6
-    _glyphMapper->SetInputData(ds);
-#else
-    _glyphMapper->SetInputConnection(ds->GetProducerPort());
-#endif
-
-    if (ds->GetPointData()->GetVectors() != NULL) {
-        TRACE("Setting scale mode to vector magnitude");
-        setScalingMode(SCALE_BY_VECTOR_MAGNITUDE);
-    } else {
-        TRACE("Setting scale mode to scalar");
-        setScalingMode(SCALE_BY_SCALAR);
-    }
-
-    double cellSizeRange[2];
-    double avgSize;
-    _dataSet->getCellSizeRange(cellSizeRange, &avgSize);
-    //_dataScale = cellSizeRange[0] + (cellSizeRange[1] - cellSizeRange[0])/2.;
-    _dataScale = avgSize;
-
-    TRACE("Cell size range: %g,%g, Data scale factor: %g",
-          cellSizeRange[0], cellSizeRange[1], _dataScale);
-
-    // Normalize sizes to [0,1] * ScaleFactor
-    _glyphMapper->SetClamping(_normalizeScale ? 1 : 0);
-    _glyphMapper->SetScaleFactor(_scaleFactor * _dataScale);
-    _glyphMapper->ScalingOn();
-
-    if (_lut == NULL) {
-        setColorMap(ColorMap::getDefault());
-    }
-
-    if (ds->GetPointData()->GetScalars() == NULL) {
-        TRACE("Setting color mode to vector magnitude");
-        setColorMode(COLOR_BY_VECTOR_MAGNITUDE);
-    } else {
-        TRACE("Setting color mode to scalar");
-        setColorMode(COLOR_BY_SCALAR);
-    }
-
-    getActor()->SetMapper(_glyphMapper);
-    _glyphMapper->Update();
-}
-
-/** 
- * \brief Control if field data range is normalized to [0,1] before
- * applying scale factor
- */
-void Glyphs::setNormalizeScale(bool normalize)
-{
-    if (_normalizeScale != normalize) {
-        _normalizeScale = normalize;
-        if (_glyphMapper != NULL) {
-            _glyphMapper->SetClamping(_normalizeScale ? 1 : 0);
-        }
-    }
-}
-
-/**
- * \brief Turn on/off orienting glyphs from a vector field
- */
-void Glyphs::setOrientMode(bool mode, const char *name)
-{
-    if (_glyphMapper != NULL) {
-        _glyphMapper->SetOrient(mode ? 1 : 0);
-        if (name != NULL && strlen(name) > 0) {
-            _glyphMapper->SetOrientationArray(name);
-        } else {
-            _glyphMapper->SetOrientationArray(vtkDataSetAttributes::VECTORS);
-        }
-    }
-}
-
-/**
- * \brief Control how glyphs are scaled
- */
-void Glyphs::setScalingMode(ScalingMode mode, const char *name, double range[2])
-{
-    _scalingMode = mode;
-
-    if (_dataSet == NULL || _glyphMapper == NULL)
-        return;
-
-    if (name != NULL && strlen(name) > 0) {
-        if (!_dataSet->hasField(name, DataSet::POINT_DATA)) {
-            ERROR("Field not found: %s", name);
-            return;
-        }
-        _scalingFieldName = name;
-    } else
-        _scalingFieldName.clear();
-    if (range == NULL) {
-        _scalingFieldRange[0] = DBL_MAX;
-        _scalingFieldRange[1] = -DBL_MAX;
-    } else {
-        memcpy(_scalingFieldRange, range, sizeof(double)*2);
-    }
-
-    if (name != NULL && strlen(name) > 0) {
-        _glyphMapper->SetScaleArray(name);
-    } else {
-        if (mode == SCALE_BY_SCALAR) {
-            _glyphMapper->SetScaleArray(vtkDataSetAttributes::SCALARS);
-        } else {
-            _glyphMapper->SetScaleArray(vtkDataSetAttributes::VECTORS);
-        }
-    }
-
-    if (range != NULL) {
-        TRACE("Setting size range to: %g,%g", range[0], range[1]);
-        _glyphMapper->SetRange(range);
-    } else if (name != NULL && strlen(name) > 0) {
-        double r[2];
-        DataSet::DataAttributeType type = DataSet::POINT_DATA;
-        int comp = -1;
-
-        if (_renderer->getUseCumulativeRange()) {
-            int numComponents;
-            if  (!_dataSet->getFieldInfo(name, type, &numComponents)) {
-                ERROR("Field not found: %s, type: %d", name, type);
-                return;
-            } else if (mode == SCALE_BY_VECTOR_COMPONENTS && numComponents < 3) {
-                ERROR("Field %s needs 3 components but has only %d components",
-                      name, numComponents);
-                return;
-            }
-            if (mode == SCALE_BY_VECTOR_COMPONENTS) {
-                double tmpR[2];
-                _renderer->getCumulativeDataRange(tmpR, name, type, numComponents, 0);
-                r[0] = tmpR[0];
-                r[1] = tmpR[1];
-                _renderer->getCumulativeDataRange(tmpR, name, type, numComponents, 1);
-                r[0] = min2(r[0], tmpR[0]);
-                r[1] = max2(r[1], tmpR[1]);
-                _renderer->getCumulativeDataRange(tmpR, name, type, numComponents, 2);
-                r[0] = min2(r[0], tmpR[0]);
-                r[1] = max2(r[1], tmpR[1]);
-            } else {
-                _renderer->getCumulativeDataRange(r, name, type, numComponents, comp);
-            }
-        } else {
-            if (mode == SCALE_BY_VECTOR_COMPONENTS) {
-                double tmpR[2];
-                _dataSet->getDataRange(tmpR, name, type, 0);
-                r[0] = tmpR[0];
-                r[1] = tmpR[1];
-                _dataSet->getDataRange(tmpR, name, type, 1);
-                r[0] = min2(r[0], tmpR[0]);
-                r[1] = max2(r[1], tmpR[1]);
-                _dataSet->getDataRange(tmpR, name, type, 2);
-                r[0] = min2(r[0], tmpR[0]);
-                r[1] = max2(r[1], tmpR[1]);
-            } else {
-                _dataSet->getDataRange(r, name, type, comp);
-            }
-        }
-        TRACE("Setting size range to: %g,%g", r[0], r[1]);
-        _glyphMapper->SetRange(r);
-    } else {
-        switch (mode) {
-        case SCALE_BY_SCALAR:
-            TRACE("Setting size range to: %g,%g", _dataRange[0], _dataRange[1]);
-            _glyphMapper->SetRange(_dataRange);
-            break;
-        case SCALE_BY_VECTOR_MAGNITUDE:
-            TRACE("Setting size range to: %g,%g", _vectorMagnitudeRange[0], _vectorMagnitudeRange[1]);
-            _glyphMapper->SetRange(_vectorMagnitudeRange);
-            break;
-        case SCALE_BY_VECTOR_COMPONENTS: {
-            double sizeRange[2];
-            sizeRange[0] = _vectorComponentRange[0][0];
-            sizeRange[1] = _vectorComponentRange[0][1];
-            sizeRange[0] = min2(sizeRange[0], _vectorComponentRange[1][0]);
-            sizeRange[1] = max2(sizeRange[1], _vectorComponentRange[1][1]);
-            sizeRange[0] = min2(sizeRange[0], _vectorComponentRange[2][0]);
-            sizeRange[1] = max2(sizeRange[1], _vectorComponentRange[2][1]);
-            TRACE("Setting size range to: %g,%g", sizeRange[0], sizeRange[1]);
-            _glyphMapper->SetRange(sizeRange);
-        }
-            break;
-        case SCALING_OFF:
-        default:
-            ;
-        }
-    }
-
-    switch (mode) {
-    case SCALE_BY_SCALAR:
-    case SCALE_BY_VECTOR_MAGNITUDE:
-        _glyphMapper->SetScaleModeToScaleByMagnitude();
-        break;
-    case SCALE_BY_VECTOR_COMPONENTS:
-        _glyphMapper->SetScaleModeToScaleByVectorComponents();
-        break;
-    case SCALING_OFF:
-    default:
-        _glyphMapper->SetScaleModeToNoDataScaling();
-    }
-}
-
-void Glyphs::setScalingMode(ScalingMode mode)
-{
-    setScalingMode(mode, NULL, NULL);
-}
-
-void Glyphs::setColorMode(ColorMode mode,
-                          const char *name, double range[2])
-{
-    _colorMode = mode;
-    if (name == NULL)
-        _colorFieldName.clear();
-    else
-        _colorFieldName = name;
-    if (range == NULL) {
-        _colorFieldRange[0] = DBL_MAX;
-        _colorFieldRange[1] = -DBL_MAX;
-    } else {
-        memcpy(_colorFieldRange, range, sizeof(double)*2);
-    }
-
-    if (_dataSet == NULL || _glyphMapper == NULL)
-        return;
-
-    if (name != NULL && strlen(name) > 0) {
-        _glyphMapper->SetScalarModeToUsePointFieldData();
-        _glyphMapper->SelectColorArray(name);
-    } else {
-        _glyphMapper->SetScalarModeToDefault();
-    }
-
-    if (_lut != NULL) {
-        if (range != NULL) {
-            _lut->SetRange(range);
-        } else if (name != NULL && strlen(name) > 0) {
-            double r[2];
-            int comp = -1;
-            if (mode == COLOR_BY_VECTOR_X)
-                comp = 0;
-            else if (mode == COLOR_BY_VECTOR_Y)
-                comp = 1;
-            else if (mode == COLOR_BY_VECTOR_Z)
-                comp = 2;
-
-            DataSet::DataAttributeType type = DataSet::POINT_DATA;
-
-            if (_renderer->getUseCumulativeRange()) {
-                int numComponents;
-                if  (!_dataSet->getFieldInfo(name, type, &numComponents)) {
-                    ERROR("Field not found: %s, type: %d", name, type);
-                    return;
-                } else if (numComponents < comp+1) {
-                    ERROR("Request for component %d in field with %d components",
-                          comp, numComponents);
-                    return;
-                }
-                _renderer->getCumulativeDataRange(r, name, type, numComponents, comp);
-            } else {
-                _dataSet->getDataRange(r, name, type, comp);
-            }
-            TRACE("Setting lut range to: %g,%g", r[0], r[1]);
-            _lut->SetRange(r);
-        }
-    }
-
-    switch (mode) {
-    case COLOR_BY_SCALAR:
-        _glyphMapper->ScalarVisibilityOn();
-        break;
-    case COLOR_BY_VECTOR_MAGNITUDE:
-        _glyphMapper->ScalarVisibilityOn();
-        if (_lut != NULL) {
-            _lut->SetVectorModeToMagnitude();
-        }
-        break;
-    case COLOR_BY_VECTOR_X:
-        _glyphMapper->ScalarVisibilityOn();
-        if (_lut != NULL) {
-            _lut->SetVectorModeToComponent();
-            _lut->SetVectorComponent(0);
-        }
-        break;
-    case COLOR_BY_VECTOR_Y:
-        _glyphMapper->ScalarVisibilityOn();
-        if (_lut != NULL) {
-            _lut->SetVectorModeToComponent();
-            _lut->SetVectorComponent(1);
-        }
-        break;
-    case COLOR_BY_VECTOR_Z:
-        _glyphMapper->ScalarVisibilityOn();
-        if (_lut != NULL) {
-            _lut->SetVectorModeToComponent();
-            _lut->SetVectorComponent(2);
-        }
-        break;
-    case COLOR_CONSTANT:
-    default:
-        _glyphMapper->ScalarVisibilityOff();
-        break;
-    }
-}
-
-void Glyphs::setColorMode(ColorMode mode)
-{
-    _colorMode = mode;
-    if (_dataSet == NULL)
-        return;
-
-    switch (mode) {
-    case COLOR_BY_SCALAR:
-        setColorMode(mode,
-                     _dataSet->getActiveScalarsName(),
-                     _dataRange);
-        break;
-    case COLOR_BY_VECTOR_MAGNITUDE:
-        setColorMode(mode,
-                     _dataSet->getActiveVectorsName(),
-                     _vectorMagnitudeRange);
-        break;
-    case COLOR_BY_VECTOR_X:
-        setColorMode(mode,
-                     _dataSet->getActiveVectorsName(),
-                     _vectorComponentRange[0]);
-        break;
-    case COLOR_BY_VECTOR_Y:
-        setColorMode(mode,
-                     _dataSet->getActiveVectorsName(),
-                     _vectorComponentRange[1]);
-        break;
-    case COLOR_BY_VECTOR_Z:
-        setColorMode(mode,
-                     _dataSet->getActiveVectorsName(),
-                     _vectorComponentRange[2]);
-        break;
-    case COLOR_CONSTANT:
-    default:
-        setColorMode(mode, NULL, NULL);
-        break;
-    }
-}
-
-/**
- * \brief Turn on/off orienting glyphs from a vector field
- */
-void Glyphs::setOrient(bool state)
-{
-    if (_glyphMapper != NULL) {
-        _glyphMapper->SetOrient(state ? 1 : 0);
-    }
-}
-
-/**
- * \brief Controls relative scaling of glyphs
- */
-void Glyphs::setScaleFactor(double scale)
-{
-    _scaleFactor = scale;
-    if (_glyphMapper != NULL) {
-        _glyphMapper->SetScaleFactor(_scaleFactor * _dataScale);
-    }
-}
-
-void Glyphs::updateRanges(Renderer *renderer)
-{
-    if (_dataSet == NULL) {
-        ERROR("called before setDataSet");
-        return;
-    }
-
-    if (renderer->getUseCumulativeRange()) {
-        renderer->getCumulativeDataRange(_dataRange,
-                                         _dataSet->getActiveScalarsName(),
-                                         1);
-        renderer->getCumulativeDataRange(_vectorMagnitudeRange,
-                                         _dataSet->getActiveVectorsName(),
-                                         3);
-        for (int i = 0; i < 3; i++) {
-            renderer->getCumulativeDataRange(_vectorComponentRange[i],
-                                             _dataSet->getActiveVectorsName(),
-                                             3, i);
-        }
-    } else {
-        _dataSet->getScalarRange(_dataRange);
-        _dataSet->getVectorRange(_vectorMagnitudeRange);
-        for (int i = 0; i < 3; i++) {
-            _dataSet->getVectorRange(_vectorComponentRange[i], i);
-        }
-    }
-
-    // Need to update color map ranges and/or active vector field
-    double *rangePtr = _colorFieldRange;
-    if (_colorFieldRange[0] > _colorFieldRange[1]) {
-        rangePtr = NULL;
-    }
-    setColorMode(_colorMode, _colorFieldName.c_str(), rangePtr);
-
-    rangePtr = _scalingFieldRange;
-    if (_scalingFieldRange[0] > _scalingFieldRange[1]) {
-        rangePtr = NULL;
-    }
-    setScalingMode(_scalingMode, _scalingFieldName.c_str(), rangePtr);
-}
-
-/**
- * \brief Called when the color map has been edited
- */
-void Glyphs::updateColorMap()
-{
-    setColorMap(_colorMap);
-}
-
-/**
- * \brief Associate a colormap lookup table with the DataSet
- */
-void Glyphs::setColorMap(ColorMap *cmap)
-{
-    if (cmap == NULL)
-        return;
-
-    _colorMap = cmap;
- 
-    if (_lut == NULL) {
-        _lut = vtkSmartPointer<vtkLookupTable>::New();
-        if (_glyphMapper != NULL) {
-            _glyphMapper->UseLookupTableScalarRangeOn();
-            _glyphMapper->SetLookupTable(_lut);
-        }
-        _lut->DeepCopy(cmap->getLookupTable());
-        switch (_colorMode) {
-        case COLOR_CONSTANT:
-        case COLOR_BY_SCALAR:
-            _lut->SetRange(_dataRange);
-            break;
-        case COLOR_BY_VECTOR_MAGNITUDE:
-            _lut->SetRange(_vectorMagnitudeRange);
-            break;
-        case COLOR_BY_VECTOR_X:
-            _lut->SetRange(_vectorComponentRange[0]);
-            break;
-        case COLOR_BY_VECTOR_Y:
-            _lut->SetRange(_vectorComponentRange[1]);
-            break;
-        case COLOR_BY_VECTOR_Z:
-            _lut->SetRange(_vectorComponentRange[2]);
-            break;
-        default:
-            break;
-        }
-    } else {
-        double range[2];
-        _lut->GetTableRange(range);
-        _lut->DeepCopy(cmap->getLookupTable());
-        _lut->SetRange(range);
-        _lut->Modified();
-    }
-
-    switch (_colorMode) {
-    case COLOR_BY_VECTOR_MAGNITUDE:
-        _lut->SetVectorModeToMagnitude();
-        break;
-    case COLOR_BY_VECTOR_X:
-        _lut->SetVectorModeToComponent();
-        _lut->SetVectorComponent(0);
-        break;
-    case COLOR_BY_VECTOR_Y:
-        _lut->SetVectorModeToComponent();
-        _lut->SetVectorComponent(1);
-        break;
-    case COLOR_BY_VECTOR_Z:
-        _lut->SetVectorModeToComponent();
-        _lut->SetVectorComponent(2);
-        break;
-    default:
-        break;
-    }
-}
-
-/**
- * \brief Set a group of world coordinate planes to clip rendering
- *
- * Passing NULL for planes will remove all cliping planes
- */
-void Glyphs::setClippingPlanes(vtkPlaneCollection *planes)
-{
-    if (_glyphMapper != NULL) {
-        _glyphMapper->SetClippingPlanes(planes);
-    }
-}
Index: unk/packages/vizservers/vtkvis/RpGlyphs.h
===================================================================
--- /trunk/packages/vizservers/vtkvis/RpGlyphs.h	(revision 3615)
+++ 	(revision )
@@ -1,141 +1,0 @@
-/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
-/*
- * Copyright (C) 2004-2012  HUBzero Foundation, LLC
- *
- * Author: Leif Delgass <ldelgass@purdue.edu>
- */
-
-#ifndef VTKVIS_GLYPHS_H
-#define VTKVIS_GLYPHS_H
-
-#include <vector>
-
-#include <vtkSmartPointer.h>
-#include <vtkProp.h>
-#include <vtkActor.h>
-#include <vtkVersion.h>
-#include <vtkGlyph3DMapper.h>
-#include <vtkLookupTable.h>
-#include <vtkPlaneCollection.h>
-
-#include "RpVtkGraphicsObject.h"
-#include "ColorMap.h"
-
-namespace VtkVis {
-
-/**
- * \brief Oriented and scaled 3D glyph shapes
- *
- * The DataSet must have vectors and/or scalars
- */
-class Glyphs : public VtkGraphicsObject {
-public:
-    enum GlyphShape {
-        ARROW,
-        CONE,
-        CUBE,
-        CYLINDER,
-        DODECAHEDRON,
-        ICOSAHEDRON,
-        LINE,
-        OCTAHEDRON,
-        SPHERE,
-        TETRAHEDRON
-    };
-    enum ScalingMode {
-        SCALE_BY_SCALAR,
-        SCALE_BY_VECTOR_MAGNITUDE,
-        SCALE_BY_VECTOR_COMPONENTS,
-        SCALING_OFF
-    };
-    enum ColorMode {
-        COLOR_BY_SCALAR,
-        COLOR_BY_VECTOR_MAGNITUDE,
-        COLOR_BY_VECTOR_X,
-        COLOR_BY_VECTOR_Y,
-        COLOR_BY_VECTOR_Z,
-        COLOR_CONSTANT
-    };
-
-    Glyphs(GlyphShape shape);
-    virtual ~Glyphs();
-
-    virtual const char *getClassName() const
-    {
-        return "Glyphs";
-    }
-
-    virtual void setDataSet(DataSet *dataSet,
-                            Renderer *renderer);
-
-    virtual void setClippingPlanes(vtkPlaneCollection *planes);
-
-    void setQuality(double quality);
-
-    void setOrient(bool state);
-
-    void setOrientMode(bool mode, const char *name);
-
-    void setScalingMode(ScalingMode mode, const char *name, double range[2]);
-
-    void setColorMode(ColorMode mode, const char *name, double range[2]);
-
-    void setScalingMode(ScalingMode mode);
-
-    void setNormalizeScale(bool normalize);
-
-    void setColorMode(ColorMode mode);
-
-    void setGlyphShape(GlyphShape shape);
-
-    void setScaleFactor(double scale);
-
-    void setColorMap(ColorMap *colorMap);
-
-    /**
-     * \brief Return the ColorMap in use
-     */
-    ColorMap *getColorMap()
-    {
-        return _colorMap;
-    }
-
-    void updateColorMap();
-
-    virtual void updateRanges(Renderer *renderer);
-
-private:
-    Glyphs();
-    virtual void update();
-    static inline double min2(double a, double b)
-    {
-        return ((a < b) ? a : b);
-    }
-    static inline double max2(double a, double b)
-    {
-        return ((a > b) ? a : b);
-    }
-
-    GlyphShape _glyphShape;
-    ScalingMode _scalingMode;
-    std::string _scalingFieldName;
-    double _scalingFieldRange[2];
-    double _dataScale;
-    double _scaleFactor;
-    bool _normalizeScale;
-    ColorMap *_colorMap;
-    ColorMode _colorMode;
-    std::string _colorFieldName;
-    double _colorFieldRange[2];
-    double _vectorMagnitudeRange[2];
-    double _vectorComponentRange[3][2];
-    Renderer *_renderer;
-
-    vtkSmartPointer<vtkLookupTable> _lut;
-    vtkSmartPointer<vtkPolyDataAlgorithm> _glyphSource;
-    vtkSmartPointer<vtkGlyph3DMapper> _glyphMapper;
-};
-
-}
-
-#endif
Index: unk/packages/vizservers/vtkvis/RpGroup.cpp
===================================================================
--- /trunk/packages/vizservers/vtkvis/RpGroup.cpp	(revision 3615)
+++ 	(revision )
@@ -1,81 +1,0 @@
-/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
-/*
- * Copyright (C) 2004-2012  HUBzero Foundation, LLC
- *
- * Author: Leif Delgass <ldelgass@purdue.edu>
- */
-
-#include "RpGroup.h"
-#include "Trace.h"
-
-using namespace VtkVis;
-
-Group::Group()
-{
-}
-
-Group::~Group()
-{
-}
-
-/**
- * \brief Create and initialize VTK Props to render the Group
- */
-void Group::initProp()
-{
-    if (_prop == NULL) {
-        _prop = vtkSmartPointer<vtkAssembly>::New();
-    }
-}
-
-void Group::update()
-{
-    initProp();
-}
-
-void Group::addChild(const NodeId& name, VtkGraphicsObject *obj)
-{
-    if (obj == NULL)
-        return;
-    if (obj->getProp3D() != NULL) {
-        getAssembly()->AddPart(obj->getProp3D());
-    }
-    _nodes[name] = obj;
-}
-
-VtkGraphicsObject *Group::getChild(const NodeId& name)
-{
-    NodeHashmap::iterator itr = _nodes.find(name);
-    if (itr == _nodes.end()) {
-        return NULL;
-    } else {
-        return itr->second;
-    }
-}
-
-void Group::removeChild(const NodeId& name)
-{
-    NodeHashmap::iterator itr = _nodes.find(name);
-    if (itr == _nodes.end()) {
-        ERROR("Node not found: '%s'", name.c_str());
-        return;
-    }
-    VtkGraphicsObject *obj = itr->second;
-    if (obj->getProp3D() != NULL) {
-        getAssembly()->RemovePart(obj->getProp3D());
-    }
-    _nodes.erase(itr);
-}
-
-/**
- * \brief Set a group of world coordinate planes to clip rendering
- *
- * Passing NULL for planes will remove all cliping planes
- */
-void Group::setClippingPlanes(vtkPlaneCollection *planes)
-{
-    for (NodeHashmap::iterator itr = _nodes.begin();
-         itr != _nodes.end(); ++itr) {
-        itr->second->setClippingPlanes(planes);
-    }
-}
Index: unk/packages/vizservers/vtkvis/RpGroup.h
===================================================================
--- /trunk/packages/vizservers/vtkvis/RpGroup.h	(revision 3615)
+++ 	(revision )
@@ -1,68 +1,0 @@
-/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
-/*
- * Copyright (C) 2004-2012  HUBzero Foundation, LLC
- *
- * Author: Leif Delgass <ldelgass@purdue.edu>
- */
-
-#ifndef VTKVIS_GROUP_H
-#define VTKVIS_GROUP_H
-
-#include <tr1/unordered_map>
-
-#include <vtkProp3D.h>
-
-#include "RpVtkGraphicsObject.h"
-
-namespace VtkVis {
-
-/**
- * \brief Collection of shapes with grouping
- */
-class Group : public VtkGraphicsObject {
-public:
-    typedef std::string NodeId;
-    typedef std::tr1::unordered_map<NodeId, VtkGraphicsObject *> NodeHashmap;
-
-    Group();
-    virtual ~Group();
-
-    virtual const char *getClassName() const 
-    {
-        return "Group";
-    }
-
-    virtual void setDataSet(DataSet *dataSet,
-                            Renderer *renderer)
-    {
-        assert(dataSet == NULL);
-        update();
-    }
-
-    virtual void setClippingPlanes(vtkPlaneCollection *planes);
-
-    void addChild(const NodeId& name, VtkGraphicsObject *obj);
-
-    VtkGraphicsObject *getChild(const NodeId& name);
-
-    void getChildren(std::vector<VtkGraphicsObject *>& children)
-    {
-        for (NodeHashmap::iterator itr = _nodes.begin();
-             itr != _nodes.end(); ++itr) {
-            children.push_back(itr->second);
-        }
-    }
-
-    void removeChild(const NodeId& name);
-
-private:
-    virtual void initProp();
-
-    virtual void update();
-
-    NodeHashmap _nodes;
-};
-
-}
-
-#endif
Index: unk/packages/vizservers/vtkvis/RpHeightMap.cpp
===================================================================
--- /trunk/packages/vizservers/vtkvis/RpHeightMap.cpp	(revision 3615)
+++ 	(revision )
@@ -1,1345 +1,0 @@
-/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
-/*
- * Copyright (C) 2004-2012  HUBzero Foundation, LLC
- *
- * Author: Leif Delgass <ldelgass@purdue.edu>
- */
-
-#include <cassert>
-
-#include <vtkDataSet.h>
-#include <vtkPointData.h>
-#include <vtkCellData.h>
-#include <vtkCellDataToPointData.h>
-#include <vtkDataSetMapper.h>
-#include <vtkPolyDataMapper.h>
-#include <vtkUnstructuredGrid.h>
-#include <vtkProperty.h>
-#include <vtkImageData.h>
-#include <vtkLookupTable.h>
-#include <vtkTransform.h>
-#include <vtkDelaunay2D.h>
-#include <vtkDelaunay3D.h>
-#include <vtkGaussianSplatter.h>
-#include <vtkExtractVOI.h>
-#include <vtkDataSetSurfaceFilter.h>
-#include <vtkContourFilter.h>
-#include <vtkStripper.h>
-#include <vtkWarpScalar.h>
-#include <vtkPropAssembly.h>
-#include <vtkCutter.h>
-#include <vtkPlane.h>
-
-#include "RpHeightMap.h"
-#include "RpVtkRenderer.h"
-#include "Trace.h"
-
-using namespace VtkVis;
-
-#define MESH_POINT_CLOUDS
-#define TRANSLATE_TO_ZORIGIN
-
-HeightMap::HeightMap(int numContours, double heightScale) :
-    VtkGraphicsObject(),
-    _numContours(numContours),
-    _contourColorMap(false),
-    _contourEdgeWidth(1.0),
-    _warpScale(heightScale),
-    _sliceAxis(Z_AXIS),
-    _pipelineInitialized(false),
-    _colorMap(NULL),
-    _colorMode(COLOR_BY_SCALAR),
-    _colorFieldType(DataSet::POINT_DATA),
-    _renderer(NULL)
-{
-    _contourEdgeColor[0] = 0.0f;
-    _contourEdgeColor[1] = 0.0f;
-    _contourEdgeColor[2] = 0.0f;
-    _colorFieldRange[0] = DBL_MAX;
-    _colorFieldRange[1] = -DBL_MAX;
-}
-
-HeightMap::HeightMap(const std::vector<double>& contours, double heightScale) :
-    VtkGraphicsObject(),
-    _numContours(contours.size()),
-    _contours(contours),
-    _contourColorMap(false),
-    _contourEdgeWidth(1.0),
-    _warpScale(heightScale),
-    _sliceAxis(Z_AXIS),
-    _pipelineInitialized(false),
-    _colorMap(NULL),
-    _colorMode(COLOR_BY_SCALAR),
-    _colorFieldType(DataSet::POINT_DATA),
-    _renderer(NULL)
-{
-    _contourEdgeColor[0] = 0.0f;
-    _contourEdgeColor[1] = 0.0f;
-    _contourEdgeColor[2] = 0.0f;
-    _colorFieldRange[0] = DBL_MAX;
-    _colorFieldRange[1] = -DBL_MAX;
-}
-
-HeightMap::~HeightMap()
-{
-#ifdef WANT_TRACE
-    if (_dataSet != NULL)
-        TRACE("Deleting HeightMap for %s", _dataSet->getName().c_str());
-    else
-        TRACE("Deleting HeightMap with NULL DataSet");
-#endif
-}
-
-void HeightMap::setDataSet(DataSet *dataSet,
-                           Renderer *renderer)
-{
-    if (_dataSet != dataSet) {
-        _dataSet = dataSet;
-        _renderer = renderer;
-
-        if (_dataSet != NULL) {
-            TRACE("DataSet name: '%s' type: %s",
-                  _dataSet->getName().c_str(),
-                  _dataSet->getVtkType());
-
-            if (renderer->getUseCumulativeRange()) {
-                renderer->getCumulativeDataRange(_dataRange,
-                                                 _dataSet->getActiveScalarsName(),
-                                                 1);
-                const char *activeVectors = _dataSet->getActiveVectorsName();
-                if (activeVectors != NULL) {
-                    renderer->getCumulativeDataRange(_vectorMagnitudeRange,
-                                                     activeVectors,
-                                                     3);
-                    for (int i = 0; i < 3; i++) {
-                        renderer->getCumulativeDataRange(_vectorComponentRange[i],
-                                                         activeVectors,
-                                                         3, i);
-                    }
-                }
-            } else {
-                _dataSet->getScalarRange(_dataRange);
-                _dataSet->getVectorRange(_vectorMagnitudeRange);
-                for (int i = 0; i < 3; i++) {
-                    _dataSet->getVectorRange(_vectorComponentRange[i], i);
-                }
-            }
-        }
-
-        update();
-    }
-}
-
-/**
- * Compute a data scaling factor to make maximum height (at default _warpScale) 
- * equivalent to largest dimension of data set
- */
-void HeightMap::computeDataScale()
-{
-    if (_dataSet == NULL)
-        return;
-
-    double bounds[6];
-    double boundsRange = 0.0;
-    _dataSet->getBounds(bounds);
-    for (int i = 0; i < 6; i+=2) {
-        double r = bounds[i+1] - bounds[i];
-        if (r > boundsRange)
-            boundsRange = r;
-    }
-    double datRange = _dataRange[1] - _dataRange[0];
-    if (datRange < 1.0e-17) {
-        _dataScale = 1.0;
-    } else {
-        _dataScale = boundsRange / datRange;
-    }
-    TRACE("Bounds range: %g data range: %g scaling: %g",
-          boundsRange, datRange, _dataScale);
-}
-
-/**
- * \brief Create and initialize VTK Props to render the colormapped dataset
- */
-void HeightMap::initProp()
-{
-    if (_dsActor == NULL) {
-        _dsActor = vtkSmartPointer<vtkActor>::New();
-        _dsActor->GetProperty()->SetOpacity(_opacity);
-        _dsActor->GetProperty()->SetColor(_color[0],
-                                          _color[1],
-                                          _color[2]);
-        _dsActor->GetProperty()->SetEdgeColor(_edgeColor[0],
-                                              _edgeColor[1],
-                                              _edgeColor[2]);
-        _dsActor->GetProperty()->SetLineWidth(_edgeWidth);
-        _dsActor->GetProperty()->EdgeVisibilityOff();
-        _dsActor->GetProperty()->SetAmbient(0.2);
-        _dsActor->GetProperty()->LightingOn();
-    }
-    if (_contourActor == NULL) {
-        _contourActor = vtkSmartPointer<vtkActor>::New();
-        _contourActor->GetProperty()->SetOpacity(_opacity);
-        _contourActor->GetProperty()->SetColor(_contourEdgeColor[0],
-                                               _contourEdgeColor[1],
-                                               _contourEdgeColor[2]);
-        _contourActor->GetProperty()->SetEdgeColor(_contourEdgeColor[0],
-                                                   _contourEdgeColor[1],
-                                                   _contourEdgeColor[2]);
-        _contourActor->GetProperty()->SetLineWidth(_contourEdgeWidth);
-        _contourActor->GetProperty()->EdgeVisibilityOff();
-        _contourActor->GetProperty()->SetAmbient(1.0);
-        _contourActor->GetProperty()->LightingOff();
-    }
-    // Contour actor is added in update() if contours are produced
-    if (_prop == NULL) {
-        _prop = vtkSmartPointer<vtkAssembly>::New();
-        getAssembly()->AddPart(_dsActor);
-    } else {
-        getAssembly()->RemovePart(_contourActor);
-    }
-}
-
-/**
- * \brief Internal method to set up pipeline after a state change
- */
-void HeightMap::update()
-{
-    if (_dataSet == NULL)
-        return;
-
-    TRACE("DataSet: %s", _dataSet->getName().c_str());
-
-    vtkDataSet *ds = _dataSet->getVtkDataSet();
-
-    computeDataScale();
-
-    // Contour filter to generate isolines
-    if (_contourFilter == NULL) {
-        _contourFilter = vtkSmartPointer<vtkContourFilter>::New();
-    }
-
-    // Mapper, actor to render color-mapped data set
-    if (_dsMapper == NULL) {
-        _dsMapper = vtkSmartPointer<vtkDataSetMapper>::New();
-        // Map scalars through lookup table regardless of type
-        _dsMapper->SetColorModeToMapScalars();
-    }
-
-    if (!_pipelineInitialized) {
-        vtkSmartPointer<vtkCellDataToPointData> cellToPtData;
-
-        if (ds->GetPointData() == NULL ||
-            ds->GetPointData()->GetScalars() == NULL) {
-            TRACE("No scalar point data in dataset %s", _dataSet->getName().c_str());
-            if (ds->GetCellData() != NULL &&
-                ds->GetCellData()->GetScalars() != NULL) {
-                cellToPtData = 
-                    vtkSmartPointer<vtkCellDataToPointData>::New();
-#ifdef USE_VTK6
-                cellToPtData->SetInputData(ds);
-#else
-                cellToPtData->SetInput(ds);
-#endif
-                //cellToPtData->PassCellDataOn();
-                cellToPtData->Update();
-                ds = cellToPtData->GetOutput();
-            } else {
-                USER_ERROR("No scalar field was found in the data set.");
-                return;
-            }
-        }
-
-        vtkPolyData *pd = vtkPolyData::SafeDownCast(ds);
-        if (pd != NULL) {
-            // DataSet is a vtkPolyData
-            if (pd->GetNumberOfLines() == 0 &&
-                pd->GetNumberOfPolys() == 0 &&
-                pd->GetNumberOfStrips() == 0) {
-                // DataSet is a point cloud
-                PrincipalPlane plane;
-                double offset;
-                if (_dataSet->is2D(&plane, &offset)) {
-#ifdef MESH_POINT_CLOUDS
-                    // Result of Delaunay2D is a PolyData
-                    vtkSmartPointer<vtkDelaunay2D> mesher = vtkSmartPointer<vtkDelaunay2D>::New();
-                    if (plane == PLANE_ZY) {
-                        vtkSmartPointer<vtkTransform> trans = vtkSmartPointer<vtkTransform>::New();
-                        trans->RotateWXYZ(90, 0, 1, 0);
-                        if (offset != 0.0) {
-                            trans->Translate(-offset, 0, 0);
-                        }
-                        mesher->SetTransform(trans);
-                        _sliceAxis = X_AXIS;
-                    } else if (plane == PLANE_XZ) {
-                        vtkSmartPointer<vtkTransform> trans = vtkSmartPointer<vtkTransform>::New();
-                        trans->RotateWXYZ(-90, 1, 0, 0);
-                        if (offset != 0.0) {
-                            trans->Translate(0, -offset, 0);
-                        }
-                        mesher->SetTransform(trans);
-                        _sliceAxis = Y_AXIS;
-                    } else if (offset != 0.0) {
-                        // XY with Z offset
-                        vtkSmartPointer<vtkTransform> trans = vtkSmartPointer<vtkTransform>::New();
-                        trans->Translate(0, 0, -offset);
-                        mesher->SetTransform(trans);
-                    }
-#ifdef USE_VTK6
-                    mesher->SetInputData(pd);
-#else
-                    mesher->SetInput(pd);
-#endif
-                    vtkAlgorithmOutput *warpOutput = initWarp(mesher->GetOutputPort());
-                    _dsMapper->SetInputConnection(warpOutput);
-                    _contourFilter->SetInputConnection(warpOutput);
-#else
-                    if (_pointSplatter == NULL)
-                        _pointSplatter = vtkSmartPointer<vtkGaussianSplatter>::New();
-                    if (_volumeSlicer == NULL)
-                        _volumeSlicer = vtkSmartPointer<vtkExtractVOI>::New();
-#ifdef USE_VTK6
-                    _pointSplatter->SetInputData(pd);
-#else
-                    _pointSplatter->SetInput(pd);
-#endif
-                    int dims[3];
-                    _pointSplatter->GetSampleDimensions(dims);
-                    TRACE("Sample dims: %d %d %d", dims[0], dims[1], dims[2]);
-                    if (plane == PLANE_ZY) {
-                        dims[0] = 3;
-                        _volumeSlicer->SetVOI(1, 1, 0, dims[1]-1, 0, dims[1]-1);
-                        _sliceAxis = X_AXIS;
-                    } else if (plane == PLANE_XZ) {
-                        dims[1] = 3;
-                        _volumeSlicer->SetVOI(0, dims[0]-1, 1, 1, 0, dims[2]-1);
-                        _sliceAxis = Y_AXIS;
-                    } else {
-                        dims[2] = 3;
-                        _volumeSlicer->SetVOI(0, dims[0]-1, 0, dims[1]-1, 1, 1);
-                    }
-                    _pointSplatter->SetSampleDimensions(dims);
-                    double bounds[6];
-                    _pointSplatter->Update();
-                    _pointSplatter->GetModelBounds(bounds);
-                    TRACE("Model bounds: %g %g %g %g %g %g",
-                          bounds[0], bounds[1],
-                          bounds[2], bounds[3],
-                          bounds[4], bounds[5]);
-                    _volumeSlicer->SetInputConnection(_pointSplatter->GetOutputPort());
-                    _volumeSlicer->SetSampleRate(1, 1, 1);
-                    vtkSmartPointer<vtkDataSetSurfaceFilter> gf = vtkSmartPointer<vtkDataSetSurfaceFilter>::New();
-                    gf->UseStripsOn();
-                    gf->SetInputConnection(_volumeSlicer->GetOutputPort());
-                    vtkAlgorithmOutput *warpOutput = initWarp(gf->GetOutputPort());
-                    _dsMapper->SetInputConnection(warpOutput);
-                    _contourFilter->SetInputConnection(warpOutput);
-#endif
-                } else {
-#ifdef MESH_POINT_CLOUDS
-                    // Data Set is a 3D point cloud
-                    // Result of Delaunay3D mesher is unstructured grid
-                    vtkSmartPointer<vtkDelaunay3D> mesher = vtkSmartPointer<vtkDelaunay3D>::New();
-#ifdef USE_VTK6
-                    mesher->SetInputData(pd);
-#else
-                    mesher->SetInput(pd);
-#endif
-                    // Run the mesher
-                    mesher->Update();
-                    // Get bounds of resulting grid
-                    double bounds[6];
-                    mesher->GetOutput()->GetBounds(bounds);
-                    // Sample a plane within the grid bounding box
-                    vtkSmartPointer<vtkCutter> cutter = vtkSmartPointer<vtkCutter>::New();
-                    cutter->SetInputConnection(mesher->GetOutputPort());
-                    if (_cutPlane == NULL) {
-                        _cutPlane = vtkSmartPointer<vtkPlane>::New();
-                    }
-                    _cutPlane->SetNormal(0, 0, 1);
-                    _cutPlane->SetOrigin(0,
-                                         0,
-                                         bounds[4] + (bounds[5]-bounds[4])/2.);
-                    cutter->SetCutFunction(_cutPlane);
-                    vtkSmartPointer<vtkDataSetSurfaceFilter> gf = vtkSmartPointer<vtkDataSetSurfaceFilter>::New();
-                    gf->UseStripsOn();
-                    gf->SetInputConnection(cutter->GetOutputPort());
-#else
-                    if (_pointSplatter == NULL)
-                        _pointSplatter = vtkSmartPointer<vtkGaussianSplatter>::New();
-#ifdef USE_VTK6
-                    _pointSplatter->SetInputData(pd);
-#else
-                    _pointSplatter->SetInput(pd);
-#endif
-                    int dims[3];
-                    _pointSplatter->GetSampleDimensions(dims);
-                    TRACE("Sample dims: %d %d %d", dims[0], dims[1], dims[2]);
-                    dims[2] = 3;
-                    _pointSplatter->SetSampleDimensions(dims);
-                    double bounds[6];
-                    _pointSplatter->Update();
-                    _pointSplatter->GetModelBounds(bounds);
-                    TRACE("Model bounds: %g %g %g %g %g %g",
-                          bounds[0], bounds[1],
-                          bounds[2], bounds[3],
-                          bounds[4], bounds[5]);
-                    if (_volumeSlicer == NULL)
-                        _volumeSlicer = vtkSmartPointer<vtkExtractVOI>::New();
-                    _volumeSlicer->SetInputConnection(_pointSplatter->GetOutputPort());
-                    _volumeSlicer->SetVOI(0, dims[0]-1, 0, dims[1]-1, 1, 1);
-                    _volumeSlicer->SetSampleRate(1, 1, 1);
-                    vtkSmartPointer<vtkDataSetSurfaceFilter> gf = vtkSmartPointer<vtkDataSetSurfaceFilter>::New();
-                    gf->UseStripsOn();
-                    gf->SetInputConnection(_volumeSlicer->GetOutputPort());
-#endif
-                    vtkAlgorithmOutput *warpOutput = initWarp(gf->GetOutputPort());
-                    _dsMapper->SetInputConnection(warpOutput);
-                    _contourFilter->SetInputConnection(warpOutput);
-                }
-            } else {
-                // DataSet is a vtkPolyData with lines and/or polygons
-                vtkAlgorithmOutput *warpOutput = initWarp(pd);
-                if (warpOutput != NULL) {
-                    _dsMapper->SetInputConnection(warpOutput);
-                    _contourFilter->SetInputConnection(warpOutput);
-                } else {
-#ifdef USE_VTK6
-                    _dsMapper->SetInputData(pd);
-                    _contourFilter->SetInputData(pd);
-#else
-                    _dsMapper->SetInput(pd);
-                    _contourFilter->SetInput(pd);
-#endif
-
-                }
-            }
-        } else {
-            // DataSet is NOT a vtkPolyData
-            // Can be: image/volume/uniform grid, structured grid, unstructured grid, rectilinear grid
-            vtkSmartPointer<vtkDataSetSurfaceFilter> gf = vtkSmartPointer<vtkDataSetSurfaceFilter>::New();
-            gf->UseStripsOn();
-            vtkImageData *imageData = vtkImageData::SafeDownCast(ds);
-            if (!_dataSet->is2D() && imageData != NULL) {
-                // 3D image/volume/uniform grid
-                if (_volumeSlicer == NULL)
-                    _volumeSlicer = vtkSmartPointer<vtkExtractVOI>::New();
-                int dims[3];
-                imageData->GetDimensions(dims);
-                TRACE("Image data dimensions: %d %d %d", dims[0], dims[1], dims[2]);
-#ifdef USE_VTK6
-                _volumeSlicer->SetInputData(ds);
-#else
-                _volumeSlicer->SetInput(ds);
-#endif
-                _volumeSlicer->SetVOI(0, dims[0]-1, 0, dims[1]-1, (dims[2]-1)/2, (dims[2]-1)/2);
-                _volumeSlicer->SetSampleRate(1, 1, 1);
-                gf->SetInputConnection(_volumeSlicer->GetOutputPort());
-            } else if (!_dataSet->is2D() && imageData == NULL) {
-                // 3D structured grid, unstructured grid, or rectilinear grid
-                double bounds[6];
-                ds->GetBounds(bounds);
-                // Sample a plane within the grid bounding box
-                vtkSmartPointer<vtkCutter> cutter = vtkSmartPointer<vtkCutter>::New();
-#ifdef USE_VTK6
-                cutter->SetInputData(ds);
-#else
-                cutter->SetInput(ds);
-#endif
-                if (_cutPlane == NULL) {
-                    _cutPlane = vtkSmartPointer<vtkPlane>::New();
-                }
-                _cutPlane->SetNormal(0, 0, 1);
-                _cutPlane->SetOrigin(0,
-                                     0,
-                                     bounds[4] + (bounds[5]-bounds[4])/2.);
-                cutter->SetCutFunction(_cutPlane);
-                gf->SetInputConnection(cutter->GetOutputPort());
-            } else {
-                // 2D data
-#ifdef USE_VTK6
-                gf->SetInputData(ds);
-#else
-                gf->SetInput(ds);
-#endif
-            }
-            vtkAlgorithmOutput *warpOutput = initWarp(gf->GetOutputPort());
-            _dsMapper->SetInputConnection(warpOutput);
-            _contourFilter->SetInputConnection(warpOutput);
-        }
-    }
-
-    _pipelineInitialized = true;
-
-    _contourFilter->ComputeNormalsOff();
-    _contourFilter->ComputeGradientsOff();
-
-    // Speed up multiple contour computation at cost of extra memory use
-    if (_numContours > 1) {
-        _contourFilter->UseScalarTreeOn();
-    } else {
-        _contourFilter->UseScalarTreeOff();
-    }
-
-    _contourFilter->SetNumberOfContours(_numContours);
-
-    if (_contours.empty()) {
-        // Evenly spaced isovalues
-        _contourFilter->GenerateValues(_numContours, _dataRange[0], _dataRange[1]);
-    } else {
-        // User-supplied isovalues
-        for (int i = 0; i < _numContours; i++) {
-            _contourFilter->SetValue(i, _contours[i]);
-        }
-    }
-
-    initProp();
-
-    if (_contourMapper == NULL) {
-        _contourMapper = vtkSmartPointer<vtkPolyDataMapper>::New();
-        _contourMapper->ScalarVisibilityOff();
-        _contourMapper->SetResolveCoincidentTopologyToPolygonOffset();
-        vtkSmartPointer<vtkStripper> stripper = vtkSmartPointer<vtkStripper>::New();
-        stripper->SetInputConnection(_contourFilter->GetOutputPort());
-        _contourMapper->SetInputConnection(stripper->GetOutputPort());
-        _contourActor->SetMapper(_contourMapper);
-        //_contourActor->InterpolateScalarsBeforeMappingOn();
-    }
-
-    setInterpolateBeforeMapping(true);
-
-    if (_lut == NULL) {
-        setColorMap(ColorMap::getDefault());
-        setColorMode(_colorMode);
-    }
-
-    // Ensure updated dataScale is applied
-    if (_warp != NULL) {
-        _warp->SetScaleFactor(_warpScale * _dataScale);
-    }
-#ifdef TRANSLATE_TO_ZORIGIN
-    double pos[3];
-    pos[0] = 0;
-    pos[1] = 0;
-    pos[2] = - _warpScale * _dataScale * _dataRange[0];
-    setPosition(pos);
-    TRACE("Z_POS: %g", pos[2]);
-#endif
-    _dsActor->SetMapper(_dsMapper);
-
-    _dsMapper->Update();
-    _contourMapper->Update();
-
-    // Only add contour actor to assembly if contours were
-    // produced, in order to prevent messing up assembly bounds
-    double bounds[6];
-    _contourActor->GetBounds(bounds);
-    if (bounds[0] <= bounds[1]) {
-        getAssembly()->AddPart(_contourActor);
-    }
-}
-
-void HeightMap::setInterpolateBeforeMapping(bool state)
-{
-    if (_dsMapper != NULL) {
-        _dsMapper->SetInterpolateScalarsBeforeMapping((state ? 1 : 0));
-    }
-}
-
-void HeightMap::setAspect(double aspect)
-{
-    double bounds[6];
-    vtkDataSet *ds = _dataSet->getVtkDataSet();
-    ds->GetBounds(bounds);
-    double size[3];
-    size[0] = bounds[1] - bounds[0];
-    size[1] = bounds[3] - bounds[2];
-    size[2] = bounds[5] - bounds[4];
-    double scale[3];
-    scale[0] = scale[1] = scale[2] = 1.;
-
-    if (aspect == 1.0) {
-        // Square
-        switch (_sliceAxis) {
-        case X_AXIS: {
-            if (size[1] > size[2] && size[2] > 1.0e-6) {
-                scale[2] = size[1] / size[2];
-            } else if (size[2] > size[1] && size[1] > 1.0e-6) {
-                scale[1] = size[2] / size[1];
-            }
-        }
-            break;
-        case Y_AXIS: {
-            if (size[0] > size[2] && size[2] > 1.0e-6) {
-                scale[2] = size[0] / size[2];
-            } else if (size[2] > size[0] && size[0] > 1.0e-6) {
-                scale[0] = size[2] / size[0];
-            }
-        }
-            break;
-        case Z_AXIS: {
-            if (size[0] > size[1] && size[1] > 1.0e-6) {
-                scale[1] = size[0] / size[1];
-            } else if (size[1] > size[0] && size[0] > 1.0e-6) {
-                scale[0] = size[1] / size[0];
-            }
-        }
-            break;
-        }
-    } else if (aspect != 0.0) {
-        switch (_sliceAxis) {
-        case X_AXIS: {
-            if (aspect > 1.0) {
-                if (size[2] > size[1]) {
-                    scale[1] = (size[2] / aspect) / size[1];
-                } else {
-                    scale[2] = (size[1] * aspect) / size[2];
-                }
-            } else {
-                if (size[1] > size[2]) {
-                    scale[2] = (size[1] * aspect) / size[2];
-                } else {
-                    scale[1] = (size[2] / aspect) / size[1];
-                }
-            }
-        }
-            break;
-        case Y_AXIS: {
-            if (aspect > 1.0) {
-                if (size[0] > size[2]) {
-                    scale[2] = (size[0] / aspect) / size[2];
-                } else {
-                    scale[0] = (size[2] * aspect) / size[0];
-                }
-            } else {
-                if (size[2] > size[0]) {
-                    scale[0] = (size[2] * aspect) / size[0];
-                } else {
-                    scale[2] = (size[0] / aspect) / size[2];
-                }
-            }
-        }
-            break;
-        case Z_AXIS: {
-            if (aspect > 1.0) {
-                if (size[0] > size[1]) {
-                    scale[1] = (size[0] / aspect) / size[1];
-                } else {
-                    scale[0] = (size[1] * aspect) / size[0];
-                }
-            } else {
-                if (size[1] > size[0]) {
-                    scale[0] = (size[1] * aspect) / size[0];
-                } else {
-                    scale[1] = (size[0] / aspect) / size[1];
-                }
-            }
-        }
-            break;
-        }
-    }
-
-    TRACE("%s dims %g,%g,%g", _dataSet->getName().c_str(),
-          size[0], size[1], size[2]);
-    TRACE("Setting scale to %g,%g,%g", scale[0], scale[1], scale[2]);
-    setScale(scale);
-}
-
-vtkAlgorithmOutput *HeightMap::initWarp(vtkAlgorithmOutput *input)
-{
-    TRACE("Warp scale: %g", _warpScale);
-    if (_warpScale == 0.0) {
-        _warp = NULL;
-        _normalsGenerator = NULL;
-        return input;
-    } else if (input == NULL) {
-        ERROR("NULL input");
-        return input;
-    } else {
-        if (_warp == NULL)
-            _warp = vtkSmartPointer<vtkWarpScalar>::New();
-        if (_normalsGenerator == NULL)
-            _normalsGenerator = vtkSmartPointer<vtkPolyDataNormals>::New();
-        switch (_sliceAxis) {
-        case X_AXIS:
-            _warp->SetNormal(1, 0, 0);
-            break;
-        case Y_AXIS:
-            _warp->SetNormal(0, 1, 0);
-            break;
-        default:
-            _warp->SetNormal(0, 0, 1);
-        }
-        _warp->UseNormalOn();
-        _warp->SetScaleFactor(_warpScale * _dataScale);
-        _warp->SetInputConnection(input);
-        _normalsGenerator->SetInputConnection(_warp->GetOutputPort());
-        _normalsGenerator->SetFeatureAngle(90.);
-        _normalsGenerator->AutoOrientNormalsOff();
-        _normalsGenerator->ComputePointNormalsOn();
-        return _normalsGenerator->GetOutputPort();
-    }
-}
-
-vtkAlgorithmOutput *HeightMap::initWarp(vtkPolyData *pdInput)
-{
-    TRACE("Warp scale: %g", _warpScale);
-    if (_warpScale == 0.0) {
-        _warp = NULL;
-        _normalsGenerator = NULL;
-        return NULL;
-    } else if (pdInput == NULL) {
-        ERROR("NULL input");
-        return NULL;
-    } else {
-        if (_warp == NULL)
-            _warp = vtkSmartPointer<vtkWarpScalar>::New();
-        if (_normalsGenerator == NULL)
-            _normalsGenerator = vtkSmartPointer<vtkPolyDataNormals>::New();
-        switch (_sliceAxis) {
-        case X_AXIS:
-            _warp->SetNormal(1, 0, 0);
-            break;
-        case Y_AXIS:
-            _warp->SetNormal(0, 1, 0);
-            break;
-        default:
-            _warp->SetNormal(0, 0, 1);
-        }
-        _warp->UseNormalOn();
-        _warp->SetScaleFactor(_warpScale * _dataScale);
-#ifdef USE_VTK6
-        _warp->SetInputData(pdInput);
-#else
-        _warp->SetInput(pdInput);
-#endif
-        _normalsGenerator->SetInputConnection(_warp->GetOutputPort());
-        _normalsGenerator->SetFeatureAngle(90.);
-        _normalsGenerator->AutoOrientNormalsOff();
-        _normalsGenerator->ComputePointNormalsOn();
-        return _normalsGenerator->GetOutputPort();
-    }
-}
-
-/**
- * \brief Controls relative scaling of height of mountain plot
- */
-void HeightMap::setHeightScale(double scale)
-{
-    if (_warpScale == scale)
-        return;
-
-    _warpScale = scale;
-    if (_warp == NULL) {
-        vtkAlgorithmOutput *warpOutput = initWarp(_dsMapper->GetInputConnection(0, 0));
-        _dsMapper->SetInputConnection(warpOutput);
-        _contourFilter->SetInputConnection(warpOutput);
-    } else if (scale == 0.0) {
-        vtkAlgorithmOutput *warpInput = _warp->GetInputConnection(0, 0);
-        _dsMapper->SetInputConnection(warpInput);
-        _contourFilter->SetInputConnection(warpInput);
-        _warp = NULL;
-    } else {
-        _warp->SetScaleFactor(_warpScale * _dataScale);
-    }
-#ifdef TRANSLATE_TO_ZORIGIN
-    double pos[3];
-    pos[0] = 0;
-    pos[1] = 0;
-    pos[2] = - _warpScale * _dataScale * _dataRange[0];
-    setPosition(pos);
-    TRACE("Z_POS: %g", pos[2]);
-#endif
-    if (_dsMapper != NULL)
-        _dsMapper->Update();
-    if (_contourMapper != NULL)
-        _contourMapper->Update();
-}
-
-/**
- * \brief Select a 2D slice plane from a 3D DataSet
- *
- * \param[in] axis Axis of slice plane
- * \param[in] ratio Position [0,1] of slice plane along axis
- */
-void HeightMap::selectVolumeSlice(Axis axis, double ratio)
-{
-    if (_dataSet->is2D()) {
-        WARN("DataSet not 3D, returning");
-        return;
-    }
-
-    if (_volumeSlicer == NULL &&
-        _cutPlane == NULL) {
-        WARN("Called before update() or DataSet is not a volume");
-        return;
-    }
-
-    _sliceAxis = axis;
-    if (_warp != NULL) {
-        switch (axis) {
-        case X_AXIS:
-            _warp->SetNormal(1, 0, 0);
-            break;
-        case Y_AXIS:
-            _warp->SetNormal(0, 1, 0);
-            break;
-        case Z_AXIS:
-            _warp->SetNormal(0, 0, 1);
-            break;
-        default:
-            ERROR("Invalid Axis");
-            return;
-        }
-    }
-
-    if (_cutPlane != NULL) {
-        double bounds[6];
-        _dataSet->getBounds(bounds);
-        switch (axis) {
-        case X_AXIS:
-            _cutPlane->SetNormal(1, 0, 0);
-            _cutPlane->SetOrigin(bounds[0] + (bounds[1]-bounds[0]) * ratio,
-                                 0,
-                                 0);
-            break;
-        case Y_AXIS:
-            _cutPlane->SetNormal(0, 1, 0);
-            _cutPlane->SetOrigin(0,
-                                 bounds[2] + (bounds[3]-bounds[2]) * ratio,
-                                 0);
-            break;
-        case Z_AXIS:
-            _cutPlane->SetNormal(0, 0, 1);
-            _cutPlane->SetOrigin(0,
-                                 0,
-                                 bounds[4] + (bounds[5]-bounds[4]) * ratio);
-            break;
-        default:
-            ERROR("Invalid Axis");
-            return;
-        }
-    } else {
-        int dims[3];
-        if (_pointSplatter != NULL) {
-            _pointSplatter->GetSampleDimensions(dims);
-        } else {
-            vtkImageData *imageData = vtkImageData::SafeDownCast(_dataSet->getVtkDataSet());
-            if (imageData == NULL) {
-                ERROR("Not a volume data set");
-                return;
-            }
-            imageData->GetDimensions(dims);
-        }
-        int voi[6];
-
-        switch (axis) {
-        case X_AXIS:
-            voi[0] = voi[1] = (int)((dims[0]-1) * ratio);
-            voi[2] = 0;
-            voi[3] = dims[1]-1;
-            voi[4] = 0;
-            voi[5] = dims[2]-1;
-            break;
-        case Y_AXIS:
-            voi[0] = 0;
-            voi[1] = dims[0]-1;
-            voi[2] = voi[3] = (int)((dims[1]-1) * ratio);
-            voi[4] = 0;
-            voi[5] = dims[2]-1;
-            break;
-        case Z_AXIS:
-            voi[0] = 0;
-            voi[1] = dims[0]-1;
-            voi[2] = 0;
-            voi[3] = dims[1]-1;
-            voi[4] = voi[5] = (int)((dims[2]-1) * ratio);
-            break;
-        default:
-            ERROR("Invalid Axis");
-            return;
-        }
-
-        _volumeSlicer->SetVOI(voi);
-    }
-
-    if (_dsMapper != NULL)
-        _dsMapper->Update();
-    if (_contourMapper != NULL)
-        _contourMapper->Update();
-}
-
-void HeightMap::updateRanges(Renderer *renderer)
-{
-    TRACE("Enter");
-
-    if (_dataSet == NULL) {
-        ERROR("called before setDataSet");
-        return;
-    }
-
-    if (renderer->getUseCumulativeRange()) {
-        renderer->getCumulativeDataRange(_dataRange,
-                                         _dataSet->getActiveScalarsName(),
-                                         1);
-        const char *activeVectors = _dataSet->getActiveVectorsName();
-        if (activeVectors != NULL) {
-            renderer->getCumulativeDataRange(_vectorMagnitudeRange,
-                                             activeVectors,
-                                             3);
-            for (int i = 0; i < 3; i++) {
-                renderer->getCumulativeDataRange(_vectorComponentRange[i],
-                                                 activeVectors,
-                                                 3, i);
-            }
-        }
-    } else {
-        _dataSet->getScalarRange(_dataRange);
-        _dataSet->getVectorRange(_vectorMagnitudeRange);
-        for (int i = 0; i < 3; i++) {
-            _dataSet->getVectorRange(_vectorComponentRange[i], i);
-        }
-    }
- 
-    // Need to update color map ranges
-    double *rangePtr = _colorFieldRange;
-    if (_colorFieldRange[0] > _colorFieldRange[1]) {
-        rangePtr = NULL;
-    }
-    setColorMode(_colorMode, _colorFieldType, _colorFieldName.c_str(), rangePtr);
-
-    if ((_contours.empty() && _numContours > 0) ||
-        _warpScale > 0.0) {
-        // Contour isovalues and/or warp need to be recomputed
-        update();
-    }
-
-    TRACE("Leave");
-}
-
-void HeightMap::setContourLineColorMapEnabled(bool mode)
-{
-    _contourColorMap = mode;
-
-    double *rangePtr = _colorFieldRange;
-    if (_colorFieldRange[0] > _colorFieldRange[1]) {
-        rangePtr = NULL;
-    }
-    setColorMode(_colorMode, _colorFieldType, _colorFieldName.c_str(), rangePtr);
-}
-
-void HeightMap::setColorMode(ColorMode mode)
-{
-    _colorMode = mode;
-    if (_dataSet == NULL)
-        return;
-
-    switch (mode) {
-    case COLOR_BY_SCALAR:
-        setColorMode(mode,
-                     _dataSet->getActiveScalarsType(),
-                     _dataSet->getActiveScalarsName(),
-                     _dataRange);
-        break;
-    case COLOR_BY_VECTOR_MAGNITUDE:
-        setColorMode(mode,
-                     _dataSet->getActiveVectorsType(),
-                     _dataSet->getActiveVectorsName(),
-                     _vectorMagnitudeRange);
-        break;
-    case COLOR_BY_VECTOR_X:
-        setColorMode(mode,
-                     _dataSet->getActiveVectorsType(),
-                     _dataSet->getActiveVectorsName(),
-                     _vectorComponentRange[0]);
-        break;
-    case COLOR_BY_VECTOR_Y:
-        setColorMode(mode,
-                     _dataSet->getActiveVectorsType(),
-                     _dataSet->getActiveVectorsName(),
-                     _vectorComponentRange[1]);
-        break;
-    case COLOR_BY_VECTOR_Z:
-        setColorMode(mode,
-                     _dataSet->getActiveVectorsType(),
-                     _dataSet->getActiveVectorsName(),
-                     _vectorComponentRange[2]);
-        break;
-    case COLOR_CONSTANT:
-    default:
-        setColorMode(mode, DataSet::POINT_DATA, NULL, NULL);
-        break;
-    }
-}
-
-void HeightMap::setColorMode(ColorMode mode,
-                             const char *name, double range[2])
-{
-    if (_dataSet == NULL)
-        return;
-    DataSet::DataAttributeType type = DataSet::POINT_DATA;
-    int numComponents = 1;
-    if (name != NULL && strlen(name) > 0 &&
-        !_dataSet->getFieldInfo(name, &type, &numComponents)) {
-        ERROR("Field not found: %s", name);
-        return;
-    }
-    setColorMode(mode, type, name, range);
-}
-
-void HeightMap::setColorMode(ColorMode mode, DataSet::DataAttributeType type,
-                             const char *name, double range[2])
-{
-    _colorMode = mode;
-    _colorFieldType = type;
-    if (name == NULL)
-        _colorFieldName.clear();
-    else
-        _colorFieldName = name;
-    if (range == NULL) {
-        _colorFieldRange[0] = DBL_MAX;
-        _colorFieldRange[1] = -DBL_MAX;
-    } else {
-        memcpy(_colorFieldRange, range, sizeof(double)*2);
-    }
-
-    if (_dataSet == NULL || _dsMapper == NULL)
-        return;
-
-    switch (type) {
-    case DataSet::POINT_DATA:
-        _dsMapper->SetScalarModeToUsePointFieldData();
-        _contourMapper->SetScalarModeToUsePointFieldData();
-        break;
-    case DataSet::CELL_DATA:
-        _dsMapper->SetScalarModeToUseCellFieldData();
-        _contourMapper->SetScalarModeToUseCellFieldData();
-        break;
-    default:
-        ERROR("Unsupported DataAttributeType: %d", type);
-        return;
-    }
-
-    if (name != NULL && strlen(name) > 0) {
-        _dsMapper->SelectColorArray(name);
-        _contourMapper->SelectColorArray(name);
-    } else {
-        _dsMapper->SetScalarModeToDefault();
-        _contourMapper->SetScalarModeToDefault();
-    }
-
-    if (_lut != NULL) {
-        if (range != NULL) {
-            _lut->SetRange(range);
-            TRACE("range %g, %g", range[0], range[1]);
-        } else if (name != NULL && strlen(name) > 0) {
-            double r[2];
-            int comp = -1;
-            if (mode == COLOR_BY_VECTOR_X)
-                comp = 0;
-            else if (mode == COLOR_BY_VECTOR_Y)
-                comp = 1;
-            else if (mode == COLOR_BY_VECTOR_Z)
-                comp = 2;
-
-            if (_renderer->getUseCumulativeRange()) {
-                int numComponents;
-                if  (!_dataSet->getFieldInfo(name, type, &numComponents)) {
-                    ERROR("Field not found: %s, type: %d", name, type);
-                    return;
-                } else if (numComponents < comp+1) {
-                    ERROR("Request for component %d in field with %d components",
-                          comp, numComponents);
-                    return;
-                }
-                _renderer->getCumulativeDataRange(r, name, type, numComponents, comp);
-            } else {
-                _dataSet->getDataRange(r, name, type, comp);
-            }
-            _lut->SetRange(r);
-            TRACE("%s range %g, %g", name, r[0], r[1]);
-        }
-        _lut->Modified();
-    }
-
-    if (_contourColorMap) {
-        _contourMapper->ScalarVisibilityOn();
-    } else {
-        _contourMapper->ScalarVisibilityOff();
-    }
-
-    switch (mode) {
-    case COLOR_BY_SCALAR:
-        _dsMapper->ScalarVisibilityOn();
-        break;
-    case COLOR_BY_VECTOR_MAGNITUDE:
-        _dsMapper->ScalarVisibilityOn();
-        if (_lut != NULL) {
-            _lut->SetVectorModeToMagnitude();
-        }
-        break;
-    case COLOR_BY_VECTOR_X:
-        _dsMapper->ScalarVisibilityOn();
-        if (_lut != NULL) {
-            _lut->SetVectorModeToComponent();
-            _lut->SetVectorComponent(0);
-        }
-        break;
-    case COLOR_BY_VECTOR_Y:
-        _dsMapper->ScalarVisibilityOn();
-        if (_lut != NULL) {
-            _lut->SetVectorModeToComponent();
-            _lut->SetVectorComponent(1);
-        }
-        break;
-    case COLOR_BY_VECTOR_Z:
-        _dsMapper->ScalarVisibilityOn();
-        if (_lut != NULL) {
-            _lut->SetVectorModeToComponent();
-            _lut->SetVectorComponent(2);
-        }
-        break;
-    case COLOR_CONSTANT:
-    default:
-        _dsMapper->ScalarVisibilityOff();
-        break;
-    }
-}
-
-/**
- * \brief Called when the color map has been edited
- */
-void HeightMap::updateColorMap()
-{
-    setColorMap(_colorMap);
-}
-
-/**
- * \brief Associate a colormap lookup table with the DataSet
- */
-void HeightMap::setColorMap(ColorMap *cmap)
-{
-    if (cmap == NULL)
-        return;
-
-    _colorMap = cmap;
-
-    if (_lut == NULL) {
-        _lut = vtkSmartPointer<vtkLookupTable>::New();
-        if (_dsMapper != NULL) {
-            _dsMapper->UseLookupTableScalarRangeOn();
-            _dsMapper->SetLookupTable(_lut);
-        }
-        if (_contourMapper != NULL) {
-            _contourMapper->UseLookupTableScalarRangeOn();
-            _contourMapper->SetLookupTable(_lut);
-        }
-        _lut->DeepCopy(cmap->getLookupTable());
-        switch (_colorMode) {
-        case COLOR_CONSTANT:
-        case COLOR_BY_SCALAR:
-            _lut->SetRange(_dataRange);
-            break;
-        case COLOR_BY_VECTOR_MAGNITUDE:
-            _lut->SetRange(_vectorMagnitudeRange);
-            break;
-        case COLOR_BY_VECTOR_X:
-            _lut->SetRange(_vectorComponentRange[0]);
-            break;
-        case COLOR_BY_VECTOR_Y:
-            _lut->SetRange(_vectorComponentRange[1]);
-            break;
-        case COLOR_BY_VECTOR_Z:
-            _lut->SetRange(_vectorComponentRange[2]);
-            break;
-        default:
-            break;
-        }
-    } else {
-        double range[2];
-        _lut->GetTableRange(range);
-        _lut->DeepCopy(cmap->getLookupTable());
-        _lut->SetRange(range);
-        _lut->Modified();
-    }
-
-    switch (_colorMode) {
-    case COLOR_BY_VECTOR_MAGNITUDE:
-        _lut->SetVectorModeToMagnitude();
-        break;
-    case COLOR_BY_VECTOR_X:
-        _lut->SetVectorModeToComponent();
-        _lut->SetVectorComponent(0);
-        break;
-    case COLOR_BY_VECTOR_Y:
-        _lut->SetVectorModeToComponent();
-        _lut->SetVectorComponent(1);
-        break;
-    case COLOR_BY_VECTOR_Z:
-        _lut->SetVectorModeToComponent();
-        _lut->SetVectorComponent(2);
-        break;
-    default:
-         break;
-    }
-}
-
-/**
- * \brief Specify number of evenly spaced contour lines to render
- *
- * Will override any existing contours
- */
-void HeightMap::setNumContours(int numContours)
-{
-    _contours.clear();
-    _numContours = numContours;
-
-    update();
-}
-
-/**
- * \brief Specify an explicit list of contour isovalues
- *
- * Will override any existing contours
- */
-void HeightMap::setContourList(const std::vector<double>& contours)
-{
-    _contours = contours;
-    _numContours = (int)_contours.size();
-
-    update();
-}
-
-/**
- * \brief Get the number of contours
- */
-int HeightMap::getNumContours() const
-{
-    return _numContours;
-}
-
-/**
- * \brief Get the contour list (may be empty if number of contours
- * was specified in place of a list)
- */
-const std::vector<double>& HeightMap::getContourList() const
-{
-    return _contours;
-}
-
-/**
- * \brief Turn on/off lighting of this object
- */
-void HeightMap::setLighting(bool state)
-{
-    _lighting = state;
-    if (_dsActor != NULL)
-        _dsActor->GetProperty()->SetLighting((state ? 1 : 0));
-}
-
-/**
- * \brief Turn on/off rendering of mesh edges
- */
-void HeightMap::setEdgeVisibility(bool state)
-{
-    if (_dsActor != NULL) {
-        _dsActor->GetProperty()->SetEdgeVisibility((state ? 1 : 0));
-    }
-}
-
-/**
- * \brief Turn on/off rendering of colormaped surface
- */
-void HeightMap::setContourSurfaceVisibility(bool state)
-{
-    if (_dsActor != NULL) {
-        _dsActor->SetVisibility((state ? 1 : 0));
-    }
-}
-
-/**
- * \brief Turn on/off rendering of contour isolines
- */
-void HeightMap::setContourLineVisibility(bool state)
-{
-    if (_contourActor != NULL) {
-        _contourActor->SetVisibility((state ? 1 : 0));
-    }
-}
-
-/**
- * \brief Set RGB color of mesh
- */
-void HeightMap::setColor(float color[3])
-{
-    _color[0] = color[0];
-    _color[1] = color[1];
-    _color[2] = color[2];
-    if (_dsActor != NULL)
-        _dsActor->GetProperty()->SetColor(_color[0], _color[1], _color[2]);
-}
-
-/**
- * \brief Set RGB color of polygon edges
- */
-void HeightMap::setEdgeColor(float color[3])
-{
-    _edgeColor[0] = color[0];
-    _edgeColor[1] = color[1];
-    _edgeColor[2] = color[2];
-    if (_dsActor != NULL)
-        _dsActor->GetProperty()->SetEdgeColor(_edgeColor[0], _edgeColor[1], _edgeColor[2]);
-}
-
-/**
- * \brief Set pixel width of polygon edges (may be a no-op)
- */
-void HeightMap::setEdgeWidth(float edgeWidth)
-{
-    _edgeWidth = edgeWidth;
-    if (_dsActor != NULL)
-        _dsActor->GetProperty()->SetLineWidth(_edgeWidth);
-}
-
-/**
- * \brief Set RGB color of contour isolines
- */
-void HeightMap::setContourEdgeColor(float color[3])
-{
-    _contourEdgeColor[0] = color[0];
-    _contourEdgeColor[1] = color[1];
-    _contourEdgeColor[2] = color[2];
-    if (_contourActor != NULL) {
-        _contourActor->GetProperty()->SetColor(_contourEdgeColor[0],
-                                               _contourEdgeColor[1],
-                                               _contourEdgeColor[2]);
-        _contourActor->GetProperty()->SetEdgeColor(_contourEdgeColor[0],
-                                                   _contourEdgeColor[1],
-                                                   _contourEdgeColor[2]);
-    }
-}
-
-/**
- * \brief Set pixel width of contour isolines (may be a no-op)
- */
-void HeightMap::setContourEdgeWidth(float edgeWidth)
-{
-    _contourEdgeWidth = edgeWidth;
-    if (_contourActor != NULL)
-        _contourActor->GetProperty()->SetLineWidth(_contourEdgeWidth);
-}
-
-/**
- * \brief Set a group of world coordinate planes to clip rendering
- *
- * Passing NULL for planes will remove all cliping planes
- */
-void HeightMap::setClippingPlanes(vtkPlaneCollection *planes)
-{
-    if (_dsMapper != NULL) {
-        _dsMapper->SetClippingPlanes(planes);
-    }
-    if (_contourMapper != NULL) {
-        _contourMapper->SetClippingPlanes(planes);
-    }
-}
-
Index: unk/packages/vizservers/vtkvis/RpHeightMap.h
===================================================================
--- /trunk/packages/vizservers/vtkvis/RpHeightMap.h	(revision 3615)
+++ 	(revision )
@@ -1,173 +1,0 @@
-/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
-/*
- * Copyright (C) 2004-2012  HUBzero Foundation, LLC
- *
- * Author: Leif Delgass <ldelgass@purdue.edu>
- */
-
-#ifndef VTKVIS_HEIGHTMAP_H
-#define VTKVIS_HEIGHTMAP_H
-
-#include <vtkSmartPointer.h>
-#include <vtkAlgorithmOutput.h>
-#include <vtkContourFilter.h>
-#include <vtkLookupTable.h>
-#include <vtkDataSetMapper.h>
-#include <vtkActor.h>
-#include <vtkPlaneCollection.h>
-#include <vtkGaussianSplatter.h>
-#include <vtkExtractVOI.h>
-#include <vtkWarpScalar.h>
-#include <vtkPolyDataNormals.h>
-#include <vtkAssembly.h>
-#include <vtkPolyData.h>
-#include <vtkPlane.h>
-
-#include <vector>
-
-#include "ColorMap.h"
-#include "RpTypes.h"
-#include "RpVtkGraphicsObject.h"
-
-namespace VtkVis {
-
-/**
- * \brief Color-mapped plot of data set
- */
-class HeightMap : public VtkGraphicsObject {
-public:
-    enum ColorMode {
-        COLOR_BY_SCALAR,
-        COLOR_BY_VECTOR_MAGNITUDE,
-        COLOR_BY_VECTOR_X,
-        COLOR_BY_VECTOR_Y,
-        COLOR_BY_VECTOR_Z,
-        COLOR_CONSTANT
-    };
-
-    HeightMap(int numContours, double heightScale = 1.0);
-
-    HeightMap(const std::vector<double>& contours, double heightScale = 1.0);
-
-    virtual ~HeightMap();
-
-    virtual const char *getClassName() const
-    {
-        return "HeightMap";
-    }
-
-    virtual void setDataSet(DataSet *dataSet,
-                            Renderer *renderer);
-
-    virtual void setLighting(bool state);
-
-    virtual void setColor(float color[3]);
-
-    virtual void setEdgeVisibility(bool state);
-
-    virtual void setEdgeColor(float color[3]);
-
-    virtual void setEdgeWidth(float edgeWidth);
-
-    virtual void setClippingPlanes(vtkPlaneCollection *planes);
-
-    virtual void setAspect(double aspect);
-
-    void selectVolumeSlice(Axis axis, double ratio);
-
-    void setHeightScale(double scale);
-
-    double getHeightScale()
-    {
-        return _warpScale;
-    }
-
-    void setInterpolateBeforeMapping(bool state);
-
-    void setNumContours(int numContours);
-
-    void setContourList(const std::vector<double>& contours);
-
-    int getNumContours() const;
-
-    const std::vector<double>& getContourList() const;
-
-    void setContourLineColorMapEnabled(bool mode);
-
-    void setColorMode(ColorMode mode, DataSet::DataAttributeType type,
-                      const char *name, double range[2] = NULL);
-
-    void setColorMode(ColorMode mode,
-                      const char *name, double range[2] = NULL);
-
-    void setColorMode(ColorMode mode);
-
-    void setColorMap(ColorMap *colorMap);
-
-    /**
-     * \brief Return the ColorMap in use
-     */
-    ColorMap *getColorMap()
-    {
-        return _colorMap;
-    }
-
-    void updateColorMap();
-
-    virtual void updateRanges(Renderer *renderer);
-
-    void setContourLineVisibility(bool state);
-
-    void setContourSurfaceVisibility(bool state);
-
-    void setContourEdgeColor(float color[3]);
-
-    void setContourEdgeWidth(float edgeWidth);
-
-private:
-    HeightMap();
-
-    virtual void initProp();
-    virtual void update();
-
-    void computeDataScale();
-
-    vtkAlgorithmOutput *initWarp(vtkAlgorithmOutput *input);
-    vtkAlgorithmOutput *initWarp(vtkPolyData *input);
-
-    int _numContours;
-    std::vector<double> _contours;
-
-    bool _contourColorMap;
-    float _contourEdgeColor[3];
-    float _contourEdgeWidth;
-    double _warpScale;
-    double _dataScale;
-    Axis _sliceAxis;
-    bool _pipelineInitialized;
-
-    ColorMap *_colorMap;
-    ColorMode _colorMode;
-    std::string _colorFieldName;
-    DataSet::DataAttributeType _colorFieldType;
-    double _colorFieldRange[2];
-    double _vectorMagnitudeRange[2];
-    double _vectorComponentRange[3][2];
-    Renderer *_renderer;
-
-    vtkSmartPointer<vtkLookupTable> _lut;
-    vtkSmartPointer<vtkDataSetMapper> _dsMapper;
-    vtkSmartPointer<vtkContourFilter> _contourFilter;
-    vtkSmartPointer<vtkPolyDataMapper> _contourMapper;
-    vtkSmartPointer<vtkGaussianSplatter> _pointSplatter;
-    vtkSmartPointer<vtkExtractVOI> _volumeSlicer;
-    vtkSmartPointer<vtkPlane> _cutPlane;
-    vtkSmartPointer<vtkWarpScalar> _warp;
-    vtkSmartPointer<vtkPolyDataNormals> _normalsGenerator;
-    vtkSmartPointer<vtkActor> _dsActor;
-    vtkSmartPointer<vtkActor> _contourActor;
-};
-
-}
-
-#endif
Index: unk/packages/vizservers/vtkvis/RpLIC.cpp
===================================================================
--- /trunk/packages/vizservers/vtkvis/RpLIC.cpp	(revision 3615)
+++ 	(revision )
@@ -1,460 +1,0 @@
-/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
-/*
- * Copyright (C) 2004-2012  HUBzero Foundation, LLC
- *
- * Author: Leif Delgass <ldelgass@purdue.edu>
- */
-
-#include <cassert>
-
-#include <vtkActor.h>
-#include <vtkProperty.h>
-#include <vtkPointData.h>
-#include <vtkCellData.h>
-#include <vtkCellDataToPointData.h>
-#include <vtkImageData.h>
-#include <vtkPolyData.h>
-#include <vtkDataSetMapper.h>
-#include <vtkPainterPolyDataMapper.h>
-#include <vtkDataSetSurfaceFilter.h>
-#include <vtkCutter.h>
-#include <vtkImageMask.h>
-#include <vtkImageCast.h>
-
-#include "RpLIC.h"
-#include "Trace.h"
-
-using namespace VtkVis;
-
-LIC::LIC() :
-    VtkGraphicsObject(),
-    _sliceAxis(Z_AXIS),
-    _colorMap(NULL)
-{
-}
-
-LIC::~LIC()
-{
-#ifdef WANT_TRACE
-    if (_dataSet != NULL)
-        TRACE("Deleting LIC for %s", _dataSet->getName().c_str());
-    else
-        TRACE("Deleting LIC with NULL DataSet");
-#endif
-}
-
-void LIC::initProp()
-{
-    if (_prop == NULL) {
-        _prop = vtkSmartPointer<vtkActor>::New();
-        vtkProperty *property = getActor()->GetProperty();
-        property->SetOpacity(_opacity);
-        property->SetEdgeColor(_edgeColor[0], _edgeColor[1], _edgeColor[2]);
-        property->SetLineWidth(_edgeWidth);
-        property->EdgeVisibilityOff();
-        property->SetAmbient(.2);
-        if (!_lighting)
-            property->LightingOff();
-    }
-}
-
-void LIC::update()
-{
-    if (_dataSet == NULL)
-        return;
-
-    vtkDataSet *ds = _dataSet->getVtkDataSet();
-
-    vtkSmartPointer<vtkCellDataToPointData> cellToPtData;
-    if (ds->GetPointData() == NULL ||
-        ds->GetPointData()->GetVectors() == NULL) {
-         TRACE("No vector point data in dataset %s", _dataSet->getName().c_str());
-         if (ds->GetCellData() != NULL &&
-             ds->GetCellData()->GetVectors() != NULL) {
-             cellToPtData = 
-                 vtkSmartPointer<vtkCellDataToPointData>::New();
-#ifdef USE_VTK6
-             cellToPtData->SetInputData(ds);
-#else
-             cellToPtData->SetInput(ds);
-#endif
-             //cellToPtData->PassCellDataOn();
-             cellToPtData->Update();
-             ds = cellToPtData->GetOutput();
-         } else {
-             USER_ERROR("No vector field was found in the data set");
-             return;
-         }
-    }
-
-    vtkImageData *imageData = vtkImageData::SafeDownCast(ds);
-    if (imageData != NULL) {
-        if (_lic == NULL) {
-            _lic = vtkSmartPointer<vtkImageDataLIC2D>::New();
-        }
-        if (!_dataSet->is2D()) {
-            // 3D image/volume/uniform grid
-            if (_volumeSlicer == NULL)
-                _volumeSlicer = vtkSmartPointer<vtkExtractVOI>::New();
-            int dims[3];
-            imageData->GetDimensions(dims);
-            TRACE("Image data dimensions: %d %d %d", dims[0], dims[1], dims[2]);
-#ifdef USE_VTK6
-            _volumeSlicer->SetInputData(ds);
-#else
-            _volumeSlicer->SetInput(ds);
-#endif
-            _volumeSlicer->SetVOI(0, dims[0]-1, 0, dims[1]-1, (dims[2]-1)/2, (dims[2]-1)/2);
-            _volumeSlicer->SetSampleRate(1, 1, 1);
-            _lic->SetInputConnection(_volumeSlicer->GetOutputPort());
-        } else {
-            // 2D image/volume/uniform grid
-#ifdef USE_VTK6
-            _lic->SetInputData(ds);
-#else
-            _lic->SetInput(ds);
-#endif
-        }
-        if (_mapper == NULL) {
-            _mapper = vtkSmartPointer<vtkDataSetMapper>::New();
-        }
-        _mapper->SetInputConnection(_lic->GetOutputPort());
-    } else if (vtkPolyData::SafeDownCast(ds) == NULL) {
-        // structured grid, unstructured grid, or rectilinear grid
-        if (_lic == NULL) {
-            _lic = vtkSmartPointer<vtkImageDataLIC2D>::New();
-        }
-
-        // Need to convert to vtkImageData
-        double bounds[6];
-        ds->GetBounds(bounds);
-        double xSize = bounds[1] - bounds[0];
-        double ySize = bounds[3] - bounds[2];
-        double zSize = bounds[5] - bounds[4];
-        int minDir = 2;
-        if (xSize < ySize && xSize < zSize)
-            minDir = 0;
-        if (ySize < xSize && ySize < zSize)
-            minDir = 1;
-        if (_probeFilter == NULL)
-            _probeFilter = vtkSmartPointer<vtkProbeFilter>::New();
-
-        if (!_dataSet->is2D()) {
-            // Sample a plane within the grid bounding box
-            vtkSmartPointer<vtkCutter> cutter = vtkSmartPointer<vtkCutter>::New();
-            if (_cutPlane == NULL) {
-                _cutPlane = vtkSmartPointer<vtkPlane>::New();
-            }
-            if (minDir == 0) {
-                _cutPlane->SetNormal(1, 0, 0);
-                _cutPlane->SetOrigin(bounds[0] + (bounds[1]-bounds[0])/2.,
-                                     0,
-                                     0);
-            } else if (minDir == 1) {
-                _cutPlane->SetNormal(0, 1, 0);
-                _cutPlane->SetOrigin(0,
-                                     bounds[2] + (bounds[3]-bounds[2])/2.,
-                                     0);
-            } else {
-                _cutPlane->SetNormal(0, 0, 1);
-                _cutPlane->SetOrigin(0,
-                                     0,
-                                     bounds[4] + (bounds[5]-bounds[4])/2.);
-            }
-#ifdef USE_VTK6
-            cutter->SetInputData(ds);
-#else
-            cutter->SetInput(ds);
-#endif
-            cutter->SetCutFunction(_cutPlane);
-            _probeFilter->SetSourceConnection(cutter->GetOutputPort());
-        } else {
-#ifdef USE_VTK6
-            _probeFilter->SetSourceData(ds);
-#else
-            _probeFilter->SetSource(ds);
-#endif
-        }
-
-        vtkSmartPointer<vtkImageData> imageData = vtkSmartPointer<vtkImageData>::New();
-        int xdim, ydim, zdim;
-        double origin[3], spacing[3];
-        if (minDir == 0) {
-            xdim = 1;
-            ydim = 128;
-            zdim = 128;
-            origin[0] = bounds[0] + xSize/2.;
-            origin[1] = bounds[2];
-            origin[2] = bounds[4];
-            spacing[0] = 0;
-            spacing[1] = ySize/((double)(ydim-1));
-            spacing[2] = zSize/((double)(zdim-1));
-            _sliceAxis = X_AXIS;
-        } else if (minDir == 1) {
-            xdim = 128;
-            ydim = 1;
-            zdim = 128;
-            origin[0] = bounds[0];
-            origin[1] = bounds[2] + ySize/2.;
-            origin[2] = bounds[4];
-            spacing[0] = xSize/((double)(xdim-1));
-            spacing[1] = 0;
-            spacing[2] = zSize/((double)(zdim-1));
-            _sliceAxis = Y_AXIS;
-        } else {
-            xdim = 128;
-            ydim = 128;
-            zdim = 1;
-            origin[0] = bounds[0];
-            origin[1] = bounds[2];
-            origin[2] = bounds[4] + zSize/2.;
-            spacing[0] = xSize/((double)(xdim-1));
-            spacing[1] = ySize/((double)(ydim-1));
-            spacing[2] = 0;
-            _sliceAxis = Z_AXIS;
-        }
-        imageData->SetDimensions(xdim, ydim, zdim);
-        imageData->SetOrigin(origin);
-        imageData->SetSpacing(spacing);
-#ifdef USE_VTK6
-        _probeFilter->SetInputData(imageData);
-#else
-        _probeFilter->SetInput(imageData);
-#endif
-        _lic->SetInputConnection(_probeFilter->GetOutputPort());
-
-        if (_mapper == NULL) {
-            _mapper = vtkSmartPointer<vtkDataSetMapper>::New();
-            _mapper->SetColorModeToMapScalars();
-        }
-        _lic->Update();
-        vtkSmartPointer<vtkImageCast> cast = vtkSmartPointer<vtkImageCast>::New();
-        cast->SetInputConnection(_probeFilter->GetOutputPort());
-        cast->SetInputArrayToProcess(0, 0, 0, vtkDataObject::FIELD_ASSOCIATION_POINTS,
-                                     _probeFilter->GetValidPointMaskArrayName());
-        cast->SetOutputScalarTypeToUnsignedChar();
-        vtkSmartPointer<vtkImageMask> mask = vtkSmartPointer<vtkImageMask>::New();
-        mask->SetInputConnection(0, _lic->GetOutputPort());
-        mask->SetInputConnection(1, cast->GetOutputPort());
-        _mapper->SetInputConnection(mask->GetOutputPort());
-    } else {
-        // DataSet is a PolyData
-        vtkPolyData *pd = vtkPolyData::SafeDownCast(ds);
-        assert(pd != NULL);
-
-        // XXX: This mapper seems to conflict with offscreen rendering, so the main
-        // renderer needs to be set not to use FBOs for this to work
-        _mapper = vtkSmartPointer<vtkPainterPolyDataMapper>::New();
-        vtkPainterPolyDataMapper *ppdmapper = vtkPainterPolyDataMapper::SafeDownCast(_mapper);
-        if (_painter == NULL) {
-            _painter = vtkSmartPointer<vtkSurfaceLICPainter>::New();
-            _painter->SetDelegatePainter(ppdmapper->GetPainter());
-         }
-        ppdmapper->SetPainter(_painter);
-#ifdef USE_VTK6
-        ppdmapper->SetInputData(pd);
-#else
-        ppdmapper->SetInput(pd);
-#endif
-    }
-
-    setInterpolateBeforeMapping(true);
-
-    if (_lut == NULL) {
-        setColorMap(ColorMap::getGrayDefault());
-    }
-
-    initProp();
-    getActor()->SetMapper(_mapper);
-
-    _mapper->Update();
-#ifdef WANT_TRACE
-    if (_lic != NULL) {
-        TRACE("FBO status: %d LIC status: %d", _lic->GetFBOSuccess(), _lic->GetLICSuccess());
-    } else if (_painter != NULL) {
-        TRACE("LIC status: %d", _painter->GetLICSuccess());
-    }
-#endif
-}
-
-void LIC::setInterpolateBeforeMapping(bool state)
-{
-    if (_mapper != NULL) {
-        _mapper->SetInterpolateScalarsBeforeMapping((state ? 1 : 0));
-    }
-}
-
-/**
- * \brief Select a 2D slice plane from a 3D DataSet
- *
- * \param[in] axis Axis of slice plane
- * \param[in] ratio Position [0,1] of slice plane along axis
- */
-void LIC::selectVolumeSlice(Axis axis, double ratio)
-{
-    if (_dataSet->is2D()) {
-        WARN("DataSet not 3D, returning");
-        return;
-    }
-
-    if (_volumeSlicer == NULL &&
-        _probeFilter == NULL) {
-        WARN("Called before update() or DataSet is not a volume");
-        return;
-    }
-
-    int dims[3];
-
-    vtkImageData *imageData = vtkImageData::SafeDownCast(_dataSet->getVtkDataSet());
-    if (imageData == NULL) {
-        if (_probeFilter != NULL) {
-            imageData = vtkImageData::SafeDownCast(_probeFilter->GetInput());
-            if (imageData == NULL) {
-                ERROR("Couldn't get probe filter input image");
-                return;
-            }
-        } else {
-            ERROR("Not a volume data set");
-            return;
-        }
-    }
-    imageData->GetDimensions(dims);
-
-    _sliceAxis = axis;
-
-    if (_probeFilter != NULL) {
-        vtkImageData *imageData = vtkImageData::SafeDownCast(_probeFilter->GetInput());
-        double bounds[6];
-        assert(vtkDataSet::SafeDownCast(_probeFilter->GetSource()) != NULL);
-        _dataSet->getBounds(bounds);
-        int dim = 128;
-
-        switch (axis) {
-        case X_AXIS:
-            imageData->SetDimensions(1, dim, dim);
-            imageData->SetOrigin(bounds[0] + (bounds[1]-bounds[0])*ratio, bounds[2], bounds[4]);
-            imageData->SetSpacing(0,
-                                  (bounds[3]-bounds[2])/((double)(dim-1)), 
-                                  (bounds[5]-bounds[4])/((double)(dim-1)));
-            if (_cutPlane != NULL) {
-                _cutPlane->SetNormal(1, 0, 0);
-                _cutPlane->SetOrigin(bounds[0] + (bounds[1]-bounds[0])*ratio, 0, 0);
-            }
-            break;
-        case Y_AXIS:
-            imageData->SetDimensions(dim, 1, dim);
-            imageData->SetOrigin(bounds[0], bounds[2] + (bounds[3]-bounds[2])*ratio, bounds[4]);
-            imageData->SetSpacing((bounds[1]-bounds[0])/((double)(dim-1)), 
-                                  0,
-                                  (bounds[5]-bounds[4])/((double)(dim-1)));
-            if (_cutPlane != NULL) {
-                _cutPlane->SetNormal(0, 1, 0);
-                _cutPlane->SetOrigin(0, bounds[2] + (bounds[3]-bounds[2])*ratio, 0);
-            }
-            break;
-        case Z_AXIS:
-            imageData->SetDimensions(dim, dim, 1);
-            imageData->SetOrigin(bounds[0], bounds[2], bounds[4] + (bounds[5]-bounds[4])*ratio);
-            imageData->SetSpacing((bounds[1]-bounds[0])/((double)(dim-1)), 
-                                  (bounds[3]-bounds[2])/((double)(dim-1)),
-                                  0);
-            if (_cutPlane != NULL) {
-                _cutPlane->SetNormal(0, 0, 1);
-                _cutPlane->SetOrigin(0, 0, bounds[4] + (bounds[5]-bounds[4])*ratio);
-            }
-            break;
-        default:
-            ERROR("Invalid Axis");
-            return;
-        }
-    } else {
-        int voi[6];
-
-        switch (axis) {
-        case X_AXIS:
-            voi[0] = voi[1] = (int)((dims[0]-1) * ratio);
-            voi[2] = 0;
-            voi[3] = dims[1]-1;
-            voi[4] = 0;
-            voi[5] = dims[2]-1;
-            break;
-        case Y_AXIS:
-            voi[2] = voi[3] = (int)((dims[1]-1) * ratio);
-            voi[0] = 0;
-            voi[1] = dims[0]-1;
-            voi[4] = 0;
-            voi[5] = dims[2]-1;
-            break;
-        case Z_AXIS:
-            voi[4] = voi[5] = (int)((dims[2]-1) * ratio);
-            voi[0] = 0;
-            voi[1] = dims[0]-1;
-            voi[2] = 0;
-            voi[3] = dims[1]-1;
-            break;
-        default:
-            ERROR("Invalid Axis");
-            return;
-        }
-
-        _volumeSlicer->SetVOI(voi);
-    }
-
-    if (_lic != NULL)
-        _lic->Update();
-
-    if (_mapper != NULL)
-        _mapper->Update();
-}
-
-/**
- * \brief Called when the color map has been edited
- */
-void LIC::updateColorMap()
-{
-    setColorMap(_colorMap);
-}
-
-/**
- * \brief Associate a colormap lookup table with the DataSet
- */
-void LIC::setColorMap(ColorMap *cmap)
-{
-    if (cmap == NULL)
-        return;
-
-    _colorMap = cmap;
- 
-    if (_lut == NULL) {
-        _lut = vtkSmartPointer<vtkLookupTable>::New();
-        if (_mapper != NULL) {
-            _mapper->UseLookupTableScalarRangeOff();
-            _mapper->SetLookupTable(_lut);
-        }
-    }
-
-    _lut->DeepCopy(cmap->getLookupTable());
-    _lut->SetRange(_dataRange);
-    _lut->Modified();
-}
-
-void LIC::updateRanges(Renderer *renderer)
-{
-    VtkGraphicsObject::updateRanges(renderer);
-
-    if (_lut != NULL) {
-        _lut->SetRange(_dataRange);
-    }
-}
-
-/**
- * \brief Set a group of world coordinate planes to clip rendering
- *
- * Passing NULL for planes will remove all cliping planes
- */
-void LIC::setClippingPlanes(vtkPlaneCollection *planes)
-{
-    if (_mapper != NULL) {
-        _mapper->SetClippingPlanes(planes);
-    }
-}
Index: unk/packages/vizservers/vtkvis/RpLIC.h
===================================================================
--- /trunk/packages/vizservers/vtkvis/RpLIC.h	(revision 3615)
+++ 	(revision )
@@ -1,81 +1,0 @@
-/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
-/*
- * Copyright (C) 2004-2012  HUBzero Foundation, LLC
- *
- * Author: Leif Delgass <ldelgass@purdue.edu>
- */
-
-#ifndef VTKVIS_LIC_H
-#define VTKVIS_LIC_H
-
-#include <vtkSmartPointer.h>
-#include <vtkProp.h>
-#include <vtkPlaneCollection.h>
-#include <vtkExtractVOI.h>
-#include <vtkProbeFilter.h>
-#include <vtkImageDataLIC2D.h>
-#include <vtkSurfaceLICPainter.h>
-#include <vtkMapper.h>
-#include <vtkLookupTable.h>
-#include <vtkPlane.h>
-
-#include "ColorMap.h"
-#include "RpTypes.h"
-#include "RpVtkGraphicsObject.h"
-
-namespace VtkVis {
-
-/**
- * \brief Line Integral Convolution visualization of vector fields
- *
- *  The DataSet must contain vectors
- */
-class LIC : public VtkGraphicsObject {
-public:
-    LIC();
-    virtual ~LIC();
-
-    virtual const char *getClassName() const
-    {
-        return "LIC";
-    }
-    
-    virtual void setClippingPlanes(vtkPlaneCollection *planes);
-
-    void selectVolumeSlice(Axis axis, double ratio);
-
-    void setInterpolateBeforeMapping(bool state);
-
-    void setColorMap(ColorMap *colorMap);
-
-    /**
-     * \brief Return the ColorMap in use
-     */
-    ColorMap *getColorMap()
-    {
-        return _colorMap;
-    }
-
-    void updateColorMap();
-
-    virtual void updateRanges(Renderer *renderer);
-
-private:
-    virtual void initProp();
-    virtual void update();
-
-    Axis _sliceAxis;
-    ColorMap *_colorMap;
-
-    vtkSmartPointer<vtkLookupTable> _lut;
-    vtkSmartPointer<vtkExtractVOI> _volumeSlicer;
-    vtkSmartPointer<vtkProbeFilter> _probeFilter;
-    vtkSmartPointer<vtkPlane> _cutPlane;
-    vtkSmartPointer<vtkImageDataLIC2D> _lic;
-    vtkSmartPointer<vtkSurfaceLICPainter> _painter;
-    vtkSmartPointer<vtkMapper> _mapper;
-};
-
-}
-
-#endif
Index: unk/packages/vizservers/vtkvis/RpLine.cpp
===================================================================
--- /trunk/packages/vizservers/vtkvis/RpLine.cpp	(revision 3615)
+++ 	(revision )
@@ -1,45 +1,0 @@
-/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
-/*
- * Copyright (C) 2004-2012  HUBzero Foundation, LLC
- *
- * Author: Leif Delgass <ldelgass@purdue.edu>
- */
-
-#include <vtkPolyDataMapper.h>
-#include <vtkActor.h>
-#include <vtkLineSource.h>
-
-#include "RpLine.h"
-#include "Trace.h"
-
-using namespace VtkVis;
-
-Line::Line() :
-    Shape()
-{
-}
-
-Line::~Line()
-{
-    TRACE("Deleting Line");
-}
-
-void Line::update()
-{
-    if (_line == NULL) {
-	_line = vtkSmartPointer<vtkLineSource>::New();
-    }
-
-    if (_pdMapper == NULL) {
-        _pdMapper = vtkSmartPointer<vtkPolyDataMapper>::New();
-        _pdMapper->SetResolveCoincidentTopologyToPolygonOffset();
-        _pdMapper->ScalarVisibilityOff();
-    }
-
-    _pdMapper->SetInputConnection(_line->GetOutputPort());
-
-    initProp();
-
-    getActor()->SetMapper(_pdMapper);
-    _pdMapper->Update();
-}
Index: unk/packages/vizservers/vtkvis/RpLine.h
===================================================================
--- /trunk/packages/vizservers/vtkvis/RpLine.h	(revision 3615)
+++ 	(revision )
@@ -1,53 +1,0 @@
-/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
-/*
- * Copyright (C) 2004-2012  HUBzero Foundation, LLC
- *
- * Author: Leif Delgass <ldelgass@purdue.edu>
- */
-
-#ifndef VTKVIS_LINE_H
-#define VTKVIS_LINE_H
-
-#include <vtkSmartPointer.h>
-#include <vtkPolyDataMapper.h>
-#include <vtkActor.h>
-#include <vtkLineSource.h>
-
-#include "RpShape.h"
-#include "RpVtkDataSet.h"
-
-namespace VtkVis {
-
-/**
- * \brief VTK PolyData Line
- *
- * This class creates a line
- */
-class Line : public Shape
-{
-public:
-    Line();
-    virtual ~Line();
-
-    virtual const char *getClassName() const
-    {
-        return "Line";
-    }
-
-    void setEndPoints(double pt1[3], double pt2[3])
-    {
-        if (_line != NULL) {
-            _line->SetPoint1(pt1);
-	    _line->SetPoint2(pt2);
-	}
-    }
-
-private:
-    virtual void update();
-
-    vtkSmartPointer<vtkLineSource> _line;
-};
-
-}
-
-#endif
Index: unk/packages/vizservers/vtkvis/RpMath.h
===================================================================
--- /trunk/packages/vizservers/vtkvis/RpMath.h	(revision 3615)
+++ 	(revision )
@@ -1,221 +1,0 @@
-/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
-/*
- * Copyright (C) 2004-2012  HUBzero Foundation, LLC
- *
- * Author: Leif Delgass <ldelgass@purdue.edu>
- */
-
-#ifndef VTKVIS_MATH_H
-#define VTKVIS_MATH_H
-
-#include <cmath>
-#include <cstring>
-
-#include <vtkMath.h>
-#include <vtkMatrix4x4.h>
-
-namespace VtkVis {
-
-/**
- * \brief Convert a quaternion to an axis/angle rotation
- * 
- * \param[in] quat Quaternion with scalar first: wxyz
- * \param[out] angleAxis axis/angle rotation with angle in degrees first
- */
-inline void quatToAngleAxis(const double quat[4], double angleAxis[4])
-{
-    angleAxis[0] = vtkMath::DegreesFromRadians(2.0 * acos(quat[0]));
-    if (angleAxis[0] < 1.0e-6) {
-        angleAxis[1] = 1;
-        angleAxis[2] = 0;
-        angleAxis[3] = 0;
-    } else {
-        double denom = sqrt(1. - quat[0] * quat[0]);
-        angleAxis[1] = quat[1] / denom;
-        angleAxis[2] = quat[2] / denom;
-        angleAxis[3] = quat[3] / denom;
-    }
-}
-
-/**
- * \brief Convert an axis/angle rotation to a quaternion
- * 
- * \param[in] angleAxis axis/angle rotation with angle in degrees first
- * \param[out] quat Quaternion with scalar first: wxyz
- */
-inline void angleAxisToQuat(const double angleAxis[4], double quat[4])
-{
-    quat[0] = cos(vtkMath::RadiansFromDegrees(angleAxis[0]) / 2.0);
-    double sinHalfAngle = sin(vtkMath::RadiansFromDegrees(angleAxis[0]) / 2.0);
-    quat[1] = angleAxis[1] * sinHalfAngle;
-    quat[2] = angleAxis[2] * sinHalfAngle;
-    quat[3] = angleAxis[3] * sinHalfAngle;
-}
-
-/**
- * \brief Fill a vtkMatrix4x4 from a quaternion
- *
- * \param[in] quat Quaternion with scalar first: wxyz
- * \param[out] mat Matrix to be filled in
- */
-inline void quaternionToMatrix4x4(const double quat[4], vtkMatrix4x4& mat)
-{
-    double ww = quat[0]*quat[0];
-    double wx = quat[0]*quat[1];
-    double wy = quat[0]*quat[2];
-    double wz = quat[0]*quat[3];
-
-    double xx = quat[1]*quat[1];
-    double yy = quat[2]*quat[2];
-    double zz = quat[3]*quat[3];
-
-    double xy = quat[1]*quat[2];
-    double xz = quat[1]*quat[3];
-    double yz = quat[2]*quat[3];
-
-    double rr = xx + yy + zz;
-    // normalization factor, just in case quaternion was not normalized
-    double f = double(1)/double(sqrt(ww + rr));
-    double s = (ww - rr)*f;
-    f *= 2;
-
-    mat[0][0] = xx*f + s;
-    mat[1][0] = (xy + wz)*f;
-    mat[2][0] = (xz - wy)*f;
-
-    mat[0][1] = (xy - wz)*f;
-    mat[1][1] = yy*f + s;
-    mat[2][1] = (yz + wx)*f;
-
-    mat[0][2] = (xz + wy)*f;
-    mat[1][2] = (yz - wx)*f;
-    mat[2][2] = zz*f + s;
-}
-
-/**
- * \brief Fill a vtkMatrix4x4 from a quaternion, but with the matrix
- * transposed.
- *
- * \param[in] quat Quaternion with scalar first: wxyz
- * \param[out] mat Matrix to be filled in
- */
-inline void quaternionToTransposeMatrix4x4(const double quat[4], vtkMatrix4x4& mat)
-{
-    double ww = quat[0]*quat[0];
-    double wx = quat[0]*quat[1];
-    double wy = quat[0]*quat[2];
-    double wz = quat[0]*quat[3];
-
-    double xx = quat[1]*quat[1];
-    double yy = quat[2]*quat[2];
-    double zz = quat[3]*quat[3];
-
-    double xy = quat[1]*quat[2];
-    double xz = quat[1]*quat[3];
-    double yz = quat[2]*quat[3];
-
-    double rr = xx + yy + zz;
-    // normalization factor, just in case quaternion was not normalized
-    double f = double(1)/double(sqrt(ww + rr));
-    double s = (ww - rr)*f;
-    f *= 2;
-
-    mat[0][0] = xx*f + s;
-    mat[0][1] = (xy + wz)*f;
-    mat[0][2] = (xz - wy)*f;
-
-    mat[1][0] = (xy - wz)*f;
-    mat[1][1] = yy*f + s;
-    mat[1][2] = (yz + wx)*f;
-
-    mat[2][0] = (xz + wy)*f;
-    mat[2][1] = (yz - wx)*f;
-    mat[2][2] = zz*f + s;
-}
-
-/**
- * \brief Multiply two quaternions and return the result
- *
- * Note: result can be the same memory location as one of the
- * inputs
- */
-inline double *quatMult(const double q1[4], const double q2[4], double result[4])
-{
-    double q1w = q1[0];
-    double q1x = q1[1];
-    double q1y = q1[2];
-    double q1z = q1[3];
-    double q2w = q2[0];
-    double q2x = q2[1];
-    double q2y = q2[2];
-    double q2z = q2[3];
-    result[0] = (q1w*q2w) - (q1x*q2x) - (q1y*q2y) - (q1z*q2z);
-    result[1] = (q1w*q2x) + (q1x*q2w) + (q1y*q2z) - (q1z*q2y);
-    result[2] = (q1w*q2y) + (q1y*q2w) + (q1z*q2x) - (q1x*q2z);
-    result[3] = (q1w*q2z) + (q1z*q2w) + (q1x*q2y) - (q1y*q2x);
-    return result;
-}
-
-/**
- * \brief Compute the conjugate of a quaternion
- *
- * Note: result can be the same memory location as the input
- */
-inline double *quatConjugate(const double quat[4], double result[4])
-{
-    if (result != quat)
-        result[0] = quat[0];
-    result[1] = -quat[1];
-    result[2] = -quat[2];
-    result[3] = -quat[3];
-    return result;
-}
-
-/**
- * \brief Compute the reciprocal of a quaternion
- *
- * Note: result can be the same memory location as the input
- */
-inline double *quatReciprocal(const double quat[4], double result[4])
-{
-    double denom = 
-        quat[0]*quat[0] + 
-        quat[1]*quat[1] + 
-        quat[2]*quat[2] + 
-        quat[3]*quat[3];
-    VtkVis::quatConjugate(quat, result);
-    for (int i = 0; i < 4; i++) {
-        result[i] /= denom;
-    }
-    return result;
-}
-
-/**
- * \brief Compute the reciprocal of a quaternion in place
- */
-inline double *quatReciprocal(double quat[4])
-{
-    return VtkVis::quatReciprocal(quat, quat);
-}
-
-/**
- * \brief Deep copy a quaternion
- */
-inline void copyQuat(const double quat[4], double result[4])
-{
-    memcpy(result, quat, sizeof(double)*4);
-}
-
-inline double min2(double a, double b)
-{
-    return ((a < b) ? a : b);
-}
-
-inline double max2(double a, double b)
-{
-    return ((a > b) ? a : b);
-}
-
-}
-
-#endif
Index: unk/packages/vizservers/vtkvis/RpMolecule.cpp
===================================================================
--- /trunk/packages/vizservers/vtkvis/RpMolecule.cpp	(revision 3615)
+++ 	(revision )
@@ -1,968 +1,0 @@
-/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
-/*
- * Copyright (C) 2004-2012  HUBzero Foundation, LLC
- *
- * Author: Leif Delgass <ldelgass@purdue.edu>
- */
-
-#include <cstdio>
-#include <cfloat>
-#include <cassert>
-
-#include <vtkDataSet.h>
-#include <vtkCellArray.h>
-#include <vtkPointData.h>
-#include <vtkFloatArray.h>
-#include <vtkDoubleArray.h>
-#include <vtkIntArray.h>
-#include <vtkStringArray.h>
-#include <vtkPolyData.h>
-#include <vtkPolyDataMapper.h>
-#include <vtkActor.h>
-#include <vtkProperty.h>
-#include <vtkSphereSource.h>
-#include <vtkCylinderSource.h>
-#include <vtkTransform.h>
-#include <vtkTransformPolyDataFilter.h>
-#include <vtkGlyph3DMapper.h>
-#include <vtkPointSetToLabelHierarchy.h>
-#include <vtkLabelPlacementMapper.h>
-#include <vtkTextProperty.h>
-
-#include "RpMolecule.h"
-#include "RpMoleculeData.h"
-#include "RpVtkRenderer.h"
-#include "Trace.h"
-
-using namespace VtkVis;
-
-Molecule::Molecule() :
-    VtkGraphicsObject(),
-    _radiusScale(0.3),
-    _atomScaling(COVALENT_RADIUS),
-    _labelsOn(false),
-    _colorMap(NULL),
-    _colorMode(COLOR_BY_ELEMENTS),
-    _colorFieldType(DataSet::POINT_DATA)
-{
-    _bondColor[0] = _bondColor[1] = _bondColor[2] = 1.0f;
-    _colorFieldRange[0] = DBL_MAX;
-    _colorFieldRange[1] = -DBL_MAX;
-    _faceCulling = true;
-}
-
-Molecule::~Molecule()
-{
-#ifdef WANT_TRACE
-    if (_dataSet != NULL)
-        TRACE("Deleting Molecule for %s", _dataSet->getName().c_str());
-    else
-        TRACE("Deleting Molecule with NULL DataSet");
-#endif
-}
-
-void Molecule::setDataSet(DataSet *dataSet,
-                          Renderer *renderer)
-{
-    if (_dataSet != dataSet) {
-        _dataSet = dataSet;
-
-        _renderer = renderer;
-
-        if (renderer->getUseCumulativeRange()) {
-            renderer->getCumulativeDataRange(_dataRange,
-                                             _dataSet->getActiveScalarsName(),
-                                             1);
-            renderer->getCumulativeDataRange(_vectorMagnitudeRange,
-                                             _dataSet->getActiveVectorsName(),
-                                             3);
-            for (int i = 0; i < 3; i++) {
-                renderer->getCumulativeDataRange(_vectorComponentRange[i],
-                                                 _dataSet->getActiveVectorsName(),
-                                                 3, i);
-            }
-        } else {
-            _dataSet->getScalarRange(_dataRange);
-            _dataSet->getVectorRange(_vectorMagnitudeRange);
-            for (int i = 0; i < 3; i++) {
-                _dataSet->getVectorRange(_vectorComponentRange[i], i);
-            }
-        }
-
-        update();
-    }
-}
-
-/**
- * \brief Create and initialize VTK Props to render a Molecule
- */
-void Molecule::initProp()
-{
-    if (_atomProp == NULL) {
-        _atomProp = vtkSmartPointer<vtkActor>::New();
-        if (_faceCulling && _opacity == 1.0)
-            setCulling(_atomProp->GetProperty(), true);
-        _atomProp->GetProperty()->EdgeVisibilityOff();
-        _atomProp->GetProperty()->SetEdgeColor(_edgeColor[0], _edgeColor[1], _edgeColor[2]);
-        _atomProp->GetProperty()->SetLineWidth(_edgeWidth);
-        _atomProp->GetProperty()->SetOpacity(_opacity);
-        _atomProp->GetProperty()->SetAmbient(.2);
-        if (!_lighting)
-            _atomProp->GetProperty()->LightingOff();
-    }
-    if (_bondProp == NULL) {
-        _bondProp = vtkSmartPointer<vtkActor>::New();
-        if (_faceCulling && _opacity == 1.0)
-            setCulling(_bondProp->GetProperty(), true);
-        _bondProp->GetProperty()->EdgeVisibilityOff();
-        _bondProp->GetProperty()->SetColor(_bondColor[0], _bondColor[1], _bondColor[2]);
-        _bondProp->GetProperty()->SetEdgeColor(_edgeColor[0], _edgeColor[1], _edgeColor[2]);
-        _bondProp->GetProperty()->SetLineWidth(_edgeWidth);
-        _bondProp->GetProperty()->SetOpacity(_opacity);
-        _bondProp->GetProperty()->SetAmbient(.2);
-        if (!_lighting)
-            _bondProp->GetProperty()->LightingOff();
-    }
-    if (_labelProp == NULL) {
-        _labelProp = vtkSmartPointer<vtkActor2D>::New();
-    }
-    if (_prop == NULL) {
-        _prop = vtkSmartPointer<vtkAssembly>::New();
-    }
-}
-
-/**
- * \brief Internal method to set up pipeline after a state change
- */
-void Molecule::update()
-{
-    if (_dataSet == NULL) {
-        return;
-    }
-    vtkDataSet *ds = _dataSet->getVtkDataSet();
-
-    if (_atomMapper == NULL) {
-        _atomMapper = vtkSmartPointer<vtkGlyph3DMapper>::New();
-        _atomMapper->SetResolveCoincidentTopologyToPolygonOffset();
-        _atomMapper->ScalarVisibilityOn();
-    }
-    if (_bondMapper == NULL) {
-        _bondMapper = vtkSmartPointer<vtkGlyph3DMapper>::New();
-        _bondMapper->SetResolveCoincidentTopologyToPolygonOffset();
-        _bondMapper->ScalarVisibilityOn();
-    }
-    if (_labelMapper == NULL) {
-        _labelMapper = vtkSmartPointer<vtkLabelPlacementMapper>::New();
-        _labelMapper->SetShapeToRoundedRect();
-        _labelMapper->SetBackgroundColor(1.0, 1.0, 0.7);
-        _labelMapper->SetBackgroundOpacity(0.8);
-        _labelMapper->SetMargin(3);
-    }
-
-    if (_lut == NULL) {
-        if (ds->GetPointData() == NULL ||
-            ds->GetPointData()->GetScalars() == NULL ||
-            strcmp(ds->GetPointData()->GetScalars()->GetName(), "element") != 0) {
-            WARN("No element array in dataset %s", _dataSet->getName().c_str());
-            setColorMap(ColorMap::getDefault());
-            if (_atomScaling != NO_ATOM_SCALING)
-                _atomScaling = NO_ATOM_SCALING;
-        } else {
-            TRACE("Using element default colormap");
-            setColorMap(ColorMap::getElementDefault());
-        }
-    }
-
-    initProp();
-
-    addLabelArray(ds);
-    addRadiusArray(ds, _atomScaling, _radiusScale);
-
-    vtkPolyData *pd = vtkPolyData::SafeDownCast(ds);
-    if (pd) {
-        TRACE("Verts: %d Lines: %d Polys: %d Strips: %d",
-                  pd->GetNumberOfVerts(),
-                  pd->GetNumberOfLines(),
-                  pd->GetNumberOfPolys(),
-                  pd->GetNumberOfStrips());
-        // DataSet is a vtkPolyData
-        if (pd->GetNumberOfLines() > 0) {
-            // Bonds
-            setupBondPolyData();
-
-            if (_cylinderSource == NULL) {
-                _cylinderSource = vtkSmartPointer<vtkCylinderSource>::New();
-                _cylinderSource->SetRadius(0.075);
-                _cylinderSource->SetHeight(1.0);
-                _cylinderSource->SetResolution(12);
-                _cylinderSource->CappingOff();
-                _cylinderTrans = vtkSmartPointer<vtkTransformPolyDataFilter>::New();
-                _cylinderTrans->SetInputConnection(_cylinderSource->GetOutputPort());
-                vtkSmartPointer<vtkTransform> trans = vtkSmartPointer<vtkTransform>::New();
-                trans->RotateZ(-90.0);
-                _cylinderTrans->SetTransform(trans);
-            }
-            if (_lineSource == NULL) {
-                _lineSource = vtkSmartPointer<vtkLineSource>::New();
-                _lineSource->SetPoint1(-0.5, 0, 0);
-                _lineSource->SetPoint2(0.5, 0, 0);
-            }
-
-            _bondMapper->SetSourceConnection(_cylinderTrans->GetOutputPort());
-#ifdef USE_VTK6
-            _bondMapper->SetInputData(_bondPD);
-#else
-            _bondMapper->SetInputConnection(_bondPD->GetProducerPort());
-#endif
-            _bondMapper->SetOrientationArray("bond_orientations");
-            _bondMapper->SetOrientationModeToDirection();
-            _bondMapper->OrientOn();
-            _bondMapper->SetScaleArray("bond_scales");
-            _bondMapper->SetScaleModeToScaleByVectorComponents();
-            _bondMapper->ScalingOn();
-            _bondMapper->ClampingOff();
-
-            _bondProp->SetMapper(_bondMapper);
-            getAssembly()->AddPart(_bondProp);
-        }
-        if (pd->GetNumberOfVerts() > 0) {
-            vtkSmartPointer<vtkPointSetToLabelHierarchy> hier = vtkSmartPointer<vtkPointSetToLabelHierarchy>::New();
-#ifdef USE_VTK6
-            hier->SetInputData(pd);
-#else
-            hier->SetInput(pd);
-#endif
-            hier->SetLabelArrayName("labels");
-            hier->GetTextProperty()->SetColor(0, 0, 0);
-            _labelMapper->SetInputConnection(hier->GetOutputPort());
-            _labelProp->SetMapper(_labelMapper);
-
-            // Atoms
-            vtkSmartPointer<vtkSphereSource> sphereSource = vtkSmartPointer<vtkSphereSource>::New();
-            sphereSource->SetRadius(1.0);
-            sphereSource->SetThetaResolution(14);
-            sphereSource->SetPhiResolution(14);
-
-            _atomMapper->SetSourceConnection(sphereSource->GetOutputPort());
-#ifdef USE_VTK6
-            _atomMapper->SetInputData(pd);
-#else
-            _atomMapper->SetInputConnection(pd->GetProducerPort());
-#endif
-            if (ds->GetPointData() != NULL &&
-                ds->GetPointData()->GetVectors() != NULL) {
-                _atomMapper->SetScaleArray(vtkDataSetAttributes::VECTORS);
-                _atomMapper->SetScaleModeToScaleByMagnitude();
-                _atomMapper->ScalingOn();
-            } else {
-                _atomMapper->SetScaleModeToNoDataScaling();
-                _atomMapper->ScalingOff();
-            }
-            _atomMapper->OrientOff();
-
-            _atomProp->SetMapper(_atomMapper);
-            getAssembly()->AddPart(_atomProp);
-        }
-    } else {
-        // DataSet is NOT a vtkPolyData
-        ERROR("DataSet is not a PolyData");
-        return;
-    }
-
-    setAtomLabelVisibility(_labelsOn);
-
-    _atomMapper->Update();
-    _bondMapper->Update();
-    _labelMapper->Update();
-}
-
-void Molecule::updateRanges(Renderer *renderer)
-{
-    if (_dataSet == NULL) {
-        ERROR("called before setDataSet");
-        return;
-    }
-
-    if (renderer->getUseCumulativeRange()) {
-        renderer->getCumulativeDataRange(_dataRange,
-                                         _dataSet->getActiveScalarsName(),
-                                         1);
-        renderer->getCumulativeDataRange(_vectorMagnitudeRange,
-                                         _dataSet->getActiveVectorsName(),
-                                         3);
-        for (int i = 0; i < 3; i++) {
-            renderer->getCumulativeDataRange(_vectorComponentRange[i],
-                                             _dataSet->getActiveVectorsName(),
-                                             3, i);
-        }
-    } else {
-        _dataSet->getScalarRange(_dataRange);
-        _dataSet->getVectorRange(_vectorMagnitudeRange);
-        for (int i = 0; i < 3; i++) {
-            _dataSet->getVectorRange(_vectorComponentRange[i], i);
-        }
-    }
-
-    // Need to update color map ranges
-    double *rangePtr = _colorFieldRange;
-    if (_colorFieldRange[0] > _colorFieldRange[1]) {
-        rangePtr = NULL;
-    }
-    setColorMode(_colorMode, _colorFieldType, _colorFieldName.c_str(), rangePtr);
-}
-
-void Molecule::setColorMode(ColorMode mode)
-{
-    _colorMode = mode;
-    if (_dataSet == NULL)
-        return;
-
-    switch (mode) {
-    case COLOR_BY_ELEMENTS: // Assume default scalar is "element" array
-        setColorMode(mode,
-                     DataSet::POINT_DATA,
-                     "element");
-        break;
-    case COLOR_BY_SCALAR:
-        setColorMode(mode,
-                     _dataSet->getActiveScalarsType(),
-                     _dataSet->getActiveScalarsName(),
-                     _dataRange);
-        break;
-    case COLOR_BY_VECTOR_MAGNITUDE:
-        setColorMode(mode,
-                     _dataSet->getActiveVectorsType(),
-                     _dataSet->getActiveVectorsName(),
-                     _vectorMagnitudeRange);
-        break;
-    case COLOR_BY_VECTOR_X:
-        setColorMode(mode,
-                     _dataSet->getActiveVectorsType(),
-                     _dataSet->getActiveVectorsName(),
-                     _vectorComponentRange[0]);
-        break;
-    case COLOR_BY_VECTOR_Y:
-        setColorMode(mode,
-                     _dataSet->getActiveVectorsType(),
-                     _dataSet->getActiveVectorsName(),
-                     _vectorComponentRange[1]);
-        break;
-    case COLOR_BY_VECTOR_Z:
-        setColorMode(mode,
-                     _dataSet->getActiveVectorsType(),
-                     _dataSet->getActiveVectorsName(),
-                     _vectorComponentRange[2]);
-        break;
-    case COLOR_CONSTANT:
-    default:
-        setColorMode(mode, DataSet::POINT_DATA, NULL, NULL);
-        break;
-    }
-}
-
-void Molecule::setColorMode(ColorMode mode,
-                            const char *name, double range[2])
-{
-    if (_dataSet == NULL)
-        return;
-    DataSet::DataAttributeType type = DataSet::POINT_DATA;
-    int numComponents = 1;
-    if (name != NULL && strlen(name) > 0 &&
-        !_dataSet->getFieldInfo(name, &type, &numComponents)) {
-        ERROR("Field not found: %s", name);
-        return;
-    }
-    setColorMode(mode, type, name, range);
-}
-
-void Molecule::setColorMode(ColorMode mode, DataSet::DataAttributeType type,
-                            const char *name, double range[2])
-{
-    _colorMode = mode;
-    _colorFieldType = type;
-    if (name == NULL)
-        _colorFieldName.clear();
-    else
-        _colorFieldName = name;
-    if (range == NULL) {
-        _colorFieldRange[0] = DBL_MAX;
-        _colorFieldRange[1] = -DBL_MAX;
-    } else {
-        memcpy(_colorFieldRange, range, sizeof(double)*2);
-    }
-
-    if (_dataSet == NULL || (_atomMapper == NULL && _bondMapper == NULL))
-        return;
-
-    switch (type) {
-    case DataSet::POINT_DATA:
-        if (_atomMapper != NULL)
-            _atomMapper->SetScalarModeToUsePointFieldData();
-        if (_bondMapper != NULL)
-            _bondMapper->SetScalarModeToUsePointFieldData();
-        break;
-    case DataSet::CELL_DATA:
-        if (_atomMapper != NULL)
-            _atomMapper->SetScalarModeToUseCellFieldData();
-        if (_bondMapper != NULL)
-            _bondMapper->SetScalarModeToUseCellFieldData();
-        break;
-    default:
-        ERROR("Unsupported DataAttributeType: %d", type);
-        return;
-    }
-
-    if (name != NULL && strlen(name) > 0) {
-        if (_atomMapper != NULL)
-            _atomMapper->SelectColorArray(name);
-        if (_bondMapper != NULL)
-            _bondMapper->SelectColorArray(name);
-    } else {
-        if (_atomMapper != NULL)
-            _atomMapper->SetScalarModeToDefault();
-        if (_bondMapper != NULL)
-            _bondMapper->SetScalarModeToDefault();
-    }
-
-    if (_lut != NULL) {
-        if (range != NULL) {
-            _lut->SetRange(range);
-        } else if (mode == COLOR_BY_ELEMENTS) {
-            double range[2];
-            range[0] = 0;
-            range[1] = NUM_ELEMENTS;
-            _lut->SetRange(range);
-        } else if (name != NULL && strlen(name) > 0) {
-            double r[2];
-            int comp = -1;
-            if (mode == COLOR_BY_VECTOR_X)
-                comp = 0;
-            else if (mode == COLOR_BY_VECTOR_Y)
-                comp = 1;
-            else if (mode == COLOR_BY_VECTOR_Z)
-                comp = 2;
-
-            if (_renderer->getUseCumulativeRange()) {
-                int numComponents;
-                if  (!_dataSet->getFieldInfo(name, type, &numComponents)) {
-                    ERROR("Field not found: %s, type: %d", name, type);
-                    return;
-                } else if (numComponents < comp+1) {
-                    ERROR("Request for component %d in field with %d components",
-                          comp, numComponents);
-                    return;
-                }
-                _renderer->getCumulativeDataRange(r, name, type, numComponents, comp);
-            } else {
-                _dataSet->getDataRange(r, name, type, comp);
-            }
-            _lut->SetRange(r);
-        }
-    }
-
-    switch (mode) {
-    case COLOR_BY_ELEMENTS:
-        if (_atomMapper != NULL)
-            _atomMapper->ScalarVisibilityOn();
-        if (_bondMapper != NULL)
-            _bondMapper->ScalarVisibilityOn();
-        break;
-    case COLOR_BY_SCALAR:
-        if (_atomMapper != NULL)
-            _atomMapper->ScalarVisibilityOn();
-        if (_bondMapper != NULL)
-            _bondMapper->ScalarVisibilityOn();
-        break;
-    case COLOR_BY_VECTOR_MAGNITUDE:
-        if (_atomMapper != NULL)
-            _atomMapper->ScalarVisibilityOn();
-        if (_bondMapper != NULL)
-            _bondMapper->ScalarVisibilityOn();
-        if (_lut != NULL) {
-            _lut->SetVectorModeToMagnitude();
-        }
-        break;
-    case COLOR_BY_VECTOR_X:
-        if (_atomMapper != NULL)
-            _atomMapper->ScalarVisibilityOn();
-        if (_bondMapper != NULL)
-            _bondMapper->ScalarVisibilityOn();
-        if (_lut != NULL) {
-            _lut->SetVectorModeToComponent();
-            _lut->SetVectorComponent(0);
-        }
-        break;
-    case COLOR_BY_VECTOR_Y:
-        if (_atomMapper != NULL)
-            _atomMapper->ScalarVisibilityOn();
-        if (_bondMapper != NULL)
-            _bondMapper->ScalarVisibilityOn();
-        if (_lut != NULL) {
-            _lut->SetVectorModeToComponent();
-            _lut->SetVectorComponent(1);
-        }
-        break;
-    case COLOR_BY_VECTOR_Z:
-        if (_atomMapper != NULL)
-            _atomMapper->ScalarVisibilityOn();
-        if (_bondMapper != NULL)
-            _bondMapper->ScalarVisibilityOn();
-        if (_lut != NULL) {
-            _lut->SetVectorModeToComponent();
-            _lut->SetVectorComponent(2);
-        }
-        break;
-    case COLOR_CONSTANT:
-    default:
-        if (_atomMapper != NULL)
-            _atomMapper->ScalarVisibilityOff();
-        if (_bondMapper != NULL)
-            _bondMapper->ScalarVisibilityOff();
-        break;
-    }
-}
-
-/**
- * \brief Called when the color map has been edited
- */
-void Molecule::updateColorMap()
-{
-    setColorMap(_colorMap);
-}
-
-/**
- * \brief Associate a colormap lookup table with the DataSet
- */
-void Molecule::setColorMap(ColorMap *cmap)
-{
-    if (cmap == NULL)
-        return;
-
-    _colorMap = cmap;
- 
-    if (_lut == NULL) {
-        _lut = vtkSmartPointer<vtkLookupTable>::New();
-        if (_atomMapper != NULL) {
-            _atomMapper->UseLookupTableScalarRangeOn();
-            _atomMapper->SetLookupTable(_lut);
-        }
-        if (_bondMapper != NULL) {
-            _bondMapper->UseLookupTableScalarRangeOn();
-            _bondMapper->SetLookupTable(_lut);
-        }
-        _lut->DeepCopy(cmap->getLookupTable());
-        switch (_colorMode) {
-        case COLOR_BY_ELEMENTS: {
-            double range[2];
-            range[0] = 0;
-            range[1] = NUM_ELEMENTS;
-            _lut->SetRange(range);
-        }
-            break;
-        case COLOR_CONSTANT:
-        case COLOR_BY_SCALAR:
-            _lut->SetRange(_dataRange);
-            break;
-        case COLOR_BY_VECTOR_MAGNITUDE:
-            _lut->SetRange(_vectorMagnitudeRange);
-            break;
-        case COLOR_BY_VECTOR_X:
-            _lut->SetRange(_vectorComponentRange[0]);
-            break;
-        case COLOR_BY_VECTOR_Y:
-            _lut->SetRange(_vectorComponentRange[1]);
-            break;
-        case COLOR_BY_VECTOR_Z:
-            _lut->SetRange(_vectorComponentRange[2]);
-            break;
-        default:
-            break;
-        }
-    } else {
-        double range[2];
-        _lut->GetTableRange(range);
-        _lut->DeepCopy(cmap->getLookupTable());
-        _lut->SetRange(range);
-        _lut->Modified();
-    }
-}
-
-/**
- * \brief Turn on/off rendering of atom labels
- */
-void Molecule::setAtomLabelVisibility(bool state)
-{
-    _labelsOn = state;
-    if (_labelProp != NULL) {
-        _labelProp->SetVisibility((state ? 1 : 0));
-    }
-}
-
-/**
- * \brief Turn on/off rendering of the atoms
- */
-void Molecule::setAtomVisibility(bool state)
-{
-    if (_atomProp != NULL) {
-        _atomProp->SetVisibility((state ? 1 : 0));
-    }
-}
-
-/**
- * \brief Turn on/off rendering of the bonds
- */
-void Molecule::setBondVisibility(bool state)
-{
-    if (_bondProp != NULL) {
-        _bondProp->SetVisibility((state ? 1 : 0));
-    }
-}
-
-/**
- * \brief Toggle visibility of the prop
- */
-void Molecule::setVisibility(bool state)
-{
-    VtkGraphicsObject::setVisibility(state);
-    if (_labelProp != NULL) {
-        if (!state)
-            _labelProp->SetVisibility(0);
-        else
-            setAtomLabelVisibility(_labelsOn);
-    }
-}
-
-/**
- * \brief Set opacity of molecule
- */
-void Molecule::setOpacity(double opacity)
-{
-    VtkGraphicsObject::setOpacity(opacity);
-    if (_labelMapper != NULL) {
-        _labelMapper->SetBackgroundOpacity(opacity);
-    }
-}
-
-void Molecule::setBondStyle(BondStyle style)
-{
-    switch (style) {
-    case BOND_STYLE_CYLINDER:
-        if (_bondProp != NULL) {
-            _bondProp->GetProperty()->SetLineWidth(_edgeWidth);
-            _bondProp->GetProperty()->SetLighting(_lighting ? 1 : 0);
-        }
-        if (_bondMapper != NULL && _cylinderTrans != NULL) {
-            _cylinderTrans->Modified();
-            _bondMapper->SetSourceConnection(_cylinderTrans->GetOutputPort());
-            _bondMapper->Modified();
-        }
-        break;
-    case BOND_STYLE_LINE:
-        if (_bondProp != NULL) {
-            _bondProp->GetProperty()->LightingOff();
-        }
-        if (_bondMapper != NULL && _lineSource != NULL) {
-            _lineSource->Modified();
-            _bondMapper->SetSourceConnection(_lineSource->GetOutputPort());
-            _bondMapper->Modified();
-        }
-         break;
-    default:
-        WARN("Unknown bond style");    
-    }
-}
-
-/**
- * \brief Set constant bond color
- */
-void Molecule::setBondColor(float color[3])
-{
-    _bondColor[0] = color[0];
-    _bondColor[1] = color[1];
-    _bondColor[2] = color[2];
-    if (_bondProp != NULL) {
-        _bondProp->GetProperty()->SetColor(_bondColor[0], _bondColor[1], _bondColor[2]);
-    }
-}
-
-/**
- * \brief Set mode to determine how bonds are colored
- */
-void Molecule::setBondColorMode(BondColorMode mode)
-{
-    if (_bondMapper == NULL) return;
-
-    switch (mode) {
-    case BOND_COLOR_BY_ELEMENTS:
-        _bondMapper->ScalarVisibilityOn();
-        break;
-    case BOND_COLOR_CONSTANT:
-        _bondMapper->ScalarVisibilityOff();
-        break;
-    default:
-        WARN("Unknown bond color mode");
-    }
-}
-
-/**
- * \brief Set a group of world coordinate planes to clip rendering
- *
- * Passing NULL for planes will remove all cliping planes
- */
-void Molecule::setClippingPlanes(vtkPlaneCollection *planes)
-{
-    if (_atomMapper != NULL) {
-        _atomMapper->SetClippingPlanes(planes);
-    }
-    if (_bondMapper != NULL) {
-        _bondMapper->SetClippingPlanes(planes);
-    }
-}
-
-/**
- * \brief Set the radius type used for scaling atoms
- */
-void Molecule::setAtomScaling(AtomScaling state)
-{
-    _atomScaling = state;
-    if (_dataSet != NULL) {
-        vtkDataSet *ds = _dataSet->getVtkDataSet();
-        addRadiusArray(ds, _atomScaling, _radiusScale);
-        if (_atomMapper != NULL) {
-             assert(ds->GetPointData() != NULL &&
-                    ds->GetPointData()->GetVectors() != NULL);
-            _atomMapper->SetScaleModeToScaleByMagnitude();
-            _atomMapper->SetScaleArray(vtkDataSetAttributes::VECTORS);
-            _atomMapper->ScalingOn();
-        }
-    }
-}
-
-/**
- * \brief Set the constant radius scaling factor for atoms.  This
- * can be used to convert from Angstroms to atom coordinates units.
- */
-void Molecule::setAtomRadiusScale(double scale)
-{
-    _radiusScale = scale;
-    if (_dataSet != NULL) {
-        vtkDataSet *ds = _dataSet->getVtkDataSet();
-        addRadiusArray(ds, _atomScaling, _radiusScale);
-    }
-}
-
-/**
- * \brief Set the constant radius scaling factor for bonds.
- */
-void Molecule::setBondRadiusScale(double scale)
-{
-    if (_cylinderSource != NULL) {
-        _cylinderSource->SetRadius(scale);
-        // Workaround bug with source modification not causing
-        // mapper to be updated
-        if (_bondMapper != NULL) {
-            _bondMapper->Modified();
-        }
-    }
-}
-
-void Molecule::setupBondPolyData()
-{
-    if (_dataSet == NULL)
-        return;
-    if (_bondPD == NULL) {
-        _bondPD = vtkSmartPointer<vtkPolyData>::New();
-    } else {
-        _bondPD->Initialize();
-    }
-    vtkPolyData *pd = vtkPolyData::SafeDownCast(_dataSet->getVtkDataSet());
-    if (pd == NULL)
-        return;
-    vtkCellArray *lines = pd->GetLines();
-    lines->InitTraversal();
-    vtkIdType npts, *pts;
-    vtkSmartPointer<vtkPoints> bondPoints = vtkSmartPointer<vtkPoints>::New();
-    vtkSmartPointer<vtkIntArray> bondElements = vtkSmartPointer<vtkIntArray>::New();
-    vtkSmartPointer<vtkDoubleArray> bondVectors = vtkSmartPointer<vtkDoubleArray>::New();
-    vtkSmartPointer<vtkDoubleArray> bondScales = vtkSmartPointer<vtkDoubleArray>::New();
-    bondElements->SetName("element");
-    bondVectors->SetName("bond_orientations");
-    bondVectors->SetNumberOfComponents(3);
-    bondScales->SetName("bond_scales");
-    bondScales->SetNumberOfComponents(3);
-    vtkDataArray *elements = NULL;
-    if (pd->GetPointData() != NULL &&
-        pd->GetPointData()->GetScalars() != NULL &&
-        strcmp(pd->GetPointData()->GetScalars()->GetName(), "element") == 0) {
-        elements = pd->GetPointData()->GetScalars();
-    }
-    for (int i = 0; lines->GetNextCell(npts, pts); i++) {
-        assert(npts == 2);
-        double pt0[3], pt1[3];
-        double newPt0[3], newPt1[3];
-        //double *pt0 = pd->GetPoint(pts[0]);
-        //double *pt1 = pd->GetPoint(pts[1]);
-        pd->GetPoint(pts[0], pt0);
-        pd->GetPoint(pts[1], pt1);
-        double center[3];
-
-        for (int j = 0; j < 3; j++)
-            center[j] = pt0[j] + (pt1[j] - pt0[j]) * 0.5;
-        for (int j = 0; j < 3; j++)
-            newPt0[j] = pt0[j] + (pt1[j] - pt0[j]) * 0.25;
-        for (int j = 0; j < 3; j++)
-            newPt1[j] = pt0[j] + (pt1[j] - pt0[j]) * 0.75;
-
-        bondPoints->InsertNextPoint(newPt0);
-        bondPoints->InsertNextPoint(newPt1);
-
-        TRACE("Bond %d: (%g,%g,%g)-(%g,%g,%g)-(%g,%g,%g)", i,
-              pt0[0], pt0[1], pt0[2], 
-              center[0], center[1], center[2],
-              pt1[0], pt1[1], pt1[2]);
-
-        double vec[3];
-        for (int j = 0; j < 3; j++)
-            vec[j] = center[j] - pt0[j];
-
-        bondVectors->InsertNextTupleValue(vec);
-        bondVectors->InsertNextTupleValue(vec);
-        TRACE("Bond %d, vec: %g,%g,%g", i, vec[0], vec[1], vec[2]);
-
-        double scale[3];
-        scale[0] = sqrt(vec[0]*vec[0] + vec[1]*vec[1] + vec[2]*vec[2]);
-        scale[1] = 1.0;
-        scale[2] = 1.0;
-
-        bondScales->InsertNextTupleValue(scale);
-        bondScales->InsertNextTupleValue(scale);
-
-        if (elements != NULL) {
-            int element = (int)elements->GetComponent(pts[0], 0);
-            TRACE("Bond %d, elt 0: %d", i, element);
-            bondElements->InsertNextValue(element);
-            element = (int)elements->GetComponent(pts[1], 0);
-            TRACE("Bond %d, elt 1: %d", i, element);
-            bondElements->InsertNextValue(element);
-        }
-    }
-    _bondPD->SetPoints(bondPoints);
-    if (elements != NULL)
-        _bondPD->GetPointData()->SetScalars(bondElements);
-    _bondPD->GetPointData()->AddArray(bondVectors);
-    _bondPD->GetPointData()->AddArray(bondScales);
-}
-
-void Molecule::addLabelArray(vtkDataSet *dataSet)
-{
-    vtkDataArray *elements = NULL;
-    if (dataSet->GetPointData() != NULL &&
-        dataSet->GetPointData()->GetScalars() != NULL &&
-        strcmp(dataSet->GetPointData()->GetScalars()->GetName(), "element") == 0) {
-        elements = dataSet->GetPointData()->GetScalars();
-    } else {
-        WARN("Can't label atoms without an element array");
-    }
-
-    vtkSmartPointer<vtkStringArray> labelArray = vtkSmartPointer<vtkStringArray>::New();
-    labelArray->SetName("labels");
-    vtkPolyData *pd = vtkPolyData::SafeDownCast(dataSet);
-    if (pd == NULL) {
-        ERROR("DataSet not a PolyData");
-        return;
-    }
-    for (int i = 0; i < pd->GetNumberOfVerts(); i++) {
-        char buf[32];
-        if (elements != NULL) {
-            int elt = (int)elements->GetComponent(i, 0);
-            sprintf(buf, "%s%d", g_elementNames[elt], i);
-        } else {
-            sprintf(buf, "%d", i);
-        }
-        labelArray->InsertNextValue(buf);
-    }
-    dataSet->GetPointData()->AddArray(labelArray);
-}
-
-/**
- * \brief Add a scalar array to dataSet with sizes for the elements
- * specified in the "element" scalar array
- */
-void Molecule::addRadiusArray(vtkDataSet *dataSet, AtomScaling scaling, double scaleFactor)
-{
-    vtkDataArray *elements = NULL;
-    if (dataSet->GetPointData() != NULL &&
-        dataSet->GetPointData()->GetScalars() != NULL &&
-        strcmp(dataSet->GetPointData()->GetScalars()->GetName(), "element") == 0) {
-        elements = dataSet->GetPointData()->GetScalars();
-    } else if (scaling != NO_ATOM_SCALING) {
-        WARN("Can't use non-constant scaling without an element array");
-    }
-    const float *radiusSource = NULL;
-    switch (scaling) {
-    case VAN_DER_WAALS_RADIUS:
-        radiusSource = g_vdwRadii;
-        break;
-    case COVALENT_RADIUS:
-        radiusSource = g_covalentRadii;
-        break;
-    case ATOMIC_RADIUS:
-        radiusSource = g_atomicRadii;
-        break;
-    case NO_ATOM_SCALING:
-    default:
-        ;
-    }
-    vtkSmartPointer<vtkFloatArray> radii = vtkSmartPointer<vtkFloatArray>::New();
-    radii->SetName("radius");
-    radii->SetNumberOfComponents(3);
-    vtkPolyData *pd = vtkPolyData::SafeDownCast(dataSet);
-    if (pd == NULL) {
-        ERROR("DataSet not a PolyData");
-        return;
-    }
-    for (int i = 0; i < pd->GetNumberOfVerts(); i++) {
-        float tuple[3];
-        tuple[1] = tuple[2] = 0;
-        if (elements != NULL && radiusSource != NULL) {
-            int elt = (int)elements->GetComponent(i, 0);
-            tuple[0] = radiusSource[elt] * scaleFactor;
-        } else {
-            tuple[0] = scaleFactor;
-        }
-        radii->InsertNextTupleValue(tuple);
-    }
-    dataSet->GetPointData()->SetVectors(radii);
-}
-
-/**
- * \brief Create a color map to map atomic numbers to element colors
- */
-ColorMap *Molecule::createElementColorMap()
-{
-    ColorMap *elementCmap = new ColorMap("elementDefault");
-    ColorMap::ControlPoint cp[NUM_ELEMENTS+1];
-
-    elementCmap->setNumberOfTableEntries(NUM_ELEMENTS+1);
-    for (int i = 0; i <= NUM_ELEMENTS; i++) {
-        cp[i].value = i/((double)NUM_ELEMENTS);
-        for (int c = 0; c < 3; c++) {
-            cp[i].color[c] = ((double)g_elementColors[i][c])/255.;
-        }
-        elementCmap->addControlPoint(cp[i]);
-    }
-    ColorMap::OpacityControlPoint ocp[2];
-    ocp[0].value = 0;
-    ocp[0].alpha = 1.0;
-    ocp[1].value = 1.0;
-    ocp[1].alpha = 1.0;
-    elementCmap->addOpacityControlPoint(ocp[0]);
-    elementCmap->addOpacityControlPoint(ocp[1]);
-    elementCmap->build();
-    double range[2];
-    range[0] = 0;
-    range[1] = NUM_ELEMENTS;
-    elementCmap->getLookupTable()->SetRange(range);
-
-    return elementCmap;
-}
Index: unk/packages/vizservers/vtkvis/RpMolecule.h
===================================================================
--- /trunk/packages/vizservers/vtkvis/RpMolecule.h	(revision 3615)
+++ 	(revision )
@@ -1,167 +1,0 @@
-/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
-/*
- * Copyright (C) 2004-2012  HUBzero Foundation, LLC
- *
- * Author: Leif Delgass <ldelgass@purdue.edu>
- */
-
-#ifndef VTKVIS_MOLECULE_H
-#define VTKVIS_MOLECULE_H
-
-#include <vtkSmartPointer.h>
-#include <vtkLookupTable.h>
-#include <vtkPolyDataMapper.h>
-#include <vtkActor.h>
-#include <vtkActor2D.h>
-#include <vtkAssembly.h>
-#include <vtkGlyph3DMapper.h>
-#include <vtkTransformPolyDataFilter.h>
-#include <vtkCylinderSource.h>
-#include <vtkLineSource.h>
-#include <vtkLabelPlacementMapper.h>
-
-#include "ColorMap.h"
-#include "RpVtkGraphicsObject.h"
-
-namespace VtkVis {
-
-/**
- * \brief Ball and stick Molecule
- *
- * The data format for this class is based on the VisIt Molecule
- * plot.  It consists of a vtkPolyData with atom coordinates as
- * points and vertices and bonds as lines.  A scalar array named
- * "element" can be included as point data to specify atomic 
- * numbers to use in coloring (via the "elementDefault" ColorMap)
- * and scaling atoms.  If the scalar array is not named 
- * "element," it will be color-mapped as a standard scalar field.
- */
-class Molecule : public VtkGraphicsObject {
-public:
-    enum AtomScaling {
-        NO_ATOM_SCALING,
-        VAN_DER_WAALS_RADIUS,
-        COVALENT_RADIUS,
-        ATOMIC_RADIUS
-    };
-    enum BondStyle {
-        BOND_STYLE_CYLINDER,
-        BOND_STYLE_LINE
-    };
-    enum ColorMode {
-        COLOR_BY_ELEMENTS,
-        COLOR_BY_SCALAR,
-        COLOR_BY_VECTOR_MAGNITUDE,
-        COLOR_BY_VECTOR_X,
-        COLOR_BY_VECTOR_Y,
-        COLOR_BY_VECTOR_Z,
-        COLOR_CONSTANT
-    };
-    enum BondColorMode {
-        BOND_COLOR_BY_ELEMENTS,
-        BOND_COLOR_CONSTANT
-    };
-
-    Molecule();
-    virtual ~Molecule();
-
-    virtual const char *getClassName() const
-    {
-        return "Molecule";
-    }
-
-    virtual vtkProp *getOverlayProp()
-    {
-        return _labelProp;
-    }
-
-    virtual void setDataSet(DataSet *dataSet,
-                            Renderer *renderer);
-
-    virtual void setClippingPlanes(vtkPlaneCollection *planes);
-
-    void setColorMode(ColorMode mode, DataSet::DataAttributeType type,
-                      const char *name, double range[2] = NULL);
-
-    void setColorMode(ColorMode mode,
-                      const char *name, double range[2] = NULL);
-
-    void setColorMode(ColorMode mode);
-
-    void setColorMap(ColorMap *colorMap);
-
-    /**
-     * \brief Return the ColorMap in use
-     */
-    ColorMap *getColorMap()
-    {
-        return _colorMap;
-    }
-
-    void updateColorMap();
-
-    virtual void updateRanges(Renderer *renderer);
-
-    void setAtomScaling(AtomScaling state);
-
-    void setAtomRadiusScale(double scale);
-
-    void setBondRadiusScale(double scale);
-
-    virtual void setVisibility(bool state);
-
-    virtual void setOpacity(double opacity);
-
-    void setAtomVisibility(bool state);
-
-    void setAtomLabelVisibility(bool state);
-
-    void setBondVisibility(bool state);
-
-    void setBondStyle(BondStyle style);
-
-    void setBondColor(float color[3]);
-
-    void setBondColorMode(BondColorMode mode);
-
-    static ColorMap *createElementColorMap();
-
-private:
-    virtual void initProp();
-    virtual void update();
-
-    void setupBondPolyData();
-
-    static void addLabelArray(vtkDataSet *dataSet);
-
-    static void addRadiusArray(vtkDataSet *dataSet, AtomScaling scaling, double scaleFactor);
-
-    float _bondColor[3];
-    double _radiusScale;
-    AtomScaling _atomScaling;
-    bool _labelsOn;
-    ColorMap *_colorMap;
-    ColorMode _colorMode;
-    std::string _colorFieldName;
-    DataSet::DataAttributeType _colorFieldType;
-    double _colorFieldRange[2];
-    double _vectorMagnitudeRange[2];
-    double _vectorComponentRange[3][2];
-    Renderer *_renderer;
-
-    vtkSmartPointer<vtkLookupTable> _lut;
-    vtkSmartPointer<vtkActor> _atomProp;
-    vtkSmartPointer<vtkActor> _bondProp;
-    vtkSmartPointer<vtkActor2D> _labelProp;
-    vtkSmartPointer<vtkPolyData> _bondPD;
-    vtkSmartPointer<vtkCylinderSource> _cylinderSource;
-    vtkSmartPointer<vtkTransformPolyDataFilter>_cylinderTrans;
-    vtkSmartPointer<vtkLineSource> _lineSource;
-    vtkSmartPointer<vtkGlyph3DMapper> _atomMapper;
-    vtkSmartPointer<vtkGlyph3DMapper> _bondMapper;
-    vtkSmartPointer<vtkLabelPlacementMapper> _labelMapper;
-};
-
-}
-
-#endif
Index: unk/packages/vizservers/vtkvis/RpMoleculeData.h
===================================================================
--- /trunk/packages/vizservers/vtkvis/RpMoleculeData.h	(revision 3615)
+++ 	(revision )
@@ -1,578 +1,0 @@
-/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
-/*
- * Copyright (C) 2004-2012  HUBzero Foundation, LLC
- *
- * Author: Leif Delgass <ldelgass@purdue.edu>
- */
-
-#define NUM_ELEMENTS 109
-
-// jmol colors (taken from VisIt)
-const unsigned char g_elementColors[NUM_ELEMENTS+1][3] = {
-    { 0x20, 0x20, 0x20 }, // ?
-    { 0xFF, 0xFF, 0xFF }, // H
-    { 0xD9, 0xFF, 0xFF }, // He
-    { 0xCC, 0x80, 0xFF }, // Li
-    { 0xC2, 0xFF, 0x00 }, // Be
-    { 0xFF, 0xB5, 0xB5 }, // B
-    { 0x90, 0x90, 0x90 }, // C
-    { 0x30, 0x50, 0xF8 }, // N
-    { 0xFF, 0x0D, 0x0D }, // O
-    { 0x90, 0xE0, 0x50 }, // F
-    { 0xB3, 0xE3, 0xF5 }, // Ne
-    { 0xAB, 0x5C, 0xF2 }, // Na
-    { 0x8A, 0xFF, 0x00 }, // Mg
-    { 0xBF, 0xA6, 0xA6 }, // Al
-    { 0xF0, 0xC8, 0xA0 }, // Si
-    { 0xFF, 0x80, 0x00 }, // P
-    { 0xFF, 0xFF, 0x30 }, // S
-    { 0x1F, 0xF0, 0x1F }, // Cl
-    { 0x80, 0xD1, 0xE3 }, // Ar
-    { 0x8F, 0x40, 0xD4 }, // K
-    { 0x3D, 0xFF, 0x00 }, // Ca
-    { 0xE6, 0xE6, 0xE6 }, // Sc
-    { 0xBF, 0xC2, 0xC7 }, // Ti
-    { 0xA6, 0xA6, 0xAB }, // V
-    { 0x8A, 0x99, 0xC7 }, // Cr
-    { 0x9C, 0x7A, 0xC7 }, // Mn
-    { 0xE0, 0x66, 0x33 }, // Fe
-    { 0xF0, 0x90, 0xA0 }, // Co
-    { 0x50, 0xD0, 0x50 }, // Ni
-    { 0xC8, 0x80, 0x33 }, // Cu
-    { 0x7D, 0x80, 0xB0 }, // Zn
-    { 0xC2, 0x8F, 0x8F }, // Ga
-    { 0x66, 0x8F, 0x8F }, // Ge
-    { 0xBD, 0x80, 0xE3 }, // As
-    { 0xFF, 0xA1, 0x00 }, // Se
-    { 0xA6, 0x29, 0x29 }, // Br
-    { 0x5C, 0xB8, 0xD1 }, // Kr
-    { 0x70, 0x2E, 0xB0 }, // Rb
-    { 0x00, 0xFF, 0x00 }, // Sr
-    { 0x94, 0xFF, 0xFF }, // Y
-    { 0x94, 0xE0, 0xE0 }, // Zr
-    { 0x73, 0xC2, 0xC9 }, // Nb
-    { 0x54, 0xB5, 0xB5 }, // Mo
-    { 0x3B, 0x9E, 0x9E }, // Tc
-    { 0x24, 0x8F, 0x8F }, // Ru
-    { 0x0A, 0x7D, 0x8C }, // Rh
-    { 0x00, 0x69, 0x85 }, // Pd
-    { 0xC0, 0xC0, 0xC0 }, // Ag
-    { 0xFF, 0xD9, 0x8F }, // Cd
-    { 0xA6, 0x75, 0x73 }, // In
-    { 0x66, 0x80, 0x80 }, // Sn
-    { 0x9E, 0x63, 0xB5 }, // Sb
-    { 0xD4, 0x7A, 0x00 }, // Te
-    { 0x94, 0x00, 0x94 }, // I
-    { 0x42, 0x9E, 0xB0 }, // Xe
-    { 0x57, 0x17, 0x8F }, // Cs
-    { 0x00, 0xC9, 0x00 }, // Ba
-    { 0x70, 0xD4, 0xFF }, // La
-    { 0xFF, 0xFF, 0xC7 }, // Ce
-    { 0xD9, 0xFF, 0xC7 }, // Pr
-    { 0xC7, 0xFF, 0xC7 }, // Nd
-    { 0xA3, 0xFF, 0xC7 }, // Pm
-    { 0x8F, 0xFF, 0xC7 }, // Sm
-    { 0x61, 0xFF, 0xC7 }, // Eu
-    { 0x45, 0xFF, 0xC7 }, // Gd
-    { 0x30, 0xFF, 0xC7 }, // Tb
-    { 0x1F, 0xFF, 0xC7 }, // Dy
-    { 0x00, 0xFF, 0x9C }, // Ho
-    { 0x00, 0xE6, 0x75 }, // Er
-    { 0x00, 0xD4, 0x52 }, // Tm
-    { 0x00, 0xBF, 0x38 }, // Yb
-    { 0x00, 0xAB, 0x24 }, // Lu
-    { 0x4D, 0xC2, 0xFF }, // Hf
-    { 0x4D, 0xA6, 0xFF }, // Ta
-    { 0x21, 0x94, 0xD6 }, // W
-    { 0x26, 0x7D, 0xAB }, // Re
-    { 0x26, 0x66, 0x96 }, // Os
-    { 0x17, 0x54, 0x87 }, // Ir
-    { 0xD0, 0xD0, 0xE0 }, // Pt
-    { 0xFF, 0xD1, 0x23 }, // Au
-    { 0xB8, 0xB8, 0xD0 }, // Hg
-    { 0xA6, 0x54, 0x4D }, // Tl
-    { 0x57, 0x59, 0x61 }, // Pb
-    { 0x9E, 0x4F, 0xB5 }, // Bi
-    { 0xAB, 0x5C, 0x00 }, // Po
-    { 0x75, 0x4F, 0x45 }, // At
-    { 0x42, 0x82, 0x96 }, // Rn
-    { 0x42, 0x00, 0x66 }, // Fr
-    { 0x00, 0x7D, 0x00 }, // Ra
-    { 0x70, 0xAB, 0xFA }, // Ac
-    { 0x00, 0xBA, 0xFF }, // Th
-    { 0x00, 0xA1, 0xFF }, // Pa
-    { 0x00, 0x8F, 0xFF }, // U
-    { 0x00, 0x80, 0xFF }, // Np
-    { 0x00, 0x6B, 0xFF }, // Pu
-    { 0x54, 0x5C, 0xF2 }, // Am
-    { 0x78, 0x5C, 0xE3 }, // Cm
-    { 0x8A, 0x4F, 0xE3 }, // Bk
-    { 0xA1, 0x36, 0xD4 }, // Cf
-    { 0xB3, 0x1F, 0xD4 }, // Es
-    { 0xB3, 0x1F, 0xBA }, // Fm
-    { 0xB3, 0x0D, 0xA6 }, // Md
-    { 0xBD, 0x0D, 0x87 }, // No
-    { 0xC7, 0x00, 0x66 }, // Lr
-    { 0xCC, 0x00, 0x59 }, // Rf
-    { 0xD1, 0x00, 0x4F }, // Db
-    { 0xD9, 0x00, 0x45 }, // Sg
-    { 0xE0, 0x00, 0x38 }, // Bh
-    { 0xE6, 0x00, 0x2E }, // Hs
-    { 0xEB, 0x00, 0x26 }  // Mt
-};
-
-// Covalent radii in Angstroms from VisIt
-const float g_covalentRadii[NUM_ELEMENTS+1] = {
-     .1f,  // ?  0
-    0.32f, // H  1
-    0.93f, // He 2
-    1.23f, // Li 3
-    0.90f, // Be 4
-    0.82f, // B  5
-    0.77f, // C  6
-    0.75f, // N  7
-    0.73f, // O  8
-    0.72f, // F  9
-    0.71f, // Ne 10
-    1.54f, // Na 11
-    1.36f, // Mg 12
-    1.18f, // Al 13
-    1.11f, // Si 14
-    1.06f, // P  15
-    1.02f, // S  16
-    0.99f, // Cl 17
-    0.98f, // Ar 18
-    2.03f, // K  19
-    1.74f, // Ca 20
-    1.44f, // Sc 21
-    1.32f, // Ti 22
-    1.22f, // V  23
-    1.18f, // Cr 24
-    1.17f, // Mn 25
-    1.17f, // Fe 26
-    1.16f, // Co 27
-    1.15f, // Ni 28
-    1.17f, // Cu 29
-    1.25f, // Zn 30
-    1.26f, // Ga 31
-    1.22f, // Ge 32
-    1.20f, // As 33
-    1.16f, // Se 34
-    1.14f, // Br 35
-    1.12f, // Kr 36
-    2.16f, // Rb 37
-    1.91f, // Sr 38
-    1.62f, // Y  39
-    1.45f, // Zr 40
-    1.34f, // Nb 41
-    1.30f, // Mo 42
-    1.27f, // Tc 43
-    1.25f, // Ru 44
-    1.25f, // Rh 45
-    1.28f, // Pd 46
-    1.34f, // Ag 47
-    1.48f, // Cd 48
-    1.44f, // In 49
-    1.41f, // Sn 50
-    1.40f, // Sb 51
-    1.36f, // Te 52
-    1.33f, // I  53
-    1.31f, // Xe 54
-    2.35f, // Cs 55
-    1.98f, // Ba 56
-    1.69f, // La 57
-    1.65f, // Ce 58
-    1.65f, // Pr 59
-    1.64f, // Nd 60
-    1.63f, // Pm 61
-    1.62f, // Sm 62
-    1.85f, // Eu 63
-    1.61f, // Gd 64
-    1.59f, // Tb 65
-    1.59f, // Dy 66
-    1.58f, // Ho 67
-    1.57f, // Er 68
-    1.56f, // Tm 69
-    1.74f, // Yb 70
-    1.56f, // Lu 71
-    1.44f, // Hf 72
-    1.34f, // Ta 73
-    1.30f, // W  74
-    1.28f, // Re 75
-    1.26f, // Os 76
-    1.27f, // Ir 77
-    1.30f, // Pt 78
-    1.34f, // Au 79
-    1.49f, // Hg 80
-    1.48f, // Tl 81
-    1.47f, // Pb 82
-    1.46f, // Bi 83
-    1.46f, // Po 84
-    1.45f, // At 85
-    1.50f, // Rn 86 // 86-96 from en.wikipedia.org/wiki/Covalent_radius 10/6/09
-    2.60f, // Fr 87
-    2.21f, // Ra 88
-    2.15f, // Ac 89
-    2.06f, // Th 90
-    2.00f, // Pa 91
-    1.96f, // U  92
-    1.90f, // Np 93
-    1.87f, // Pu 94
-    1.80f, // Am 95
-    1.69f, // Cm 96
-    .1f,
-    .1f,
-    .1f,
-    .1f,
-    .1f,
-    .1f,
-    .1f,
-    .1f,
-    .1f,
-    .1f,
-    .1f,
-    .1f,
-    .1f
-};
-
-// Atomic radii in Angstroms from VisIt
-const float g_atomicRadii[NUM_ELEMENTS+1] = {
-     .1f,  // ?  0
-    0.79f, // H  1
-    0.49f, // He 2
-    2.05f, // Li 3
-    1.40f, // Be 4
-    1.17f, // B  5
-    0.91f, // C  6
-    0.75f, // N  7
-    0.65f, // O  8
-    0.57f, // F  9
-    0.51f, // Ne 10
-    2.23f, // Na 11
-    1.72f, // Mg 12
-    1.82f, // Al 13
-    1.46f, // Si 14
-    1.23f, // P  15
-    1.09f, // S  16
-    0.97f, // Cl 17
-    0.88f, // Ar 18
-    2.77f, // K  19
-    2.23f, // Ca 20
-    2.09f, // Sc 21
-    2.00f, // Ti 22
-    1.92f, // V  23
-    1.85f, // Cr 24
-    1.79f, // Mn 25
-    1.72f, // Fe 26
-    1.67f, // Co 27
-    1.62f, // Ni 28
-    1.57f, // Cu 29
-    1.53f, // Zn 30
-    1.81f, // Ga 31
-    1.52f, // Ge 32
-    1.33f, // As 33
-    1.22f, // Se 34
-    1.12f, // Br 35
-    1.03f, // Kr 36
-    2.98f, // Rb 37
-    2.45f, // Sr 38
-    2.27f, // Y  39
-    2.16f, // Zr 40
-    2.08f, // Nb 41
-    2.01f, // Mo 42
-    1.95f, // Tc 43
-    1.89f, // Ru 44
-    1.83f, // Rh 45
-    1.79f, // Pd 46
-    1.75f, // Ag 47
-    1.71f, // Cd 48
-    2.00f, // In 49
-    1.72f, // Sn 50
-    1.53f, // Sb 51
-    1.42f, // Te 52
-    1.32f, // I  53
-    1.24f, // Xe 54
-    3.34f, // Cs 55
-    2.78f, // Ba 56
-    2.74f, // La 57
-    2.70f, // Ce 58
-    2.67f, // Pr 59
-    2.64f, // Nd 60
-    2.62f, // Pm 61
-    2.59f, // Sm 62
-    2.56f, // Eu 63
-    2.54f, // Gd 64
-    2.51f, // Tb 65
-    2.49f, // Dy 66
-    2.47f, // Ho 67
-    2.45f, // Er 68
-    2.42f, // Tm 69
-    2.40f, // Yb 70
-    2.25f, // Lu 71
-    2.16f, // Hf 72
-    2.09f, // Ta 73
-    2.02f, // W  74
-    1.97f, // Re 75
-    1.92f, // Os 76
-    1.87f, // Ir 77
-    1.83f, // Pt 78
-    1.79f, // Au 79
-    1.76f, // Hg 80
-    2.08f, // Tl 81
-    1.81f, // Pb 82
-    1.63f, // Bi 83
-    1.53f, // Po 84
-    1.43f, // At 85
-    1.34f, // Rn 86
-    2.60f, // Fr 87 (using covalent radius just to get a number here)
-    2.15f, // Ra 88 (88-99 from "http://en.wikipedia.org/wiki/Atomic_radii_of_the_elements_(data_page)", which references J.C. Slater, J. Chem. Phys. 1964, 41, 3199.)
-    1.95f, // Ac 89
-    1.80f, // Th 90
-    1.80f, // Pa 91
-    1.75f, // U  92
-    1.75f, // Np 93
-    1.75f, // Pu 94
-    1.75f, // Am 95
-    1.74f, // Cm 96 (96-99 use metallic radius to just get a number)
-    1.70f, // Bk 97
-    1.86f, // Cf 98
-    1.86f, // Es 99
-    .1f,
-    .1f,
-    .1f,
-    .1f,
-    .1f,
-    .1f,
-    .1f,
-    .1f,
-    .1f,
-    .1f
-};
-
-// From JMol / OpenBabel
-/// van der Waals radii in Angstroms
-const float g_vdwRadii[NUM_ELEMENTS+1] = {
-    1.0,    //   0  ?
-    1.200f, //   1  H
-    1.400f, //   2  He
-    1.820f, //   3  Li
-    1.700f, //   4  Be
-    2.080f, //   5  B
-    1.950f, //   6  C
-    1.850f, //   7  N
-    1.700f, //   8  O
-    1.730f, //   9  F
-    1.540f, //  10  Ne
-    2.270f, //  11  Na
-    1.730f, //  12  Mg
-    2.050f, //  13  Al
-    2.100f, //  14  Si
-    2.080f, //  15  P
-    2.000f, //  16  S
-    1.970f, //  17  Cl
-    1.880f, //  18  Ar
-    2.750f, //  19  K
-    1.973f, //  20  Ca
-    1.700f, //  21  Sc
-    1.700f, //  22  Ti
-    1.700f, //  23  V
-    1.700f, //  24  Cr
-    1.700f, //  25  Mn
-    1.700f, //  26  Fe
-    1.700f, //  27  Co
-    1.630f, //  28  Ni
-    1.400f, //  29  Cu
-    1.390f, //  30  Zn
-    1.870f, //  31  Ga
-    1.700f, //  32  Ge
-    1.850f, //  33  As
-    1.900f, //  34  Se
-    2.100f, //  35  Br
-    2.020f, //  36  Kr
-    1.700f, //  37  Rb
-    1.700f, //  38  Sr
-    1.700f, //  39  Y
-    1.700f, //  40  Zr
-    1.700f, //  41  Nb
-    1.700f, //  42  Mo
-    1.700f, //  43  Tc
-    1.700f, //  44  Ru
-    1.700f, //  45  Rh
-    1.630f, //  46  Pd
-    1.720f, //  47  Ag
-    1.580f, //  48  Cd
-    1.930f, //  49  In
-    2.170f, //  50  Sn
-    2.200f, //  51  Sb
-    2.060f, //  52  Te
-    2.150f, //  53  I
-    2.160f, //  54  Xe
-    1.700f, //  55  Cs
-    1.700f, //  56  Ba
-    1.700f, //  57  La
-    1.700f, //  58  Ce
-    1.700f, //  59  Pr
-    1.700f, //  60  Nd
-    1.700f, //  61  Pm
-    1.700f, //  62  Sm
-    1.700f, //  63  Eu
-    1.700f, //  64  Gd
-    1.700f, //  65  Tb
-    1.700f, //  66  Dy
-    1.700f, //  67  Ho
-    1.700f, //  68  Er
-    1.700f, //  69  Tm
-    1.700f, //  70  Yb
-    1.700f, //  71  Lu
-    1.700f, //  72  Hf
-    1.700f, //  73  Ta
-    1.700f, //  74  W
-    1.700f, //  75  Re
-    1.700f, //  76  Os
-    1.700f, //  77  Ir
-    1.720f, //  78  Pt
-    1.660f, //  79  Au
-    1.550f, //  80  Hg
-    1.960f, //  81  Tl
-    2.020f, //  82  Pb
-    1.700f, //  83  Bi
-    1.700f, //  84  Po
-    1.700f, //  85  At
-    1.700f, //  86  Rn
-    1.700f, //  87  Fr
-    1.700f, //  88  Ra
-    1.700f, //  89  Ac
-    1.700f, //  90  Th
-    1.700f, //  91  Pa
-    1.860f, //  92  U
-    1.700f, //  93  Np
-    1.700f, //  94  Pu
-    1.700f, //  95  Am
-    1.700f, //  96  Cm
-    1.700f, //  97  Bk
-    1.700f, //  98  Cf
-    1.700f, //  99  Es
-    1.700f, // 100  Fm
-    1.700f, // 101  Md
-    1.700f, // 102  No
-    1.700f, // 103  Lr
-    1.700f, // 104  Rf
-    1.700f, // 105  Db
-    1.700f, // 106  Sg
-    1.700f, // 107  Bh
-    1.700f, // 108  Hs
-    1.700f, // 109  Mt
-};
-
-const char * g_elementNames[NUM_ELEMENTS+1] = {
-    "?",    //   0  ?
-    "H",    //   1  H
-    "He",   //   2  He
-    "Li",   //   3  Li
-    "Be",   //   4  Be
-    "B",    //   5  B
-    "C",    //   6  C
-    "N",    //   7  N
-    "O",    //   8  O
-    "F",    //   9  F
-    "Ne",   //  10  Ne
-    "Na",   //  11  Na
-    "Mg",   //  12  Mg
-    "Al",   //  13  Al
-    "Si",   //  14  Si
-    "P",    //  15  P
-    "S",    //  16  S
-    "Cl",   //  17  Cl
-    "Ar",   //  18  Ar
-    "K",    //  19  K
-    "Ca",   //  20  Ca
-    "Sc",   //  21  Sc
-    "Ti",   //  22  Ti
-    "V",    //  23  V
-    "Cr",   //  24  Cr
-    "Mn",   //  25  Mn
-    "Fe",   //  26  Fe
-    "Co",   //  27  Co
-    "Ni",   //  28  Ni
-    "Cu",   //  29  Cu
-    "Zn",   //  30  Zn
-    "Ga",   //  31  Ga
-    "Ge",   //  32  Ge
-    "As",   //  33  As
-    "Se",   //  34  Se
-    "Br",   //  35  Br
-    "Kr",   //  36  Kr
-    "Rb",   //  37  Rb
-    "Sr",   //  38  Sr
-    "Y",    //  39  Y
-    "Zr",   //  40  Zr
-    "Nb",   //  41  Nb
-    "Mo",   //  42  Mo
-    "Tc",   //  43  Tc
-    "Ru",   //  44  Ru
-    "Rh",   //  45  Rh
-    "Pd",   //  46  Pd
-    "Ag",   //  47  Ag
-    "Cd",   //  48  Cd
-    "In",   //  49  In
-    "Sn",   //  50  Sn
-    "Sb",   //  51  Sb
-    "Te",   //  52  Te
-    "I",    //  53  I
-    "Xe",   //  54  Xe
-    "Cs",   //  55  Cs
-    "Ba",   //  56  Ba
-    "La",   //  57  La
-    "Ce",   //  58  Ce
-    "Pr",   //  59  Pr
-    "Nd",   //  60  Nd
-    "Pm",   //  61  Pm
-    "Sm",   //  62  Sm
-    "Eu",   //  63  Eu
-    "Gd",   //  64  Gd
-    "Tb",   //  65  Tb
-    "Dy",   //  66  Dy
-    "Ho",   //  67  Ho
-    "Er",   //  68  Er
-    "Tm",   //  69  Tm
-    "Yb",   //  70  Yb
-    "Lu",   //  71  Lu
-    "Hf",   //  72  Hf
-    "Ta",   //  73  Ta
-    "W",    //  74  W
-    "Re",   //  75  Re
-    "Os",   //  76  Os
-    "Ir",   //  77  Ir
-    "Pt",   //  78  Pt
-    "Au",   //  79  Au
-    "Hg",   //  80  Hg
-    "Tl",   //  81  Tl
-    "Pb",   //  82  Pb
-    "Bi",   //  83  Bi
-    "Po",   //  84  Po
-    "At",   //  85  At
-    "Rn",   //  86  Rn
-    "Fr",   //  87  Fr
-    "Ra",   //  88  Ra
-    "Ac",   //  89  Ac
-    "Th",   //  90  Th
-    "Pa",   //  91  Pa
-    "U",    //  92  U
-    "Np",   //  93  Np
-    "Pu",   //  94  Pu
-    "Am",   //  95  Am
-    "Cm",   //  96  Cm
-    "Bk",   //  97  Bk
-    "Cf",   //  98  Cf
-    "Es",   //  99  Es
-    "Fm",   // 100  Fm
-    "Md",   // 101  Md
-    "No",   // 102  No
-    "Lr",   // 103  Lr
-    "Rf",   // 104  Rf
-    "Db",   // 105  Db
-    "Sg",   // 106  Sg
-    "Bh",   // 107  Bh
-    "Hs",   // 108  Hs
-    "Mt",   // 109  Mt
-};
Index: unk/packages/vizservers/vtkvis/RpOutline.cpp
===================================================================
--- /trunk/packages/vizservers/vtkvis/RpOutline.cpp	(revision 3615)
+++ 	(revision )
@@ -1,104 +1,0 @@
-/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
-/*
- * Copyright (C) 2004-2013  HUBzero Foundation, LLC
- *
- * Author: Leif Delgass <ldelgass@purdue.edu>
- */
-
-#include <cassert>
-
-#include <vtkDataSet.h>
-#include <vtkStructuredGrid.h>
-#include <vtkPolyData.h>
-#include <vtkOutlineFilter.h>
-#include <vtkStructuredGridOutlineFilter.h>
-
-#include "RpOutline.h"
-#include "Trace.h"
-
-using namespace VtkVis;
-
-Outline::Outline() :
-    VtkGraphicsObject()
-{
-}
-
-Outline::~Outline()
-{
-#ifdef WANT_TRACE
-    if (_dataSet != NULL)
-        TRACE("Deleting Outline for %s", _dataSet->getName().c_str());
-    else
-        TRACE("Deleting Outline with NULL DataSet");
-#endif
-}
-
-/**
- * \brief Create and initialize a VTK Prop to render a mesh
- */
-void Outline::initProp()
-{
-    VtkGraphicsObject::initProp();
-}
-
-/**
- * \brief Internal method to set up pipeline after a state change
- */
-void Outline::update()
-{
-    if (_dataSet == NULL) {
-        return;
-    }
-
-    if (_pdMapper == NULL) {
-        _pdMapper = vtkSmartPointer<vtkPolyDataMapper>::New();
-        _pdMapper->SetResolveCoincidentTopologyToPolygonOffset();
-        _pdMapper->ScalarVisibilityOff();
-    }
-
-    vtkDataSet *ds = _dataSet->getVtkDataSet();
-    vtkStructuredGrid *sg = vtkStructuredGrid::SafeDownCast(ds);
-    if (sg != NULL) {
-        vtkSmartPointer<vtkStructuredGridOutlineFilter> ofilter = vtkSmartPointer<vtkStructuredGridOutlineFilter>::New();
-#ifdef USE_VTK6
-        ofilter->SetInputData(ds);
-#else
-        ofilter->SetInput(ds);
-#endif
-        ofilter->ReleaseDataFlagOn();
-        _pdMapper->SetInputConnection(ofilter->GetOutputPort());
-    } else {
-        vtkSmartPointer<vtkOutlineFilter> ofilter = vtkSmartPointer<vtkOutlineFilter>::New();
-#ifdef USE_VTK6
-        ofilter->SetInputData(ds);
-#else
-        ofilter->SetInput(ds);
-#endif
-        ofilter->ReleaseDataFlagOn();
-        _pdMapper->SetInputConnection(ofilter->GetOutputPort());
-    }
-
-    initProp();
-
-    setVisibility(_dataSet->getVisibility());
-
-    getActor()->SetMapper(_pdMapper);
-    _pdMapper->Update();
-
-#ifdef WANT_TRACE
-    double *b = getBounds();
-    TRACE("bounds: %g %g %g %g %g %g", b[0], b[1], b[2], b[3], b[4], b[5]);
-#endif
-}
-
-/**
- * \brief Set a group of world coordinate planes to clip rendering
- *
- * Passing NULL for planes will remove all cliping planes
- */
-void Outline::setClippingPlanes(vtkPlaneCollection *planes)
-{
-    if (_pdMapper != NULL) {
-        _pdMapper->SetClippingPlanes(planes);
-    }
-}
Index: unk/packages/vizservers/vtkvis/RpOutline.h
===================================================================
--- /trunk/packages/vizservers/vtkvis/RpOutline.h	(revision 3615)
+++ 	(revision )
@@ -1,46 +1,0 @@
-/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
-/*
- * Copyright (C) 2004-2013  HUBzero Foundation, LLC
- *
- * Author: Leif Delgass <ldelgass@purdue.edu>
- */
-
-#ifndef VTKVIS_OUTLINE_H
-#define VTKVIS_OUTLINE_H
-
-#include <vtkSmartPointer.h>
-#include <vtkPolyDataMapper.h>
-#include <vtkActor.h>
-
-#include "RpVtkGraphicsObject.h"
-#include "RpVtkDataSet.h"
-
-namespace VtkVis {
-
-/**
- * \brief VTK Wire outline of DataSet
- *
- * This class creates a wireframe box around the DataSet bounds
- */
-class Outline : public VtkGraphicsObject {
-public:
-    Outline();
-    virtual ~Outline();
-
-    virtual const char *getClassName() const
-    {
-        return "Outline";
-    }
-
-    virtual void setClippingPlanes(vtkPlaneCollection *planes);
-
-private:
-    virtual void initProp();
-    virtual void update();
-
-    vtkSmartPointer<vtkPolyDataMapper> _pdMapper;
-};
-
-}
-
-#endif
Index: unk/packages/vizservers/vtkvis/RpPolyData.cpp
===================================================================
--- /trunk/packages/vizservers/vtkvis/RpPolyData.cpp	(revision 3615)
+++ 	(revision )
@@ -1,205 +1,0 @@
-/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
-/*
- * Copyright (C) 2004-2012  HUBzero Foundation, LLC
- *
- * Author: Leif Delgass <ldelgass@purdue.edu>
- */
-
-#include <cassert>
-
-#include <vtkDataSet.h>
-#include <vtkPolyData.h>
-#include <vtkUnstructuredGrid.h>
-#include <vtkPolyDataMapper.h>
-#include <vtkActor.h>
-#include <vtkProperty.h>
-#include <vtkTransform.h>
-#include <vtkDelaunay2D.h>
-#include <vtkDelaunay3D.h>
-#include <vtkDataSetSurfaceFilter.h>
-
-#include "RpPolyData.h"
-#include "Trace.h"
-
-using namespace VtkVis;
-
-PolyData::PolyData() :
-    VtkGraphicsObject()
-{
-}
-
-PolyData::~PolyData()
-{
-#ifdef WANT_TRACE
-    if (_dataSet != NULL)
-        TRACE("Deleting PolyData for %s", _dataSet->getName().c_str());
-    else
-        TRACE("Deleting PolyData with NULL DataSet");
-#endif
-}
-
-/**
- * \brief Create and initialize a VTK Prop to render a mesh
- */
-void PolyData::initProp()
-{
-    VtkGraphicsObject::initProp();
-}
-
-/**
- * \brief Internal method to set up pipeline after a state change
- */
-void PolyData::update()
-{
-    if (_dataSet == NULL) {
-        return;
-    }
-
-    if (_pdMapper == NULL) {
-        _pdMapper = vtkSmartPointer<vtkPolyDataMapper>::New();
-        _pdMapper->SetResolveCoincidentTopologyToPolygonOffset();
-        _pdMapper->ScalarVisibilityOff();
-    }
-
-    vtkDataSet *ds = _dataSet->getVtkDataSet();
-    vtkPolyData *pd = vtkPolyData::SafeDownCast(ds);
-    if (pd) {
-        TRACE("Points: %d Verts: %d Lines: %d Polys: %d Strips: %d",
-              pd->GetNumberOfPoints(),
-              pd->GetNumberOfVerts(),
-              pd->GetNumberOfLines(),
-              pd->GetNumberOfPolys(),
-              pd->GetNumberOfStrips());
-        // DataSet is a vtkPolyData
-        if (pd->GetNumberOfLines() == 0 &&
-            pd->GetNumberOfPolys() == 0 &&
-            pd->GetNumberOfStrips() == 0) {
-            // DataSet is a point cloud
-            PrincipalPlane plane;
-            double offset;
-            if (_dataSet->numDimensions() < 2 || pd->GetNumberOfPoints() < 3) {
-                // 0D or 1D or not enough points to mesh
-#ifdef USE_VTK6
-                _pdMapper->SetInputData(pd);
-#else
-                _pdMapper->SetInput(pd);
-#endif
-            } else if (_dataSet->is2D(&plane, &offset)) {
-                vtkSmartPointer<vtkDelaunay2D> mesher = vtkSmartPointer<vtkDelaunay2D>::New();
-                if (plane == PLANE_ZY) {
-                    vtkSmartPointer<vtkTransform> trans = vtkSmartPointer<vtkTransform>::New();
-                    trans->RotateWXYZ(90, 0, 1, 0);
-                    if (offset != 0.0) {
-                        trans->Translate(-offset, 0, 0);
-                    }
-                    mesher->SetTransform(trans);
-                } else if (plane == PLANE_XZ) {
-                     vtkSmartPointer<vtkTransform> trans = vtkSmartPointer<vtkTransform>::New();
-                    trans->RotateWXYZ(-90, 1, 0, 0);
-                    if (offset != 0.0) {
-                        trans->Translate(0, -offset, 0);
-                    }
-                    mesher->SetTransform(trans);
-                } else if (offset != 0.0) {
-                    // XY with Z offset
-                    vtkSmartPointer<vtkTransform> trans = vtkSmartPointer<vtkTransform>::New();
-                    trans->Translate(0, 0, -offset);
-                    mesher->SetTransform(trans);
-                }
-#ifdef USE_VTK6
-                mesher->SetInputData(pd);
-#else
-                mesher->SetInput(pd);
-#endif
-                mesher->ReleaseDataFlagOn();
-                mesher->Update();
-                vtkPolyData *outpd = mesher->GetOutput();
-                TRACE("Delaunay2D Verts: %d Lines: %d Polys: %d Strips: %d",
-                      outpd->GetNumberOfVerts(),
-                      outpd->GetNumberOfLines(),
-                      outpd->GetNumberOfPolys(),
-                      outpd->GetNumberOfStrips());
-                if (outpd->GetNumberOfPolys() == 0) {
-                    WARN("Delaunay2D mesher failed");
-#ifdef USE_VTK6
-                    _pdMapper->SetInputData(pd);
-#else
-                    _pdMapper->SetInput(pd);
-#endif
-                } else {
-                    _pdMapper->SetInputConnection(mesher->GetOutputPort());
-                }
-            } else {
-                vtkSmartPointer<vtkDelaunay3D> mesher = vtkSmartPointer<vtkDelaunay3D>::New();
-#ifdef USE_VTK6
-                mesher->SetInputData(pd);
-#else
-                mesher->SetInput(pd);
-#endif
-                mesher->ReleaseDataFlagOn();
-                mesher->Update();
-                vtkUnstructuredGrid *grid = mesher->GetOutput();
-                TRACE("Delaunay3D Cells: %d",
-                      grid->GetNumberOfCells());
-                if (grid->GetNumberOfCells() == 0) {
-                    WARN("Delaunay3D mesher failed");
-#ifdef USE_VTK6
-                    _pdMapper->SetInputData(pd);
-#else
-                    _pdMapper->SetInput(pd);
-#endif
-                } else {
-                    // Delaunay3D returns an UnstructuredGrid, so feed it 
-                    // through a surface filter to get the grid boundary 
-                    // as a PolyData
-                    vtkSmartPointer<vtkDataSetSurfaceFilter> gf = vtkSmartPointer<vtkDataSetSurfaceFilter>::New();
-                    gf->UseStripsOn();
-                    gf->SetInputConnection(mesher->GetOutputPort());
-                    gf->ReleaseDataFlagOn();
-                    _pdMapper->SetInputConnection(gf->GetOutputPort());
-                }
-             }
-        } else {
-            // DataSet is a vtkPolyData with lines and/or polygons
-#ifdef USE_VTK6
-            _pdMapper->SetInputData(pd);
-#else
-            _pdMapper->SetInput(pd);
-#endif
-        }
-    } else {
-        // DataSet is NOT a vtkPolyData
-        TRACE("DataSet is not a PolyData");
-        vtkSmartPointer<vtkDataSetSurfaceFilter> gf = vtkSmartPointer<vtkDataSetSurfaceFilter>::New();
-        gf->UseStripsOn();
-#ifdef USE_VTK6
-        gf->SetInputData(ds);
-#else
-        gf->SetInput(ds);
-#endif
-        gf->ReleaseDataFlagOn();
-        _pdMapper->SetInputConnection(gf->GetOutputPort());
-    }
-
-    initProp();
-    setVisibility(_dataSet->getVisibility());
-    getActor()->SetMapper(_pdMapper);
-    _pdMapper->Update();
-#ifdef WANT_TRACE
-    double *b = getBounds();
-    TRACE("bounds: %g %g %g %g %g %g", b[0], b[1], b[2], b[3], b[4], b[5]);
-#endif
-}
-
-/**
- * \brief Set a group of world coordinate planes to clip rendering
- *
- * Passing NULL for planes will remove all cliping planes
- */
-void PolyData::setClippingPlanes(vtkPlaneCollection *planes)
-{
-    if (_pdMapper != NULL) {
-        _pdMapper->SetClippingPlanes(planes);
-    }
-}
-
Index: unk/packages/vizservers/vtkvis/RpPolyData.h
===================================================================
--- /trunk/packages/vizservers/vtkvis/RpPolyData.h	(revision 3615)
+++ 	(revision )
@@ -1,46 +1,0 @@
-/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
-/*
- * Copyright (C) 2004-2012  HUBzero Foundation, LLC
- *
- * Author: Leif Delgass <ldelgass@purdue.edu>
- */
-
-#ifndef VTKVIS_POLYDATA_H
-#define VTKVIS_POLYDATA_H
-
-#include <vtkSmartPointer.h>
-#include <vtkPolyDataMapper.h>
-#include <vtkActor.h>
-
-#include "RpVtkGraphicsObject.h"
-#include "RpVtkDataSet.h"
-
-namespace VtkVis {
-
-/**
- * \brief VTK Mesh (Polygon data)
- *
- * This class creates a boundary mesh of a DataSet
- */
-class PolyData : public VtkGraphicsObject {
-public:
-    PolyData();
-    virtual ~PolyData();
-
-    virtual const char *getClassName() const
-    {
-        return "PolyData";
-    }
-
-    virtual void setClippingPlanes(vtkPlaneCollection *planes);
-
-private:
-    virtual void initProp();
-    virtual void update();
-
-    vtkSmartPointer<vtkPolyDataMapper> _pdMapper;
-};
-
-}
-
-#endif
Index: unk/packages/vizservers/vtkvis/RpPolygon.cpp
===================================================================
--- /trunk/packages/vizservers/vtkvis/RpPolygon.cpp	(revision 3615)
+++ 	(revision )
@@ -1,45 +1,0 @@
-/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
-/*
- * Copyright (C) 2004-2012  HUBzero Foundation, LLC
- *
- * Author: Leif Delgass <ldelgass@purdue.edu>
- */
-
-#include <vtkPolyDataMapper.h>
-#include <vtkActor.h>
-#include <vtkRegularPolygonSource.h>
-
-#include "RpPolygon.h"
-#include "Trace.h"
-
-using namespace VtkVis;
-
-Polygon::Polygon() :
-    Shape()
-{
-}
-
-Polygon::~Polygon()
-{
-    TRACE("Deleting Polygon");
-}
-
-void Polygon::update()
-{
-    if (_polygon == NULL) {
-	_polygon = vtkSmartPointer<vtkRegularPolygonSource>::New();
-    }
-
-    if (_pdMapper == NULL) {
-        _pdMapper = vtkSmartPointer<vtkPolyDataMapper>::New();
-        _pdMapper->SetResolveCoincidentTopologyToPolygonOffset();
-        _pdMapper->ScalarVisibilityOff();
-    }
-
-    _pdMapper->SetInputConnection(_polygon->GetOutputPort());
-
-    initProp();
-
-    getActor()->SetMapper(_pdMapper);
-    _pdMapper->Update();
-}
Index: unk/packages/vizservers/vtkvis/RpPolygon.h
===================================================================
--- /trunk/packages/vizservers/vtkvis/RpPolygon.h	(revision 3615)
+++ 	(revision )
@@ -1,73 +1,0 @@
-/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
-/*
- * Copyright (C) 2004-2012  HUBzero Foundation, LLC
- *
- * Author: Leif Delgass <ldelgass@purdue.edu>
- */
-
-#ifndef VTKVIS_POLYGON_H
-#define VTKVIS_POLYGON_H_
-
-#include <vtkSmartPointer.h>
-#include <vtkPolyDataMapper.h>
-#include <vtkActor.h>
-#include <vtkRegularPolygonSource.h>
-
-#include "RpShape.h"
-#include "RpVtkDataSet.h"
-
-namespace VtkVis {
-
-/**
- * \brief VTK PolyData regular n-sided polygon
- *
- * This class creates a regular n-sided polygon
- */
-class Polygon : public Shape
-{
-public:
-    Polygon();
-    virtual ~Polygon();
-
-    virtual const char *getClassName() const
-    {
-        return "Polygon";
-    }
-
-    void setNumberOfSides(int numSides)
-    {
-        if (_polygon != NULL) {
-            _polygon->SetNumberOfSides(numSides);
-	}
-    }
-
-    void setCenter(double center[3])
-    {
-        if (_polygon != NULL) {
-            _polygon->SetCenter(center);
-	}
-    }
-
-    void setNormal(double normal[3])
-    {
-        if (_polygon != NULL) {
-            _polygon->SetNormal(normal);
-	}
-    }
-
-    void setRadius(double radius)
-    {
-        if (_polygon != NULL) {
-            _polygon->SetRadius(radius);
-	}
-    }
-
-private:
-    virtual void update();
-
-    vtkSmartPointer<vtkRegularPolygonSource> _polygon;
-};
-
-}
-
-#endif
Index: unk/packages/vizservers/vtkvis/RpPseudoColor.cpp
===================================================================
--- /trunk/packages/vizservers/vtkvis/RpPseudoColor.cpp	(revision 3615)
+++ 	(revision )
@@ -1,514 +1,0 @@
-/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
-/*
- * Copyright (C) 2004-2012  HUBzero Foundation, LLC
- *
- * Author: Leif Delgass <ldelgass@purdue.edu>
- */
-
-#include <cassert>
-#include <cfloat>
-#include <cstring>
-
-#include <vtkDataSet.h>
-#include <vtkPointData.h>
-#include <vtkCellData.h>
-#include <vtkDataSetMapper.h>
-#include <vtkUnstructuredGrid.h>
-#include <vtkProperty.h>
-#include <vtkImageData.h>
-#include <vtkLookupTable.h>
-#include <vtkTransform.h>
-#include <vtkDelaunay2D.h>
-#include <vtkDelaunay3D.h>
-#include <vtkGaussianSplatter.h>
-#include <vtkExtractVOI.h>
-#include <vtkDataSetSurfaceFilter.h>
-
-#include "RpPseudoColor.h"
-#include "RpVtkRenderer.h"
-#include "Trace.h"
-
-#define MESH_POINT_CLOUDS
-
-using namespace VtkVis;
-
-PseudoColor::PseudoColor() :
-    VtkGraphicsObject(),
-    _colorMap(NULL),
-    _colorMode(COLOR_BY_SCALAR),
-    _colorFieldType(DataSet::POINT_DATA),
-    _renderer(NULL)
-{
-    _colorFieldRange[0] = DBL_MAX;
-    _colorFieldRange[1] = -DBL_MAX;
-}
-
-PseudoColor::~PseudoColor()
-{
-#ifdef WANT_TRACE
-    if (_dataSet != NULL)
-        TRACE("Deleting PseudoColor for %s", _dataSet->getName().c_str());
-    else
-        TRACE("Deleting PseudoColor with NULL DataSet");
-#endif
-}
-
-void PseudoColor::setDataSet(DataSet *dataSet,
-                             Renderer *renderer)
-{
-    if (_dataSet != dataSet) {
-        _dataSet = dataSet;
-
-        _renderer = renderer;
-
-        if (renderer->getUseCumulativeRange()) {
-            renderer->getCumulativeDataRange(_dataRange,
-                                             _dataSet->getActiveScalarsName(),
-                                             1);
-            renderer->getCumulativeDataRange(_vectorMagnitudeRange,
-                                             _dataSet->getActiveVectorsName(),
-                                             3);
-            for (int i = 0; i < 3; i++) {
-                renderer->getCumulativeDataRange(_vectorComponentRange[i],
-                                                 _dataSet->getActiveVectorsName(),
-                                                 3, i);
-            }
-        } else {
-            _dataSet->getScalarRange(_dataRange);
-            _dataSet->getVectorRange(_vectorMagnitudeRange);
-            for (int i = 0; i < 3; i++) {
-                _dataSet->getVectorRange(_vectorComponentRange[i], i);
-            }
-        }
-
-        update();
-    }
-}
-
-/**
- * \brief Internal method to set up pipeline after a state change
- */
-void PseudoColor::update()
-{
-    if (_dataSet == NULL)
-        return;
-
-    vtkDataSet *ds = _dataSet->getVtkDataSet();
-
-    // Mapper, actor to render color-mapped data set
-    if (_dsMapper == NULL) {
-        _dsMapper = vtkSmartPointer<vtkDataSetMapper>::New();
-        // Map scalars through lookup table regardless of type
-        _dsMapper->SetColorModeToMapScalars();
-    }
-
-    vtkPolyData *pd = vtkPolyData::SafeDownCast(ds);
-    if (pd) {
-        // DataSet is a vtkPolyData
-        if (pd->GetNumberOfLines() == 0 &&
-            pd->GetNumberOfPolys() == 0 &&
-            pd->GetNumberOfStrips() == 0) {
-            // DataSet is a point cloud
-            PrincipalPlane plane;
-            double offset;
-            if (_dataSet->is2D(&plane, &offset)) {
-#ifdef MESH_POINT_CLOUDS
-                vtkSmartPointer<vtkDelaunay2D> mesher = vtkSmartPointer<vtkDelaunay2D>::New();
-                if (plane == PLANE_ZY) {
-                    vtkSmartPointer<vtkTransform> trans = vtkSmartPointer<vtkTransform>::New();
-                    trans->RotateWXYZ(90, 0, 1, 0);
-                    if (offset != 0.0) {
-                        trans->Translate(-offset, 0, 0);
-                    }
-                    mesher->SetTransform(trans);
-                } else if (plane == PLANE_XZ) {
-                    vtkSmartPointer<vtkTransform> trans = vtkSmartPointer<vtkTransform>::New();
-                    trans->RotateWXYZ(-90, 1, 0, 0);
-                    if (offset != 0.0) {
-                        trans->Translate(0, -offset, 0);
-                    }
-                    mesher->SetTransform(trans);
-                } else if (offset != 0.0) {
-                    // XY with Z offset
-                    vtkSmartPointer<vtkTransform> trans = vtkSmartPointer<vtkTransform>::New();
-                    trans->Translate(0, 0, -offset);
-                    mesher->SetTransform(trans);
-                }
-#ifdef USE_VTK6
-                mesher->SetInputData(pd);
-#else
-                mesher->SetInput(pd);
-#endif
-                _dsMapper->SetInputConnection(mesher->GetOutputPort());
-#else
-                vtkSmartPointer<vtkGaussianSplatter> splatter = vtkSmartPointer<vtkGaussianSplatter>::New();
-                vtkSmartPointer<vtkExtractVOI> slicer = vtkSmartPointer<vtkExtractVOI>::New();
-#ifdef USE_VTK6
-                splatter->SetInputData(pd);
-#else
-                splatter->SetInput(pd);
-#endif
-                int dims[3];
-                splatter->GetSampleDimensions(dims);
-                TRACE("Sample dims: %d %d %d", dims[0], dims[1], dims[2]);
-                if (plane == PLANE_ZY) {
-                    dims[0] = 3;
-                    slicer->SetVOI(1, 1, 0, dims[1]-1, 0, dims[1]-1);
-                } else if (plane == PLANE_XZ) {
-                    dims[1] = 3;
-                    slicer->SetVOI(0, dims[0]-1, 1, 1, 0, dims[2]-1);
-                } else {
-                    dims[2] = 3;
-                    slicer->SetVOI(0, dims[0]-1, 0, dims[1]-1, 1, 1);
-                }
-                splatter->SetSampleDimensions(dims);
-                double bounds[6];
-                splatter->Update();
-                splatter->GetModelBounds(bounds);
-                TRACE("Model bounds: %g %g %g %g %g %g",
-                      bounds[0], bounds[1],
-                      bounds[2], bounds[3],
-                      bounds[4], bounds[5]);
-                slicer->SetInputConnection(splatter->GetOutputPort());
-                slicer->SetSampleRate(1, 1, 1);
-                vtkSmartPointer<vtkDataSetSurfaceFilter> gf = vtkSmartPointer<vtkDataSetSurfaceFilter>::New();
-                gf->UseStripsOn();
-                gf->SetInputConnection(slicer->GetOutputPort());
-                _dsMapper->SetInputConnection(gf->GetOutputPort());
-#endif
-            } else {
-                vtkSmartPointer<vtkDelaunay3D> mesher = vtkSmartPointer<vtkDelaunay3D>::New();
-#ifdef USE_VTK6
-                mesher->SetInputData(pd);
-#else
-                mesher->SetInput(pd);
-#endif
-                vtkSmartPointer<vtkDataSetSurfaceFilter> gf = vtkSmartPointer<vtkDataSetSurfaceFilter>::New();
-                gf->SetInputConnection(mesher->GetOutputPort());
-                _dsMapper->SetInputConnection(gf->GetOutputPort());
-             }
-        } else {
-            // DataSet is a vtkPolyData with lines and/or polygons
-#ifdef USE_VTK6
-            _dsMapper->SetInputData(ds);
-#else
-            _dsMapper->SetInput(ds);
-#endif
-        }
-    } else {
-        TRACE("Generating surface for data set");
-        // DataSet is NOT a vtkPolyData
-        vtkSmartPointer<vtkDataSetSurfaceFilter> gf = vtkSmartPointer<vtkDataSetSurfaceFilter>::New();
-#ifdef USE_VTK6
-        gf->SetInputData(ds);
-#else
-        gf->SetInput(ds);
-#endif
-        _dsMapper->SetInputConnection(gf->GetOutputPort());
-    }
-
-    setInterpolateBeforeMapping(true);
-
-    if (_lut == NULL) {
-        setColorMap(ColorMap::getDefault());
-    }
-
-    setColorMode(_colorMode);
-
-    initProp();
-    getActor()->SetMapper(_dsMapper);
-    _dsMapper->Update();
-}
-
-void PseudoColor::setInterpolateBeforeMapping(bool state)
-{
-    if (_dsMapper != NULL) {
-        _dsMapper->SetInterpolateScalarsBeforeMapping((state ? 1 : 0));
-    }
-}
-
-void PseudoColor::updateRanges(Renderer *renderer)
-{
-    if (_dataSet == NULL) {
-        ERROR("called before setDataSet");
-        return;
-    }
-
-    if (renderer->getUseCumulativeRange()) {
-        renderer->getCumulativeDataRange(_dataRange,
-                                         _dataSet->getActiveScalarsName(),
-                                         1);
-        renderer->getCumulativeDataRange(_vectorMagnitudeRange,
-                                         _dataSet->getActiveVectorsName(),
-                                         3);
-        for (int i = 0; i < 3; i++) {
-            renderer->getCumulativeDataRange(_vectorComponentRange[i],
-                                             _dataSet->getActiveVectorsName(),
-                                             3, i);
-        }
-    } else {
-        _dataSet->getScalarRange(_dataRange);
-        _dataSet->getVectorRange(_vectorMagnitudeRange);
-        for (int i = 0; i < 3; i++) {
-            _dataSet->getVectorRange(_vectorComponentRange[i], i);
-        }
-    }
-
-    // Need to update color map ranges
-    double *rangePtr = _colorFieldRange;
-    if (_colorFieldRange[0] > _colorFieldRange[1]) {
-        rangePtr = NULL;
-    }
-    setColorMode(_colorMode, _colorFieldType, _colorFieldName.c_str(), rangePtr);
-}
-
-void PseudoColor::setColorMode(ColorMode mode)
-{
-    _colorMode = mode;
-    if (_dataSet == NULL)
-        return;
-
-    switch (mode) {
-    case COLOR_BY_SCALAR:
-        setColorMode(mode,
-                     _dataSet->getActiveScalarsType(),
-                     _dataSet->getActiveScalarsName(),
-                     _dataRange);
-        break;
-    case COLOR_BY_VECTOR_MAGNITUDE:
-        setColorMode(mode,
-                     _dataSet->getActiveVectorsType(),
-                     _dataSet->getActiveVectorsName(),
-                     _vectorMagnitudeRange);
-        break;
-    case COLOR_BY_VECTOR_X:
-        setColorMode(mode,
-                     _dataSet->getActiveVectorsType(),
-                     _dataSet->getActiveVectorsName(),
-                     _vectorComponentRange[0]);
-        break;
-    case COLOR_BY_VECTOR_Y:
-        setColorMode(mode,
-                     _dataSet->getActiveVectorsType(),
-                     _dataSet->getActiveVectorsName(),
-                     _vectorComponentRange[1]);
-        break;
-    case COLOR_BY_VECTOR_Z:
-        setColorMode(mode,
-                     _dataSet->getActiveVectorsType(),
-                     _dataSet->getActiveVectorsName(),
-                     _vectorComponentRange[2]);
-        break;
-    case COLOR_CONSTANT:
-    default:
-        setColorMode(mode, DataSet::POINT_DATA, NULL, NULL);
-        break;
-    }
-}
-
-void PseudoColor::setColorMode(ColorMode mode,
-                               const char *name, double range[2])
-{
-    if (_dataSet == NULL)
-        return;
-    DataSet::DataAttributeType type = DataSet::POINT_DATA;
-    int numComponents = 1;
-    if (name != NULL && strlen(name) > 0 &&
-        !_dataSet->getFieldInfo(name, &type, &numComponents)) {
-        ERROR("Field not found: %s", name);
-        return;
-    }
-    setColorMode(mode, type, name, range);
-}
-
-void PseudoColor::setColorMode(ColorMode mode, DataSet::DataAttributeType type,
-                               const char *name, double range[2])
-{
-    _colorMode = mode;
-    _colorFieldType = type;
-    if (name == NULL)
-        _colorFieldName.clear();
-    else
-        _colorFieldName = name;
-    if (range == NULL) {
-        _colorFieldRange[0] = DBL_MAX;
-        _colorFieldRange[1] = -DBL_MAX;
-    } else {
-        memcpy(_colorFieldRange, range, sizeof(double)*2);
-    }
-
-    if (_dataSet == NULL || _dsMapper == NULL)
-        return;
-
-    switch (type) {
-    case DataSet::POINT_DATA:
-        _dsMapper->SetScalarModeToUsePointFieldData();
-        break;
-    case DataSet::CELL_DATA:
-        _dsMapper->SetScalarModeToUseCellFieldData();
-        break;
-    default:
-        ERROR("Unsupported DataAttributeType: %d", type);
-        return;
-    }
-
-    if (name != NULL && strlen(name) > 0) {
-        _dsMapper->SelectColorArray(name);
-    } else {
-        _dsMapper->SetScalarModeToDefault();
-    }
-
-    if (_lut != NULL) {
-        if (range != NULL) {
-            _lut->SetRange(range);
-        } else if (name != NULL && strlen(name) > 0) {
-            double r[2];
-            int comp = -1;
-            if (mode == COLOR_BY_VECTOR_X)
-                comp = 0;
-            else if (mode == COLOR_BY_VECTOR_Y)
-                comp = 1;
-            else if (mode == COLOR_BY_VECTOR_Z)
-                comp = 2;
-
-            if (_renderer->getUseCumulativeRange()) {
-                int numComponents;
-                if  (!_dataSet->getFieldInfo(name, type, &numComponents)) {
-                    ERROR("Field not found: %s, type: %d", name, type);
-                    return;
-                } else if (numComponents < comp+1) {
-                    ERROR("Request for component %d in field with %d components",
-                          comp, numComponents);
-                    return;
-                }
-                _renderer->getCumulativeDataRange(r, name, type, numComponents, comp);
-            } else {
-                _dataSet->getDataRange(r, name, type, comp);
-            }
-            _lut->SetRange(r);
-        }
-    }
-
-    switch (mode) {
-    case COLOR_BY_SCALAR:
-        _dsMapper->ScalarVisibilityOn();
-        break;
-    case COLOR_BY_VECTOR_MAGNITUDE:
-        _dsMapper->ScalarVisibilityOn();
-        if (_lut != NULL) {
-            _lut->SetVectorModeToMagnitude();
-        }
-        break;
-    case COLOR_BY_VECTOR_X:
-        _dsMapper->ScalarVisibilityOn();
-        if (_lut != NULL) {
-            _lut->SetVectorModeToComponent();
-            _lut->SetVectorComponent(0);
-        }
-        break;
-    case COLOR_BY_VECTOR_Y:
-        _dsMapper->ScalarVisibilityOn();
-        if (_lut != NULL) {
-            _lut->SetVectorModeToComponent();
-            _lut->SetVectorComponent(1);
-        }
-        break;
-    case COLOR_BY_VECTOR_Z:
-        _dsMapper->ScalarVisibilityOn();
-        if (_lut != NULL) {
-            _lut->SetVectorModeToComponent();
-            _lut->SetVectorComponent(2);
-        }
-        break;
-    case COLOR_CONSTANT:
-    default:
-        _dsMapper->ScalarVisibilityOff();
-        break;
-    }
-}
-
-/**
- * \brief Called when the color map has been edited
- */
-void PseudoColor::updateColorMap()
-{
-    setColorMap(_colorMap);
-}
-
-/**
- * \brief Associate a colormap lookup table with the DataSet
- */
-void PseudoColor::setColorMap(ColorMap *cmap)
-{
-    if (cmap == NULL)
-        return;
-
-    _colorMap = cmap;
- 
-    if (_lut == NULL) {
-        _lut = vtkSmartPointer<vtkLookupTable>::New();
-        if (_dsMapper != NULL) {
-            _dsMapper->UseLookupTableScalarRangeOn();
-            _dsMapper->SetLookupTable(_lut);
-        }
-        _lut->DeepCopy(cmap->getLookupTable());
-        switch (_colorMode) {
-        case COLOR_CONSTANT:
-        case COLOR_BY_SCALAR:
-            _lut->SetRange(_dataRange);
-            break;
-        case COLOR_BY_VECTOR_MAGNITUDE:
-            _lut->SetRange(_vectorMagnitudeRange);
-            break;
-        case COLOR_BY_VECTOR_X:
-            _lut->SetRange(_vectorComponentRange[0]);
-            break;
-        case COLOR_BY_VECTOR_Y:
-            _lut->SetRange(_vectorComponentRange[1]);
-            break;
-        case COLOR_BY_VECTOR_Z:
-            _lut->SetRange(_vectorComponentRange[2]);
-            break;
-        default:
-            break;
-        }
-    } else {
-        double range[2];
-        _lut->GetTableRange(range);
-        _lut->DeepCopy(cmap->getLookupTable());
-        _lut->SetRange(range);
-        _lut->Modified();
-    }
-
-    switch (_colorMode) {
-    case COLOR_BY_VECTOR_MAGNITUDE:
-        _lut->SetVectorModeToMagnitude();
-        break;
-    case COLOR_BY_VECTOR_X:
-        _lut->SetVectorModeToComponent();
-        _lut->SetVectorComponent(0);
-        break;
-    case COLOR_BY_VECTOR_Y:
-        _lut->SetVectorModeToComponent();
-        _lut->SetVectorComponent(1);
-        break;
-    case COLOR_BY_VECTOR_Z:
-        _lut->SetVectorModeToComponent();
-        _lut->SetVectorComponent(2);
-        break;
-    default:
-         break;
-    }
-}
-
-/**
- * \brief Set a group of world coordinate planes to clip rendering
- *
- * Passing NULL for planes will remove all cliping planes
- */
-void PseudoColor::setClippingPlanes(vtkPlaneCollection *planes)
-{
-    if (_dsMapper != NULL) {
-        _dsMapper->SetClippingPlanes(planes);
-    }
-}
Index: unk/packages/vizservers/vtkvis/RpPseudoColor.h
===================================================================
--- /trunk/packages/vizservers/vtkvis/RpPseudoColor.h	(revision 3615)
+++ 	(revision )
@@ -1,91 +1,0 @@
-/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
-/*
- * Copyright (C) 2004-2012  HUBzero Foundation, LLC
- *
- * Author: Leif Delgass <ldelgass@purdue.edu>
- */
-
-#ifndef VTKVIS_PSEUDOCOLOR_H
-#define VTKVIS_PSEUDOCOLOR_H
-
-#include <vtkSmartPointer.h>
-#include <vtkLookupTable.h>
-#include <vtkDataSetMapper.h>
-#include <vtkActor.h>
-#include <vtkPlaneCollection.h>
-
-#include "ColorMap.h"
-#include "RpVtkGraphicsObject.h"
-
-namespace VtkVis {
-
-/**
- * \brief Color-mapped plot of data set
- */
-class PseudoColor : public VtkGraphicsObject {
-public:
-    enum ColorMode {
-        COLOR_BY_SCALAR,
-        COLOR_BY_VECTOR_MAGNITUDE,
-        COLOR_BY_VECTOR_X,
-        COLOR_BY_VECTOR_Y,
-        COLOR_BY_VECTOR_Z,
-        COLOR_CONSTANT
-    };
-
-    PseudoColor();
-    virtual ~PseudoColor();
-
-    virtual const char *getClassName() const
-    {
-        return "PseudoColor";
-    }
-
-    virtual void setDataSet(DataSet *dataSet,
-                            Renderer *renderer);
-
-    virtual void setClippingPlanes(vtkPlaneCollection *planes);
-
-    void setInterpolateBeforeMapping(bool state);
-
-    void setColorMode(ColorMode mode, DataSet::DataAttributeType type,
-                      const char *name, double range[2] = NULL);
-
-    void setColorMode(ColorMode mode,
-                      const char *name, double range[2] = NULL);
-
-    void setColorMode(ColorMode mode);
-
-    void setColorMap(ColorMap *colorMap);
-
-    /**
-     * \brief Return the ColorMap in use
-     */
-    ColorMap *getColorMap()
-    {
-        return _colorMap;
-    }
-
-    void updateColorMap();
-
-    virtual void updateRanges(Renderer *renderer);
-
-private:
-    virtual void update();
-
-    ColorMap *_colorMap;
-    ColorMode _colorMode;
-    std::string _colorFieldName;
-    DataSet::DataAttributeType _colorFieldType;
-    double _colorFieldRange[2];
-    double _vectorMagnitudeRange[2];
-    double _vectorComponentRange[3][2];
-    Renderer *_renderer;
-
-    vtkSmartPointer<vtkLookupTable> _lut;
-    vtkSmartPointer<vtkDataSetMapper> _dsMapper;
-};
-
-}
-
-#endif
Index: unk/packages/vizservers/vtkvis/RpShape.cpp
===================================================================
--- /trunk/packages/vizservers/vtkvis/RpShape.cpp	(revision 3615)
+++ 	(revision )
@@ -1,42 +1,0 @@
-/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
-/*
- * Copyright (C) 2004-2012  HUBzero Foundation, LLC
- *
- * Author: Leif Delgass <ldelgass@purdue.edu>
- */
-
-#include <cassert>
-
-#include <vtkDataSet.h>
-#include <vtkPolyData.h>
-#include <vtkPolyDataMapper.h>
-#include <vtkActor.h>
-#include <vtkProperty.h>
-#include <vtkTransform.h>
-
-#include "RpShape.h"
-#include "Trace.h"
-
-using namespace VtkVis;
-
-Shape::Shape() :
-    VtkGraphicsObject()
-{
-}
-
-Shape::~Shape()
-{
-    //TRACE("Deleting Shape");
-}
-
-/**
- * \brief Set a group of world coordinate planes to clip rendering
- *
- * Passing NULL for planes will remove all cliping planes
- */
-void Shape::setClippingPlanes(vtkPlaneCollection *planes)
-{
-    if (_pdMapper != NULL) {
-        _pdMapper->SetClippingPlanes(planes);
-    }
-}
Index: unk/packages/vizservers/vtkvis/RpShape.h
===================================================================
--- /trunk/packages/vizservers/vtkvis/RpShape.h	(revision 3615)
+++ 	(revision )
@@ -1,52 +1,0 @@
-/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
-/*
- * Copyright (C) 2004-2012  HUBzero Foundation, LLC
- *
- * Author: Leif Delgass <ldelgass@purdue.edu>
- */
-
-#ifndef VTKVIS_SHAPE_H
-#define VTKVIS_SHAPE_H
-
-#include <cassert>
-
-#include <vtkSmartPointer.h>
-#include <vtkPolyDataMapper.h>
-#include <vtkActor.h>
-
-#include "RpVtkGraphicsObject.h"
-#include "RpVtkDataSet.h"
-
-namespace VtkVis {
-
-/**
- * \brief VTK Mesh (Polygon data)
- *
- * This class creates a boundary mesh of a DataSet
- */
-class Shape : public VtkGraphicsObject {
-public:
-    Shape();
-    virtual ~Shape();
-
-    virtual const char *getClassName() const
-    {
-        return "Shape";
-    }
-
-    virtual void setDataSet(DataSet *dataSet,
-                            Renderer *renderer)
-    {
-        assert(dataSet == NULL);
-        update();
-    }
-
-    virtual void setClippingPlanes(vtkPlaneCollection *planes);
-
-protected:
-    vtkSmartPointer<vtkPolyDataMapper> _pdMapper;
-};
-
-}
-
-#endif
Index: unk/packages/vizservers/vtkvis/RpSphere.cpp
===================================================================
--- /trunk/packages/vizservers/vtkvis/RpSphere.cpp	(revision 3615)
+++ 	(revision )
@@ -1,51 +1,0 @@
-/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
-/*
- * Copyright (C) 2004-2012  HUBzero Foundation, LLC
- *
- * Author: Leif Delgass <ldelgass@purdue.edu>
- */
-
-#include <cassert>
-
-#include <vtkDataSet.h>
-#include <vtkPolyData.h>
-#include <vtkPolyDataMapper.h>
-#include <vtkActor.h>
-#include <vtkProperty.h>
-#include <vtkTransform.h>
-#include <vtkSphereSource.h>
-
-#include "RpSphere.h"
-#include "Trace.h"
-
-using namespace VtkVis;
-
-Sphere::Sphere() :
-    Shape()
-{
-}
-
-Sphere::~Sphere()
-{
-    TRACE("Deleting Sphere");
-}
-
-void Sphere::update()
-{
-    if (_sphere == NULL) {
-	_sphere = vtkSmartPointer<vtkSphereSource>::New();
-    }
-
-    if (_pdMapper == NULL) {
-        _pdMapper = vtkSmartPointer<vtkPolyDataMapper>::New();
-        _pdMapper->SetResolveCoincidentTopologyToPolygonOffset();
-        _pdMapper->ScalarVisibilityOff();
-    }
-
-    _pdMapper->SetInputConnection(_sphere->GetOutputPort());
-
-    initProp();
-
-    getActor()->SetMapper(_pdMapper);
-    _pdMapper->Update();
-}
Index: unk/packages/vizservers/vtkvis/RpSphere.h
===================================================================
--- /trunk/packages/vizservers/vtkvis/RpSphere.h	(revision 3615)
+++ 	(revision )
@@ -1,93 +1,0 @@
-/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
-/*
- * Copyright (C) 2004-2012  HUBzero Foundation, LLC
- *
- * Author: Leif Delgass <ldelgass@purdue.edu>
- */
-
-#ifndef VTKVIS_SPHERE_H
-#define VTKVIS_SPHERE_H
-
-#include <vtkSmartPointer.h>
-#include <vtkPolyDataMapper.h>
-#include <vtkActor.h>
-#include <vtkSphereSource.h>
-
-#include "RpShape.h"
-#include "RpVtkDataSet.h"
-
-namespace VtkVis {
-
-/**
- * \brief VTK PolyData sphere
- *
- * This class creates a mesh sphere
- */
-class Sphere : public Shape
-{
-public:
-    Sphere();
-    virtual ~Sphere();
-
-    virtual const char *getClassName() const
-    {
-        return "Sphere";
-    }
-
-    void setThetaResolution(int res)
-    {
-        if (_sphere != NULL)
-            _sphere->SetThetaResolution(res);
-    }
-
-    void setPhiResolution(int res)
-    {
-        if (_sphere != NULL)
-            _sphere->SetPhiResolution(res);
-    }
-
-    void setStartTheta(double val)
-    {
-        if (_sphere != NULL)
-            _sphere->SetStartTheta(val);
-    }
-
-    void setEndTheta(double val)
-    {
-        if (_sphere != NULL)
-            _sphere->SetEndTheta(val);
-    }
-
-    void setStartPhi(double val)
-    {
-        if (_sphere != NULL)
-            _sphere->SetStartPhi(val);
-    }
-
-    void setEndPhi(double val)
-    {
-        if (_sphere != NULL)
-            _sphere->SetEndPhi(val);
-    }
-
-    void setLatLongTessellation(bool val)
-    {
-        if (_sphere != NULL)
-            _sphere->SetLatLongTessellation((val ? 1 : 0));
-    }
-
-    void setRadius(double radius)
-    {
-        if (_sphere != NULL)
-            _sphere->SetRadius(radius);
-    }
-
-private:
-    virtual void update();
-
-    vtkSmartPointer<vtkSphereSource> _sphere;
-};
-
-}
-
-#endif
Index: unk/packages/vizservers/vtkvis/RpStreamlines.cpp
===================================================================
--- /trunk/packages/vizservers/vtkvis/RpStreamlines.cpp	(revision 3615)
+++ 	(revision )
@@ -1,1727 +1,0 @@
-/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
-/*
- * Copyright (C) 2004-2012  HUBzero Foundation, LLC
- *
- * Author: Leif Delgass <ldelgass@purdue.edu>
- */
-
-#include <cstdlib>
-#include <ctime>
-#include <cfloat>
-#include <cmath>
-#include <cstring>
-
-#include <vtkMath.h>
-#include <vtkActor.h>
-#include <vtkProperty.h>
-#include <vtkPoints.h>
-#include <vtkCellArray.h>
-#include <vtkPolyLine.h>
-#include <vtkRegularPolygonSource.h>
-#include <vtkPointData.h>
-#include <vtkCellData.h>
-#include <vtkCellDataToPointData.h>
-#include <vtkPolygon.h>
-#include <vtkPolyData.h>
-#include <vtkTubeFilter.h>
-#include <vtkRibbonFilter.h>
-#include <vtkTransform.h>
-#include <vtkTransformPolyDataFilter.h>
-#include <vtkVertexGlyphFilter.h>
-
-#include "RpStreamlines.h"
-#include "RpVtkRenderer.h"
-#include "Trace.h"
-
-using namespace VtkVis;
-
-Streamlines::Streamlines() :
-    VtkGraphicsObject(),
-    _lineType(LINES),
-    _colorMap(NULL),
-    _colorMode(COLOR_BY_VECTOR_MAGNITUDE),
-    _colorFieldType(DataSet::POINT_DATA),
-    _seedVisible(true),
-    _renderer(NULL),
-    _dataScale(1)
-{
-    _faceCulling = true;
-    _color[0] = 1.0f;
-    _color[1] = 1.0f;
-    _color[2] = 1.0f;
-    _seedColor[0] = 1.0f;
-    _seedColor[1] = 1.0f;
-    _seedColor[2] = 1.0f;
-    _colorFieldRange[0] = DBL_MAX;
-    _colorFieldRange[1] = -DBL_MAX;
-    vtkMath::RandomSeed((int)time(NULL));
-    srand((unsigned int)time(NULL));
-}
-
-Streamlines::~Streamlines()
-{
-#ifdef WANT_TRACE
-    if (_dataSet != NULL)
-        TRACE("Deleting Streamlines for %s", _dataSet->getName().c_str());
-    else
-        TRACE("Deleting Streamlines with NULL DataSet");
-#endif
-}
-
-void Streamlines::setDataSet(DataSet *dataSet,
-                             Renderer *renderer)
-{
-    if (_dataSet != dataSet) {
-        _dataSet = dataSet;
-
-        _renderer = renderer;
-
-        if (renderer->getUseCumulativeRange()) {
-            renderer->getCumulativeDataRange(_dataRange,
-                                             _dataSet->getActiveScalarsName(),
-                                             1);
-            renderer->getCumulativeDataRange(_vectorMagnitudeRange,
-                                             _dataSet->getActiveVectorsName(),
-                                             3);
-            for (int i = 0; i < 3; i++) {
-                renderer->getCumulativeDataRange(_vectorComponentRange[i],
-                                                 _dataSet->getActiveVectorsName(),
-                                                 3, i);
-            }
-        } else {
-            _dataSet->getScalarRange(_dataRange);
-            _dataSet->getVectorRange(_vectorMagnitudeRange);
-            for (int i = 0; i < 3; i++) {
-                _dataSet->getVectorRange(_vectorComponentRange[i], i);
-            }
-        }
-
-        update();
-    }
-}
-
-/**
- * \brief Create and initialize a VTK Prop to render Streamlines
- */
-void Streamlines::initProp()
-{
-    if (_linesActor == NULL) {
-        _linesActor = vtkSmartPointer<vtkActor>::New();
-        _linesActor->GetProperty()->SetColor(_color[0], _color[1], _color[2]);
-        _linesActor->GetProperty()->SetEdgeColor(_edgeColor[0], _edgeColor[1], _edgeColor[2]);
-        _linesActor->GetProperty()->SetLineWidth(_edgeWidth);
-        _linesActor->GetProperty()->SetOpacity(_opacity);
-        _linesActor->GetProperty()->SetAmbient(.2);
-        if (!_lighting)
-            _linesActor->GetProperty()->LightingOff();
-        switch (_lineType) {
-        case LINES:
-            setCulling(_linesActor->GetProperty(), false);
-            _linesActor->GetProperty()->SetRepresentationToWireframe();
-            _linesActor->GetProperty()->EdgeVisibilityOff();
-            break;
-        case TUBES:
-            if (_faceCulling && _opacity == 1.0)
-                setCulling(_linesActor->GetProperty(), true);
-            _linesActor->GetProperty()->SetRepresentationToSurface();
-            _linesActor->GetProperty()->EdgeVisibilityOff();
-            break;
-        case RIBBONS:
-            setCulling(_linesActor->GetProperty(), false);
-            _linesActor->GetProperty()->SetRepresentationToSurface();
-            _linesActor->GetProperty()->EdgeVisibilityOff();
-            break;
-        default:
-            ;
-        }
-    }
-    if (_seedActor == NULL) {
-        _seedActor = vtkSmartPointer<vtkActor>::New();
-        _seedActor->GetProperty()->SetColor(_seedColor[0], _seedColor[1], _seedColor[2]);
-        _seedActor->GetProperty()->SetEdgeColor(_seedColor[0], _seedColor[1], _seedColor[2]);
-        _seedActor->GetProperty()->SetLineWidth(1);
-        _seedActor->GetProperty()->SetPointSize(2);
-        _seedActor->GetProperty()->SetOpacity(_opacity);
-        _seedActor->GetProperty()->SetRepresentationToWireframe();
-        _seedActor->GetProperty()->LightingOff();
-        setSeedVisibility(_seedVisible);
-    }
-    if (_prop == NULL) {
-        _prop = vtkSmartPointer<vtkAssembly>::New();
-        getAssembly()->AddPart(_linesActor);
-        getAssembly()->AddPart(_seedActor);
-    }
-}
-
-/**
- * \brief Get a pseudo-random number in range [min,max]
- */
-double Streamlines::getRandomNum(double min, double max)
-{
-#if 1
-    return vtkMath::Random(min, max);
-#else
-    int r = rand();
-    return (min + ((double)r / RAND_MAX) * (max - min));
-#endif
-}
-
-/**
- * \brief Get a random 3D point within an AABB
- *
- * \param[out] pt The random point
- * \param[in] bounds The bounds of the AABB
- */
-void Streamlines::getRandomPoint(double pt[3], const double bounds[6])
-{
-    pt[0] = getRandomNum(bounds[0], bounds[1]);
-    pt[1] = getRandomNum(bounds[2], bounds[3]);
-    pt[2] = getRandomNum(bounds[4], bounds[5]);
-}
-
-/**
- * \brief Get a random point within a triangle (including edges)
- *
- * \param[out] pt The random point
- * \param[in] v1 Triangle vertex 1
- * \param[in] v2 Triangle vertex 2
- * \param[in] v3 Triangle vertex 3
- */
-void Streamlines::getRandomPointInTriangle(double pt[3],
-                                           const double v0[3],
-                                           const double v1[3],
-                                           const double v2[3])
-{
-    // Choose random barycentric coordinates
-    double bary[3];
-    bary[0] = getRandomNum(0, 1);
-    bary[1] = getRandomNum(0, 1);
-    if (bary[0] + bary[1] > 1.0) {
-        bary[0] = 1.0 - bary[0];
-        bary[1] = 1.0 - bary[1];
-    }
-    bary[2] = 1.0 - bary[0] - bary[1];
-
-    //TRACE("bary %g %g %g", bary[0], bary[1], bary[2]);
-    // Convert to cartesian coords
-    for (int i = 0; i < 3; i++) {
-        pt[i] = v0[i] * bary[0] + v1[i] * bary[1] + v2[i] * bary[2];
-    }
-}
-
-void Streamlines::getRandomPointInTetrahedron(double pt[3],
-                                              const double v0[3],
-                                              const double v1[3],
-                                              const double v2[3],
-                                              const double v3[3])
-{
-    // Choose random barycentric coordinates
-    double bary[4];
-    bary[0] = getRandomNum(0, 1);
-    bary[1] = getRandomNum(0, 1);
-    bary[2] = getRandomNum(0, 1);
-    if (bary[0] + bary[1] > 1.0) {
-        bary[0] = 1.0 - bary[0];
-        bary[1] = 1.0 - bary[1];
-    }
-    if (bary[1] + bary[2] > 1.0) {
-        double tmp = bary[2];
-        bary[2] = 1.0 - bary[0] - bary[1];
-        bary[1] = 1.0 - tmp;
-    } else if (bary[0] + bary[1] + bary[2] > 1.0) {
-        double tmp = bary[2];
-        bary[2] = bary[0] + bary[1] + bary[2] - 1.0;
-        bary[0] = 1.0 - bary[1] - tmp;
-    }
-    bary[3] = 1.0 - bary[0] - bary[1] - bary[2];
-    //TRACE("bary %g %g %g %g", bary[0], bary[1], bary[2], bary[3]);
-    // Convert to cartesian coords
-    for (int i = 0; i < 3; i++) {
-#if 0
-        pt[i] = (v0[i] - v3[i]) * bary[0] +
-                (v1[i] - v3[i]) * bary[1] + 
-                (v2[i] - v3[i]) * bary[2] + v3[i];
-#else
-        pt[i] = v0[i] * bary[0] + v1[i] * bary[1] +
-                v2[i] * bary[2] + v3[i] * bary[3];
-#endif
-    }
-}
-
-/**
- * \brief Get a random point on a line segment (including endpoints)
- */
-void Streamlines::getRandomPointOnLineSegment(double pt[3],
-                                              const double endpt[3],
-                                              const double endpt2[3])
-{
-    double ratio = getRandomNum(0, 1);
-    pt[0] = endpt[0] + ratio * (endpt2[0] - endpt[0]);
-    pt[1] = endpt[1] + ratio * (endpt2[1] - endpt[1]);
-    pt[2] = endpt[2] + ratio * (endpt2[2] - endpt[2]);
-}
-
-/**
- * \brief Get a random point within a vtkDataSet's mesh
- *
- * Note: This currently doesn't always give a uniform distribution 
- * of points in space and can generate points outside the mesh for
- * unusual cell types
- */
-void Streamlines::getRandomCellPt(double pt[3], vtkDataSet *ds)
-{
-    int numCells = (int)ds->GetNumberOfCells();
-    // XXX: Not uniform distribution (shouldn't use mod, and assumes
-    // all cells are equal area/volume)
-    int cell = rand() % numCells;
-    int type = ds->GetCellType(cell);
-    switch (type) {
-    case VTK_VERTEX: {
-        vtkSmartPointer<vtkIdList> ptIds = vtkSmartPointer<vtkIdList>::New();
-        ds->GetCellPoints(cell, ptIds);
-        assert(ptIds->GetNumberOfIds() == 1);
-        ds->GetPoint(ptIds->GetId(0), pt);
-    }
-        break;
-    case VTK_POLY_VERTEX: {
-        vtkSmartPointer<vtkIdList> ptIds = vtkSmartPointer<vtkIdList>::New();
-        ds->GetCellPoints(cell, ptIds);
-        assert(ptIds->GetNumberOfIds() >= 1);
-        int id = rand() % ptIds->GetNumberOfIds();
-        ds->GetPoint(ptIds->GetId(id), pt);
-    }
-        break;
-    case VTK_LINE: {
-        double v[2][3];
-        vtkSmartPointer<vtkIdList> ptIds = vtkSmartPointer<vtkIdList>::New();
-        ds->GetCellPoints(cell, ptIds);
-        assert(ptIds->GetNumberOfIds() == 2);
-        for (int i = 0; i < 2; i++) {
-            ds->GetPoint(ptIds->GetId(i), v[i]);
-        }
-        getRandomPointOnLineSegment(pt, v[0], v[1]);
-    }
-        break;
-    case VTK_POLY_LINE: {
-        double v[2][3];
-        vtkSmartPointer<vtkIdList> ptIds = vtkSmartPointer<vtkIdList>::New();
-        ds->GetCellPoints(cell, ptIds);
-        assert(ptIds->GetNumberOfIds() >= 2);
-        int id = rand() % (ptIds->GetNumberOfIds()-1);
-        for (int i = 0; i < 2; i++) {
-            ds->GetPoint(ptIds->GetId(id+i), v[i]);
-        }
-        getRandomPointOnLineSegment(pt, v[0], v[1]);
-    }
-        break;
-    case VTK_TRIANGLE: {
-        double v[3][3];
-        vtkSmartPointer<vtkIdList> ptIds = vtkSmartPointer<vtkIdList>::New();
-        ds->GetCellPoints(cell, ptIds);
-        assert(ptIds->GetNumberOfIds() == 3);
-        for (int i = 0; i < 3; i++) {
-            ds->GetPoint(ptIds->GetId(i), v[i]);
-        }
-        getRandomPointInTriangle(pt, v[0], v[1], v[2]);
-    }
-        break;
-    case VTK_TRIANGLE_STRIP: {
-        double v[3][3];
-        vtkSmartPointer<vtkIdList> ptIds = vtkSmartPointer<vtkIdList>::New();
-        ds->GetCellPoints(cell, ptIds);
-        assert(ptIds->GetNumberOfIds() >= 3);
-        int id = rand() % (ptIds->GetNumberOfIds()-2);
-        for (int i = 0; i < 3; i++) {
-            ds->GetPoint(ptIds->GetId(id+i), v[i]);
-        }
-        getRandomPointInTriangle(pt, v[0], v[1], v[2]);
-    }
-        break;
-    case VTK_POLYGON: {
-        vtkPolygon *poly = vtkPolygon::SafeDownCast(ds->GetCell(cell));
-        assert (poly != NULL);
-        vtkSmartPointer<vtkIdList> ptIds = vtkSmartPointer<vtkIdList>::New();
-        poly->Triangulate(ptIds);
-        assert(ptIds->GetNumberOfIds() >= 3 && ptIds->GetNumberOfIds() % 3 == 0);
-        int tri = rand() % (ptIds->GetNumberOfIds()/3);
-        double v[3][3];
-        for (int i = 0; i < 3; i++) {
-            ds->GetPoint(ptIds->GetId(i + tri * 3), v[i]);
-        }
-        getRandomPointInTriangle(pt, v[0], v[1], v[2]);
-    }
-        break;
-    case VTK_QUAD: {
-        double v[4][3];
-        vtkSmartPointer<vtkIdList> ptIds = vtkSmartPointer<vtkIdList>::New();
-        ds->GetCellPoints(cell, ptIds);
-        assert(ptIds->GetNumberOfIds() == 4);
-        for (int i = 0; i < 4; i++) {
-            ds->GetPoint(ptIds->GetId(i), v[i]);
-        }
-        int tri = rand() & 0x1;
-        if (tri) {
-            getRandomPointInTriangle(pt, v[0], v[1], v[2]);
-        } else {
-            getRandomPointInTriangle(pt, v[0], v[2], v[3]);
-        }
-    }
-        break;
-    case VTK_TETRA: {
-        double v[4][3];
-        vtkSmartPointer<vtkIdList> ptIds = vtkSmartPointer<vtkIdList>::New();
-        ds->GetCellPoints(cell, ptIds);
-        assert(ptIds->GetNumberOfIds() == 4);
-        for (int i = 0; i < 4; i++) {
-            ds->GetPoint(ptIds->GetId(i), v[i]);
-        }
-        getRandomPointInTetrahedron(pt, v[0], v[1], v[2], v[3]);
-    }
-        break;
-    case VTK_WEDGE: {
-        double v[6][3];
-        vtkSmartPointer<vtkIdList> ptIds = vtkSmartPointer<vtkIdList>::New();
-        ds->GetCellPoints(cell, ptIds);
-        assert(ptIds->GetNumberOfIds() == 6);
-        for (int i = 0; i < 6; i++) {
-            ds->GetPoint(ptIds->GetId(i), v[i]);
-        }
-        double vv[3][3];
-        getRandomPointOnLineSegment(vv[0], v[0], v[3]);
-        getRandomPointOnLineSegment(vv[1], v[1], v[4]);
-        getRandomPointOnLineSegment(vv[2], v[2], v[5]);
-        getRandomPointInTriangle(pt, vv[0], vv[1], vv[2]);
-    }
-        break;
-    case VTK_PYRAMID: {
-        double v[5][3];
-        vtkSmartPointer<vtkIdList> ptIds = vtkSmartPointer<vtkIdList>::New();
-        ds->GetCellPoints(cell, ptIds);
-        assert(ptIds->GetNumberOfIds() == 5);
-        for (int i = 0; i < 5; i++) {
-            ds->GetPoint(ptIds->GetId(i), v[i]);
-        }
-        int tetra = rand() & 0x1;
-        if (tetra) {
-            getRandomPointInTetrahedron(pt, v[0], v[1], v[2], v[4]);
-        } else {
-            getRandomPointInTetrahedron(pt, v[0], v[2], v[3], v[4]);
-        }
-    }
-        break;
-    case VTK_PIXEL:
-    case VTK_VOXEL: {
-        double bounds[6];
-        ds->GetCellBounds(cell, bounds);
-        getRandomPoint(pt, bounds);
-    }
-        break;
-    default: {
-        vtkSmartPointer<vtkIdList> ptIds = vtkSmartPointer<vtkIdList>::New();
-        vtkSmartPointer<vtkPoints> pts = vtkSmartPointer<vtkPoints>::New();
-        ds->GetCell(cell)->Triangulate(0, ptIds, pts);
-        if (ptIds->GetNumberOfIds() % 4 == 0) {
-            int tetra = rand() % (ptIds->GetNumberOfIds()/4);
-            double v[4][3];
-            for (int i = 0; i < 4; i++) {
-                ds->GetPoint(ptIds->GetId(i + tetra * 4), v[i]);
-            }
-            getRandomPointInTetrahedron(pt, v[0], v[1], v[2], v[4]);
-        } else {
-            assert(ptIds->GetNumberOfIds() % 3 == 0);
-            int tri = rand() % (ptIds->GetNumberOfIds()/3);
-            double v[3][3];
-            for (int i = 0; i < 3; i++) {
-                ds->GetPoint(ptIds->GetId(i + tri * 3), v[i]);
-            }
-            getRandomPointInTriangle(pt, v[0], v[1], v[2]);
-        }
-    }
-    }
-}
-
-/**
- * \brief Internal method to set up pipeline after a state change
- */
-void Streamlines::update()
-{
-    if (_dataSet == NULL) {
-        return;
-    }
-
-    vtkDataSet *ds = _dataSet->getVtkDataSet();
-
-    double bounds[6];
-    _dataSet->getBounds(bounds);
-    double xLen = bounds[1] - bounds[0];
-    double yLen = bounds[3] - bounds[2];
-    double zLen = bounds[5] - bounds[4];
-    double maxBound = 0.0;
-    if (xLen > maxBound) {
-        maxBound = xLen;
-    }
-    if (yLen > maxBound) {
-        maxBound = yLen;
-    }
-    if (zLen > maxBound) {
-        maxBound = zLen;
-    }
-
-    double cellSizeRange[2];
-    double avgSize;
-    _dataSet->getCellSizeRange(cellSizeRange, &avgSize);
-    _dataScale = avgSize / 8.;
-
-    vtkSmartPointer<vtkCellDataToPointData> cellToPtData;
-
-    if (ds->GetPointData() == NULL ||
-        ds->GetPointData()->GetVectors() == NULL) {
-        TRACE("No vector point data found in DataSet %s", _dataSet->getName().c_str());
-        if (ds->GetCellData() != NULL &&
-            ds->GetCellData()->GetVectors() != NULL) {
-            cellToPtData = 
-                vtkSmartPointer<vtkCellDataToPointData>::New();
-#ifdef USE_VTK6
-            cellToPtData->SetInputData(ds);
-#else
-            cellToPtData->SetInput(ds);
-#endif
-            //cellToPtData->PassCellDataOn();
-            cellToPtData->Update();
-            ds = cellToPtData->GetOutput();
-        } else {
-            USER_ERROR("No vector field was found in the data set.");
-            return;
-        }
-    }
-
-    if (_streamTracer == NULL) {
-        _streamTracer = vtkSmartPointer<vtkStreamTracer>::New();
-    }
-
-#ifdef USE_VTK6
-    _streamTracer->SetInputData(ds);
-#else
-    _streamTracer->SetInput(ds);
-#endif
-    _streamTracer->SetMaximumPropagation(xLen + yLen + zLen);
-    _streamTracer->SetIntegratorTypeToRungeKutta45();
-
-    TRACE("Setting streamlines max length to %g", 
-          _streamTracer->GetMaximumPropagation());
-
-    if (_pdMapper == NULL) {
-        _pdMapper = vtkSmartPointer<vtkPolyDataMapper>::New();
-        _pdMapper->SetResolveCoincidentTopologyToPolygonOffset();
-        _pdMapper->ScalarVisibilityOn();
-    }
-    if (_seedMapper == NULL) {
-        _seedMapper = vtkSmartPointer<vtkPolyDataMapper>::New();
-        _seedMapper->SetResolveCoincidentTopologyToPolygonOffset();
-        _seedMapper->ScalarVisibilityOff();
-    }
-
-    // Set up seed source object
-    setSeedToFilledMesh(200);
-
-    switch (_lineType) {
-    case LINES: {
-        _streamTracer->SetComputeVorticity(false);
-        _pdMapper->SetInputConnection(_streamTracer->GetOutputPort());
-    }
-        break;
-    case TUBES: {
-        _streamTracer->SetComputeVorticity(true);
-        _lineFilter = vtkSmartPointer<vtkTubeFilter>::New();
-        vtkTubeFilter *tubeFilter = vtkTubeFilter::SafeDownCast(_lineFilter);
-        tubeFilter->SetNumberOfSides(5);
-        _lineFilter->SetInputConnection(_streamTracer->GetOutputPort());
-        _pdMapper->SetInputConnection(_lineFilter->GetOutputPort());
-    }
-        break;
-    case RIBBONS: {
-        _streamTracer->SetComputeVorticity(true);
-        _lineFilter = vtkSmartPointer<vtkRibbonFilter>::New();
-        _lineFilter->SetInputConnection(_streamTracer->GetOutputPort());
-        _pdMapper->SetInputConnection(_lineFilter->GetOutputPort());
-    }
-        break;
-    default:
-        ERROR("Unknown LineType: %d", _lineType);
-    }
-
-#if 0 && defined(WANT_TRACE)
-    _streamTracer->Update();
-    vtkPolyData *pd = _streamTracer->GetOutput();
-    TRACE("Verts: %d Lines: %d Polys: %d Strips: %d",
-          pd->GetNumberOfVerts(),
-          pd->GetNumberOfLines(),
-          pd->GetNumberOfPolys(),
-          pd->GetNumberOfStrips());
-    vtkCellArray *arr = pd->GetLines();
-    arr->InitTraversal();
-    vtkIdType npts, *pts;
-    arr->GetNextCell(npts, pts);
-    for (int i = 0; i < npts; i++) {
-        TRACE("Pt: %d", pts[i]);
-    }
-#endif
-
-    initProp();
-
-    _seedActor->SetMapper(_seedMapper);
-
-    if (_lut == NULL) {
-        setColorMap(ColorMap::getDefault());
-    }
-
-    setColorMode(_colorMode);
-
-    _linesActor->SetMapper(_pdMapper);
-    _pdMapper->Update();
-    _seedMapper->Update();
-#ifdef WANT_TRACE
-    double *b = getBounds();
-    TRACE("bounds: %g %g %g %g %g %g", b[0], b[1], b[2], b[3], b[4], b[5]);
-#endif
-}
-
-void Streamlines::setNumberOfSeedPoints(int numPoints)
-{
-    switch(_seedType) {
-    case DATASET_FILLED_MESH:
-        setSeedToFilledMesh(numPoints);
-        break;
-    case FILLED_MESH:
-        if (_seedMesh != NULL) {
-            setSeedToFilledMesh(_seedMesh, numPoints);
-        } else {
-            ERROR("NULL _seedMesh");
-        }
-        break;
-    default:
-        ERROR("Can't set number of points for seed type %d", _seedType);
-        break;
-    }
-    _pdMapper->Update();
-    _seedMapper->Update();
-}
-
-/**
- * \brief Use points of the DataSet associated with this 
- * Streamlines as seeds
- */
-void Streamlines::setSeedToMeshPoints()
-{
-    _seedType = DATASET_MESH_POINTS;
-    setSeedToMeshPoints(_dataSet->getVtkDataSet());
-}
-
-/**
- * \brief Use seed points randomly distributed within the cells 
- * of the DataSet associated with this Streamlines
- *
- * Note: The current implementation doesn't give a uniform 
- * distribution of points, and points outside the mesh bounds
- * may be generated
- *
- * \param[in] numPoints Number of random seed points to generate
- */
-void Streamlines::setSeedToFilledMesh(int numPoints)
-{
-    _seedType = DATASET_FILLED_MESH;
-    setSeedToFilledMesh(_dataSet->getVtkDataSet(), numPoints);
-}
-
-/**
- * \brief Use points of a supplied vtkDataSet as seeds
- *
- * \param[in] seed vtkDataSet with points to use as seeds
- */
-void Streamlines::setSeedToMeshPoints(vtkDataSet *seed)
-{
-    if (seed != _dataSet->getVtkDataSet()) {
-        _seedType = MESH_POINTS;
-    }
-    _seedMesh = NULL;
-    if (_streamTracer != NULL) {
-        TRACE("Seed points: %d", seed->GetNumberOfPoints());
-        vtkSmartPointer<vtkDataSet> oldSeed;
-        if (_streamTracer->GetSource() != NULL) {
-            oldSeed = _streamTracer->GetSource();
-        }
-
-#ifdef USE_VTK6
-        _streamTracer->SetSourceData(seed);
-#else
-        _streamTracer->SetSource(seed);
-
-        if (oldSeed != NULL) {
-            oldSeed->SetPipelineInformation(NULL);
-        }
-#endif
-        if (vtkPolyData::SafeDownCast(seed) != NULL) {
-#ifdef USE_VTK6
-            _seedMapper->SetInputData(vtkPolyData::SafeDownCast(seed));
-#else
-            _seedMapper->SetInput(vtkPolyData::SafeDownCast(seed));
-#endif
-        } else {
-            vtkSmartPointer<vtkVertexGlyphFilter> vertFilter = vtkSmartPointer<vtkVertexGlyphFilter>::New();
-#ifdef USE_VTK6
-            vertFilter->SetInputData(seed);
-#else
-            vertFilter->SetInput(seed);
-#endif
-            _seedMapper->SetInputConnection(vertFilter->GetOutputPort());
-        }
-    }
-}
-
-/**
- * \brief Use seed points randomly distributed within the cells 
- * of a supplied vtkDataSet
- *
- * Note: The current implementation doesn't give a uniform 
- * distribution of points, and points outside the mesh bounds
- * may be generated
- *
- * \param[in] ds vtkDataSet containing cells
- * \param[in] numPoints Number of random seed points to generate
- */
-void Streamlines::setSeedToFilledMesh(vtkDataSet *ds, int numPoints)
-{
-    if (ds != _dataSet->getVtkDataSet()) {
-        _seedMesh = ds;
-        _seedType = FILLED_MESH;
-#ifdef DEBUG
-        DataSet::print(ds);
-#endif
-    } else {
-        _seedMesh = NULL;
-    }
-    if (_streamTracer != NULL) {
-        // Set up seed source object
-        vtkSmartPointer<vtkPolyData> seed = vtkSmartPointer<vtkPolyData>::New();
-        vtkSmartPointer<vtkPoints> pts = vtkSmartPointer<vtkPoints>::New();
-        vtkSmartPointer<vtkCellArray> cells = vtkSmartPointer<vtkCellArray>::New();
-
-        if (ds->GetNumberOfCells() < 1) {
-            ERROR("No cells in mesh");
-        }
-
-        for (int i = 0; i < numPoints; i++) {
-            double pt[3];
-            getRandomCellPt(pt, ds);
-            //TRACE("Seed pt: %g %g %g", pt[0], pt[1], pt[2]);
-            pts->InsertNextPoint(pt);
-            cells->InsertNextCell(1);
-            cells->InsertCellPoint(i);
-        }
-
-        seed->SetPoints(pts);
-        seed->SetVerts(cells);
-
-        TRACE("Seed points: %d", seed->GetNumberOfPoints());
-        vtkSmartPointer<vtkDataSet> oldSeed;
-        if (_streamTracer->GetSource() != NULL) {
-            oldSeed = _streamTracer->GetSource();
-        }
-
-#ifdef USE_VTK6
-        _streamTracer->SetSourceData(seed);
-        _seedMapper->SetInputData(seed);
-#else
-        _streamTracer->SetSource(seed);
-
-        if (oldSeed != NULL) {
-            oldSeed->SetPipelineInformation(NULL);
-        }
-        _seedMapper->SetInput(seed);
-#endif
-    }
-}
-
-/**
- * \brief Use seed points along a line
- *
- * \param[in] start Starting point of rake line
- * \param[in] end End point of rake line
- * \param[in] numPoints Number of points along line to generate
- */
-void Streamlines::setSeedToRake(double start[3], double end[3], int numPoints)
-{
-    if (numPoints < 2)
-        return;
-    _seedType = RAKE;
-    _seedMesh = NULL;
-    if (_streamTracer != NULL) {
-        // Set up seed source object
-        vtkSmartPointer<vtkPolyData> seed = vtkSmartPointer<vtkPolyData>::New();
-        vtkSmartPointer<vtkPoints> pts = vtkSmartPointer<vtkPoints>::New();
-        vtkSmartPointer<vtkCellArray> cells = vtkSmartPointer<vtkCellArray>::New();
-        vtkSmartPointer<vtkPolyLine> polyline = vtkSmartPointer<vtkPolyLine>::New();
-
-        double dir[3];
-        for (int i = 0; i < 3; i++) {
-            dir[i] = end[i] - start[i];
-        }
-
-        polyline->GetPointIds()->SetNumberOfIds(numPoints);
-        for (int i = 0; i < numPoints; i++) {
-            double pt[3];
-            for (int ii = 0; ii < 3; ii++) {
-                pt[ii] = start[ii] + dir[ii] * ((double)i / (numPoints-1));
-            }
-            //TRACE("Seed pt: %g %g %g", pt[0], pt[1], pt[2]);
-            pts->InsertNextPoint(pt);
-            polyline->GetPointIds()->SetId(i, i);
-        }
-
-        cells->InsertNextCell(polyline);
-        seed->SetPoints(pts);
-        seed->SetLines(cells);
-
-        TRACE("Seed points: %d", seed->GetNumberOfPoints());
-        vtkSmartPointer<vtkDataSet> oldSeed;
-        if (_streamTracer->GetSource() != NULL) {
-            oldSeed = _streamTracer->GetSource();
-        }
-#ifdef USE_VTK6
-        _streamTracer->SetSourceData(seed);
-        _seedMapper->SetInputData(seed);
-#else
-        _streamTracer->SetSource(seed);
-        if (oldSeed != NULL) {
-            oldSeed->SetPipelineInformation(NULL);
-        }
-
-        _seedMapper->SetInput(seed);
-#endif
-    }
-}
-
-/**
- * \brief Create seed points inside a disk with an optional hole
- *
- * \param[in] center Center point of disk
- * \param[in] normal Normal vector to orient disk
- * \param[in] radius Radius of disk
- * \param[in] innerRadius Radius of hole at center of disk
- * \param[in] numPoints Number of random points to generate
- */
-void Streamlines::setSeedToDisk(double center[3],
-                                double normal[3],
-                                double radius,
-                                double innerRadius,
-                                int numPoints)
-{
-    _seedType = DISK;
-    _seedMesh = NULL;
-    if (_streamTracer != NULL) {
-        // Set up seed source object
-        vtkSmartPointer<vtkPolyData> seed = vtkSmartPointer<vtkPolyData>::New();
-        vtkSmartPointer<vtkPoints> pts = vtkSmartPointer<vtkPoints>::New();
-        vtkSmartPointer<vtkCellArray> cells = vtkSmartPointer<vtkCellArray>::New();
-
-        // The following code is based on vtkRegularPolygonSource::RequestData
-
-        double px[3];
-        double py[3];
-        double axis[3] = {1., 0., 0.};
-
-        if (vtkMath::Normalize(normal) == 0.0) {
-            normal[0] = 0.0;
-            normal[1] = 0.0;
-            normal[2] = 1.0;
-        }
-
-        // Find axis in plane (orthogonal to normal)
-        bool done = false;
-        vtkMath::Cross(normal, axis, px);
-        if (vtkMath::Normalize(px) > 1.0e-3) {
-            done = true;
-        }
-        if (!done) {
-            axis[0] = 0.0;
-            axis[1] = 1.0;
-            axis[2] = 0.0;
-            vtkMath::Cross(normal, axis, px);
-            if (vtkMath::Normalize(px) > 1.0e-3) {
-                done = true;
-            }
-        }
-        if (!done) {
-            axis[0] = 0.0;
-            axis[1] = 0.0;
-            axis[2] = 1.0;
-            vtkMath::Cross(normal, axis, px);
-            vtkMath::Normalize(px);
-        }
-        // Create third orthogonal basis vector
-        vtkMath::Cross(px, normal, py);
-
-        double minSquared = (innerRadius*innerRadius)/(radius*radius);
-        for (int j = 0; j < numPoints; j++) {
-            // Get random sweep angle and radius
-#ifdef USE_VTK6
-            double angle = getRandomNum(0, 2.0 * vtkMath::Pi());
-#else
-            double angle = getRandomNum(0, 2.0 * vtkMath::DoublePi());
-#endif
-            // Need sqrt to get uniform distribution
-            double r = sqrt(getRandomNum(minSquared, 1)) * radius;
-            double pt[3];
-            for (int i = 0; i < 3; i++) {
-                pt[i] = center[i] + r * (px[i] * cos(angle) + py[i] * sin(angle));
-            }
-            //TRACE("Seed pt: %g %g %g", pt[0], pt[1], pt[2]);
-            pts->InsertNextPoint(pt);
-            cells->InsertNextCell(1);
-            cells->InsertCellPoint(j);
-        }
-
-        seed->SetPoints(pts);
-        seed->SetVerts(cells);
-
-        TRACE("Seed points: %d", seed->GetNumberOfPoints());
-        vtkSmartPointer<vtkDataSet> oldSeed;
-        if (_streamTracer->GetSource() != NULL) {
-            oldSeed = _streamTracer->GetSource();
-        }
-#ifdef USE_VTK6
-        _streamTracer->SetSourceData(seed);
-        _seedMapper->SetInputData(seed);
-#else
-        _streamTracer->SetSource(seed);
-        if (oldSeed != NULL) {
-            oldSeed->SetPipelineInformation(NULL);
-        }
-
-        _seedMapper->SetInput(seed);
-#endif
-    }
-}
-
-/**
- * \brief Use seed points from an n-sided polygon
- *
- * \param[in] center Center point of polygon
- * \param[in] normal Normal vector to orient polygon
- * \param[in] angle Angle in degrees to rotate about normal
- * \param[in] radius Radius of circumscribing circle
- * \param[in] numSides Number of polygon sides (and points) to generate
- */
-void Streamlines::setSeedToPolygon(double center[3],
-                                   double normal[3],
-                                   double angle,
-                                   double radius,
-                                   int numSides)
-{
-    _seedType = POLYGON;
-    _seedMesh = NULL;
-    if (_streamTracer != NULL) {
-        // Set up seed source object
-        vtkSmartPointer<vtkRegularPolygonSource> seed = vtkSmartPointer<vtkRegularPolygonSource>::New();
-
-        seed->SetCenter(center);
-        seed->SetNormal(normal);
-        seed->SetRadius(radius);
-        seed->SetNumberOfSides(numSides);
-        seed->GeneratePolygonOn();
-
-        if (angle != 0.0) {
-            vtkSmartPointer<vtkTransform> trans = vtkSmartPointer<vtkTransform>::New();
-            trans->RotateWXYZ(angle, normal);
-            vtkSmartPointer<vtkTransformPolyDataFilter> transFilt =
-                vtkSmartPointer<vtkTransformPolyDataFilter>::New();
-            transFilt->SetInputConnection(seed->GetOutputPort());
-            transFilt->SetTransform(trans);
-        }
-
-        TRACE("Seed points: %d", numSides);
-        vtkSmartPointer<vtkDataSet> oldSeed;
-        if (_streamTracer->GetSource() != NULL) {
-            oldSeed = _streamTracer->GetSource();
-        }
-
-        if (angle != 0.0) {
-            vtkSmartPointer<vtkTransform> trans = vtkSmartPointer<vtkTransform>::New();
-            trans->Translate(+center[0], +center[1], +center[2]);
-            trans->RotateWXYZ(angle, normal);
-            trans->Translate(-center[0], -center[1], -center[2]);
-            vtkSmartPointer<vtkTransformPolyDataFilter> transFilt =
-                vtkSmartPointer<vtkTransformPolyDataFilter>::New();
-            transFilt->SetInputConnection(seed->GetOutputPort());
-            transFilt->SetTransform(trans);
-            _streamTracer->SetSourceConnection(transFilt->GetOutputPort());
-            _seedMapper->SetInputConnection(transFilt->GetOutputPort());
-        } else {
-            _streamTracer->SetSourceConnection(seed->GetOutputPort());
-            _seedMapper->SetInputConnection(seed->GetOutputPort());
-        }
-
-#ifndef USE_VTK6
-        if (oldSeed != NULL) {
-            oldSeed->SetPipelineInformation(NULL);
-        }
-#endif
-    }
-}
-
-/**
- * \brief Use seed points from an n-sided polygon
- *
- * \param[in] center Center point of polygon
- * \param[in] normal Normal vector to orient polygon
- * \param[in] angle Angle in degrees to rotate about normal
- * \param[in] radius Radius of circumscribing circle
- * \param[in] numSides Number of polygon sides (and points) to generate
- * \param[in] numPoints Number of random points to generate
- */
-void Streamlines::setSeedToFilledPolygon(double center[3],
-                                         double normal[3],
-                                         double angle,
-                                         double radius,
-                                         int numSides,
-                                         int numPoints)
-{
-    _seedType = FILLED_POLYGON;
-    _seedMesh = NULL;
-    if (_streamTracer != NULL) {
-         // Set up seed source object
-        vtkSmartPointer<vtkPolyData> seed = vtkSmartPointer<vtkPolyData>::New();
-        vtkSmartPointer<vtkPoints> pts = vtkSmartPointer<vtkPoints>::New();
-        vtkSmartPointer<vtkCellArray> cells = vtkSmartPointer<vtkCellArray>::New();
-
-        // The following code is based on vtkRegularPolygonSource::RequestData
-
-        double px[3];
-        double py[3];
-        double axis[3] = {1., 0., 0.};
-
-        if (vtkMath::Normalize(normal) == 0.0) {
-            normal[0] = 0.0;
-            normal[1] = 0.0;
-            normal[2] = 1.0;
-        }
-
-        // Find axis in plane (orthogonal to normal)
-        bool done = false;
-        vtkMath::Cross(normal, axis, px);
-        if (vtkMath::Normalize(px) > 1.0e-3) {
-            done = true;
-        }
-        if (!done) {
-            axis[0] = 0.0;
-            axis[1] = 1.0;
-            axis[2] = 0.0;
-            vtkMath::Cross(normal, axis, px);
-            if (vtkMath::Normalize(px) > 1.0e-3) {
-                done = true;
-            }
-        }
-        if (!done) {
-            axis[0] = 0.0;
-            axis[1] = 0.0;
-            axis[2] = 1.0;
-            vtkMath::Cross(normal, axis, px);
-            vtkMath::Normalize(px);
-        }
-        // Create third orthogonal basis vector
-        vtkMath::Cross(px, normal, py);
-
-        double verts[numSides][3];
-#ifdef USE_VTK6
-        double sliceTheta = 2.0 * vtkMath::Pi() / (double)numSides;
-#else
-        double sliceTheta = 2.0 * vtkMath::DoublePi() / (double)numSides;
-#endif
-        angle = vtkMath::RadiansFromDegrees(angle);
-        for (int j = 0; j < numSides; j++) {
-            for (int i = 0; i < 3; i++) {
-                double theta = sliceTheta * (double)j - angle;
-                verts[j][i] = center[i] + radius * (px[i] * cos(theta) + 
-                                                    py[i] * sin(theta));
-            }
-            //TRACE("Vert %d: %g %g %g", j, verts[j][0], verts[j][1], verts[j][2]);
-        }
-
-        // Note: this gives a uniform distribution because the polygon is regular and
-        // the triangular sections have equal area
-        if (numSides == 3) {
-            for (int j = 0; j < numPoints; j++) {
-                double pt[3];
-                getRandomPointInTriangle(pt, verts[0], verts[1], verts[2]);
-                //TRACE("Seed pt: %g %g %g", pt[0], pt[1], pt[2]);
-                pts->InsertNextPoint(pt);
-                cells->InsertNextCell(1);
-                cells->InsertCellPoint(j);
-            }
-        } else {
-            for (int j = 0; j < numPoints; j++) {
-                // Get random triangle section
-                int tri = rand() % numSides;
-                double pt[3];
-                getRandomPointInTriangle(pt, center, verts[tri], verts[(tri+1) % numSides]);
-                //TRACE("Seed pt: %g %g %g", pt[0], pt[1], pt[2]);
-                pts->InsertNextPoint(pt);
-                cells->InsertNextCell(1);
-                cells->InsertCellPoint(j);
-            }
-        }
-
-        seed->SetPoints(pts);
-        seed->SetVerts(cells);
-
-        TRACE("Seed points: %d", seed->GetNumberOfPoints());
-        vtkSmartPointer<vtkDataSet> oldSeed;
-        if (_streamTracer->GetSource() != NULL) {
-            oldSeed = _streamTracer->GetSource();
-        }
-
-#ifdef USE_VTK6
-        _streamTracer->SetSourceData(seed);
-        _seedMapper->SetInputData(seed);
-#else
-        _streamTracer->SetSource(seed);
-        if (oldSeed != NULL) {
-            oldSeed->SetPipelineInformation(NULL);
-        }
-
-        _seedMapper->SetInput(seed);
-#endif
-    }
-}
-
-/**
- * \brief Set the integration method used
- */
-void Streamlines::setIntegrator(IntegratorType integrator)
-{
-    if (_streamTracer != NULL) {
-        switch (integrator) {
-        case RUNGE_KUTTA2:
-            _streamTracer->SetIntegratorTypeToRungeKutta2();
-            break;
-        case RUNGE_KUTTA4:
-            _streamTracer->SetIntegratorTypeToRungeKutta4();
-            break;
-        case RUNGE_KUTTA45:
-            _streamTracer->SetIntegratorTypeToRungeKutta45();
-            break;
-        default:
-            ;
-        }
-    }
-}
-
-/**
- * \brief Set the direction of integration
- */
-void Streamlines::setIntegrationDirection(IntegrationDirection dir)
-{
-    if (_streamTracer != NULL) {
-        switch (dir) {
-        case FORWARD:
-            _streamTracer->SetIntegrationDirectionToForward();
-            break;
-        case BACKWARD:
-            _streamTracer->SetIntegrationDirectionToBackward();
-            break;
-        case BOTH:
-            _streamTracer->SetIntegrationDirectionToBoth();
-            break;
-        default:
-            ;
-        }
-    }
-}
-
-/**
- * \brief Set the step size units.  Length units are world 
- * coordinates, and cell units means steps are from cell to 
- * cell.  Default is cell units.
- *
- * Note: calling this function will not convert existing
- * initial, minimum or maximum step value settings to the
- * new units, so this function should be called before 
- * setting step values.
- */
-void Streamlines::setIntegrationStepUnit(StepUnit unit)
-{
-    if (_streamTracer != NULL) {
-        switch (unit) {
-        case LENGTH_UNIT:
-            _streamTracer->SetIntegrationStepUnit(vtkStreamTracer::LENGTH_UNIT);
-            break;
-        case CELL_LENGTH_UNIT:
-            _streamTracer->SetIntegrationStepUnit(vtkStreamTracer::CELL_LENGTH_UNIT);
-            break;
-        default:
-            ;
-        }
-    }
-}
-
-/**
- * \brief Set initial step size for adaptive step integrator in 
- * step units (see setIntegrationStepUnit).  For non-adaptive
- * integrators, this is the fixed step size.
- */
-void Streamlines::setInitialIntegrationStep(double step)
-{
-    if (_streamTracer != NULL) {
-        _streamTracer->SetInitialIntegrationStep(step);
-    }
-}
-
-/**
- * \brief Set minimum step for adaptive step integrator in 
- * step units (see setIntegrationStepUnit)
- */
-void Streamlines::setMinimumIntegrationStep(double step)
-{
-    if (_streamTracer != NULL) {
-        _streamTracer->SetMinimumIntegrationStep(step);
-    }
-}
-
-/**
- * \brief Set maximum step for adaptive step integrator in 
- * step units (see setIntegrationStepUnit)
- */
-void Streamlines::setMaximumIntegrationStep(double step)
-{
-    if (_streamTracer != NULL) {
-        _streamTracer->SetMaximumIntegrationStep(step);
-    }
-}
-
-/**
- * \brief Set maximum error tolerance
- */
-void Streamlines::setMaximumError(double error)
-{
-    if (_streamTracer != NULL) {
-        _streamTracer->SetMaximumError(error);
-    }
-}
-
-/**
- * \brief Set maximum length of stream lines in world
- * coordinates
- */
-void Streamlines::setMaxPropagation(double length)
-{
-    if (_streamTracer != NULL) {
-        _streamTracer->SetMaximumPropagation(length);
-    }
-}
-
-/**
- * \brief Set maximum number of integration steps
- */
-void Streamlines::setMaxNumberOfSteps(int steps)
-{
-    if (_streamTracer != NULL) {
-        _streamTracer->SetMaximumNumberOfSteps(steps);
-    }
-}
-
-/**
- * \brief Set the minimum speed before integration stops
- */
-void Streamlines::setTerminalSpeed(double speed)
-{
-    if (_streamTracer != NULL) {
-        _streamTracer->SetTerminalSpeed(speed);
-    }
-}
-
-/**
- * \brief Set streamline type to polylines
- */
-void Streamlines::setLineTypeToLines()
-{
-    _lineType = LINES;
-    if (_streamTracer != NULL &&
-        _pdMapper != NULL) {
-        _streamTracer->SetComputeVorticity(false);
-        _pdMapper->SetInputConnection(_streamTracer->GetOutputPort());
-        _lineFilter = NULL;
-        setCulling(_linesActor->GetProperty(), false);
-        _linesActor->GetProperty()->SetRepresentationToWireframe();
-        _linesActor->GetProperty()->LightingOff();
-    }
-}
-
-/**
- * \brief Set streamline type to 3D tubes
- *
- * \param[in] numSides Number of sides (>=3) for tubes
- * \param[in] radius World coordinate minimum tube radius
- */
-void Streamlines::setLineTypeToTubes(int numSides, double radius)
-{
-    _lineType = TUBES;
-    if (_streamTracer != NULL) {
-        _streamTracer->SetComputeVorticity(true);
-        if (vtkTubeFilter::SafeDownCast(_lineFilter) == NULL) {
-            _lineFilter = vtkSmartPointer<vtkTubeFilter>::New();
-            _lineFilter->SetInputConnection(_streamTracer->GetOutputPort());
-        }
-        vtkTubeFilter *tubeFilter = vtkTubeFilter::SafeDownCast(_lineFilter);
-        if (numSides < 3)
-            numSides = 3;
-        tubeFilter->SetNumberOfSides(numSides);
-        tubeFilter->SetRadius(_dataScale * radius);
-        _pdMapper->SetInputConnection(_lineFilter->GetOutputPort());
-        if (_faceCulling && _opacity == 1.0)
-            setCulling(_linesActor->GetProperty(), true);
-        _linesActor->GetProperty()->SetRepresentationToSurface();
-        _linesActor->GetProperty()->LightingOn();
-     }
-}
-
-/**
- * \brief Set streamline type to 3D ribbons
- *
- * \param[in] width Minimum half-width of ribbons
- * \param[in] angle Default ribbon angle in degrees from normal
- */
-void Streamlines::setLineTypeToRibbons(double width, double angle)
-{
-    _lineType = RIBBONS;
-    if (_streamTracer != NULL) {
-        _streamTracer->SetComputeVorticity(true);
-        if (vtkRibbonFilter::SafeDownCast(_lineFilter) == NULL) {
-            _lineFilter = vtkSmartPointer<vtkRibbonFilter>::New();
-            _lineFilter->SetInputConnection(_streamTracer->GetOutputPort());
-        }
-        vtkRibbonFilter *ribbonFilter = vtkRibbonFilter::SafeDownCast(_lineFilter);
-        ribbonFilter->SetWidth(_dataScale * width);
-        ribbonFilter->SetAngle(angle);
-        ribbonFilter->UseDefaultNormalOn();
-        _pdMapper->SetInputConnection(_lineFilter->GetOutputPort());
-        setCulling(_linesActor->GetProperty(), false);
-        _linesActor->GetProperty()->SetRepresentationToSurface();
-        _linesActor->GetProperty()->LightingOn();
-    }
-}
-
-void Streamlines::updateRanges(Renderer *renderer)
-{
-    if (_dataSet == NULL) {
-        ERROR("called before setDataSet");
-        return;
-    }
-
-    if (renderer->getUseCumulativeRange()) {
-        renderer->getCumulativeDataRange(_dataRange,
-                                         _dataSet->getActiveScalarsName(),
-                                         1);
-        renderer->getCumulativeDataRange(_vectorMagnitudeRange,
-                                         _dataSet->getActiveVectorsName(),
-                                         3);
-        for (int i = 0; i < 3; i++) {
-            renderer->getCumulativeDataRange(_vectorComponentRange[i],
-                                             _dataSet->getActiveVectorsName(),
-                                             3, i);
-        }
-    } else {
-        _dataSet->getScalarRange(_dataRange);
-        _dataSet->getVectorRange(_vectorMagnitudeRange);
-        for (int i = 0; i < 3; i++) {
-            _dataSet->getVectorRange(_vectorComponentRange[i], i);
-        }
-    }
-
-    // Need to update color map ranges and/or active vector field
-    double *rangePtr = _colorFieldRange;
-    if (_colorFieldRange[0] > _colorFieldRange[1]) {
-        rangePtr = NULL;
-    }
-    setColorMode(_colorMode, _colorFieldType, _colorFieldName.c_str(), rangePtr);
-}
-
-void Streamlines::setColorMode(ColorMode mode)
-{
-    _colorMode = mode;
-    if (_dataSet == NULL)
-        return;
-
-    switch (mode) {
-    case COLOR_BY_SCALAR:
-        setColorMode(mode,
-                     _dataSet->getActiveScalarsType(),
-                     _dataSet->getActiveScalarsName(),
-                     _dataRange);
-        break;
-    case COLOR_BY_VECTOR_MAGNITUDE:
-        setColorMode(mode,
-                     _dataSet->getActiveVectorsType(),
-                     _dataSet->getActiveVectorsName(),
-                     _vectorMagnitudeRange);
-        break;
-    case COLOR_BY_VECTOR_X:
-        setColorMode(mode,
-                     _dataSet->getActiveVectorsType(),
-                     _dataSet->getActiveVectorsName(),
-                     _vectorComponentRange[0]);
-        break;
-    case COLOR_BY_VECTOR_Y:
-        setColorMode(mode,
-                     _dataSet->getActiveVectorsType(),
-                     _dataSet->getActiveVectorsName(),
-                     _vectorComponentRange[1]);
-        break;
-    case COLOR_BY_VECTOR_Z:
-        setColorMode(mode,
-                     _dataSet->getActiveVectorsType(),
-                     _dataSet->getActiveVectorsName(),
-                     _vectorComponentRange[2]);
-        break;
-    case COLOR_CONSTANT:
-    default:
-        setColorMode(mode, DataSet::POINT_DATA, NULL, NULL);
-        break;
-    }
-}
-
-void Streamlines::setColorMode(ColorMode mode,
-                               const char *name, double range[2])
-{
-    if (_dataSet == NULL)
-        return;
-    DataSet::DataAttributeType type = DataSet::POINT_DATA;
-    int numComponents = 1;
-    if (name != NULL && strlen(name) > 0 &&
-        !_dataSet->getFieldInfo(name, &type, &numComponents)) {
-        ERROR("Field not found: %s", name);
-        return;
-    }
-    setColorMode(mode, type, name, range);
-}
-
-void Streamlines::setColorMode(ColorMode mode, DataSet::DataAttributeType type,
-                               const char *name, double range[2])
-{
-    _colorMode = mode;
-    _colorFieldType = type;
-    if (name == NULL)
-        _colorFieldName.clear();
-    else
-        _colorFieldName = name;
-    if (range == NULL) {
-        _colorFieldRange[0] = DBL_MAX;
-        _colorFieldRange[1] = -DBL_MAX;
-    } else {
-        memcpy(_colorFieldRange, range, sizeof(double)*2);
-    }
-
-    if (_dataSet == NULL || _pdMapper == NULL)
-        return;
-
-    switch (type) {
-    case DataSet::POINT_DATA:
-        _pdMapper->SetScalarModeToUsePointFieldData();
-        break;
-    case DataSet::CELL_DATA:
-        _pdMapper->SetScalarModeToUseCellFieldData();
-        break;
-    default:
-        ERROR("Unsupported DataAttributeType: %d", type);
-        return;
-    }
-
-    if (name != NULL && strlen(name) > 0) {
-        _pdMapper->SelectColorArray(name);
-    } else {
-        _pdMapper->SetScalarModeToDefault();
-    }
-
-    if (_lut != NULL) {
-        if (range != NULL) {
-            _lut->SetRange(range);
-        } else if (name != NULL && strlen(name) > 0) {
-            double r[2];
-            int comp = -1;
-            if (mode == COLOR_BY_VECTOR_X)
-                comp = 0;
-            else if (mode == COLOR_BY_VECTOR_Y)
-                comp = 1;
-            else if (mode == COLOR_BY_VECTOR_Z)
-                comp = 2;
-
-            if (_renderer->getUseCumulativeRange()) {
-                int numComponents;
-                if  (!_dataSet->getFieldInfo(name, type, &numComponents)) {
-                    ERROR("Field not found: %s, type: %d", name, type);
-                    return;
-                } else if (numComponents < comp+1) {
-                    ERROR("Request for component %d in field with %d components",
-                          comp, numComponents);
-                    return;
-                }
-                _renderer->getCumulativeDataRange(r, name, type, numComponents, comp);
-            } else {
-                _dataSet->getDataRange(r, name, type, comp);
-            }
-            _lut->SetRange(r);
-        }
-    }
-
-    switch (mode) {
-    case COLOR_BY_SCALAR:
-        _pdMapper->ScalarVisibilityOn();
-        break;
-    case COLOR_BY_VECTOR_MAGNITUDE:
-        _pdMapper->ScalarVisibilityOn();
-        if (_lut != NULL) {
-            _lut->SetVectorModeToMagnitude();
-        }
-        break;
-    case COLOR_BY_VECTOR_X:
-        _pdMapper->ScalarVisibilityOn();
-        if (_lut != NULL) {
-            _lut->SetVectorModeToComponent();
-            _lut->SetVectorComponent(0);
-        }
-        break;
-    case COLOR_BY_VECTOR_Y:
-        _pdMapper->ScalarVisibilityOn();
-        if (_lut != NULL) {
-            _lut->SetVectorModeToComponent();
-            _lut->SetVectorComponent(1);
-        }
-        break;
-    case COLOR_BY_VECTOR_Z:
-        _pdMapper->ScalarVisibilityOn();
-        if (_lut != NULL) {
-            _lut->SetVectorModeToComponent();
-            _lut->SetVectorComponent(2);
-        }
-        break;
-    case COLOR_CONSTANT:
-    default:
-        _pdMapper->ScalarVisibilityOff();
-        break;
-    }
-}
-
-/**
- * \brief Called when the color map has been edited
- */
-void Streamlines::updateColorMap()
-{
-    setColorMap(_colorMap);
-}
-
-/**
- * \brief Associate a colormap lookup table with the DataSet
- */
-void Streamlines::setColorMap(ColorMap *cmap)
-{
-    if (cmap == NULL)
-        return;
-
-    _colorMap = cmap;
- 
-    if (_lut == NULL) {
-        _lut = vtkSmartPointer<vtkLookupTable>::New();
-        if (_pdMapper != NULL) {
-            _pdMapper->UseLookupTableScalarRangeOn();
-            _pdMapper->SetLookupTable(_lut);
-        }
-        _lut->DeepCopy(cmap->getLookupTable());
-        switch (_colorMode) {
-        case COLOR_CONSTANT:
-        case COLOR_BY_SCALAR:
-            _lut->SetRange(_dataRange);
-            break;
-        case COLOR_BY_VECTOR_MAGNITUDE:
-            _lut->SetRange(_vectorMagnitudeRange);
-            break;
-        case COLOR_BY_VECTOR_X:
-            _lut->SetRange(_vectorComponentRange[0]);
-            break;
-        case COLOR_BY_VECTOR_Y:
-            _lut->SetRange(_vectorComponentRange[1]);
-            break;
-        case COLOR_BY_VECTOR_Z:
-            _lut->SetRange(_vectorComponentRange[2]);
-            break;
-        default:
-            break;
-        }
-    } else {
-        double range[2];
-        _lut->GetTableRange(range);
-        _lut->DeepCopy(cmap->getLookupTable());
-        _lut->SetRange(range);
-        _lut->Modified();
-    }
-
-    switch (_colorMode) {
-    case COLOR_BY_VECTOR_MAGNITUDE:
-        _lut->SetVectorModeToMagnitude();
-        break;
-    case COLOR_BY_VECTOR_X:
-        _lut->SetVectorModeToComponent();
-        _lut->SetVectorComponent(0);
-        break;
-    case COLOR_BY_VECTOR_Y:
-        _lut->SetVectorModeToComponent();
-        _lut->SetVectorComponent(1);
-        break;
-    case COLOR_BY_VECTOR_Z:
-        _lut->SetVectorModeToComponent();
-        _lut->SetVectorComponent(2);
-        break;
-    default:
-         break;
-    }
-}
-
-/**
- * \brief Turn on/off lighting of this object
- */
-void Streamlines::setLighting(bool state)
-{
-    _lighting = state;
-    if (_linesActor != NULL)
-        _linesActor->GetProperty()->SetLighting((state ? 1 : 0));
-}
-
-/**
- * \brief Set opacity of this object
- */
-void Streamlines::setOpacity(double opacity)
-{
-    _opacity = opacity;
-    if (_linesActor != NULL) {
-        _linesActor->GetProperty()->SetOpacity(_opacity);
-        if (_opacity < 1.0)
-            setCulling(_linesActor->GetProperty(), false);
-        else if (_faceCulling && _lineType == TUBES)
-            setCulling(_linesActor->GetProperty(), true);
-    }
-    if (_seedActor != NULL) {
-        _seedActor->GetProperty()->SetOpacity(_opacity);
-    }
-}
-
-/**
- * \brief Turn on/off rendering of this Streamlines
- */
-void Streamlines::setVisibility(bool state)
-{
-    if (_linesActor != NULL) {
-        _linesActor->SetVisibility((state ? 1 : 0));
-    }
-    if (_seedActor != NULL) {
-        if (!state ||
-            (state && _seedVisible)) {
-            _seedActor->SetVisibility((state ? 1 : 0));
-        }
-    }
-}
-
-/**
- * \brief Turn on/off rendering of the seed geometry
- */
-void Streamlines::setSeedVisibility(bool state)
-{
-    _seedVisible = state;
-    if (_seedActor != NULL) {
-        _seedActor->SetVisibility((state ? 1 : 0));
-    }
-}
-
-/**
- * \brief Get visibility state of the Streamlines
- * 
- * \return Are the Streamlines visible?
- */
-bool Streamlines::getVisibility()
-{
-    if (_linesActor == NULL) {
-        return false;
-    } else {
-        return (_linesActor->GetVisibility() != 0);
-    }
-}
-
-/**
- * \brief Turn on/off rendering of edges
- */
-void Streamlines::setEdgeVisibility(bool state)
-{
-    if (_linesActor != NULL) {
-        _linesActor->GetProperty()->SetEdgeVisibility((state ? 1 : 0));
-    }
-}
-
-/**
- * \brief Set RGB color of stream lines
- */
-void Streamlines::setColor(float color[3])
-{
-    _color[0] = color[0];
-    _color[1] = color[1];
-    _color[2] = color[2];
-    if (_linesActor != NULL)
-        _linesActor->GetProperty()->SetColor(_color[0], _color[1], _color[2]);
-}
-
-/**
- * \brief Set RGB color of stream line edges
- */
-void Streamlines::setEdgeColor(float color[3])
-{
-    _edgeColor[0] = color[0];
-    _edgeColor[1] = color[1];
-    _edgeColor[2] = color[2];
-    if (_linesActor != NULL)
-        _linesActor->GetProperty()->SetEdgeColor(_edgeColor[0], _edgeColor[1], _edgeColor[2]);
-}
-
-/**
- * \brief Set RGB color of seed geometry
- */
-void Streamlines::setSeedColor(float color[3])
-{
-    _seedColor[0] = color[0];
-    _seedColor[1] = color[1];
-    _seedColor[2] = color[2];
-    if (_seedActor != NULL) {
-        _seedActor->GetProperty()->SetColor(_seedColor[0], _seedColor[1], _seedColor[2]);
-        _seedActor->GetProperty()->SetEdgeColor(_seedColor[0], _seedColor[1], _seedColor[2]);
-    }
-}
-
-/**
- * \brief Set pixel width of stream lines (may be a no-op)
- */
-void Streamlines::setEdgeWidth(float edgeWidth)
-{
-    _edgeWidth = edgeWidth;
-    if (_linesActor != NULL)
-        _linesActor->GetProperty()->SetLineWidth(_edgeWidth);
-}
-
-/**
- * \brief Set a group of world coordinate planes to clip rendering
- *
- * Passing NULL for planes will remove all cliping planes
- */
-void Streamlines::setClippingPlanes(vtkPlaneCollection *planes)
-{
-    if (_pdMapper != NULL) {
-        _pdMapper->SetClippingPlanes(planes);
-    }
-    if (_seedMapper != NULL) {
-        _seedMapper->SetClippingPlanes(planes);
-    }
-}
Index: unk/packages/vizservers/vtkvis/RpStreamlines.h
===================================================================
--- /trunk/packages/vizservers/vtkvis/RpStreamlines.h	(revision 3615)
+++ 	(revision )
@@ -1,221 +1,0 @@
-/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
-/*
- * Copyright (C) 2004-2012  HUBzero Foundation, LLC
- *
- * Author: Leif Delgass <ldelgass@purdue.edu>
- */
-
-#ifndef VTKVIS_STREAMLINES_H
-#define VTKVIS_STREAMLINES_H
-
-#include <vtkSmartPointer.h>
-#include <vtkProp.h>
-#include <vtkPlaneCollection.h>
-#include <vtkStreamTracer.h>
-#include <vtkPolyDataAlgorithm.h>
-#include <vtkPolyDataMapper.h>
-#include <vtkLookupTable.h>
-#include <vtkAssembly.h>
-
-#include "ColorMap.h"
-#include "RpVtkGraphicsObject.h"
-#include "RpVtkDataSet.h"
-
-namespace VtkVis {
-
-/**
- * \brief Streamline visualization of vector fields
- *
- * The DataSet must contain vectors
- */
-class Streamlines : public VtkGraphicsObject {
-public:
-    enum LineType {
-        LINES,
-        TUBES,
-        RIBBONS
-    };
-    enum ColorMode {
-        COLOR_BY_SCALAR,
-        COLOR_BY_VECTOR_MAGNITUDE,
-        COLOR_BY_VECTOR_X,
-        COLOR_BY_VECTOR_Y,
-        COLOR_BY_VECTOR_Z,
-        COLOR_CONSTANT
-    };
-    enum StepUnit {
-        LENGTH_UNIT,
-        CELL_LENGTH_UNIT
-    };
-    enum IntegratorType {
-        RUNGE_KUTTA2,
-        RUNGE_KUTTA4,
-        RUNGE_KUTTA45
-    };
-    enum IntegrationDirection {
-        FORWARD,
-        BACKWARD,
-        BOTH
-    };
-    enum SeedType {
-        DATASET_MESH_POINTS,
-        DATASET_FILLED_MESH,
-        MESH_POINTS,
-        FILLED_MESH,
-        RAKE,
-        DISK,
-        POLYGON,
-        FILLED_POLYGON
-    };
-
-    Streamlines();
-    virtual ~Streamlines();
-
-    virtual const char *getClassName() const 
-    {
-        return "Streamlines";
-    }
-
-    virtual void setDataSet(DataSet *dataSet,
-                            Renderer *renderer);
-
-    virtual void setLighting(bool state);
-
-    virtual void setOpacity(double opacity);
-
-    virtual void setVisibility(bool state);
-
-    virtual bool getVisibility();
-
-    virtual void setColor(float color[3]);
-
-    virtual void setEdgeVisibility(bool state);
-
-    virtual void setEdgeColor(float color[3]);
-
-    virtual void setEdgeWidth(float edgeWidth);
-
-    virtual void setClippingPlanes(vtkPlaneCollection *planes);
-
-    void setNumberOfSeedPoints(int numPoints);
-
-    void setSeedToMeshPoints();
-
-    void setSeedToFilledMesh(int numPoints);
-
-    void setSeedToMeshPoints(vtkDataSet *ds);
-
-    void setSeedToFilledMesh(vtkDataSet *ds, int numPoints);
-
-    void setSeedToRake(double start[3], double end[3], int numPoints);
-
-    void setSeedToDisk(double center[3], double normal[3],
-                       double radius, double innerRadius, int numPoints);
-
-    void setSeedToPolygon(double center[3], double normal[3],
-                          double angle, double radius,
-                          int numSides);
-
-    void setSeedToFilledPolygon(double center[3], double normal[3],
-                                double angle, double radius,
-                                int numSides, int numPoints);
-
-    void setIntegrator(IntegratorType integrator);
-
-    void setIntegrationDirection(IntegrationDirection dir);
-
-    void setIntegrationStepUnit(StepUnit unit);
-
-    void setInitialIntegrationStep(double step);
-
-    void setMinimumIntegrationStep(double step);
-
-    void setMaximumIntegrationStep(double step);
-
-    void setMaximumError(double error);
-
-    void setMaxPropagation(double length);
-
-    void setMaxNumberOfSteps(int steps);
-
-    void setTerminalSpeed(double speed);
-
-    void setLineTypeToLines();
-
-    void setLineTypeToTubes(int numSides, double radius);
-
-    void setLineTypeToRibbons(double width, double angle);
-
-    void setColorMode(ColorMode mode, DataSet::DataAttributeType type,
-                      const char *name, double range[2] = NULL);
-
-    void setColorMode(ColorMode mode,
-                      const char *name, double range[2] = NULL);
-
-    void setColorMode(ColorMode mode);
-
-    void setColorMap(ColorMap *colorMap);
-
-    /**
-     * \brief Return the ColorMap in use
-     */
-    ColorMap *getColorMap()
-    {
-        return _colorMap;
-    }
-
-    void updateColorMap();
-
-    virtual void updateRanges(Renderer *renderer);
-
-    void setSeedVisibility(bool state);
-
-    void setSeedColor(float color[3]);
-
-private:
-    virtual void initProp();
-    virtual void update();
-
-    static double getRandomNum(double min, double max);
-    static void getRandomPoint(double pt[3], const double bounds[6]);
-    static void getRandomPointInTriangle(double pt[3],
-                                         const double v0[3],
-                                         const double v1[3],
-                                         const double v2[3]);
-    static void getRandomPointOnLineSegment(double pt[3],
-                                            const double endpt[3],
-                                            const double endpt2[3]);
-    static void getRandomPointInTetrahedron(double pt[3],
-                                            const double v0[3],
-                                            const double v1[3],
-                                            const double v2[3],
-                                            const double v3[3]);
-    static void getRandomCellPt(double pt[3], vtkDataSet *ds);
-
-    LineType _lineType;
-    ColorMap *_colorMap;
-    ColorMode _colorMode;
-    std::string _colorFieldName;
-    DataSet::DataAttributeType _colorFieldType;
-    double _colorFieldRange[2];
-    SeedType _seedType;
-    float _seedColor[3];
-    bool _seedVisible;
-    double _vectorMagnitudeRange[2];
-    double _vectorComponentRange[3][2];
-    Renderer *_renderer;
-    double _dataScale;
-
-    vtkSmartPointer<vtkLookupTable> _lut;
-    vtkSmartPointer<vtkActor> _linesActor;
-    vtkSmartPointer<vtkActor> _seedActor;
-    vtkSmartPointer<vtkDataSet> _seedMesh;
-    vtkSmartPointer<vtkStreamTracer> _streamTracer;
-    vtkSmartPointer<vtkPolyDataAlgorithm> _lineFilter;
-    vtkSmartPointer<vtkPolyDataMapper> _pdMapper;
-    vtkSmartPointer<vtkPolyDataMapper> _seedMapper;
-};
-
-}
-
-#endif
Index: unk/packages/vizservers/vtkvis/RpTypes.h
===================================================================
--- /trunk/packages/vizservers/vtkvis/RpTypes.h	(revision 3615)
+++ 	(revision )
@@ -1,27 +1,0 @@
-/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
-/*
- * Copyright (C) 2004-2012  HUBzero Foundation, LLC
- *
- * Author: Leif Delgass <ldelgass@purdue.edu>
- */
-
-#ifndef VTKVIS_TYPES_H
-#define VTKVIS_TYPES_H
-
-namespace VtkVis {
-
-    enum Axis {
-        X_AXIS = 0,
-        Y_AXIS,
-        Z_AXIS
-    };
-
-    enum PrincipalPlane {
-        PLANE_XY = 0,
-        PLANE_ZY,
-        PLANE_XZ
-    };
-
-}
-
-#endif
Index: unk/packages/vizservers/vtkvis/RpVolume.cpp
===================================================================
--- /trunk/packages/vizservers/vtkvis/RpVolume.cpp	(revision 3615)
+++ 	(revision )
@@ -1,282 +1,0 @@
-/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
-/*
- * Copyright (C) 2004-2012  HUBzero Foundation, LLC
- *
- * Author: Leif Delgass <ldelgass@purdue.edu>
- */
-
-#include <cassert>
-
-#include <vtkDataSet.h>
-#include <vtkPointData.h>
-#include <vtkImageData.h>
-#include <vtkVolumeProperty.h>
-#include <vtkGPUVolumeRayCastMapper.h>
-#include <vtkVolumeTextureMapper3D.h>
-#include <vtkUnstructuredGrid.h>
-#include <vtkPolyData.h>
-#include <vtkCellType.h>
-#include <vtkUnstructuredGridVolumeMapper.h>
-#include <vtkUnstructuredGridVolumeRayCastMapper.h>
-#include <vtkProjectedTetrahedraMapper.h>
-#include <vtkDataSetTriangleFilter.h>
-#include <vtkGaussianSplatter.h>
-
-#include "RpVolume.h"
-#include "Trace.h"
-
-using namespace VtkVis;
-
-Volume::Volume() :
-    VtkGraphicsObject(),
-    _colorMap(NULL)
-{
-}
-
-Volume::~Volume()
-{
-#ifdef WANT_TRACE
-    if (_dataSet != NULL)
-        TRACE("Deleting Volume for %s", _dataSet->getName().c_str());
-    else
-        TRACE("Deleting Volume with NULL DataSet");
-#endif
-}
-
-/**
- * \brief Create and initialize a VTK Prop to render the Volume
- */
-void Volume::initProp()
-{
-    if (_prop == NULL) {
-        _prop = vtkSmartPointer<vtkVolume>::New();
-        getVolume()->GetProperty()->SetInterpolationTypeToLinear();
-    }
-}
-
-/**
- * \brief Get the voxel dimensions (if the volume is not a
- * uniform grid, unit spacing is returned)
- */
-void Volume::getSpacing(double spacing[3])
-{
-    spacing[0] = spacing[1] = spacing[2] = 1.0;
-    if (_dataSet == NULL)
-        return;
-    vtkDataSet *ds = _dataSet->getVtkDataSet();
-    if (ds != NULL && vtkImageData::SafeDownCast(ds) != NULL) {
-        vtkImageData::SafeDownCast(ds)->GetSpacing(spacing);
-    } else if (ds != NULL && vtkVolumeMapper::SafeDownCast(_volumeMapper) != NULL) {
-        vtkImageData *imgData = vtkVolumeMapper::SafeDownCast(_volumeMapper)->GetInput();
-        if (imgData != NULL) {
-            imgData->GetSpacing(spacing);
-        }
-    }
-}
-
-/**
- * \brief Get the average voxel dimension (if the volume is not a
- * uniform grid, unit spacing is returned)
- */
-double Volume::getAverageSpacing()
-{
-    double spacing[3];
-    getSpacing(spacing);
-    return (spacing[0] + spacing[1] + spacing[2]) * 0.333;
-}
-
-/**
- * \brief Internal method to set up pipeline after a state change
- */
-void Volume::update()
-{
-    if (_dataSet == NULL)
-        return;
-
-    vtkDataSet *ds = _dataSet->getVtkDataSet();
-
-    if (_dataSet->is2D()) {
-        USER_ERROR("Volume rendering requires a 3D data set");
-        _dataSet = NULL;
-        return;
-    }
-
-    if (vtkImageData::SafeDownCast(ds) != NULL) {
-        // Image data required for these mappers
-#ifdef USE_GPU_RAYCAST_MAPPER
-        _volumeMapper = vtkSmartPointer<vtkGPUVolumeRayCastMapper>::New();
-        vtkGPUVolumeRayCastMapper::SafeDownCast(_volumeMapper)->AutoAdjustSampleDistancesOff();
-#else
-        _volumeMapper = vtkSmartPointer<vtkVolumeTextureMapper3D>::New();
-#endif
-#ifdef USE_VTK6
-#ifdef USE_GPU_RAYCAST_MAPPER
-        vtkGPUVolumeRayCastMapper::SafeDownCast(_volumeMapper)->SetInputData(ds);
-#else
-        vtkVolumeTextureMapper3D::SafeDownCast(_volumeMapper)->SetInputData(ds);
-#endif
-#else
-        _volumeMapper->SetInput(ds);
-#endif
-        vtkVolumeMapper::SafeDownCast(_volumeMapper)->SetBlendModeToComposite();
-    } else if (vtkUnstructuredGrid::SafeDownCast(ds) != NULL) {
-        vtkUnstructuredGrid *ugrid = vtkUnstructuredGrid::SafeDownCast(ds);
-        // DataSet is unstructured grid
-        // Only works if cells are all tetrahedra
-        _volumeMapper = vtkSmartPointer<vtkProjectedTetrahedraMapper>::New();
-        // Software raycast rendering - requires all tetrahedra
-        //_volumeMapper = vtkSmartPointer<vtkUnstructuredGridVolumeRayCastMapper>::New();
-        if (ugrid->GetCellType(0) == VTK_TETRA &&
-            ugrid->IsHomogeneous()) {
-#ifdef USE_VTK6
-            vtkProjectedTetrahedraMapper::SafeDownCast(_volumeMapper)->SetInputData(ds);
-#else
-            _volumeMapper->SetInput(ds);
-#endif
-        } else {
-            // Decompose to tetrahedra
-            vtkSmartPointer<vtkDataSetTriangleFilter> filter = 
-                vtkSmartPointer<vtkDataSetTriangleFilter>::New();
-#ifdef USE_VTK6
-            filter->SetInputData(ugrid);
-#else
-            filter->SetInput(ugrid);
-#endif
-            filter->TetrahedraOnlyOn();
-            _volumeMapper->SetInputConnection(filter->GetOutputPort());
-        }
-
-        vtkUnstructuredGridVolumeMapper::SafeDownCast(_volumeMapper)->
-            SetBlendModeToComposite();
-    } else if (vtkPolyData::SafeDownCast(ds) != NULL &&
-               vtkPolyData::SafeDownCast(ds)->GetNumberOfLines() == 0 &&
-               vtkPolyData::SafeDownCast(ds)->GetNumberOfPolys() == 0 &&
-               vtkPolyData::SafeDownCast(ds)->GetNumberOfStrips() == 0 ) {
-        // DataSet is a 3D point cloud
-        vtkSmartPointer<vtkGaussianSplatter> splatter = vtkSmartPointer<vtkGaussianSplatter>::New();
-#ifdef USE_VTK6
-        splatter->SetInputData(ds);
-#else
-        splatter->SetInput(ds);
-#endif
-        int dims[3];
-        dims[0] = dims[1] = dims[2] = 64;
-        TRACE("Generating volume with dims (%d,%d,%d) from point cloud",
-              dims[0], dims[1], dims[2]);
-        splatter->SetSampleDimensions(dims);
-#ifdef USE_GPU_RAYCAST_MAPPER
-        _volumeMapper = vtkSmartPointer<vtkGPUVolumeRayCastMapper>::New();
-        vtkGPUVolumeRayCastMapper::SafeDownCast(_volumeMapper)->AutoAdjustSampleDistancesOff();
-#else
-        _volumeMapper = vtkSmartPointer<vtkVolumeTextureMapper3D>::New();
-#endif
-        _volumeMapper->SetInputConnection(splatter->GetOutputPort());
-        vtkVolumeMapper::SafeDownCast(_volumeMapper)->SetBlendModeToComposite();
-    } else {
-        ERROR("Unsupported DataSet type: %s", _dataSet->getVtkType());
-        _dataSet = NULL;
-        return;
-    }
-
-    TRACE("Using mapper type: %s", _volumeMapper->GetClassName());
-
-    initProp();
-
-    if (ds->GetPointData() == NULL ||
-        ds->GetPointData()->GetScalars() == NULL) {
-        WARN("No scalar point data in dataset %s", _dataSet->getName().c_str());
-    }
-
-    if (_colorMap == NULL) {
-        setColorMap(ColorMap::getVolumeDefault());
-    }
-
-    setSampleDistance(getAverageSpacing());
-
-    getVolume()->SetMapper(_volumeMapper);
-    _volumeMapper->Update();
-}
-
-void Volume::updateRanges(Renderer *renderer)
-{
-    VtkGraphicsObject::updateRanges(renderer);
-
-    if (getVolume() != NULL) {
-        getVolume()->GetProperty()->SetColor(_colorMap->getColorTransferFunction(_dataRange));
-        getVolume()->GetProperty()->SetScalarOpacity(_colorMap->getOpacityTransferFunction(_dataRange));
-    }
-}
-
-void Volume::updateColorMap()
-{
-    setColorMap(_colorMap);
-}
-
-/**
- * \brief Assign a color map (transfer function) to use in rendering the Volume
- */
-void Volume::setColorMap(ColorMap *cmap)
-{
-    if (cmap == NULL)
-        return;
-
-    _colorMap = cmap;
-
-    if (getVolume() != NULL) {
-        getVolume()->GetProperty()->SetColor(_colorMap->getColorTransferFunction(_dataRange));
-        getVolume()->GetProperty()->SetScalarOpacity(_colorMap->getOpacityTransferFunction(_dataRange));
-    }
-}
-
-/**
- * \brief Return the ColorMap assigned to this Volume
- */
-ColorMap *Volume::getColorMap()
-{
-    return _colorMap;
-}
-
-/**
- * \brief Set opacity scaling used to render the Volume
- */
-void Volume::setOpacity(double opacity)
-{
-    _opacity = opacity;
-    // FIXME: There isn't really a good opacity scaling option that works
-    // across the different mappers/algorithms.  This only works with the
-    // 3D texture mapper, not the GPU raycast mapper
-    if (getVolume() != NULL) {
-        if (opacity < 1.0e-6)
-            opacity = 1.0e-6;
-        getVolume()->GetProperty()->SetScalarOpacityUnitDistance(1.0/opacity);
-    }
-}
-
-/**
- * \brief Set a group of world coordinate planes to clip rendering
- *
- * Passing NULL for planes will remove all cliping planes
- */
-void Volume::setClippingPlanes(vtkPlaneCollection *planes)
-{
-    if (_volumeMapper != NULL) {
-        _volumeMapper->SetClippingPlanes(planes);
-    }
-}
-
-/**
- * \brief Set distance between samples along rays
- */
-void Volume::setSampleDistance(float d)
-{
-    TRACE("Sample distance: %g", d);
-    if (_volumeMapper != NULL &&
-#ifdef USE_GPU_RAYCAST_MAPPER
-        vtkGPUVolumeRayCastMapper::SafeDownCast(_volumeMapper) != NULL) {
-        vtkGPUVolumeRayCastMapper::SafeDownCast(_volumeMapper)->SetSampleDistance(d);
-#else
-        vtkVolumeTextureMapper3D::SafeDownCast(_volumeMapper) != NULL) {
-        vtkVolumeTextureMapper3D::SafeDownCast(_volumeMapper)->SetSampleDistance(d);
-#endif
-    }
-}
Index: unk/packages/vizservers/vtkvis/RpVolume.h
===================================================================
--- /trunk/packages/vizservers/vtkvis/RpVolume.h	(revision 3615)
+++ 	(revision )
@@ -1,72 +1,0 @@
-/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
-/*
- * Copyright (C) 2004-2012  HUBzero Foundation, LLC
- *
- * Author: Leif Delgass <ldelgass@purdue.edu>
- */
-
-#ifndef VTKVIS_VOLUME_H
-#define VTKVIS_VOLUME_H
-
-#include <vtkSmartPointer.h>
-#include <vtkProp.h>
-#include <vtkVolume.h>
-#include <vtkAbstractVolumeMapper.h>
-#include <vtkPlaneCollection.h>
-
-#include "RpVtkGraphicsObject.h"
-#include "ColorMap.h"
-
-namespace VtkVis {
-
-/**
- * \brief Volume Rendering
- *
- * Currently the DataSet must be image data (3D uniform grid),
- * or an UnstructuredGrid
- */
-class Volume : public VtkGraphicsObject {
-public:
-    enum BlendMode {
-        COMPOSITE = 0,
-        MAX_INTENSITY,
-        MIN_INTENSITY
-    };
-
-    Volume();
-    virtual ~Volume();
-
-    virtual const char *getClassName() const
-    {
-        return "Volume";
-    }
-
-    void getSpacing(double spacing[3]);
-
-    double getAverageSpacing();
-
-    virtual void setOpacity(double opacity);
-
-    virtual void setClippingPlanes(vtkPlaneCollection *planes);
-
-    void setColorMap(ColorMap *cmap);
-
-    ColorMap *getColorMap();
-
-    void updateColorMap();
-
-    virtual void updateRanges(Renderer *renderer);
-
-    void setSampleDistance(float d);
-
-private:
-    virtual void initProp();
-    virtual void update();
-
-    ColorMap *_colorMap;
-    vtkSmartPointer<vtkAbstractVolumeMapper> _volumeMapper;
-};
-
-}
-
-#endif
Index: unk/packages/vizservers/vtkvis/RpVtkDataSet.cpp
===================================================================
--- /trunk/packages/vizservers/vtkvis/RpVtkDataSet.cpp	(revision 3615)
+++ 	(revision )
@@ -1,930 +1,0 @@
-/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
-/*
- * Copyright (C) 2004-2012  HUBzero Foundation, LLC
- *
- * Author: Leif Delgass <ldelgass@purdue.edu>
- */
-
-#include <cassert>
-#include <cstring>
-#include <cfloat>
-#include <cmath>
-
-#include <vtkCharArray.h>
-#include <vtkDataSetReader.h>
-#include <vtkDataSetWriter.h>
-#include <vtkPolyData.h>
-#include <vtkStructuredPoints.h>
-#include <vtkStructuredGrid.h>
-#include <vtkRectilinearGrid.h>
-#include <vtkUnstructuredGrid.h>
-#include <vtkProperty.h>
-#include <vtkPointData.h>
-#include <vtkCellData.h>
-#include <vtkCell.h>
-#include <vtkLookupTable.h>
-
-#include "RpVtkDataSet.h"
-#include "Trace.h"
-
-using namespace VtkVis;
-
-DataSet::DataSet(const std::string& name) :
-    _name(name),
-    _visible(true),
-    _opacity(1),
-    _cellSizeAverage(0)
-{
-    _cellSizeRange[0] = -1;
-    _cellSizeRange[1] = -1;
-}
-
-DataSet::~DataSet()
-{
-}
-
-/**
- * \brief Set opacity of DataSet outline
- *
- * This method is used for record-keeping and opacity of the
- * DataSet bounds outline.  The renderer controls opacity 
- * of other related graphics objects.
- */
-void DataSet::setOpacity(double opacity)
-{
-    _opacity = opacity;
-}
-
-/**
- * \brief Set visibility flag in DataSet
- *
- * This method is used for record-keeping and visibility of the
- * DataSet bounds outline.  The renderer controls visibility 
- * of other related graphics objects.
- */
-void DataSet::setVisibility(bool state)
-{
-    _visible = state;
-}
-
-/**
- * \brief Get visibility flag in DataSet
- *
- * This method is used for record-keeping.  The renderer controls
- * the visibility of related graphics objects.
- */
-bool DataSet::getVisibility() const
-{
-    return _visible;
-}
-
-void DataSet::writeDataFile(const char *filename)
-{
-    if (_dataSet == NULL)
-        return;
-    
-    vtkSmartPointer<vtkDataSetWriter> writer = vtkSmartPointer<vtkDataSetWriter>::New();
-
-    writer->SetFileName(filename);
-#ifdef USE_VTK6
-    writer->SetInputData(_dataSet);
-#else
-    writer->SetInput(_dataSet);
-#endif
-    writer->Write();
-}
-
-/**
- * \brief Read a VTK data file
- */
-bool DataSet::setDataFile(const char *filename)
-{
-    vtkSmartPointer<vtkDataSetReader> reader = vtkSmartPointer<vtkDataSetReader>::New();
-
-#if defined(WANT_TRACE) && defined(DEBUG)
-    reader->DebugOn();
-#endif
-
-    reader->SetFileName(filename);
-    reader->ReadAllNormalsOn();
-    //reader->ReadAllTCoordsOn();
-    reader->ReadAllScalarsOn();
-    //reader->ReadAllColorScalarsOn();
-    reader->ReadAllVectorsOn();
-    //reader->ReadAllTensorsOn();
-    reader->ReadAllFieldsOn();
-
-    return setData(reader);
-}
-
-/**
- * \brief Read a VTK data file from a memory buffer
- */
-bool DataSet::setData(char *data, int nbytes)
-{
-    vtkSmartPointer<vtkDataSetReader> reader = vtkSmartPointer<vtkDataSetReader>::New();
-    vtkSmartPointer<vtkCharArray> dataSetString = vtkSmartPointer<vtkCharArray>::New();
-
-#if defined(WANT_TRACE) && defined(DEBUG)
-    reader->DebugOn();
-    dataSetString->DebugOn();
-#endif
-
-    dataSetString->SetArray(data, nbytes, 1);
-    reader->SetInputArray(dataSetString);
-    reader->ReadFromInputStringOn();
-    reader->ReadAllNormalsOn();
-    //reader->ReadAllTCoordsOn();
-    reader->ReadAllScalarsOn();
-    //reader->ReadAllColorScalarsOn();
-    reader->ReadAllVectorsOn();
-    //reader->ReadAllTensorsOn();
-    reader->ReadAllFieldsOn();
-
-    return setData(reader);
-}
-
-void DataSet::print() const
-{
-    print(_dataSet);
-}
-
-void DataSet::print(vtkDataSet *ds)
-{
-    if (ds == NULL)
-        return;
-
-    TRACE("DataSet class: %s", ds->GetClassName());
-
-    TRACE("DataSet memory: %g MiB", ds->GetActualMemorySize()/1024.);
-
-    double bounds[6];
-    ds->GetBounds(bounds);
-
-    // Topology
-    TRACE("DataSet bounds: %g %g %g %g %g %g",
-          bounds[0], bounds[1],
-          bounds[2], bounds[3],
-          bounds[4], bounds[5]);
-    TRACE("Points: %d Cells: %d", ds->GetNumberOfPoints(), ds->GetNumberOfCells());
-
-    double dataRange[2];
-    if (ds->GetPointData() != NULL) {
-        TRACE("PointData arrays: %d", ds->GetPointData()->GetNumberOfArrays());
-        for (int i = 0; i < ds->GetPointData()->GetNumberOfArrays(); i++) {
-            if (ds->GetPointData()->GetArray(i) != NULL) {
-                ds->GetPointData()->GetArray(i)->GetRange(dataRange, -1);
-                TRACE("PointData[%d]: '%s' comp:%d, (%g,%g)", i,
-                      ds->GetPointData()->GetArrayName(i),
-                      ds->GetPointData()->GetAbstractArray(i)->GetNumberOfComponents(),
-                      dataRange[0], dataRange[1]);
-            } else {
-                TRACE("PointData[%d]: '%s' comp:%d", i,
-                      ds->GetPointData()->GetArrayName(i),
-                      ds->GetPointData()->GetAbstractArray(i)->GetNumberOfComponents());
-            }
-        }
-    }
-    if (ds->GetCellData() != NULL) {
-        TRACE("CellData arrays: %d", ds->GetCellData()->GetNumberOfArrays());
-        for (int i = 0; i < ds->GetCellData()->GetNumberOfArrays(); i++) {
-            if (ds->GetCellData()->GetArray(i) != NULL) {
-                ds->GetCellData()->GetArray(i)->GetRange(dataRange, -1);
-                TRACE("CellData[%d]: '%s' comp:%d, (%g,%g)", i,
-                      ds->GetCellData()->GetArrayName(i),
-                      ds->GetCellData()->GetAbstractArray(i)->GetNumberOfComponents(),
-                      dataRange[0], dataRange[1]);
-            } else {
-                TRACE("CellData[%d]: '%s' comp:%d", i,
-                      ds->GetCellData()->GetArrayName(i),
-                      ds->GetCellData()->GetAbstractArray(i)->GetNumberOfComponents());
-            }
-        }
-    }
-    if (ds->GetFieldData() != NULL) {
-        TRACE("FieldData arrays: %d", ds->GetFieldData()->GetNumberOfArrays());
-        for (int i = 0; i < ds->GetFieldData()->GetNumberOfArrays(); i++) {
-            if (ds->GetFieldData()->GetArray(i) != NULL) {
-                ds->GetFieldData()->GetArray(i)->GetRange(dataRange, -1);
-                TRACE("FieldData[%d]: '%s' comp:%d, tuples:%d (%g,%g)", i,
-                      ds->GetFieldData()->GetArrayName(i),
-                      ds->GetFieldData()->GetAbstractArray(i)->GetNumberOfComponents(),
-                      ds->GetFieldData()->GetAbstractArray(i)->GetNumberOfTuples(),
-                      dataRange[0], dataRange[1]);
-            } else {
-                TRACE("FieldData[%d]: '%s' comp:%d, tuples:%d", i,
-                      ds->GetFieldData()->GetArrayName(i),
-                      ds->GetFieldData()->GetAbstractArray(i)->GetNumberOfComponents(),
-                      ds->GetFieldData()->GetAbstractArray(i)->GetNumberOfTuples());
-            }
-        }
-    }
-}
-
-void DataSet::setDefaultArrays()
-{
-    if (_dataSet->GetPointData() != NULL &&
-        _dataSet->GetPointData()->GetScalars() == NULL &&
-        _dataSet->GetPointData()->GetNumberOfArrays() > 0) {
-        for (int i = 0; i < _dataSet->GetPointData()->GetNumberOfArrays(); i++) {
-            if (_dataSet->GetPointData()->GetArray(i) != NULL &&
-                _dataSet->GetPointData()->GetArray(i)->GetNumberOfComponents() == 1) {
-                TRACE("Setting point scalars to '%s'", _dataSet->GetPointData()->GetArrayName(i));
-                _dataSet->GetPointData()->SetActiveScalars(_dataSet->GetPointData()->GetArrayName(i));
-                break;
-            }
-        }
-    }
-    if (_dataSet->GetPointData() != NULL &&
-        _dataSet->GetPointData()->GetVectors() == NULL &&
-        _dataSet->GetPointData()->GetNumberOfArrays() > 0) {
-        for (int i = 0; i < _dataSet->GetPointData()->GetNumberOfArrays(); i++) {
-            if (_dataSet->GetPointData()->GetArray(i) != NULL &&
-                _dataSet->GetPointData()->GetArray(i)->GetNumberOfComponents() == 3) {
-                TRACE("Setting point vectors to '%s'", _dataSet->GetPointData()->GetArrayName(i));
-                _dataSet->GetPointData()->SetActiveVectors(_dataSet->GetPointData()->GetArrayName(i));
-                break;
-            }
-        }
-    }
-    if (_dataSet->GetCellData() != NULL &&
-        _dataSet->GetCellData()->GetScalars() == NULL &&
-        _dataSet->GetCellData()->GetNumberOfArrays() > 0) {
-        for (int i = 0; i < _dataSet->GetCellData()->GetNumberOfArrays(); i++) {
-            if (_dataSet->GetCellData()->GetArray(i) != NULL &&
-                _dataSet->GetCellData()->GetArray(i)->GetNumberOfComponents() == 1) {
-                TRACE("Setting cell scalars to '%s'", _dataSet->GetCellData()->GetArrayName(i));
-                _dataSet->GetCellData()->SetActiveScalars(_dataSet->GetCellData()->GetArrayName(i));
-                break;
-            }
-        }
-    }
-    if (_dataSet->GetCellData() != NULL &&
-        _dataSet->GetCellData()->GetVectors() == NULL &&
-        _dataSet->GetCellData()->GetNumberOfArrays() > 0) {
-        for (int i = 0; i < _dataSet->GetCellData()->GetNumberOfArrays(); i++) {
-            if (_dataSet->GetCellData()->GetArray(i) != NULL &&
-                _dataSet->GetCellData()->GetArray(i)->GetNumberOfComponents() == 3) {
-                TRACE("Setting cell vectors to '%s'", _dataSet->GetCellData()->GetArrayName(i));
-                _dataSet->GetCellData()->SetActiveVectors(_dataSet->GetCellData()->GetArrayName(i));
-                break;
-            }
-        }
-    }
-}
-
-/**
- * \brief Read dataset using supplied reader
- *
- * Pipeline information is removed from the resulting 
- * vtkDataSet, so that the reader and its data can be 
- * released
- */
-bool DataSet::setData(vtkDataSetReader *reader)
-{
-    TRACE("Enter");
-    // Force reading data set
-    reader->SetLookupTableName("");
-    reader->Update();
-
-    _dataSet = reader->GetOutput();
-    if (_dataSet == NULL)
-        return false;
-#ifndef USE_VTK6
-    _dataSet->SetPipelineInformation(NULL);
-#endif
-    if (_dataSet->GetPointData() != NULL &&
-        _dataSet->GetPointData()->GetScalars() != NULL &&
-        _dataSet->GetPointData()->GetScalars()->GetLookupTable() != NULL) {
-        USER_ERROR("No lookup table should be specified in VTK data sets");
-    }
-
-    setDefaultArrays();
-
-#ifdef WANT_TRACE
-    print();
-#endif
-    TRACE("Leave");
-    return true;
-}
-
-/**
- * \brief Set DataSet from existing vtkDataSet object
- *
- * Pipeline information is removed from the supplied vtkDataSet
- */
-bool DataSet::setData(vtkDataSet *ds)
-{
-    _dataSet = ds;
-#ifndef USE_VTK6
-    _dataSet->SetPipelineInformation(NULL);
-#endif
-
-    if (_dataSet->GetPointData() != NULL &&
-        _dataSet->GetPointData()->GetScalars() != NULL &&
-        _dataSet->GetPointData()->GetScalars()->GetLookupTable() != NULL) {
-        USER_ERROR("No lookup table should be specified in VTK data sets");
-    }
-
-    setDefaultArrays();
-
-#ifdef WANT_TRACE
-    print();
-#endif
-    return true;
-}
-
-/**
- * \brief Copy an existing vtkDataSet object
- *
- * Pipeline information is not copied from the supplied vtkDataSet
- * into this DataSet, but pipeline information in the supplied 
- * vtkDataSet is not removed
- */
-vtkDataSet *DataSet::copyData(vtkDataSet *ds)
-{
-    if (vtkPolyData::SafeDownCast(ds) != NULL) {
-        _dataSet = vtkSmartPointer<vtkPolyData>::New();
-        _dataSet->DeepCopy(vtkPolyData::SafeDownCast(ds));
-    } else if (vtkStructuredPoints::SafeDownCast(ds) != NULL) {
-        _dataSet = vtkSmartPointer<vtkStructuredPoints>::New();
-        _dataSet->DeepCopy(vtkStructuredPoints::SafeDownCast(ds));
-    } else if (vtkStructuredGrid::SafeDownCast(ds) != NULL) {
-        _dataSet = vtkSmartPointer<vtkStructuredGrid>::New();
-        _dataSet->DeepCopy(vtkStructuredGrid::SafeDownCast(ds));
-    } else if (vtkRectilinearGrid::SafeDownCast(ds) != NULL) {
-        _dataSet = vtkSmartPointer<vtkRectilinearGrid>::New();
-        _dataSet->DeepCopy(vtkRectilinearGrid::SafeDownCast(ds));
-    } else if (vtkUnstructuredGrid::SafeDownCast(ds) != NULL) {
-        _dataSet = vtkSmartPointer<vtkUnstructuredGrid>::New();
-        _dataSet->DeepCopy(vtkUnstructuredGrid::SafeDownCast(ds));
-    } else {
-        ERROR("Unknown data type");
-        return NULL;
-    }
-
-#ifdef WANT_TRACE
-    print();
-#endif    
-    return _dataSet;
-}
-
-/**
- * \brief Does DataSet lie in the XY plane (z = 0)
- */
-bool DataSet::isXY() const
-{
-    double bounds[6];
-    getBounds(bounds);
-    return (bounds[4] == 0. && bounds[4] == bounds[5]);
-}
-
-/**
- * \brief Returns the dimensionality of the AABB
- */
-int DataSet::numDimensions() const
-{
-    double bounds[6];
-    getBounds(bounds);
-    int numDims = 0;
-    if (bounds[0] != bounds[1])
-        numDims++;
-    if (bounds[2] != bounds[3])
-        numDims++;
-    if (bounds[4] != bounds[5])
-        numDims++;
-
-    return numDims;
-}
-
-/**
- * \brief Determines if DataSet lies in a principal axis plane
- * and if so, returns the plane normal and offset from origin
- */
-bool DataSet::is2D(PrincipalPlane *plane, double *offset) const
-{
-    double bounds[6];
-    getBounds(bounds);
-    if (bounds[4] == bounds[5]) {
-        // Z = 0, XY plane
-        if (plane != NULL) {
-            *plane = PLANE_XY;
-        }
-        if (offset != NULL)
-            *offset = bounds[4];
-        return true;
-    } else if (bounds[0] == bounds[1]) {
-        // X = 0, ZY plane
-        if (plane != NULL) {
-            *plane = PLANE_ZY;
-        }
-        if (offset != NULL)
-            *offset = bounds[0];
-        return true;
-    } else if (bounds[2] == bounds[3]) {
-        // Y = 0, XZ plane
-        if (plane != NULL) {
-            *plane = PLANE_XZ;
-         }
-        if (offset != NULL)
-            *offset = bounds[2];
-        return true;
-    }
-    return false;
-}
-
-/**
- * \brief Determines a principal plane with the
- * largest two dimensions of the AABB
- */
-PrincipalPlane DataSet::principalPlane() const
-{
-    double bounds[6];
-    getBounds(bounds);
-    double xlen = bounds[1] - bounds[0];
-    double ylen = bounds[3] - bounds[2];
-    double zlen = bounds[5] - bounds[4];
-    if (zlen <= xlen && zlen <= ylen) {
-        return PLANE_XY;
-    } else if (xlen <= ylen && xlen <= zlen) {
-        return PLANE_ZY;
-    } else {
-        return PLANE_XZ;
-    }
-}
-
-/**
- * \brief Get the name/id of this dataset
- */
-const std::string& DataSet::getName() const
-{
-    return _name;
-}
-
-/**
- * \brief Get the underlying VTK DataSet object
- */
-vtkDataSet *DataSet::getVtkDataSet()
-{
-    return _dataSet;
-}
-
-/**
- * \brief Get the underlying VTK DataSet subclass class name
- */
-const char *DataSet::getVtkType() const
-{
-    return _dataSet->GetClassName();
-}
-
-/**
- * \brief Set the ative scalar array to the named field
- */
-bool DataSet::setActiveScalars(const char *name)
-{
-    bool found = false;
-    if (_dataSet != NULL) {
-        if (_dataSet->GetPointData() != NULL) {
-            if (_dataSet->GetPointData()->SetActiveScalars(name) >= 0) {
-                TRACE("Set active point data scalars to %s", name);
-                found = true;
-            }
-        }
-        if (_dataSet->GetCellData() != NULL) {
-            if (_dataSet->GetCellData()->SetActiveScalars(name) >= 0) {
-                TRACE("Set active cell data scalars to %s", name);
-                found = true;
-            }
-        }
-    }
-#ifdef WANT_TRACE
-    if (_dataSet->GetPointData() != NULL) {
-        if (_dataSet->GetPointData()->GetScalars() != NULL) {
-            TRACE("Point data scalars: %s", _dataSet->GetPointData()->GetScalars()->GetName());
-        } else {
-            TRACE("NULL point data scalars");
-        }
-    }
-    if (_dataSet->GetCellData() != NULL) {
-        if (_dataSet->GetCellData()->GetScalars() != NULL) {
-            TRACE("Cell data scalars: %s", _dataSet->GetCellData()->GetScalars()->GetName());
-        } else {
-            TRACE("NULL cell data scalars");
-        }
-    }
-#endif
-    return found;
-}
-
-/**
- * \brief Get the active scalar array field name
- */
-const char *DataSet::getActiveScalarsName() const
-{
-    if (_dataSet != NULL) {
-         if (_dataSet->GetPointData() != NULL &&
-             _dataSet->GetPointData()->GetScalars() != NULL) {
-            return _dataSet->GetPointData()->GetScalars()->GetName();
-        }
-        TRACE("No point scalars");
-        if (_dataSet->GetCellData() != NULL &&
-            _dataSet->GetCellData()->GetScalars() != NULL) {
-            return _dataSet->GetCellData()->GetScalars()->GetName();
-        }
-        TRACE("No cell scalars");
-    }
-    return NULL;
-}
-
-/**
- * \brief Get the active scalar array default attribute type
- */
-DataSet::DataAttributeType DataSet::getActiveScalarsType() const
-{
-    if (_dataSet != NULL) {
-         if (_dataSet->GetPointData() != NULL &&
-             _dataSet->GetPointData()->GetScalars() != NULL) {
-            return POINT_DATA;
-        }
-        TRACE("No point scalars");
-        if (_dataSet->GetCellData() != NULL &&
-            _dataSet->GetCellData()->GetScalars() != NULL) {
-            return CELL_DATA;
-        }
-        TRACE("No cell scalars");
-    }
-    return POINT_DATA;
-}
-
-/**
- * \brief Set the ative vector array to the named field
- */
-bool DataSet::setActiveVectors(const char *name)
-{
-    bool found = false;
-    if (_dataSet != NULL) {
-        if (_dataSet->GetPointData() != NULL) {
-            if (_dataSet->GetPointData()->SetActiveVectors(name) >= 0) {
-                TRACE("Set active point data vectors to %s", name);
-                found = true;
-            }
-        }
-        if (_dataSet->GetCellData() != NULL) {
-            if (_dataSet->GetCellData()->SetActiveVectors(name) >= 0) {
-                TRACE("Set active cell data vectors to %s", name);
-                found = true;
-            }
-        }
-    }
-
-    return found;
-}
-
-/**
- * \brief Get the active vector array default attribute type
- */
-DataSet::DataAttributeType DataSet::getActiveVectorsType() const
-{
-    if (_dataSet != NULL) {
-         if (_dataSet->GetPointData() != NULL &&
-             _dataSet->GetPointData()->GetVectors() != NULL) {
-            return POINT_DATA;
-        }
-        TRACE("No point vectors");
-        if (_dataSet->GetCellData() != NULL &&
-            _dataSet->GetCellData()->GetVectors() != NULL) {
-            return CELL_DATA;
-        }
-        TRACE("No cell vectors");
-    }
-    return POINT_DATA;
-}
-
-/**
- * \brief Get the active vector array field name
- */
-const char *DataSet::getActiveVectorsName() const
-{
-    if (_dataSet != NULL) {
-        if (_dataSet->GetPointData() != NULL &&
-            _dataSet->GetPointData()->GetVectors() != NULL) {
-            return _dataSet->GetPointData()->GetVectors()->GetName();
-        }
-        TRACE("No point vectors");
-        if (_dataSet->GetCellData() != NULL &&
-            _dataSet->GetCellData()->GetVectors() != NULL) {
-            return _dataSet->GetCellData()->GetVectors()->GetName();
-        }
-        TRACE("No cell vectors");
-    }
-    return NULL;
-}
-
-bool DataSet::getFieldInfo(const char *fieldName,
-                           DataAttributeType *type,
-                           int *numComponents) const
-{
-    if (_dataSet->GetPointData() != NULL &&
-        _dataSet->GetPointData()->GetAbstractArray(fieldName) != NULL) {
-        if (type != NULL)
-            *type = POINT_DATA;
-        if (numComponents != NULL)
-            *numComponents = _dataSet->GetPointData()->GetAbstractArray(fieldName)->GetNumberOfComponents();
-        return true;
-    } else if (_dataSet->GetCellData() != NULL &&
-               _dataSet->GetCellData()->GetAbstractArray(fieldName) != NULL) {
-        if (type != NULL)
-            *type = CELL_DATA;
-        if (numComponents != NULL)
-            *numComponents = _dataSet->GetCellData()->GetAbstractArray(fieldName)->GetNumberOfComponents();
-        return true;
-    } else if (_dataSet->GetFieldData() != NULL &&
-               _dataSet->GetFieldData()->GetAbstractArray(fieldName) != NULL) {
-        if (type != NULL)
-            *type = FIELD_DATA;
-        if (numComponents != NULL)
-            *numComponents = _dataSet->GetFieldData()->GetAbstractArray(fieldName)->GetNumberOfComponents();
-        return true;
-    }
-    return false;
-}
-
-bool DataSet::getFieldInfo(const char *fieldName,
-                           DataAttributeType type,
-                           int *numComponents) const
-{
-    switch (type) {
-    case POINT_DATA:
-        if (_dataSet->GetPointData() != NULL &&
-            _dataSet->GetPointData()->GetAbstractArray(fieldName) != NULL) {
-            if (numComponents != NULL)
-                *numComponents = _dataSet->GetPointData()->GetAbstractArray(fieldName)->GetNumberOfComponents();
-            return true;
-        } else
-            return false;
-        break;
-    case CELL_DATA:
-        if (_dataSet->GetCellData() != NULL &&
-            _dataSet->GetCellData()->GetAbstractArray(fieldName) != NULL) {
-            if (numComponents != NULL)
-                *numComponents = _dataSet->GetCellData()->GetAbstractArray(fieldName)->GetNumberOfComponents();
-            return true;
-        } else
-            return false;
-        break;
-    case FIELD_DATA:
-        if (_dataSet->GetFieldData() != NULL &&
-            _dataSet->GetFieldData()->GetAbstractArray(fieldName) != NULL) {
-            if (numComponents != NULL)
-                *numComponents = _dataSet->GetFieldData()->GetAbstractArray(fieldName)->GetNumberOfComponents();
-            return true;
-        } else
-            return false;
-        break;
-    default:
-        ;
-    }
-    return false;
-}
-
-/**
- * \brief Get the list of field names in the DataSet
- * 
- * \param[in,out] names The field names will be appended to this list
- * \param[in] type The DataAttributeType: e.g. POINT_DATA, CELL_DATA
- * \param[in] numComponents Filter list by number of components, -1 means to
- * return all fields regardless of dimension
- */
-void DataSet::getFieldNames(std::vector<std::string>& names,
-                            DataAttributeType type, int numComponents) const
-{
-    if (_dataSet == NULL)
-        return;
-    switch (type) {
-    case POINT_DATA:
-        if (_dataSet->GetPointData() != NULL) {
-            for (int i = 0; i < _dataSet->GetPointData()->GetNumberOfArrays(); i++) {
-                if (numComponents == -1 ||
-                    (_dataSet->GetPointData()->GetAbstractArray(i) != NULL &&
-                     _dataSet->GetPointData()->GetAbstractArray(i)->GetNumberOfComponents() == numComponents)) {
-                    names.push_back(_dataSet->GetPointData()->GetArrayName(i));
-                }
-            }
-        }
-        break;
-    case CELL_DATA:
-        if (_dataSet->GetCellData() != NULL) {
-            for (int i = 0; i < _dataSet->GetCellData()->GetNumberOfArrays(); i++) {
-                if (numComponents == -1 ||
-                    (_dataSet->GetCellData()->GetAbstractArray(i) != NULL &&
-                     _dataSet->GetCellData()->GetAbstractArray(i)->GetNumberOfComponents() == numComponents)) {
-                    names.push_back(_dataSet->GetCellData()->GetArrayName(i));
-                }
-            }
-        }
-        break;
-    case FIELD_DATA:
-        if (_dataSet->GetFieldData() != NULL) {
-            for (int i = 0; i < _dataSet->GetFieldData()->GetNumberOfArrays(); i++) {
-                if (numComponents == -1 ||
-                    (_dataSet->GetFieldData()->GetAbstractArray(i) != NULL &&
-                     _dataSet->GetFieldData()->GetAbstractArray(i)->GetNumberOfComponents() == numComponents)) {
-                    names.push_back(_dataSet->GetFieldData()->GetArrayName(i));
-                }
-            }
-        }
-        break;
-    default:
-        ERROR("Unknown DataAttributeType %d", type);
-    }
-}
-
-/**
- * \brief Get the range of scalar values in the DataSet
- */
-void DataSet::getScalarRange(double minmax[2]) const
-{
-    if (_dataSet == NULL)
-        return;
-    if (_dataSet->GetPointData() != NULL &&
-        _dataSet->GetPointData()->GetScalars() != NULL) {
-        _dataSet->GetPointData()->GetScalars()->GetRange(minmax, -1);
-    } else if (_dataSet->GetCellData() != NULL &&
-               _dataSet->GetCellData()->GetScalars() != NULL) {
-        _dataSet->GetCellData()->GetScalars()->GetRange(minmax, -1);
-    }
-}
-
-/**
- * \brief Get the range of a vector component in the DataSet
- *
- * \param[out] minmax The data range
- * \param[in] component The field component, -1 means magnitude
- */
-void DataSet::getVectorRange(double minmax[2], int component) const
-{
-    if (_dataSet == NULL)
-        return;
-    if (_dataSet->GetPointData() != NULL &&
-        _dataSet->GetPointData()->GetVectors() != NULL) {
-        _dataSet->GetPointData()->GetVectors()->GetRange(minmax, component);
-    } else if (_dataSet->GetCellData() != NULL &&
-               _dataSet->GetCellData()->GetVectors() != NULL) {
-        _dataSet->GetCellData()->GetVectors()->GetRange(minmax, component);
-    }
-}
-
-/**
- * \brief Get the range of values for the named field in the DataSet
- *
- * \param[out] minmax The data range
- * \param[in] fieldName The array name
- * \param[in] type The DataAttributeType
- * \param[in] component The field component, -1 means magnitude
- * \return boolean indicating if field was found
- */
-bool DataSet::getDataRange(double minmax[2], const char *fieldName,
-                           DataAttributeType type, int component) const
-{
-    if (_dataSet == NULL)
-        return false;
-    switch (type) {
-    case POINT_DATA:
-        if (_dataSet->GetPointData() != NULL &&
-            _dataSet->GetPointData()->GetArray(fieldName) != NULL) {
-            _dataSet->GetPointData()->GetArray(fieldName)->GetRange(minmax, component);
-            return true;
-        } else {
-            return false;
-        }
-        break;
-    case CELL_DATA:
-        if (_dataSet->GetCellData() != NULL &&
-            _dataSet->GetCellData()->GetArray(fieldName) != NULL) {
-            _dataSet->GetCellData()->GetArray(fieldName)->GetRange(minmax, component);
-            return true;
-        } else {
-            return false;
-        }
-        break;
-    case FIELD_DATA:
-        if (_dataSet->GetFieldData() != NULL &&
-            _dataSet->GetFieldData()->GetArray(fieldName) != NULL) {
-            _dataSet->GetFieldData()->GetArray(fieldName)->GetRange(minmax, component);
-            return true;
-        } else {
-            return false;
-        }
-        break;
-    default:
-        ERROR("Unknown DataAttributeType %d", type);
-        break;
-    }
-    return false;
-}
-
-/**
- * \brief Get the bounds the DataSet
- */
-void DataSet::getBounds(double bounds[6]) const
-{
-    _dataSet->GetBounds(bounds);
-}
-
-/**
- * \brief Get the range of cell AABB diagonal lengths in the DataSet
- */
-void DataSet::getCellSizeRange(double minmax[2], double *average)
-{
-    if (_dataSet == NULL ||
-        _dataSet->GetNumberOfCells() < 1) {
-        minmax[0] = 1;
-        minmax[1] = 1;
-        *average = 1;
-        return;
-    }
-
-    if (_cellSizeRange[0] >= 0.0) {
-        minmax[0] = _cellSizeRange[0];
-        minmax[1] = _cellSizeRange[1];
-        *average = _cellSizeAverage;
-        return;
-    }
-
-    minmax[0] = DBL_MAX;
-    minmax[1] = -DBL_MAX;
-
-    *average = 0;
-    for (int i = 0; i < _dataSet->GetNumberOfCells(); i++) {
-        double length2 = _dataSet->GetCell(i)->GetLength2();
-        if (length2 < minmax[0])
-            minmax[0] = length2;
-        if (length2 > minmax[1])
-            minmax[1] = length2;
-        *average += length2;
-    }
-    if (minmax[0] == DBL_MAX)
-        minmax[0] = 1;
-    if (minmax[1] == -DBL_MAX)
-        minmax[1] = 1;
-
-    minmax[0] = sqrt(minmax[0]);
-    minmax[1] = sqrt(minmax[1]);
-    *average = sqrt(*average/((double)_dataSet->GetNumberOfCells()));
-    _cellSizeRange[0] = minmax[0];
-    _cellSizeRange[1] = minmax[1];
-    _cellSizeAverage = *average;
-}
-
-/**
- * \brief Get nearest data value given world coordinates x,y,z
- *
- * Note: no interpolation is performed on data
- *
- * \param[in] x World x coordinate to probe
- * \param[in] y World y coordinate to probe
- * \param[in] z World z coordinate to probe
- * \param[out] value On success, contains the data value
- * \return boolean indicating success or failure
- */
-bool DataSet::getScalarValue(double x, double y, double z, double *value) const
-{
-    if (_dataSet == NULL)
-        return false;
-    if (_dataSet->GetPointData() == NULL ||
-        _dataSet->GetPointData()->GetScalars() == NULL) {
-        return false;
-    }
-    vtkIdType pt = _dataSet->FindPoint(x, y, z);
-    if (pt < 0)
-        return false;
-    *value = _dataSet->GetPointData()->GetScalars()->GetComponent(pt, 0);
-    return true;
-}
-
-/**
- * \brief Get nearest vector data value given world coordinates x,y,z
- *
- * Note: no interpolation is performed on data
- *
- * \param[in] x World x coordinate to probe
- * \param[in] y World y coordinate to probe
- * \param[in] z World z coordinate to probe
- * \param[out] vector On success, contains the data values
- * \return boolean indicating success or failure
- */
-bool DataSet::getVectorValue(double x, double y, double z, double vector[3]) const
-{
-    if (_dataSet == NULL)
-        return false;
-    if (_dataSet->GetPointData() == NULL ||
-        _dataSet->GetPointData()->GetVectors() == NULL) {
-        return false;
-    }
-    vtkIdType pt = _dataSet->FindPoint(x, y, z);
-    if (pt < 0)
-        return false;
-    assert(_dataSet->GetPointData()->GetVectors()->GetNumberOfComponents() == 3);
-    _dataSet->GetPointData()->GetVectors()->GetTuple(pt, vector);
-    return true;
-}
Index: unk/packages/vizservers/vtkvis/RpVtkDataSet.h
===================================================================
--- /trunk/packages/vizservers/vtkvis/RpVtkDataSet.h	(revision 3615)
+++ 	(revision )
@@ -1,141 +1,0 @@
-/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
-/*
- * Copyright (C) 2004-2012  HUBzero Foundation, LLC
- *
- * Author: Leif Delgass <ldelgass@purdue.edu>
- */
-
-#ifndef VTKVIS_DATASET_H
-#define VTKVIS_DATASET_H
-
-#include <vtkSmartPointer.h>
-#include <vtkDataSet.h>
-#include <vtkDataSetReader.h>
-
-#include <string>
-#include <vector>
-
-#include "RpTypes.h"
-#include "Trace.h"
-
-namespace VtkVis {
-
-/**
- * \brief VTK DataSet wrapper
- */
-class DataSet {
-public:
-    enum DataAttributeType {
-        POINT_DATA,
-        CELL_DATA,
-        FIELD_DATA
-    };
-    DataSet(const std::string& name);
-    virtual ~DataSet();
-
-    void writeDataFile(const char *filename);
-
-    bool setDataFile(const char *filename);
-
-    bool setData(char *data, int nbytes);
-
-    bool setData(vtkDataSetReader *reader);
-
-    bool setData(vtkDataSet *ds);
-
-    vtkDataSet *copyData(vtkDataSet *ds);
-
-    bool isXY() const;
-
-    int numDimensions() const;
-
-    bool is2D(PrincipalPlane *plane = NULL, double *offset = NULL) const;
-
-    PrincipalPlane principalPlane() const;
-
-    const std::string& getName() const;
-
-    vtkDataSet *getVtkDataSet();
-
-    const char *getVtkType() const;
-
-    bool setActiveScalars(const char *name);
-
-    const char *getActiveScalarsName() const;
-
-    DataAttributeType getActiveScalarsType() const;
-
-    bool setActiveVectors(const char *name);
-
-    const char *getActiveVectorsName() const;
-
-    DataAttributeType getActiveVectorsType() const;
-
-    bool hasField(const char *fieldName) const
-    {
-        return getFieldInfo(fieldName, NULL, NULL);
-    }
-
-    bool hasField(const char *fieldName, DataAttributeType type) const
-    {
-        return getFieldInfo(fieldName, type, NULL);
-    }
-
-    bool getFieldInfo(const char *fieldName, DataAttributeType *type, int *numComponents) const;
-
-    bool getFieldInfo(const char *fieldName, DataAttributeType type, int *numComponents) const;
-
-    void getFieldNames(std::vector<std::string>& names,
-                       DataAttributeType type, int numComponents = -1) const;
-
-    bool getDataRange(double minmax[2], const char *fieldName,
-                      DataAttributeType type, int component = -1) const;
-
-    void getScalarRange(double minmax[2]) const;
-
-    void getVectorRange(double minmax[2], int component = -1) const;
-
-    void getBounds(double bounds[6]) const;
-
-    void getCellSizeRange(double minmax[2], double *average);
-
-    bool getScalarValue(double x, double y, double z, double *value) const;
-
-    bool getVectorValue(double x, double y, double z, double vector[3]) const;
-
-    void setOpacity(double opacity);
-
-    /**
-     * \brief Get the opacity setting for the DataSet
-     *
-     * This method is used for record-keeping.  The renderer controls
-     * the visibility of related graphics objects.
-     */
-    inline double getOpacity()
-    {
-        return _opacity;
-    }
-
-    void setVisibility(bool state);
-
-    bool getVisibility() const;
-
-    static void print(vtkDataSet *ds);
-
-private:
-    DataSet();
-
-    void setDefaultArrays();
-    void print() const;
-
-    std::string _name;
-    vtkSmartPointer<vtkDataSet> _dataSet;
-    bool _visible;
-    double _opacity;
-    double _cellSizeRange[2];
-    double _cellSizeAverage;
-};
-
-}
-
-#endif
Index: unk/packages/vizservers/vtkvis/RpVtkGraphicsObject.cpp
===================================================================
--- /trunk/packages/vizservers/vtkvis/RpVtkGraphicsObject.cpp	(revision 3615)
+++ 	(revision )
@@ -1,52 +1,0 @@
-/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
-/*
- * Copyright (C) 2004-2012  HUBzero Foundation, LLC
- *
- * Author: Leif Delgass <ldelgass@purdue.edu>
- */
-
-#include "RpVtkGraphicsObject.h"
-#include "RpVtkRenderer.h"
-#include "Trace.h"
-
-using namespace VtkVis;
-
-void VtkGraphicsObject::setDataSet(DataSet *dataSet,
-                                   Renderer *renderer)
-{
-    if (_dataSet != dataSet) {
-        _dataSet = dataSet;
-
-        if (renderer != NULL &&
-            dataSet != NULL &&
-            renderer->getUseCumulativeRange()) {
-            renderer->getCumulativeDataRange(_dataRange,
-                                             _dataSet->getActiveScalarsName(),
-                                             1);
-        } else if (_dataSet != NULL) {
-            _dataSet->getScalarRange(_dataRange);
-        }
-
-        update();
-    }
-}
-
-void VtkGraphicsObject::updateRanges(Renderer *renderer)
-{
-    if (_dataSet == NULL) {
-        ERROR("called before setDataSet");
-        return;
-    }
-    if (renderer == NULL) {
-        ERROR("NULL renderer");
-        return;
-    }
-
-    if (renderer->getUseCumulativeRange()) {
-        renderer->getCumulativeDataRange(_dataRange,
-                                         _dataSet->getActiveScalarsName(),
-                                         1);
-    } else {
-        _dataSet->getScalarRange(_dataRange);
-    }
-}
Index: unk/packages/vizservers/vtkvis/RpVtkGraphicsObject.h
===================================================================
--- /trunk/packages/vizservers/vtkvis/RpVtkGraphicsObject.h	(revision 3615)
+++ 	(revision )
@@ -1,933 +1,0 @@
-/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
-/*
- * Copyright (C) 2004-2012  HUBzero Foundation, LLC
- *
- * Author: Leif Delgass <ldelgass@purdue.edu>
- */
-
-#ifndef VTKVIS_VTKGRAPHICSOBJECT_H
-#define VTKVIS_VTKGRAPHICSOBJECT_H
-
-#include <cmath>
-#include <string>
-
-#include <vtkSmartPointer.h>
-#include <vtkProp.h>
-#include <vtkProp3D.h>
-#include <vtkProp3DCollection.h>
-#include <vtkAssembly.h>
-#include <vtkActor.h>
-#include <vtkVolume.h>
-#include <vtkProperty.h>
-#include <vtkVolumeProperty.h>
-#include <vtkMath.h>
-#include <vtkMatrix4x4.h>
-#include <vtkPlaneCollection.h>
-
-#include "RpVtkDataSet.h"
-#include "Trace.h"
-
-namespace VtkVis {
-
-class Renderer;
-
-/**
- * \brief Base class for graphics objects
- */
-class VtkGraphicsObject {
-public:
-    enum CullFace {
-        CULL_FRONT,
-        CULL_BACK,
-        CULL_FRONT_AND_BACK
-    };
-
-    VtkGraphicsObject() :
-        _dataSet(NULL),
-        _opacity(1.0),
-        _edgeWidth(1.0f),
-        _pointSize(1.0f),
-        _lighting(true),
-        _cullFace(CULL_BACK),
-        _faceCulling(false)
-    {
-        _dataRange[0] = 0;
-        _dataRange[1] = 1;
-        _color[0] = 1.0f;
-        _color[1] = 1.0f;
-        _color[2] = 1.0f;
-        _edgeColor[0] = 0.0f;
-        _edgeColor[1] = 0.0f;
-        _edgeColor[2] = 0.0f;
-    }
-
-    virtual ~VtkGraphicsObject()
-    {}
-
-    /**
-     * \brief Return the name of the sublass of VtkGraphicsObject
-     */
-    virtual const char *getClassName() const = 0;
-
-    /**
-     * \brief Specify input DataSet and information on cumulative data ranges
-     *
-     * Default implementation calls update() and stores scalarRange to
-     * _dataRange based on cumulative range settings
-     *
-     * \param[in] dataSet DataSet to use in rendering
-     * \param[in] renderer Pointer to Renderer -- may be used to get 
-     * cumulative data ranges
-     */
-    virtual void setDataSet(DataSet *dataSet,
-                            Renderer *renderer);
-
-    /**
-     * \brief Called when scalar or vector field changes (e.g. active field) or 
-     * cumulative ranges or settings change
-     *
-     * \param[in] renderer Pointer to Renderer -- may be used to get 
-     * cumulative data ranges
-     */
-    virtual void updateRanges(Renderer *renderer);
-
-    /**
-     * \brief Return the DataSet this object renders
-     */
-    inline DataSet *getDataSet()
-    {
-        return _dataSet;
-    }
-
-    /**
-     * \brief Return the VTK prop object to render
-     */
-    inline vtkProp *getProp()
-    {
-        return _prop;
-    }
-
-    /**
-     * \brief Cast the vktProp to a vtkProp3D
-     *
-     * \return NULL or a vtkProp3D pointer
-     */
-    inline vtkProp3D *getProp3D()
-    {
-        return vtkProp3D::SafeDownCast(_prop);
-    }
-
-    /**
-     * \brief Cast the vktProp to a vtkActor
-     *
-     * \return NULL or a vtkActor pointer
-     */
-    inline vtkActor *getActor()
-    {
-        return vtkActor::SafeDownCast(_prop);
-    }
-
-    /**
-     * \brief Cast the vktProp to a vtkVolume
-     *
-     * \return NULL or a vtkVolume pointer
-     */
-    inline vtkVolume *getVolume()
-    {
-        return vtkVolume::SafeDownCast(_prop);
-    }
-
-    /**
-     * \brief Cast the vktProp to a vtkAssembly
-     *
-     * \return NULL or a vtkAssembly pointer
-     */
-    inline vtkAssembly *getAssembly()
-    {
-        return vtkAssembly::SafeDownCast(_prop);
-    }
-
-    /**
-     * \brief If the object has a 2D overlay prop, return it
-     *
-     * \return NULL or a vtkProp pointer
-     */
-    virtual vtkProp *getOverlayProp()
-    {
-        return NULL;
-    }
-
-    /**
-     * \brief Set an additional transform on the prop
-     * 
-     * prop must be a vtkProp3D.  The transform is 
-     * concatenated with the internal transform created
-     * by setting the prop position, orientation and scale
-     */
-    virtual void setTransform(vtkMatrix4x4 *matrix)
-    {
-        if (getProp3D() != NULL) {
-            getProp3D()->SetUserMatrix(matrix);
-        }
-    }
-
-    /**
-     * \brief Set the prop center of rotation
-     *
-     * \param[in] origin The point about which the object rotates
-     */
-    virtual void setOrigin(double origin[3])
-    {
-        if (getProp3D() != NULL) {
-            getProp3D()->SetOrigin(origin);
-        }
-    }
-
-    /**
-     * \brief Set the prop orientation with a quaternion
-     *
-     * \param[in] quat Quaternion with scalar part first
-     */
-    virtual void setOrientation(double quat[4])
-    {
-        if (getProp3D() != NULL) {
-            double angle = vtkMath::DegreesFromRadians(2.0 * acos(quat[0]));
-            double axis[3];
-            if (angle < 1.0e-6) {
-                axis[0] = 1;
-                axis[1] = 0;
-                axis[2] = 0;
-            } else {
-                double denom = sqrt(1. - quat[0] * quat[0]);
-                axis[0] = quat[1] / denom;
-                axis[1] = quat[2] / denom;
-                axis[2] = quat[3] / denom;
-            }
-            setOrientation(angle, axis);
-        }
-    }
-
-    /**
-     * \brief Set the prop orientation with a rotation about an axis
-     *
-     * \param[in] angle Angle in degrees
-     * \param[in] axis Axis of rotation
-     */
-    virtual void setOrientation(double angle, double axis[3])
-    {
-        if (getProp3D() != NULL) {
-            getProp3D()->SetOrientation(0, 0, 0);
-            getProp3D()->RotateWXYZ(angle, axis[0], axis[1], axis[2]);
-        }
-    }
-
-    /**
-     * \brief Set the prop position
-     *
-     * \param[in] pos Position in world coordinates
-     */
-    virtual void setPosition(double pos[3])
-    {
-        if (getProp3D() != NULL) {
-            getProp3D()->SetPosition(pos);
-        }
-    }
-
-    /**
-     * \brief Set 2D aspect ratio scaling
-     *
-     * \param aspect 0=no scaling, otherwise aspect
-     * is horiz/vertical ratio
-     */
-    virtual void setAspect(double aspect)
-    {
-        double scale[3];
-        scale[0] = scale[1] = scale[2] = 1.;
-
-        if (aspect == 0.0) {
-            setScale(scale);
-            return;
-        }
-        if (_dataSet == NULL ||
-            _dataSet->getVtkDataSet() == NULL) {
-            TRACE("Not setting aspect for object with no data set");
-            return;
-        }
-
-        PrincipalPlane plane;
-        if (!_dataSet->is2D(&plane)) {
-            TRACE("Not setting aspect for 3D object");
-            return;
-        }
-
-        double bounds[6];
-        vtkDataSet *ds = _dataSet->getVtkDataSet();
-        ds->GetBounds(bounds);
-        double size[3];
-        size[0] = bounds[1] - bounds[0];
-        size[1] = bounds[3] - bounds[2];
-        size[2] = bounds[5] - bounds[4];
-
-        if (aspect == 1.0) {
-            // Square
-            switch (plane) {
-            case PLANE_XY: {
-                if (size[0] > size[1] && size[1] > 1.0e-6) {
-                    scale[1] = size[0] / size[1];
-                } else if (size[1] > size[0] && size[0] > 1.0e-6) {
-                    scale[0] = size[1] / size[0];
-                }
-            }
-                break;
-            case PLANE_ZY: {
-                if (size[1] > size[2] && size[2] > 1.0e-6) {
-                    scale[2] = size[1] / size[2];
-                } else if (size[2] > size[1] && size[1] > 1.0e-6) {
-                    scale[1] = size[2] / size[1];
-                }
-            }
-                break;
-            case PLANE_XZ: {
-                if (size[0] > size[2] && size[2] > 1.0e-6) {
-                    scale[2] = size[0] / size[2];
-                } else if (size[2] > size[0] && size[0] > 1.0e-6) {
-                    scale[0] = size[2] / size[0];
-                }
-            }
-                break;
-            default:
-                break;
-            }
-        } else {
-            switch (plane) {
-            case PLANE_XY: {
-                if (aspect > 1.0) {
-                    if (size[0] > size[1]) {
-                        scale[1] = (size[0] / aspect) / size[1];
-                    } else {
-                        scale[0] = (size[1] * aspect) / size[0];
-                    }
-                } else {
-                    if (size[1] > size[0]) {
-                        scale[0] = (size[1] * aspect) / size[0];
-                    } else {
-                        scale[1] = (size[0] / aspect) / size[1];
-                    }
-                }
-            }
-                break;
-            case PLANE_ZY: {
-                if (aspect > 1.0) {
-                    if (size[2] > size[1]) {
-                        scale[1] = (size[2] / aspect) / size[1];
-                    } else {
-                        scale[2] = (size[1] * aspect) / size[2];
-                    }
-                } else {
-                    if (size[1] > size[2]) {
-                        scale[2] = (size[1] * aspect) / size[2];
-                    } else {
-                        scale[1] = (size[2] / aspect) / size[1];
-                    }
-                }
-            }
-                break;
-            case PLANE_XZ: {
-                if (aspect > 1.0) {
-                    if (size[0] > size[2]) {
-                        scale[2] = (size[0] / aspect) / size[2];
-                    } else {
-                        scale[0] = (size[2] * aspect) / size[0];
-                    }
-                } else {
-                    if (size[2] > size[0]) {
-                        scale[0] = (size[2] * aspect) / size[0];
-                    } else {
-                        scale[2] = (size[0] / aspect) / size[2];
-                    }
-                }
-            }
-            default:
-                break;
-            }
-        }
-
-        TRACE("obj %g,%g,%g", size[0], size[1], size[2]);
-        TRACE("Setting scale to %g,%g,%g", scale[0], scale[1], scale[2]);
-        setScale(scale);
-    }
-
-    /**
-     * \brief Get the prop scaling
-     *
-     * \param[out] scale Scaling in x,y,z
-     */
-    virtual void getScale(double scale[3])
-    {
-        if (getProp3D() != NULL) {
-            getProp3D()->GetScale(scale);
-        } else {
-            scale[0] = scale[1] = scale[2] = 1.0;
-        }
-    }
-
-    /**
-     * \brief Set the prop scaling
-     *
-     * \param[in] scale Scaling in x,y,z
-     */
-    virtual void setScale(double scale[3])
-    {
-        if (getProp3D() != NULL) {
-            getProp3D()->SetScale(scale);
-        }
-    }
-
-    /**
-     * \brief Get the physical bounds of the prop
-     *
-     * If the prop is scaled, these bounds will be
-     * scaled as well
-     */
-    virtual double *getBounds()
-    {
-        if (getProp() != NULL)
-            return getProp()->GetBounds();
-        else
-            return NULL;
-    }
-
-    /**
-     * \brief Get the data bounds of the prop
-     *
-     * If the prop is scaled, these bounds will NOT
-     * be scaled, they will reflect the unscaled data
-     * bounds.
-     */
-    virtual double *getUnscaledBounds()
-    {
-        if (getProp3D() != NULL) {
-            double scale[3];
-            getProp3D()->GetScale(scale);
-            if (scale[0] == scale[1] && scale[1] == scale[2] &&
-                scale[0] == 1.0) {
-                return getBounds();
-            } else if (getBounds() != NULL) {
-                _unscaledBounds[0] = getBounds()[0] / scale[0];
-                _unscaledBounds[1] = getBounds()[1] / scale[0];
-                _unscaledBounds[2] = getBounds()[2] / scale[1];
-                _unscaledBounds[3] = getBounds()[3] / scale[1];
-                _unscaledBounds[4] = getBounds()[4] / scale[2];
-                _unscaledBounds[5] = getBounds()[5] / scale[2];
-                return _unscaledBounds;
-            }
-        }
-        return getBounds();
-    }
-
-    /**
-     * \brief Toggle visibility of the prop
-     */
-    virtual void setVisibility(bool state)
-    {
-        if (_prop != NULL)
-            _prop->SetVisibility((state ? 1 : 0));
-    }
-
-    /**
-     * \brief Get visibility state of the prop
-     */
-    virtual bool getVisibility()
-    {
-        if (_prop != NULL &&
-            _prop->GetVisibility() != 0) {
-            return true;
-        } else {
-            return false;
-        }
-    }
-
-    /**
-     * \brief Set the opacity of the object
-     *
-     * The prop must be a vtkActor or vtkAssembly
-     */
-    virtual void setOpacity(double opacity)
-    {
-        _opacity = opacity;
-        if (getActor() != NULL) {
-            getActor()->GetProperty()->SetOpacity(opacity);
-            if (_faceCulling && _opacity < 1.0) {
-                setCulling(getActor()->GetProperty(), false);
-                TRACE("Culling off");
-            } else if (_faceCulling && _opacity == 1.0) {
-                setCulling(getActor()->GetProperty(), true);
-                TRACE("Culling on");
-            }
-        } else if (getAssembly() != NULL) {
-            vtkProp3DCollection *props = getAssembly()->GetParts();
-            vtkProp3D *prop;
-            props->InitTraversal();
-            while ((prop = props->GetNextProp3D()) != NULL) {
-                if (vtkActor::SafeDownCast(prop) != NULL) {
-                    vtkActor::SafeDownCast(prop)->GetProperty()->SetOpacity(opacity);
-                    if (_faceCulling && _opacity < 1.0) {
-                        setCulling(vtkActor::SafeDownCast(prop)->GetProperty(), false);
-                        TRACE("Culling off");
-                    } else if (_faceCulling && _opacity == 1.0) {
-                        setCulling(vtkActor::SafeDownCast(prop)->GetProperty(), true);
-                        TRACE("Culling on");
-                    }
-                }
-            }
-        }
-    }
-
-    /**
-     * \brief Get the opacity of the object
-     */
-    inline double getOpacity()
-    {
-        return _opacity;
-    }
-
-    /**
-     * \brief Set the ambient material coefficient
-     */
-    virtual void setAmbient(double ambient)
-    {
-        if (getActor() != NULL) {
-            getActor()->GetProperty()->SetAmbient(ambient);
-        } else if (getVolume() != NULL) {
-            getVolume()->GetProperty()->SetAmbient(ambient);
-        } else if (getAssembly() != NULL) {
-            vtkProp3DCollection *props = getAssembly()->GetParts();
-            vtkProp3D *prop;
-            props->InitTraversal();
-            while ((prop = props->GetNextProp3D()) != NULL) {
-                if (vtkActor::SafeDownCast(prop) != NULL) {
-                    vtkActor::SafeDownCast(prop)->GetProperty()->SetAmbient(ambient);
-                } else if (vtkVolume::SafeDownCast(prop) != NULL) {
-                    vtkVolume::SafeDownCast(prop)->GetProperty()->SetAmbient(ambient);
-                }
-            }
-        }
-    }
-
-    /**
-     * \brief Set the diffuse material coefficient
-     */
-    virtual void setDiffuse(double diffuse)
-    {
-        if (getActor() != NULL) {
-            getActor()->GetProperty()->SetDiffuse(diffuse);
-        } else if (getVolume() != NULL) {
-            getVolume()->GetProperty()->SetDiffuse(diffuse);
-        } else if (getAssembly() != NULL) {
-            vtkProp3DCollection *props = getAssembly()->GetParts();
-            vtkProp3D *prop;
-            props->InitTraversal();
-            while ((prop = props->GetNextProp3D()) != NULL) {
-                if (vtkActor::SafeDownCast(prop) != NULL) {
-                    vtkActor::SafeDownCast(prop)->GetProperty()->SetDiffuse(diffuse);
-                } else if (vtkVolume::SafeDownCast(prop) != NULL) {
-                    vtkVolume::SafeDownCast(prop)->GetProperty()->SetDiffuse(diffuse);
-                }
-            }
-        }
-    }
-
-    /**
-     * \brief Set the specular material coefficient and power
-     */
-    virtual void setSpecular(double coeff, double power)
-    {
-        if (getActor() != NULL) {
-            getActor()->GetProperty()->SetSpecular(coeff);
-            getActor()->GetProperty()->SetSpecularPower(power);
-        } else if (getVolume() != NULL) {
-            getVolume()->GetProperty()->SetSpecular(coeff);
-            getVolume()->GetProperty()->SetSpecularPower(power);
-        } else if (getAssembly() != NULL) {
-            vtkProp3DCollection *props = getAssembly()->GetParts();
-            vtkProp3D *prop;
-            props->InitTraversal();
-            while ((prop = props->GetNextProp3D()) != NULL) {
-                if (vtkActor::SafeDownCast(prop) != NULL) {
-                    vtkActor::SafeDownCast(prop)->GetProperty()->SetSpecular(coeff);
-                    vtkActor::SafeDownCast(prop)->GetProperty()->SetSpecularPower(power);
-                } else if (vtkVolume::SafeDownCast(prop) != NULL) {
-                    vtkVolume::SafeDownCast(prop)->GetProperty()->SetSpecular(coeff);
-                    vtkVolume::SafeDownCast(prop)->GetProperty()->SetSpecularPower(power);
-                }
-            }
-        }
-    }
-
-    /**
-     * \brief Set material properties (coefficients and specular power) of object
-     */
-    virtual void setMaterial(double ambient, double diffuse, double specular, double specPower)
-    {
-        if (getActor() != NULL) {
-            vtkProperty *property = getActor()->GetProperty();
-            property->SetAmbient(ambient);
-            property->SetDiffuse(diffuse);
-            property->SetSpecular(specular);
-            property->SetSpecularPower(specPower);
-        } else if (getVolume() != NULL) {
-            vtkVolumeProperty *property = getVolume()->GetProperty();
-            property->SetAmbient(ambient);
-            property->SetDiffuse(diffuse);
-            property->SetSpecular(specular);
-            property->SetSpecularPower(specPower);
-        } else if (getAssembly() != NULL) {
-            vtkProp3DCollection *props = getAssembly()->GetParts();
-            vtkProp3D *prop;
-            props->InitTraversal();
-            while ((prop = props->GetNextProp3D()) != NULL) {
-                if (vtkActor::SafeDownCast(prop) != NULL) {
-                    vtkProperty *property = vtkActor::SafeDownCast(prop)->GetProperty();
-                    property->SetAmbient(ambient);
-                    property->SetDiffuse(diffuse);
-                    property->SetSpecular(specular);
-                    property->SetSpecularPower(specPower);
-                } else if (vtkVolume::SafeDownCast(prop) != NULL) {
-                    vtkVolumeProperty *property = vtkVolume::SafeDownCast(prop)->GetProperty();
-                    property->SetAmbient(ambient);
-                    property->SetDiffuse(diffuse);
-                    property->SetSpecular(specular);
-                    property->SetSpecularPower(specPower);
-                }
-            }
-        }
-    }
-
-    /**
-     * \brief Set the material color (sets ambient, diffuse, and specular)
-     */
-    virtual void setColor(float color[3])
-    {
-        for (int i = 0; i < 3; i++)
-            _color[i] = color[i];
-        if (getActor() != NULL) {
-            getActor()->GetProperty()->SetColor(color[0], color[1], color[2]);
-        } else if (getAssembly() != NULL) {
-            vtkProp3DCollection *props = getAssembly()->GetParts();
-            vtkProp3D *prop;
-            props->InitTraversal();
-            while ((prop = props->GetNextProp3D()) != NULL) {
-                if (vtkActor::SafeDownCast(prop) != NULL) {
-                    vtkActor::SafeDownCast(prop)->GetProperty()->SetColor(color[0], color[1], color[2]);
-                }
-            }
-        }
-    }
-
-    /**
-     * \brief Set the material ambient color
-     */
-    virtual void setAmbientColor(float color[3])
-    {
-        if (getActor() != NULL) {
-            getActor()->GetProperty()->SetAmbientColor(color[0], color[1], color[2]);
-        } else if (getAssembly() != NULL) {
-            vtkProp3DCollection *props = getAssembly()->GetParts();
-            vtkProp3D *prop;
-            props->InitTraversal();
-            while ((prop = props->GetNextProp3D()) != NULL) {
-                if (vtkActor::SafeDownCast(prop) != NULL) {
-                    vtkActor::SafeDownCast(prop)->GetProperty()->SetAmbientColor(color[0], color[1], color[2]);
-                }
-            }
-        }
-    }
-
-    /**
-     * \brief Set the material diffuse color
-     */
-    virtual void setDiffuseColor(float color[3])
-    {
-        if (getActor() != NULL) {
-            getActor()->GetProperty()->SetDiffuseColor(color[0], color[1], color[2]);
-        } else if (getAssembly() != NULL) {
-            vtkProp3DCollection *props = getAssembly()->GetParts();
-            vtkProp3D *prop;
-            props->InitTraversal();
-            while ((prop = props->GetNextProp3D()) != NULL) {
-                if (vtkActor::SafeDownCast(prop) != NULL) {
-                    vtkActor::SafeDownCast(prop)->GetProperty()->SetDiffuseColor(color[0], color[1], color[2]);
-                }
-            }
-        }
-    }
-
-    /**
-     * \brief Set the material specular color
-     */
-    virtual void setSpecularColor(float color[3])
-    {
-        if (getActor() != NULL) {
-            getActor()->GetProperty()->SetSpecularColor(color[0], color[1], color[2]);
-        } else if (getAssembly() != NULL) {
-            vtkProp3DCollection *props = getAssembly()->GetParts();
-            vtkProp3D *prop;
-            props->InitTraversal();
-            while ((prop = props->GetNextProp3D()) != NULL) {
-                if (vtkActor::SafeDownCast(prop) != NULL) {
-                    vtkActor::SafeDownCast(prop)->GetProperty()->SetSpecularColor(color[0], color[1], color[2]);
-                }
-            }
-        }
-    }
-
-    /**
-     * \brief Toggle lighting of the prop
-     */
-    virtual void setLighting(bool state)
-    {
-        _lighting = state;
-        if (getActor() != NULL) {
-            getActor()->GetProperty()->SetLighting((state ? 1 : 0));
-        } else if (getVolume() != NULL) {
-            getVolume()->GetProperty()->SetShade((state ? 1 : 0));
-         } else if (getAssembly() != NULL) {
-            vtkProp3DCollection *props = getAssembly()->GetParts();
-            vtkProp3D *prop;
-            props->InitTraversal();
-            while ((prop = props->GetNextProp3D()) != NULL) {
-                if (vtkActor::SafeDownCast(prop) != NULL) {
-                    vtkActor::SafeDownCast(prop)->GetProperty()->SetLighting((state ? 1 : 0));
-                } else if (vtkVolume::SafeDownCast(prop) != NULL) {
-                    vtkVolume::SafeDownCast(prop)->GetProperty()->SetShade((state ? 1 : 0));
-                }
-            }
-        }
-    }
-
-    /**
-     * \brief Toggle drawing of edges
-     */
-    virtual void setEdgeVisibility(bool state)
-    {
-        if (getActor() != NULL) {
-            getActor()->GetProperty()->SetEdgeVisibility((state ? 1 : 0));
-        } else if (getAssembly() != NULL) {
-            vtkProp3DCollection *props = getAssembly()->GetParts();
-            vtkProp3D *prop;
-            props->InitTraversal();
-            while ((prop = props->GetNextProp3D()) != NULL) {
-                if (vtkActor::SafeDownCast(prop) != NULL) {
-                    vtkActor::SafeDownCast(prop)->GetProperty()->SetEdgeVisibility((state ? 1 : 0));
-                }
-            }
-        }
-    }
-
-    /**
-     * \brief Set color of edges
-     */
-    virtual void setEdgeColor(float color[3])
-    {
-        for (int i = 0; i < 3; i++)
-            _edgeColor[i] = color[i];
-        if (getActor() != NULL) {
-            getActor()->GetProperty()->SetEdgeColor(color[0], color[1], color[2]);
-        } else if (getAssembly() != NULL) {
-            vtkProp3DCollection *props = getAssembly()->GetParts();
-            vtkProp3D *prop;
-            props->InitTraversal();
-            while ((prop = props->GetNextProp3D()) != NULL) {
-                if (vtkActor::SafeDownCast(prop) != NULL) {
-                    vtkActor::SafeDownCast(prop)->GetProperty()->SetEdgeColor(color[0], color[1], color[2]);
-                }
-            }
-        }
-    }
-
-    /**
-     * \brief Set pixel width of edges
-     *
-     * NOTE: May be a no-op if OpenGL implementation doesn't support wide lines
-     */
-    virtual void setEdgeWidth(float width)
-    {
-        _edgeWidth = width;
-        if (getActor() != NULL) {
-            getActor()->GetProperty()->SetLineWidth(width);
-        } else if (getAssembly() != NULL) {
-            vtkProp3DCollection *props = getAssembly()->GetParts();
-            vtkProp3D *prop;
-            props->InitTraversal();
-            while ((prop = props->GetNextProp3D()) != NULL) {
-                if (vtkActor::SafeDownCast(prop) != NULL) {
-                    vtkActor::SafeDownCast(prop)->GetProperty()->SetLineWidth(width);
-                }
-            }
-        }
-    }
-
-    /**
-     * \brief Set point size
-     *
-     * NOTE: May be a no-op if OpenGL implementation doesn't support wide points
-     */
-    virtual void setPointSize(float size)
-    {
-        _pointSize = size;
-        if (getActor() != NULL) {
-            getActor()->GetProperty()->SetPointSize(size);
-        } else if (getAssembly() != NULL) {
-            vtkProp3DCollection *props = getAssembly()->GetParts();
-            vtkProp3D *prop;
-            props->InitTraversal();
-            while ((prop = props->GetNextProp3D()) != NULL) {
-                if (vtkActor::SafeDownCast(prop) != NULL) {
-                    vtkActor::SafeDownCast(prop)->GetProperty()->SetPointSize(size);
-                }
-            }
-        }
-    }
-
-    /**
-     * \brief Toggle wireframe rendering of prop
-     */
-    virtual void setWireframe(bool state)
-    {
-        if (getActor() != NULL) {
-            if (state) {
-                getActor()->GetProperty()->SetRepresentationToWireframe();
-                getActor()->GetProperty()->LightingOff();
-            } else {
-                getActor()->GetProperty()->SetRepresentationToSurface();
-                setLighting(_lighting);
-            }
-        } else if (getAssembly() != NULL) {
-            vtkProp3DCollection *props = getAssembly()->GetParts();
-            vtkProp3D *prop;
-            props->InitTraversal();
-            while ((prop = props->GetNextProp3D()) != NULL) {
-                if (vtkActor::SafeDownCast(prop) != NULL) {
-                    if (state) {
-                        vtkActor::SafeDownCast(prop)->GetProperty()->SetRepresentationToWireframe();
-                        vtkActor::SafeDownCast(prop)->GetProperty()->LightingOff();
-                    } else {
-                        vtkActor::SafeDownCast(prop)->GetProperty()->SetRepresentationToSurface();
-                        vtkActor::SafeDownCast(prop)->GetProperty()->SetLighting((_lighting ? 1 : 0));
-                    }
-                }
-            }
-        }
-    }
-
-    /**
-     * \brief Toggle culling of selected CullFace
-     */
-    virtual void setCulling(bool state)
-    {
-        _faceCulling = state;
-        if (state && _opacity < 1.0)
-            return;
-        if (getActor() != NULL) {
-            setCulling(getActor()->GetProperty(), state);
-        } else if (getAssembly() != NULL) {
-            vtkProp3DCollection *props = getAssembly()->GetParts();
-            vtkProp3D *prop;
-            props->InitTraversal();
-            while ((prop = props->GetNextProp3D()) != NULL) {
-                if (vtkActor::SafeDownCast(prop) != NULL) {
-                    setCulling(vtkActor::SafeDownCast(prop)->GetProperty(), state);
-                }
-            }
-        }
-    }
-
-    /**
-     * \brief Specify which face(s) to cull when culling is enabled
-     */
-    virtual void setCullFace(CullFace cull)
-    {
-        _cullFace = cull;
-        setCulling(_faceCulling);
-    }
-
-    /**
-     * \brief Subclasses need to implement setting clipping planes in their mappers
-     */
-    virtual void setClippingPlanes(vtkPlaneCollection *planes) = 0;
-
-protected:
-    /**
-     * \brief Create and initialize a VTK Prop to render the object
-     */
-    virtual void initProp()
-    {
-        if (_prop == NULL) {
-            _prop = vtkSmartPointer<vtkActor>::New();
-            vtkProperty *property = getActor()->GetProperty();
-            property->SetColor(_color[0], _color[1], _color[2]);
-            property->SetEdgeColor(_edgeColor[0], _edgeColor[1], _edgeColor[2]);
-            property->SetLineWidth(_edgeWidth);
-            property->SetPointSize(_pointSize);
-            property->EdgeVisibilityOff();
-            if (_dataSet != NULL)
-                _opacity = _dataSet->getOpacity();
-            property->SetOpacity(_opacity);
-            property->SetAmbient(.2);
-            if (!_lighting)
-                property->LightingOff();
-            if (_faceCulling && _opacity == 1.0) {
-                setCulling(property, true);
-            }
-            if (_dataSet != NULL)
-                setVisibility(_dataSet->getVisibility());
-        }
-    }
-
-    /**
-     * \brief Subclasses implement this to create the VTK pipeline
-     * on a state change (e.g. new DataSet)
-     */
-    virtual void update() = 0;
-
-    /**
-     * \brief Convenience method to set culling state on a vtkProperty
-     *
-     * Note: Does not change the culling state flag of this VtkGraphicsObject
-     */
-    virtual void setCulling(vtkProperty *property, bool state)
-    {
-        switch (_cullFace) {
-        case CULL_FRONT:
-            property->SetFrontfaceCulling((state ? 1 : 0));
-            property->BackfaceCullingOff();
-            break;
-        case CULL_BACK:
-            property->SetBackfaceCulling((state ? 1 : 0));
-            property->FrontfaceCullingOff();
-            break;
-        case CULL_FRONT_AND_BACK:
-            property->SetBackfaceCulling((state ? 1 : 0));
-            property->SetFrontfaceCulling((state ? 1 : 0));
-            break;
-        }
-    }
-
-    DataSet *_dataSet;
-    double _dataRange[2];
-    double _unscaledBounds[6];
-    double _opacity;
-    float _color[3];
-    float _edgeColor[3];
-    float _edgeWidth;
-    float _pointSize;
-    bool _lighting;
-    CullFace _cullFace;
-    bool _faceCulling;
-
-    vtkSmartPointer<vtkProp> _prop;
-};
-
-}
-
-#endif
Index: unk/packages/vizservers/vtkvis/RpVtkRenderServer.cpp
===================================================================
--- /trunk/packages/vizservers/vtkvis/RpVtkRenderServer.cpp	(revision 3615)
+++ 	(revision )
@@ -1,579 +1,0 @@
-/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
-/*
- * Copyright (C) 2004-2012  HUBzero Foundation, LLC
- *
- * Author: Leif Delgass <ldelgass@purdue.edu>
- */
-
-#include <cstdio>
-#include <cstring>
-#include <cstdlib>
-#include <cerrno>
-#include <unistd.h>
-#include <signal.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <sys/time.h>
-#include <sys/times.h>
-
-#include <string>
-#include <sstream>
-
-#include <tcl.h>
-
-#include "Trace.h"
-#include "ReadBuffer.h"
-#include "RpVtkRenderServer.h"
-#include "RpVtkRendererCmd.h"
-#include "RpVtkRenderer.h"
-#include "PPMWriter.h"
-#include "TGAWriter.h"
-#ifdef USE_THREADS
-#include <pthread.h>
-#include "ResponseQueue.h"
-#endif 
-#include <md5.h>
-
-using namespace VtkVis;
-
-Stats VtkVis::g_stats;
-
-int VtkVis::g_statsFile = -1; ///< Stats output file descriptor.
-int VtkVis::g_fdIn = STDIN_FILENO; ///< Input file descriptor
-int VtkVis::g_fdOut = STDOUT_FILENO; ///< Output file descriptor
-FILE *VtkVis::g_fOut = stdout; ///< Output file handle
-FILE *VtkVis::g_fLog = NULL; ///< Trace logging file handle
-Renderer *VtkVis::g_renderer = NULL; ///< Main render worker
-ReadBuffer *VtkVis::g_inBufPtr = NULL; ///< Socket read buffer
-
-#ifdef USE_THREADS
-static void
-queueFrame(ResponseQueue *queue, vtkUnsignedCharArray *imgData)
-{
-#ifdef DEBUG
-    if (g_renderer->getCameraMode() == Renderer::IMAGE) {
-        double xywh[4];
-        g_renderer->getScreenWorldCoords(xywh);
-        TRACE("Image bbox: %g %g %g %g", 
-              xywh[0], 
-              (xywh[1] + xywh[3]), 
-              (xywh[0] + xywh[2]), 
-              xywh[1]);
-    }
-
-#ifdef RENDER_TARGA
-    writeTGAFile("/tmp/frame.tga",
-                 imgData->GetPointer(0),
-                 g_renderer->getWindowWidth(),
-                 g_renderer->getWindowHeight(),
-                 TARGA_BYTES_PER_PIXEL);
-#else
-    writeTGAFile("/tmp/frame.tga",
-                 imgData->GetPointer(0),
-                 g_renderer->getWindowWidth(),
-                 g_renderer->getWindowHeight(),
-                 TARGA_BYTES_PER_PIXEL,
-                 true);
-#endif  /*RENDER_TARGA*/
-
-#else
-    if (g_renderer->getCameraMode() == Renderer::IMAGE) {
-        double xywh[4];
-        g_renderer->getCameraZoomRegion(xywh);
-        std::ostringstream oss;
-        oss.precision(12);
-        // Send upper left and lower right corners as bbox
-        oss << "nv>image -type image -bbox {"
-            << std::scientific
-            << xywh[0] << " "
-            << xywh[1] << " "
-            << xywh[2] << " "
-            << xywh[3] << "} -bytes";
-
-#ifdef RENDER_TARGA
-        queueTGA(queue, oss.str().c_str(),
-                 imgData->GetPointer(0),
-                 g_renderer->getWindowWidth(),
-                 g_renderer->getWindowHeight(),
-                 TARGA_BYTES_PER_PIXEL);
-#else
-        queuePPM(queue, oss.str().c_str(),
-                 imgData->GetPointer(0),
-                 g_renderer->getWindowWidth(),
-                 g_renderer->getWindowHeight());
-#endif  /*RENDER_TARGA*/
-    } else {
-#ifdef RENDER_TARGA
-        queueTGA(queue, "nv>image -type image -bytes",
-                 imgData->GetPointer(0),
-                 g_renderer->getWindowWidth(),
-                 g_renderer->getWindowHeight(),
-                 TARGA_BYTES_PER_PIXEL);
-#else
-        queuePPM(queue, "nv>image -type image -bytes",
-                 imgData->GetPointer(0),
-                 g_renderer->getWindowWidth(),
-                 g_renderer->getWindowHeight());
-#endif  /*RENDER_TARGA*/
-    }
-#endif  /*DEBUG*/
-}
-
-#else
-
-static void
-writeFrame(int fd, vtkUnsignedCharArray *imgData)
-{
-#ifdef DEBUG
-    if (g_renderer->getCameraMode() == Renderer::IMAGE) {
-        double xywh[4];
-        g_renderer->getScreenWorldCoords(xywh);
-        TRACE("Image bbox: %g %g %g %g", 
-              xywh[0], 
-              (xywh[1] + xywh[3]), 
-              (xywh[0] + xywh[2]), 
-              xywh[1]);
-    }
-
-#ifdef RENDER_TARGA
-    writeTGAFile("/tmp/frame.tga",
-                 imgData->GetPointer(0),
-                 g_renderer->getWindowWidth(),
-                 g_renderer->getWindowHeight(),
-                 TARGA_BYTES_PER_PIXEL);
-#else
-    writeTGAFile("/tmp/frame.tga",
-                 imgData->GetPointer(0),
-                 g_renderer->getWindowWidth(),
-                 g_renderer->getWindowHeight(),
-                 TARGA_BYTES_PER_PIXEL,
-                 true);
-#endif  /*RENDER_TARGA*/
-
-#else
-    if (g_renderer->getCameraMode() == Renderer::IMAGE) {
-        double xywh[4];
-        g_renderer->getCameraZoomRegion(xywh);
-        std::ostringstream oss;
-        oss.precision(12);
-        // Send upper left and lower right corners as bbox
-        oss << "nv>image -type image -bbox {"
-            << std::scientific
-            << xywh[0] << " "
-            << xywh[1] << " "
-            << xywh[2] << " "
-            << xywh[3] << "} -bytes";
-
-#ifdef RENDER_TARGA
-        writeTGA(fd, oss.str().c_str(),
-                 imgData->GetPointer(0),
-                 g_renderer->getWindowWidth(),
-                 g_renderer->getWindowHeight(),
-                 TARGA_BYTES_PER_PIXEL);
-#else
-        writePPM(fd, oss.str().c_str(),
-                 imgData->GetPointer(0),
-                 g_renderer->getWindowWidth(),
-                 g_renderer->getWindowHeight());
-#endif  /*RENDER_TARGA*/
-    } else {
-#ifdef RENDER_TARGA
-        writeTGA(fd, "nv>image -type image -bytes",
-                 imgData->GetPointer(0),
-                 g_renderer->getWindowWidth(),
-                 g_renderer->getWindowHeight(),
-                 TARGA_BYTES_PER_PIXEL);
-#else
-        writePPM(fd, "nv>image -type image -bytes",
-                 imgData->GetPointer(0),
-                 g_renderer->getWindowWidth(),
-                 g_renderer->getWindowHeight());
-#endif  /*RENDER_TARGA*/
-    }
-#endif  /*DEBUG*/
-}
-#endif /*USE_THREADS*/
-
-static int
-sendAck(ClientData clientData, int fdOut)
-{
-    std::ostringstream oss;
-    oss << "nv>ok -token " << g_stats.nCommands <<  "\n";
-    int nBytes = oss.str().length();
-
-    TRACE("Sending OK for commands through %lu", g_stats.nCommands);
-#ifdef USE_THREADS
-    queueResponse(clientData, oss.str().c_str(), nBytes, Response::VOLATILE, Response::OK);
-#else
-    if (write(fdOut, oss.str().c_str(), nBytes) < 0) {
-        ERROR("write failed: %s", strerror(errno));
-        return -1;
-    }
-#endif
-    return 0;
-}
-
-int
-VtkVis::getStatsFile(Tcl_Interp *interp, Tcl_Obj *objPtr)
-{
-    Tcl_DString ds;
-    Tcl_Obj **objv;
-    int objc;
-    int i;
-    char fileName[33];
-    const char *path;
-    md5_state_t state;
-    md5_byte_t digest[16];
-    char *string;
-    int length;
-
-    if ((objPtr == NULL) || (g_statsFile >= 0)) {
-        return g_statsFile;
-    }
-    if (Tcl_ListObjGetElements(interp, objPtr, &objc, &objv) != TCL_OK) {
-	return -1;
-    }
-    Tcl_ListObjAppendElement(interp, objPtr, Tcl_NewStringObj("pid", 3));
-    Tcl_ListObjAppendElement(interp, objPtr, Tcl_NewIntObj(getpid()));
-    string = Tcl_GetStringFromObj(objPtr, &length);
-
-    md5_init(&state);
-    md5_append(&state, (const md5_byte_t *)string, length);
-    md5_finish(&state, digest);
-    for (i = 0; i < 16; i++) {
-        sprintf(fileName + i * 2, "%02x", digest[i]);
-    }
-    Tcl_DStringInit(&ds);
-    Tcl_DStringAppend(&ds, STATSDIR, -1);
-    Tcl_DStringAppend(&ds, "/", 1);
-    Tcl_DStringAppend(&ds, fileName, 32);
-    path = Tcl_DStringValue(&ds);
-
-    g_statsFile = open(path, O_EXCL | O_CREAT | O_WRONLY, 0600);
-    Tcl_DStringFree(&ds);
-    if (g_statsFile < 0) {
-	ERROR("can't open \"%s\": %s", fileName, strerror(errno));
-	return -1;
-    }
-    return g_statsFile;
-}
-
-int
-VtkVis::writeToStatsFile(int f, const char *s, size_t length)
-{
-    if (f >= 0) {
-        ssize_t numWritten;
-
-        numWritten = write(f, s, length);
-        if (numWritten == (ssize_t)length) {
-            close(dup(f));
-        }
-    }
-    return 0;
-}
-
-static int
-serverStats(int code) 
-{
-    double start, finish;
-    char buf[BUFSIZ];
-    Tcl_DString ds;
-    int result;
-    int f;
-
-    {
-	struct timeval tv;
-
-	/* Get ending time.  */
-	gettimeofday(&tv, NULL);
-	finish = CVT2SECS(tv);
-	tv = g_stats.start;
-	start = CVT2SECS(tv);
-    }
-    /* 
-     * Session information:
-     *   - Name of render server
-     *   - Process ID
-     *   - Hostname where server is running
-     *   - Start date of session
-     *   - Start date of session in seconds
-     *   - Number of data sets loaded from client
-     *   - Number of data bytes total loaded from client
-     *   - Number of frames returned
-     *   - Number of bytes total returned (in frames)
-     *   - Number of commands received
-     *   - Total elapsed time of all commands
-     *   - Total elapsed time of session
-     *   - Exit code of vizserver
-     *   - User time 
-     *   - System time
-     *   - User time of children 
-     *   - System time of children 
-     */
-
-    Tcl_DStringInit(&ds);
-    
-    Tcl_DStringAppendElement(&ds, "render_stop");
-    /* renderer */
-    Tcl_DStringAppendElement(&ds, "renderer");
-    Tcl_DStringAppendElement(&ds, "vtkvis");
-    /* pid */
-    Tcl_DStringAppendElement(&ds, "pid");
-    sprintf(buf, "%d", getpid());
-    Tcl_DStringAppendElement(&ds, buf);
-    /* host */
-    Tcl_DStringAppendElement(&ds, "host");
-    gethostname(buf, BUFSIZ-1);
-    buf[BUFSIZ-1] = '\0';
-    Tcl_DStringAppendElement(&ds, buf);
-    /* date */
-    Tcl_DStringAppendElement(&ds, "date");
-    strcpy(buf, ctime(&g_stats.start.tv_sec));
-    buf[strlen(buf) - 1] = '\0';
-    Tcl_DStringAppendElement(&ds, buf);
-    /* date_secs */
-    Tcl_DStringAppendElement(&ds, "date_secs");
-    sprintf(buf, "%ld", g_stats.start.tv_sec);
-    Tcl_DStringAppendElement(&ds, buf);
-    /* num_data_sets */
-    Tcl_DStringAppendElement(&ds, "num_data_sets");
-    sprintf(buf, "%lu", (unsigned long int)g_stats.nDataSets);
-    Tcl_DStringAppendElement(&ds, buf);
-    /* data_set_bytes */
-    Tcl_DStringAppendElement(&ds, "data_set_bytes");
-    sprintf(buf, "%lu", (unsigned long int)g_stats.nDataBytes);
-    Tcl_DStringAppendElement(&ds, buf);
-    /* num_frames */
-    Tcl_DStringAppendElement(&ds, "num_frames");
-    sprintf(buf, "%lu", (unsigned long int)g_stats.nFrames);
-    Tcl_DStringAppendElement(&ds, buf);
-    /* frame_bytes */
-    Tcl_DStringAppendElement(&ds, "frame_bytes");
-    sprintf(buf, "%lu", (unsigned long int)g_stats.nFrameBytes);
-    Tcl_DStringAppendElement(&ds, buf);
-    /* num_commands */
-    Tcl_DStringAppendElement(&ds, "num_commands");
-    sprintf(buf, "%lu", (unsigned long int)g_stats.nCommands);
-    Tcl_DStringAppendElement(&ds, buf);
-    /* cmd_time */
-    Tcl_DStringAppendElement(&ds, "cmd_time");
-    sprintf(buf, "%g", g_stats.cmdTime);
-    Tcl_DStringAppendElement(&ds, buf);
-    /* session_time */
-    Tcl_DStringAppendElement(&ds, "session_time");
-    sprintf(buf, "%g", finish - start);
-    Tcl_DStringAppendElement(&ds, buf);
-    /* status */
-    Tcl_DStringAppendElement(&ds, "status");
-    sprintf(buf, "%d", code);
-    Tcl_DStringAppendElement(&ds, buf);
-    {
-	long clocksPerSec = sysconf(_SC_CLK_TCK);
-	double clockRes = 1.0 / clocksPerSec;
-	struct tms tms;
-
-	memset(&tms, 0, sizeof(tms));
-	times(&tms);
-	/* utime */
-	Tcl_DStringAppendElement(&ds, "utime");
-	sprintf(buf, "%g", tms.tms_utime * clockRes);
-	Tcl_DStringAppendElement(&ds, buf);
-	/* stime */
-	Tcl_DStringAppendElement(&ds, "stime");
-	sprintf(buf, "%g", tms.tms_stime * clockRes);
-	Tcl_DStringAppendElement(&ds, buf);
-	/* cutime */
-	Tcl_DStringAppendElement(&ds, "cutime");
-	sprintf(buf, "%g", tms.tms_cutime * clockRes);
-	Tcl_DStringAppendElement(&ds, buf);
-	/* cstime */
-	Tcl_DStringAppendElement(&ds, "cstime");
-	sprintf(buf, "%g", tms.tms_cstime * clockRes);
-	Tcl_DStringAppendElement(&ds, buf);
-    }
-    Tcl_DStringAppend(&ds, "\n", -1);
-    f = getStatsFile(NULL, NULL);
-    result = writeToStatsFile(f, Tcl_DStringValue(&ds), 
-                              Tcl_DStringLength(&ds));
-    close(f);
-    Tcl_DStringFree(&ds);
-    return result;
-}
-
-static void
-initService()
-{
-    TRACE("Enter");
-
-    const char *user = getenv("USER");
-    char *logName = NULL;
-    int logNameLen = 0;
-
-    if (user == NULL) {
-        logNameLen = 19+1;
-        logName = (char *)calloc(logNameLen, sizeof(char));
-        strncpy(logName, "/tmp/vtkvis_log.txt", logNameLen);
-    }
-    else {
-        logNameLen = 16+strlen(user)+4+1;
-        logName = (char *)calloc(logNameLen, sizeof(char));
-        strncpy(logName, "/tmp/vtkvis_log_", logNameLen);
-        strncat(logName, user, strlen(user));
-        strncat(logName, ".txt", 4);
-    }
-
-    // open log and map stderr to log file
-    g_fLog = fopen(logName, "w");
-    close(STDERR_FILENO);
-    dup2(fileno(g_fLog), STDERR_FILENO);
-    // flush junk
-    fflush(stderr);
-
-    // clean up malloc'd memory
-    if (logName != NULL) {
-        free(logName);
-    }
-
-    TRACE("Leave");
-}
-
-static void
-exitService()
-{
-    TRACE("Enter");
-
-    serverStats(0);
-
-    // close log file
-    if (g_fLog != NULL) {
-        fclose(g_fLog);
-	g_fLog = NULL;
-    }
-}
-
-#ifdef USE_THREADS
-
-static void *
-writerThread(void *clientData)
-{
-    ResponseQueue *queue = (ResponseQueue *)clientData;
-
-    TRACE("Starting writer thread");
-    for (;;) {
-        Response *response = queue->dequeue();
-        if (response == NULL)
-            continue;
-        if (fwrite(response->message(), sizeof(char), response->length(),
-                   g_fOut) != response->length()) {
-            ERROR("short write while trying to write %ld bytes", 
-                  response->length());
-        }
-        fflush(g_fOut);
-        TRACE("Wrote response of type %d", response->type());
-        delete response;
-        if (feof(g_fOut))
-            break;
-    }    
-    return NULL;
-}
-
-#endif  /*USE_THREADS*/
-
-int
-main(int argc, char *argv[])
-{
-    // Ignore SIGPIPE.  **Is this needed? **
-    signal(SIGPIPE, SIG_IGN);
-    initService();
-    initLog();
-
-    memset(&g_stats, 0, sizeof(g_stats));
-    gettimeofday(&g_stats.start, NULL);
-
-    TRACE("Starting VTKVis Server");
-
-    /* This synchronizes the client with the server, so that the client 
-     * doesn't start writing commands before the server is ready. It could
-     * also be used to supply information about the server (version, memory
-     * size, etc). */
-    fprintf(g_fOut, "VtkVis %s (build %s)\n", VTKVIS_VERSION_STRING, SVN_VERSION);
-    fflush(g_fOut);
-
-    g_renderer = new Renderer();
-    g_inBufPtr = new ReadBuffer(g_fdIn, 1<<12);
-
-    Tcl_Interp *interp = Tcl_CreateInterp();
-    ClientData clientData = NULL;
-#ifdef USE_THREADS
-    ResponseQueue *queue = new ResponseQueue();
-    clientData = (ClientData)queue;
-    initTcl(interp, clientData);
-
-    pthread_t writerThreadId;
-    if (pthread_create(&writerThreadId, NULL, &writerThread, queue) < 0) {
-        ERROR("Can't create writer thread: %s", strerror(errno));
-    }
-#else 
-    initTcl(interp, clientData);
-#endif
-
-    vtkSmartPointer<vtkUnsignedCharArray> imgData = 
-        vtkSmartPointer<vtkUnsignedCharArray>::New();
-
-    // Start main server loop
-    for (;;) {
-        if (processCommands(interp, clientData, g_inBufPtr, g_fdOut) < 0)
-            break;
-
-        if (g_renderer->render()) {
-            TRACE("Rendering new frame");
-            g_renderer->getRenderedFrame(imgData);
-#ifdef USE_THREADS
-            queueFrame(queue, imgData);
-#else
-            writeFrame(g_fdOut, imgData);
-#endif
-            g_stats.nFrames++;
-            g_stats.nFrameBytes += imgData->GetDataSize() * imgData->GetDataTypeSize();
-        } else {
-            TRACE("No render required");
-            sendAck(clientData, g_fdOut);
-        }
-
-        if (g_inBufPtr->status() == ReadBuffer::ENDFILE)
-            break;
-    }
-#ifdef USE_THREADS
-    // Writer thread is probably blocked on sem_wait, so cancel instead
-    // of joining
-    if (pthread_cancel(writerThreadId) < 0) {
-        ERROR("Can't cancel writer thread: %s", strerror(errno));
-    } else {
-        TRACE("Cancelled writer thread");
-    }
-
-    TRACE("Deleting ResponseQueue");
-    delete queue;
-    queue = NULL;
-#endif
-
-    TRACE("Stopping Tcl interpreter");
-    exitTcl(interp);
-    interp = NULL;
-
-    TRACE("Deleting ReadBuffer");
-    delete g_inBufPtr;
-    g_inBufPtr = NULL;
-
-    TRACE("Deleting renderer");
-    delete g_renderer;
-    g_renderer = NULL;
-
-    TRACE("Exiting VTKVis Server");
-
-    closeLog();
-    exitService();
-
-    return 0;
-}
Index: unk/packages/vizservers/vtkvis/RpVtkRenderServer.h
===================================================================
--- /trunk/packages/vizservers/vtkvis/RpVtkRenderServer.h	(revision 3615)
+++ 	(revision )
@@ -1,55 +1,0 @@
-/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
-/*
- * Copyright (C) 2004-2012  HUBzero Foundation, LLC
- *
- * Author: Leif Delgass <ldelgass@purdue.edu>
- */
-
-#ifndef VTKVIS_RENDERSERVER_H
-#define VTKVIS_RENDERSERVER_H
-
-#include <sys/types.h>
-#include <sys/time.h>
-
-namespace VtkVis {
-
-class Renderer;
-
-#define VTKVIS_VERSION_STRING "1.3"
-
-#define MSECS_ELAPSED(t1, t2) \
-    ((t1).tv_sec == (t2).tv_sec ? (((t2).tv_usec - (t1).tv_usec)/1.0e+3) : \
-     (((t2).tv_sec - (t1).tv_sec))*1.0e+3 + (double)((t2).tv_usec - (t1).tv_usec)/1.0e+3)
-
-#define CVT2SECS(x)  ((double)(x).tv_sec) + ((double)(x).tv_usec * 1.0e-6)
-
-#ifndef STATSDIR
-#define STATSDIR	"/var/tmp/visservers"
-#endif
-
-typedef struct {
-    pid_t pid;
-    size_t nDataSets;       /**< # of data sets received */
-    size_t nDataBytes;      /**< # of bytes received as data sets */
-    size_t nFrames;         /**< # of frames sent to client. */
-    size_t nFrameBytes;     /**< # of bytes for all frames. */
-    size_t nCommands;       /**< # of commands executed */
-    double cmdTime;         /**< Elasped time spend executing commands. */
-    struct timeval start;   /**< Start of elapsed time. */
-} Stats;
-
-extern Stats g_stats;
-
-extern int g_fdIn;
-extern int g_fdOut;
-extern FILE *g_fOut;
-extern FILE *g_fLog;
-extern Renderer *g_renderer;
-extern ReadBuffer *g_inBufPtr;
-extern int g_statsFile;
-extern int writeToStatsFile(int f, const char *s, size_t length);
-extern int getStatsFile(Tcl_Interp * interp, Tcl_Obj *objPtr);
-
-}
-
-#endif
Index: unk/packages/vizservers/vtkvis/RpVtkRenderer.cpp
===================================================================
--- /trunk/packages/vizservers/vtkvis/RpVtkRenderer.cpp	(revision 3615)
+++ 	(revision )
@@ -1,4353 +1,0 @@
-/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
-/*
- * Copyright (C) 2004-2012  HUBzero Foundation, LLC
- *
- * Author: Leif Delgass <ldelgass@purdue.edu>
- */
-
-#include <cfloat>
-#include <cstring>
-#include <cassert>
-#include <cmath>
-
-#include <GL/gl.h>
-
-#ifdef WANT_TRACE
-#include <sys/time.h>
-#endif
-
-#include <vtkMath.h>
-#include <vtkCamera.h>
-#include <vtkLight.h>
-#include <vtkCoordinate.h>
-#include <vtkTransform.h>
-#include <vtkCharArray.h>
-#ifdef USE_CUSTOM_AXES
-#include "vtkRpCubeAxesActor.h"
-#else
-#include <vtkCubeAxesActor.h>
-#endif
-#include <vtkDataSetReader.h>
-#include <vtkDataSetMapper.h>
-#include <vtkContourFilter.h>
-#include <vtkPolyDataMapper.h>
-#include <vtkProperty.h>
-#include <vtkProperty2D.h>
-#include <vtkPointData.h>
-#include <vtkLookupTable.h>
-#include <vtkTextProperty.h>
-#include <vtkOpenGLRenderWindow.h>
-#include <vtkVersion.h>
-
-#include "RpVtkRenderer.h"
-#include "RpVtkRendererGraphicsObjs.h"
-#include "RpMath.h"
-#include "ColorMap.h"
-#include "Trace.h"
-
-#define MSECS_ELAPSED(t1, t2) \
-    ((t1).tv_sec == (t2).tv_sec ? (((t2).tv_usec - (t1).tv_usec)/1.0e+3) : \
-     (((t2).tv_sec - (t1).tv_sec))*1.0e+3 + (double)((t2).tv_usec - (t1).tv_usec)/1.0e+3)
-
-#define printCameraInfo(camera)                                         \
-do {                                                                    \
-    TRACE("pscale: %g, angle: %g, d: %g pos: %g %g %g, fpt: %g %g %g, vup: %g %g %g, clip: %g %g", \
-          (camera)->GetParallelScale(),                                 \
-          (camera)->GetViewAngle(),                                     \
-          (camera)->GetDistance(),                                      \
-          (camera)->GetPosition()[0],                                   \
-          (camera)->GetPosition()[1],                                   \
-          (camera)->GetPosition()[2],                                   \
-          (camera)->GetFocalPoint()[0],                                 \
-          (camera)->GetFocalPoint()[1],                                 \
-          (camera)->GetFocalPoint()[2],                                 \
-          (camera)->GetViewUp()[0],                                     \
-          (camera)->GetViewUp()[1],                                     \
-          (camera)->GetViewUp()[2],                                     \
-          (camera)->GetClippingRange()[0],                              \
-          (camera)->GetClippingRange()[1]);                             \
-} while(0)
-
-using namespace VtkVis;
-
-Renderer::Renderer() :
-    _needsRedraw(true),
-    _needsAxesReset(false),
-    _needsCameraClippingRangeReset(false),
-    _needsCameraReset(false),
-    _windowWidth(500),
-    _windowHeight(500),
-    _cameraMode(PERSPECTIVE),
-    _cameraAspect(ASPECT_NATIVE),
-    _imgCameraPlane(PLANE_XY),
-    _imgCameraOffset(0),
-    _cameraZoomRatio(1),
-    _useCumulativeRange(true),
-    _cumulativeRangeOnlyVisible(false)
-{
-    _bgColor[0] = 0;
-    _bgColor[1] = 0;
-    _bgColor[2] = 0;
-    _cameraPan[0] = 0;
-    _cameraPan[1] = 0;
-    _cameraOrientation[0] = 1.0;
-    _cameraOrientation[1] = 0.0;
-    _cameraOrientation[2] = 0.0;
-    _cameraOrientation[3] = 0.0;
-    // clipping planes to prevent overdrawing axes
-    _activeClipPlanes = vtkSmartPointer<vtkPlaneCollection>::New();
-    // bottom
-    _cameraClipPlanes[0] = vtkSmartPointer<vtkPlane>::New();
-    _cameraClipPlanes[0]->SetNormal(0, 1, 0);
-    _cameraClipPlanes[0]->SetOrigin(0, 0, 0);
-    if (_cameraMode == IMAGE)
-        _activeClipPlanes->AddItem(_cameraClipPlanes[0]);
-    // left
-    _cameraClipPlanes[1] = vtkSmartPointer<vtkPlane>::New();
-    _cameraClipPlanes[1]->SetNormal(1, 0, 0);
-    _cameraClipPlanes[1]->SetOrigin(0, 0, 0);
-    if (_cameraMode == IMAGE)
-        _activeClipPlanes->AddItem(_cameraClipPlanes[1]);
-    // top
-    _cameraClipPlanes[2] = vtkSmartPointer<vtkPlane>::New();
-    _cameraClipPlanes[2]->SetNormal(0, -1, 0);
-    _cameraClipPlanes[2]->SetOrigin(0, 1, 0);
-    if (_cameraMode == IMAGE)
-        _activeClipPlanes->AddItem(_cameraClipPlanes[2]);
-    // right
-    _cameraClipPlanes[3] = vtkSmartPointer<vtkPlane>::New();
-    _cameraClipPlanes[3]->SetNormal(-1, 0, 0);
-    _cameraClipPlanes[3]->SetOrigin(1, 0, 0);
-    if (_cameraMode == IMAGE)
-        _activeClipPlanes->AddItem(_cameraClipPlanes[3]);
-    _renderer = vtkSmartPointer<vtkRenderer>::New();
-
-    // Global ambient (defaults to 1,1,1)
-    //_renderer->SetAmbient(.2, .2, .2);
-
-    vtkSmartPointer<vtkLight> headlight = vtkSmartPointer<vtkLight>::New();
-    headlight->SetLightTypeToHeadlight();
-    headlight->PositionalOff();
-    // Light ambient color defaults to 0,0,0
-    //headlight->SetAmbientColor(1, 1, 1);
-    _renderer->AddLight(headlight);
-    vtkSmartPointer<vtkLight> skylight = vtkSmartPointer<vtkLight>::New();
-    skylight->SetLightTypeToCameraLight();
-    skylight->SetPosition(0, 1, 0);
-    skylight->SetFocalPoint(0, 0, 0);
-    skylight->PositionalOff();
-    // Light ambient color defaults to 0,0,0
-    //skylight->SetAmbientColor(1, 1, 1);
-    _renderer->AddLight(skylight);
-    _renderer->LightFollowCameraOn();
-    _renderWindow = vtkSmartPointer<vtkRenderWindow>::New();
-#ifdef USE_OFFSCREEN_RENDERING
-    _renderWindow->DoubleBufferOff();
-    _renderWindow->OffScreenRenderingOn();
-#else
-    _renderWindow->SwapBuffersOff();
-#endif
-    _renderWindow->SetSize(_windowWidth, _windowHeight);
-    // Next 2 options needed to support depth peeling
-    _renderWindow->SetAlphaBitPlanes(1);
-    _renderWindow->SetMultiSamples(0);
-    _renderer->SetMaximumNumberOfPeels(100);
-    _renderer->SetUseDepthPeeling(1);
-    _renderer->SetTwoSidedLighting(1);
-    _renderWindow->AddRenderer(_renderer);
-    setViewAngle(_windowHeight);
-    initAxes();
-    initCamera();
-    addColorMap("default", ColorMap::getDefault());
-    addColorMap("grayDefault", ColorMap::getGrayDefault());
-    addColorMap("volumeDefault", ColorMap::getVolumeDefault());
-    addColorMap("elementDefault", ColorMap::getElementDefault());
-}
-
-Renderer::~Renderer()
-{
-    TRACE("Enter");
-
-    deleteAllGraphicsObjects<Arc>();
-    deleteAllGraphicsObjects<Arrow>();
-    deleteAllGraphicsObjects<Box>();
-    deleteAllGraphicsObjects<Cone>();
-    deleteAllGraphicsObjects<Contour2D>();
-    deleteAllGraphicsObjects<Contour3D>();
-    deleteAllGraphicsObjects<Cutplane>();
-    deleteAllGraphicsObjects<Cylinder>();
-    deleteAllGraphicsObjects<Disk>();
-    deleteAllGraphicsObjects<Glyphs>();
-    deleteAllGraphicsObjects<Group>();
-    deleteAllGraphicsObjects<HeightMap>();
-    deleteAllGraphicsObjects<LIC>();
-    deleteAllGraphicsObjects<Line>();
-    deleteAllGraphicsObjects<Molecule>();
-    deleteAllGraphicsObjects<Outline>();
-    deleteAllGraphicsObjects<PolyData>();
-    deleteAllGraphicsObjects<Polygon>();
-    deleteAllGraphicsObjects<PseudoColor>();
-    deleteAllGraphicsObjects<Sphere>();
-    deleteAllGraphicsObjects<Streamlines>();
-    deleteAllGraphicsObjects<Volume>();
-    deleteAllGraphicsObjects<Warp>();
-
-    TRACE("Deleting ColorMaps");
-    // Delete color maps and data sets last in case references still
-    // exist
-    for (ColorMapHashmap::iterator itr = _colorMaps.begin();
-         itr != _colorMaps.end(); ++itr) {
-        delete itr->second;
-    }
-    _colorMaps.clear();
-    TRACE("Deleting DataSets");
-    for (DataSetHashmap::iterator itr = _dataSets.begin();
-         itr != _dataSets.end(); ++itr) {
-        delete itr->second;
-    }
-    _dataSets.clear();
-
-    clearFieldRanges();
-    clearUserFieldRanges();
-
-    TRACE("Leave");
-}
-
-/**
- * \brief Add a DataSet to this Renderer
- *
- * This just adds the DataSet to the Renderer's list of data sets.
- * In order to render the data, a graphics object using the data
- * set must be added to the Renderer.
- */
-void Renderer::addDataSet(const DataSetId& id)
-{
-    if (getDataSet(id) != NULL) {
-        WARN("Replacing existing DataSet %s", id.c_str());
-        deleteDataSet(id);
-    }
-    _dataSets[id] = new DataSet(id);
-}
-
-/**
- * \brief Remove the specified DataSet and associated rendering objects
- *
- * The underlying DataSet and any associated graphics 
- * objects are deleted, freeing the memory used.
- */
-void Renderer::deleteDataSet(const DataSetId& id)
-{
-    DataSetHashmap::iterator itr;
-
-    bool doAll = false;
-
-    if (id.compare("all") == 0) {
-        itr = _dataSets.begin();
-        doAll = true;
-    } else {
-        itr = _dataSets.find(id);
-    }
-    if (itr == _dataSets.end()) {
-        ERROR("Unknown dataset %s", id.c_str());
-        return;
-    }
-
-    do {
-        TRACE("Deleting dataset %s", itr->second->getName().c_str());
-
-        deleteGraphicsObject<Contour2D>(itr->second->getName());
-        deleteGraphicsObject<Contour3D>(itr->second->getName());
-        deleteGraphicsObject<Cutplane>(itr->second->getName());
-        deleteGraphicsObject<Glyphs>(itr->second->getName());
-        deleteGraphicsObject<HeightMap>(itr->second->getName());
-        deleteGraphicsObject<LIC>(itr->second->getName());
-        deleteGraphicsObject<Molecule>(itr->second->getName());
-        deleteGraphicsObject<Outline>(itr->second->getName());
-        deleteGraphicsObject<PolyData>(itr->second->getName());
-        deleteGraphicsObject<PseudoColor>(itr->second->getName());
-        deleteGraphicsObject<Streamlines>(itr->second->getName());
-        deleteGraphicsObject<Volume>(itr->second->getName());
-        deleteGraphicsObject<Warp>(itr->second->getName());
-
-        TRACE("After deleting graphics objects");
-
-        delete itr->second;
-        itr = _dataSets.erase(itr);
-    } while (doAll && itr != _dataSets.end());
-
-    // Update cumulative data range
-    initFieldRanges();
-    updateFieldRanges();
-
-    sceneBoundsChanged();
-    _needsRedraw = true;
-}
-
-/**
- * \brief Get a list of DataSets this Renderer knows about
- */
-void Renderer::getDataSetNames(std::vector<std::string>& names)
-{
-    names.clear();
-    for (DataSetHashmap::iterator itr = _dataSets.begin();
-         itr != _dataSets.end(); ++itr) {
-        names.push_back(itr->second->getName());
-    }
-}
-
-/**
- * \brief Find the DataSet for the given DataSetId key
- *
- * \return A pointer to the DataSet, or NULL if not found
- */
-DataSet *Renderer::getDataSet(const DataSetId& id)
-{
-    DataSetHashmap::iterator itr = _dataSets.find(id);
-    if (itr == _dataSets.end()) {
-#ifdef DEBUG
-        TRACE("DataSet not found: %s", id.c_str());
-#endif
-        return NULL;
-    } else
-        return itr->second;
-}
-
-/**
- * \brief (Re-)load the data for the specified DataSet key from a file
- */
-bool Renderer::setDataFile(const DataSetId& id, const char *filename)
-{
-    DataSet *ds = getDataSet(id);
-    if (ds) {
-        bool ret = ds->setDataFile(filename);
-        initFieldRanges();
-        updateFieldRanges();
-        _needsRedraw = true;
-        return ret;
-    } else
-        return false;
-}
-
-/**
- * \brief (Re-)load the data for the specified DataSet key from a memory buffer
- */
-bool Renderer::setData(const DataSetId& id, char *data, int nbytes)
-{
-    DataSet *ds = getDataSet(id);
-    if (ds) {
-        bool ret = ds->setData(data, nbytes);
-        initFieldRanges();
-        updateFieldRanges();
-        _needsRedraw = true;
-        return ret;
-    } else
-        return false;
-}
-
-/**
- * \brief Set the active scalar field array by name for a DataSet
- */
-bool Renderer::setDataSetActiveScalars(const DataSetId& id, const char *scalarName)
-{
-    DataSetHashmap::iterator itr;
-
-    bool doAll = false;
-
-    if (id.compare("all") == 0) {
-        itr = _dataSets.begin();
-        doAll = true;
-    } else {
-        itr = _dataSets.find(id);
-    }
-    if (itr == _dataSets.end()) {
-        ERROR("DataSet not found: %s", id.c_str());
-        return false;
-    }
-
-    bool ret = true;
-    bool needRangeUpdate = false;
-    do {
-        if (strcmp(itr->second->getActiveScalarsName(), scalarName) != 0) {
-            if (!itr->second->setActiveScalars(scalarName)) {
-                ret = false;
-            } else {
-                needRangeUpdate = true;
-            }
-        }
-    } while (doAll && ++itr != _dataSets.end());
-
-    if (needRangeUpdate) {
-         updateFieldRanges();
-        _needsRedraw = true;
-    } 
-
-    return ret;
-}
-
-/**
- * \brief Set the active vector field array by name for a DataSet
- */
-bool Renderer::setDataSetActiveVectors(const DataSetId& id, const char *vectorName)
-{
-    DataSetHashmap::iterator itr;
-
-    bool doAll = false;
-
-    if (id.compare("all") == 0) {
-        itr = _dataSets.begin();
-        doAll = true;
-    } else {
-        itr = _dataSets.find(id);
-    }
-    if (itr == _dataSets.end()) {
-        ERROR("DataSet not found: %s", id.c_str());
-        return false;
-    }
-
-    bool ret = true;
-    bool needRangeUpdate = false;
-    do {
-        if (strcmp(itr->second->getActiveVectorsName(), vectorName) != 0) {
-            if (!itr->second->setActiveVectors(vectorName)) {
-                ret = false;
-            } else {
-                needRangeUpdate = true;
-            }
-        }
-    } while (doAll && ++itr != _dataSets.end());
-
-    if (needRangeUpdate) {
-        updateFieldRanges();
-        _needsRedraw = true;
-    } 
-
-    return ret;
-}
-
-/**
- * \brief Control whether the cumulative data range of datasets is used for 
- * colormapping and contours
- *
- * NOTE: If using explicit range(s), setting cumulative ranges on will
- * remove explicit ranges on all fields
- */
-void Renderer::setUseCumulativeDataRange(bool state, bool onlyVisible)
-{
-    TRACE("use cumulative: %d, only visible: %d", (state ? 1 : 0), (onlyVisible ? 1 : 0));
-    _useCumulativeRange = state;
-    _cumulativeRangeOnlyVisible = onlyVisible;
-    clearUserFieldRanges();
-    updateFieldRanges();
-    resetAxes();
-    _needsRedraw = true;
-}
-
-void Renderer::resetAxes(double bounds[6])
-{
-    TRACE("Resetting axes");
-
-    if (_cubeAxesActor == NULL) {
-        initAxes();
-    }
-
-    if (_cameraMode == IMAGE) {
-        _cubeAxesActor->SetUse2DMode(1);
-    } else {
-        _cubeAxesActor->SetUse2DMode(0);
-    }
-
-    if (_cameraMode == IMAGE) {
-        return;
-    }
-
-    setAxesBounds(bounds);
-    setAxesRanges();
-}
-
-/**
- * \brief Explicitly set world coordinate bounds of axes
- *
- * This determines the region in world coordinates around which
- * the axes are drawn
- */
-void Renderer::setAxesBounds(double min, double max)
-{
-    setAxisBounds(X_AXIS, min, max);
-    setAxisBounds(Y_AXIS, min, max);
-    setAxisBounds(Z_AXIS, min, max);
-}
-
-/**
- * \brief Set axes bounds based on auto/explicit settings
- */
-void Renderer::setAxesBounds(double boundsIn[6])
-{
-    double newBounds[6];
-    if (boundsIn != NULL) { 
-        memcpy(&newBounds[0], &boundsIn[0], sizeof(double)*6);
-    } else {
-        if (_axesAutoBounds[X_AXIS] ||
-            _axesAutoBounds[Y_AXIS] ||
-            _axesAutoBounds[Z_AXIS]) {
-            collectBounds(newBounds, false);
-        }
-    }
-
-    double bounds[6];
-    if (_axesAutoBounds[X_AXIS]) {
-        memcpy(&bounds[0], &newBounds[0], sizeof(double)*2);
-    } else {
-        memcpy(&bounds[0], &_axesUserBounds[0], sizeof(double)*2);
-    }
-    if (_axesAutoBounds[Y_AXIS]) {
-        memcpy(&bounds[2], &newBounds[2], sizeof(double)*2);
-    } else {
-        memcpy(&bounds[2], &_axesUserBounds[2], sizeof(double)*2);
-    }
-    if (_axesAutoBounds[Z_AXIS]) {
-        memcpy(&bounds[4], &newBounds[4], sizeof(double)*2);
-    } else {
-        memcpy(&bounds[4], &_axesUserBounds[4], sizeof(double)*2);
-    }
-
-    _cubeAxesActor->SetBounds(bounds);
-
-    TRACE("Axis bounds: %g %g %g %g %g %g",
-              bounds[0],
-              bounds[1],
-              bounds[2],
-              bounds[3],
-              bounds[4],
-              bounds[5]);
-
-    _needsRedraw = true;
-}
-
-/**
- * \brief Toggle automatic vs. explicit range setting on all axes
- */
-void Renderer::setAxesAutoBounds(bool state)
-{
-    _axesAutoBounds[X_AXIS] = state;
-    _axesAutoBounds[Y_AXIS] = state;
-    _axesAutoBounds[Z_AXIS] = state;
-
-    TRACE("Set axes bounds to %s", (state ? "auto" : "explicit"));
-
-    setAxesBounds();
-
-    _needsRedraw = true;
-}
-
-/**
- * \brief Toggle automatic vs. explicit range setting on all axes
- */
-void Renderer::setAxisAutoBounds(Axis axis, bool state)
-{
-    _axesAutoBounds[axis] = state;
-
-    TRACE("Set axis %d bounds to %s", axis, (state ? "auto" : "explicit"));
-
-    setAxesBounds();
-
-    _needsRedraw = true;
-}
-
-/**
- * \brief Toggle automatic vs. explicit range setting on all axes
- */
-void Renderer::setAxesAutoRange(bool state)
-{
-    _axesRangeMode[X_AXIS] = state ? RANGE_AUTO : RANGE_EXPLICIT;
-    _axesRangeMode[Y_AXIS] = state ? RANGE_AUTO : RANGE_EXPLICIT;
-    _axesRangeMode[Z_AXIS] = state ? RANGE_AUTO : RANGE_EXPLICIT;
-
-    TRACE("Set axes range to %s", (state ? "auto" : "explicit"));
-
-    setAxesRanges();
-
-    _needsRedraw = true;
-}
-
-/**
- * \brief Explicitly set world coordinate bounds of axis
- *
- * This determines the region in world coordinates around which
- * the axes are drawn
- */
-void Renderer::setAxisBounds(Axis axis, double min, double max)
-{
-    double bounds[6];
-    _cubeAxesActor->GetBounds(bounds);
-
-    bounds[axis*2  ] = _axesUserBounds[axis*2  ] = min;
-    bounds[axis*2+1] = _axesUserBounds[axis*2+1] = max;
-
-    _cubeAxesActor->SetBounds(bounds);
-
-    _axesAutoBounds[axis] = false;
-
-    TRACE("Axis bounds: %g %g %g %g %g %g",
-              bounds[0],
-              bounds[1],
-              bounds[2],
-              bounds[3],
-              bounds[4],
-              bounds[5]);
-
-    _needsRedraw = true;
-}
-
-/**
- * \brief Toggle automatic vs. explicit range setting on specific axis
- */
-void Renderer::setAxisAutoRange(Axis axis, bool state)
-{
-    _axesRangeMode[axis] = state ? RANGE_AUTO : RANGE_EXPLICIT;
-
-    TRACE("Set axis %d range to %s", axis, (state ? "auto" : "explicit"));
-
-    setAxesRanges();
-
-    _needsRedraw = true;
-}
-
-/**
- * \brief Set explicit range on axes and disable auto range
- */
-void Renderer::setAxesRange(double min, double max)
-{
-    setAxisRange(X_AXIS, min, max);
-    setAxisRange(Y_AXIS, min, max);
-    setAxisRange(Z_AXIS, min, max);
-}
-
-/**
- * \brief Explicitly set power multiplier for axes labels
- *
- * The exponent will appear in the axis title and be omitted from labels
- */
-void Renderer::setAxesLabelPowerScaling(int xPow, int yPow, int zPow, bool useCustom)
-{
-    _cubeAxesActor->SetLabelScaling(!useCustom, xPow, yPow, zPow);
-
-    TRACE("Set axis label scaling: custom: %d, powers: %d,%d,%d", (int)useCustom, xPow, yPow, zPow);
-
-    _needsRedraw = true;
-}
-
-/**
- * \brief Set explicit range on axis and disable auto range
- */
-void Renderer::setAxisRange(Axis axis, double min, double max)
-{
-    switch (axis) {
-    case X_AXIS:
-        _axesRangeMode[X_AXIS] = RANGE_EXPLICIT;
-        _cubeAxesActor->SetXAxisRange(min, max);
-        break;
-    case Y_AXIS:
-        _axesRangeMode[Y_AXIS] = RANGE_EXPLICIT;
-        _cubeAxesActor->SetYAxisRange(min, max);
-        break;
-    case Z_AXIS:
-        _axesRangeMode[Z_AXIS] = RANGE_EXPLICIT;
-        _cubeAxesActor->SetZAxisRange(min, max);
-        break;
-    default:
-        break;
-    }
-
-    TRACE("Set axis %d range to: %g, %g", axis, min, max);
-
-     _needsRedraw = true;
-}
-
-/**
- * \brief Set axes ranges based on bounds and range modes
- */
-void Renderer::setAxesRanges()
-{
-    computeAxesScale();
-
-    double bounds[6];
-    _cubeAxesActor->GetBounds(bounds);
-
-    double ranges[6];
-    if (_axesRangeMode[X_AXIS] != RANGE_EXPLICIT) {
-        ranges[0] = bounds[0] * _axesScale[X_AXIS];
-        ranges[1] = bounds[1] * _axesScale[X_AXIS];
-        _cubeAxesActor->SetXAxisRange(&ranges[0]);
-    } else {
-        _cubeAxesActor->GetXAxisRange(&ranges[0]);
-    }
-
-    if (_axesRangeMode[Y_AXIS] != RANGE_EXPLICIT) {
-        ranges[2] = bounds[2] * _axesScale[Y_AXIS];
-        ranges[3] = bounds[3] * _axesScale[Y_AXIS];
-        _cubeAxesActor->SetYAxisRange(&ranges[2]);
-    } else {
-        _cubeAxesActor->GetYAxisRange(&ranges[2]);
-    }
-
-    if (_axesRangeMode[Z_AXIS] != RANGE_EXPLICIT) {
-        ranges[4] = bounds[4] * _axesScale[Z_AXIS];
-        ranges[5] = bounds[5] * _axesScale[Z_AXIS];
-        _cubeAxesActor->SetZAxisRange(&ranges[4]);
-    } else {
-        _cubeAxesActor->GetZAxisRange(&ranges[4]);
-    }
-
-    TRACE("Axis ranges: %g %g %g %g %g %g",
-          ranges[0],
-          ranges[1],
-          ranges[2],
-          ranges[3],
-          ranges[4],
-          ranges[5]);
-
-    _needsRedraw = true;
-}
-
-/**
- * \brief Compute scaling from axes bounds to ranges
- *
- * Uses actor scaling to determine if world coordinates
- * need to be scaled to undo actor scaling in range labels
- */
-void Renderer::computeAxesScale()
-{
-    if (_axesRangeMode[X_AXIS] != RANGE_AUTO &&
-        _axesRangeMode[Y_AXIS] != RANGE_AUTO &&
-        _axesRangeMode[Z_AXIS] != RANGE_AUTO)
-        return;
-
-    double bounds[6];
-    if (_cameraMode == IMAGE) {
-        collectBounds(bounds, false);
-    } else
-        _cubeAxesActor->GetBounds(bounds);
-
-    double unscaledBounds[6];
-    collectUnscaledBounds(unscaledBounds, false);
-
-    if (_axesRangeMode[X_AXIS] == RANGE_AUTO) {
-        double sx = (bounds[1] == bounds[0]) ? 1.0 : (unscaledBounds[1] - unscaledBounds[0]) / (bounds[1] - bounds[0]);
-        _axesScale[X_AXIS] = sx;
-        TRACE("Setting X axis scale to: %g", sx);
-    }
-    if (_axesRangeMode[Y_AXIS] == RANGE_AUTO) {
-        double sy = (bounds[3] == bounds[2]) ? 1.0 : (unscaledBounds[3] - unscaledBounds[2]) / (bounds[3] - bounds[2]);
-        _axesScale[Y_AXIS] = sy;
-        TRACE("Setting Y axis scale to: %g", sy);
-    }
-    if (_axesRangeMode[Y_AXIS] == RANGE_AUTO) {
-        double sz = (bounds[5] == bounds[4]) ? 1.0 : (unscaledBounds[5] - unscaledBounds[4]) / (bounds[5] - bounds[4]);
-        _axesScale[Z_AXIS] = sz;
-        TRACE("Setting Z axis scale to: %g", sz);
-    }
-}
-
-/**
- * \brief Set scaling factor to convert world coordinates to axis 
- * label values in X, Y, Z
- */
-void Renderer::setAxesScale(double scale)
-{
-    _axesRangeMode[X_AXIS] = RANGE_SCALE_BOUNDS;
-    _axesRangeMode[Y_AXIS] = RANGE_SCALE_BOUNDS;
-    _axesRangeMode[Z_AXIS] = RANGE_SCALE_BOUNDS;
-
-    _axesScale[X_AXIS] = scale;
-    _axesScale[Y_AXIS] = scale;
-    _axesScale[Z_AXIS] = scale;
-
-    TRACE("Setting axes scale to: %g", scale);
-
-    setAxesRanges();
-}
-
-/**
- * \brief Set scaling factor to convert world coordinates to axis label values
- */
-void Renderer::setAxisScale(Axis axis, double scale)
-{
-    _axesRangeMode[axis] = RANGE_SCALE_BOUNDS;
-    _axesScale[axis] = scale;
-
-    TRACE("Setting axis %d scale to: %g", axis, scale);
-
-    setAxesRanges();
-}
-
-/**
- * \brief Set an origin point within the axes bounds where the axes will intersect
- *
- * \param x X coordinate of origin
- * \param y Y coordinate of origin
- * \param z Z coordinate of origin
- * \param useCustom Flag indicating if custom origin is to be used/enabled
- */
-void Renderer::setAxesOrigin(double x, double y, double z, bool useCustom)
-{
-    _cubeAxesActor->SetAxisOrigin(x, y, z);
-    _cubeAxesActor->SetUseAxisOrigin((useCustom ? 1 : 0));
-
-    _needsRedraw = true;
-}
-
-/**
- * \brief Set inital properties on the 2D Axes
- */
-void Renderer::initAxes()
-{
-    TRACE("Initializing axes");
-#ifdef USE_CUSTOM_AXES
-    if (_cubeAxesActor == NULL)
-        _cubeAxesActor = vtkSmartPointer<vtkRpCubeAxesActor>::New();
-#else
-    if (_cubeAxesActor == NULL)
-        _cubeAxesActor = vtkSmartPointer<vtkCubeAxesActor>::New();
-#endif
-    _cubeAxesActor->SetCamera(_renderer->GetActiveCamera());
-    _cubeAxesActor->GetProperty()->LightingOff();
-    // Don't offset labels at origin
-    _cubeAxesActor->SetCornerOffset(0);
-    _cubeAxesActor->SetFlyModeToStaticTriad();
-
-    _cubeAxesActor->SetGridLineLocation(VTK_GRID_LINES_ALL);
-    _cubeAxesActor->SetDrawXInnerGridlines(0);
-    _cubeAxesActor->SetDrawYInnerGridlines(0);
-    _cubeAxesActor->SetDrawZInnerGridlines(0);
-    _cubeAxesActor->SetDrawXGridpolys(0);
-    _cubeAxesActor->SetDrawYGridpolys(0);
-    _cubeAxesActor->SetDrawZGridpolys(0);
-    _cubeAxesActor->SetDistanceLODThreshold(1);
-    _cubeAxesActor->SetEnableDistanceLOD(0);
-    _cubeAxesActor->SetViewAngleLODThreshold(0);
-    _cubeAxesActor->SetEnableViewAngleLOD(0);
-    // Attempt to set font sizes for 2D (this currently doesn't work)
-    for (int i = 0; i < 3; i++) {
-        _cubeAxesActor->GetTitleTextProperty(i)->SetFontSize(14);
-        _cubeAxesActor->GetLabelTextProperty(i)->SetFontSize(12);
-    }
-    // Set font pixel size for 3D
-    _cubeAxesActor->SetScreenSize(8.0);
-
-    _cubeAxesActor->SetBounds(0, 1, 0, 1, 0, 1);
-    _cubeAxesActor->SetXAxisRange(0, 1);
-    _cubeAxesActor->SetYAxisRange(0, 1);
-    _cubeAxesActor->SetZAxisRange(0, 1);
-    for (int axis = 0; axis < 3; axis++) {
-        _axesAutoBounds[axis] = true;
-        _axesRangeMode[axis] = RANGE_AUTO;
-        _axesScale[axis] = 1.0;
-    }
-
-    double axesColor[] = {1,1,1};
-    setAxesColor(axesColor);
-
-    if (!_renderer->HasViewProp(_cubeAxesActor))
-        _renderer->AddViewProp(_cubeAxesActor);
-
-    if (_cameraMode == IMAGE) {
-        _cubeAxesActor->SetUse2DMode(1);
-    } else {
-        _cubeAxesActor->SetUse2DMode(0);
-    }
-}
-
-/**
- * \brief Set Fly mode of axes
- */
-void Renderer::setAxesFlyMode(AxesFlyMode mode)
-{
-    if (_cubeAxesActor == NULL)
-        return;
-
-    switch (mode) {
-    case FLY_STATIC_EDGES:
-        _cubeAxesActor->SetFlyModeToStaticEdges();
-        _cubeAxesActor->SetGridLineLocation(VTK_GRID_LINES_ALL);
-        break;
-    case FLY_STATIC_TRIAD:
-        _cubeAxesActor->SetFlyModeToStaticTriad();
-        _cubeAxesActor->SetGridLineLocation(VTK_GRID_LINES_ALL);
-        break;
-    case FLY_OUTER_EDGES:
-        _cubeAxesActor->SetFlyModeToOuterEdges();
-        _cubeAxesActor->SetGridLineLocation(VTK_GRID_LINES_ALL);
-        break;
-    case FLY_FURTHEST_TRIAD:
-        _cubeAxesActor->SetFlyModeToFurthestTriad();
-        _cubeAxesActor->SetGridLineLocation(VTK_GRID_LINES_FURTHEST);
-        break;
-    case FLY_CLOSEST_TRIAD:
-    default:
-        _cubeAxesActor->SetFlyModeToClosestTriad();
-        _cubeAxesActor->SetGridLineLocation(VTK_GRID_LINES_CLOSEST);
-        break;
-    }
-    _needsRedraw = true;
-}
-
-/**
- * \brief Set color of axes, ticks, labels, titles
- */
-void Renderer::setAxesColor(double color[3], double opacity)
-{
-    setAxesTitleColor(color, opacity);
-    setAxesLabelColor(color, opacity);
-    setAxesLinesColor(color, opacity);
-    setAxesGridlinesColor(color, opacity);
-    setAxesInnerGridlinesColor(color, opacity);
-    setAxesGridpolysColor(color, opacity);
-}
-
-/**
- * \brief Set color of axes title text
- */
-void Renderer::setAxesTitleColor(double color[3], double opacity)
-{
-    setAxisTitleColor(X_AXIS, color, opacity);
-    setAxisTitleColor(Y_AXIS, color, opacity);
-    setAxisTitleColor(Z_AXIS, color, opacity);
-}
-
-/**
- * \brief Set color of axes label text
- */
-void Renderer::setAxesLabelColor(double color[3], double opacity)
-{
-    setAxisLabelColor(X_AXIS, color, opacity);
-    setAxisLabelColor(Y_AXIS, color, opacity);
-    setAxisLabelColor(Z_AXIS, color, opacity);
-}
-
-/**
- * \brief Set color of main axes lines
- */
-void Renderer::setAxesLinesColor(double color[3], double opacity)
-{
-    setAxisLinesColor(X_AXIS, color, opacity);
-    setAxisLinesColor(Y_AXIS, color, opacity);
-    setAxisLinesColor(Z_AXIS, color, opacity);
-}
-
-/**
- * \brief Set color of axis gridlines
- */
-void Renderer::setAxesGridlinesColor(double color[3], double opacity)
-{
-    setAxisGridlinesColor(X_AXIS, color, opacity);
-    setAxisGridlinesColor(Y_AXIS, color, opacity);
-    setAxisGridlinesColor(Z_AXIS, color, opacity);
-}
-
-/**
- * \brief Set color of axes inner gridlines
- */
-void Renderer::setAxesInnerGridlinesColor(double color[3], double opacity)
-{
-    setAxisInnerGridlinesColor(X_AXIS, color, opacity);
-    setAxisInnerGridlinesColor(Y_AXIS, color, opacity);
-    setAxisInnerGridlinesColor(Z_AXIS, color, opacity);
-}
-
-/**
- * \brief Set color of axes inner grid polygons
- */
-void Renderer::setAxesGridpolysColor(double color[3], double opacity)
-{
-    setAxisGridpolysColor(X_AXIS, color, opacity);
-    setAxisGridpolysColor(Y_AXIS, color, opacity);
-    setAxisGridpolysColor(Z_AXIS, color, opacity);
-}
-
-/**
- * \brief Turn on/off rendering of all enabled axes
- */
-void Renderer::setAxesVisibility(bool state)
-{
-    if (_cubeAxesActor != NULL) {
-        _cubeAxesActor->SetVisibility((state ? 1 : 0));
-        _needsRedraw = true;
-    }
-}
-
-/**
- * \brief Turn on/off rendering of all axes gridlines
- */
-void Renderer::setAxesGridVisibility(bool state)
-{
-    setAxisGridVisibility(X_AXIS, state);
-    setAxisGridVisibility(Y_AXIS, state);
-    setAxisGridVisibility(Z_AXIS, state);
-}
-
-/**
- * \brief Turn on/off rendering of all axes inner gridlines
- */
-void Renderer::setAxesInnerGridVisibility(bool state)
-{
-    setAxisInnerGridVisibility(X_AXIS, state);
-    setAxisInnerGridVisibility(Y_AXIS, state);
-    setAxisInnerGridVisibility(Z_AXIS, state);
-}
-
-/**
- * \brief Turn on/off rendering of all axes inner grid polygons
- */
-void Renderer::setAxesGridpolysVisibility(bool state)
-{
-    setAxisGridpolysVisibility(X_AXIS, state);
-    setAxisGridpolysVisibility(Y_AXIS, state);
-    setAxisGridpolysVisibility(Z_AXIS, state);
-}
-
-/**
- * \brief Turn on/off rendering of all axis labels
- */
-void Renderer::setAxesLabelVisibility(bool state)
-{
-    setAxisLabelVisibility(X_AXIS, state);
-    setAxisLabelVisibility(Y_AXIS, state);
-    setAxisLabelVisibility(Z_AXIS, state);
-}
-
-/**
- * \brief Turn on/off rendering of all axis ticks
- */
-void Renderer::setAxesTickVisibility(bool state)
-{
-    setAxisTickVisibility(X_AXIS, state);
-    setAxisTickVisibility(Y_AXIS, state);
-    setAxisTickVisibility(Z_AXIS, state);
-}
-
-/**
- * \brief Turn on/off rendering of all axis ticks
- */
-void Renderer::setAxesMinorTickVisibility(bool state)
-{
-    setAxisMinorTickVisibility(X_AXIS, state);
-    setAxisMinorTickVisibility(Y_AXIS, state);
-    setAxisMinorTickVisibility(Z_AXIS, state);
-}
-
-/**
- * \brief Control position of ticks on 3D axes
- */
-void Renderer::setAxesTickPosition(AxesTickPosition pos)
-{
-    if (_cubeAxesActor == NULL)
-        return;
-
-    switch (pos) {
-    case TICKS_BOTH:
-        _cubeAxesActor->SetTickLocationToBoth();
-        break;
-    case TICKS_OUTSIDE:
-        _cubeAxesActor->SetTickLocationToOutside();
-        break;
-    case TICKS_INSIDE:
-    default:
-        _cubeAxesActor->SetTickLocationToInside();
-        break;
-    }
-    _needsRedraw = true;
-}
-
-/**
- * \brief Controls label scaling by power of 10
- */
-void Renderer::setAxesLabelScaling(bool autoScale, int xpow, int ypow, int zpow)
-{
-    if (_cubeAxesActor != NULL) {
-        _cubeAxesActor->SetLabelScaling(autoScale, xpow, ypow, zpow);
-        _needsRedraw = true;
-    }
-}
-
-/**
- * \brief Set axes title/label font size in pixels
- */
-void Renderer::setAxesPixelFontSize(double screenSize)
-{
-    if (_cubeAxesActor != NULL) {
-        TRACE("Setting axes font size to: %g px", screenSize);
-        _cubeAxesActor->SetScreenSize(screenSize);
-        _needsRedraw = true;
-    }
-}
-
-/**
- * \brief Set axis title font family
- */
-void Renderer::setAxesTitleFont(const char *fontName)
-{
-    setAxisTitleFont(X_AXIS, fontName);
-    setAxisTitleFont(Y_AXIS, fontName);
-    setAxisTitleFont(Z_AXIS, fontName);
-}
-
-/**
- * \brief Set axis title font size
- */
-void Renderer::setAxesTitleFontSize(int sz)
-{
-    setAxisTitleFontSize(X_AXIS, sz);
-    setAxisTitleFontSize(Y_AXIS, sz);
-    setAxisTitleFontSize(Z_AXIS, sz);
-}
-
-/**
- * \brief Set orientation (as rotation in degrees) of axis title
- */
-void Renderer::setAxesTitleOrientation(double orientation)
-{
-    setAxisTitleOrientation(X_AXIS, orientation);
-    setAxisTitleOrientation(Y_AXIS, orientation);
-    setAxisTitleOrientation(Z_AXIS, orientation);
-}
-
-/**
- * \brief Set axis label font family
- */
-void Renderer::setAxesLabelFont(const char *fontName)
-{
-    setAxisLabelFont(X_AXIS, fontName);
-    setAxisLabelFont(Y_AXIS, fontName);
-    setAxisLabelFont(Z_AXIS, fontName);
-}
-
-/**
- * \brief Set axis label font size
- */
-void Renderer::setAxesLabelFontSize(int sz)
-{
-    setAxisLabelFontSize(X_AXIS, sz);
-    setAxisLabelFontSize(Y_AXIS, sz);
-    setAxisLabelFontSize(Z_AXIS, sz);
-}
-
-/**
- * \brief Set orientation (as rotation in degrees) of axis labels
- */
-void Renderer::setAxesLabelOrientation(double orientation)
-{
-    setAxisLabelOrientation(X_AXIS, orientation);
-    setAxisLabelOrientation(Y_AXIS, orientation);
-    setAxisLabelOrientation(Z_AXIS, orientation);
-}
-
-/**
- * \brief Set printf style label format string
- */
-void Renderer::setAxesLabelFormat(const char *format)
-{
-    setAxisLabelFormat(X_AXIS, format);
-    setAxisLabelFormat(Y_AXIS, format);
-    setAxisLabelFormat(Z_AXIS, format);
-}
-
-/**
- * \brief Turn on/off rendering of the specified axis
- */
-void Renderer::setAxisVisibility(Axis axis, bool state)
-{
-    if (_cubeAxesActor != NULL) {
-        if (axis == X_AXIS) {
-            _cubeAxesActor->SetXAxisVisibility((state ? 1 : 0));
-        } else if (axis == Y_AXIS) {
-            _cubeAxesActor->SetYAxisVisibility((state ? 1 : 0));
-        } else if (axis == Z_AXIS) {
-            _cubeAxesActor->SetZAxisVisibility((state ? 1 : 0));
-        }
-        _needsRedraw = true;
-    }
-}
-
-/**
- * \brief Turn on/off rendering of single axis gridlines
- */
-void Renderer::setAxisGridVisibility(Axis axis, bool state)
-{
-    if (_cubeAxesActor != NULL) {
-        if (axis == X_AXIS) {
-            _cubeAxesActor->SetDrawXGridlines((state ? 1 : 0));
-        } else if (axis == Y_AXIS) {
-            _cubeAxesActor->SetDrawYGridlines((state ? 1 : 0));
-        } else if (axis == Z_AXIS) {
-            _cubeAxesActor->SetDrawZGridlines((state ? 1 : 0));
-        }
-        _needsRedraw = true;
-    }
-}
-
-/**
- * \brief Turn on/off rendering of single axis gridlines
- */
-void Renderer::setAxisInnerGridVisibility(Axis axis, bool state)
-{
-    if (_cubeAxesActor != NULL) {
-        if (axis == X_AXIS) {
-            _cubeAxesActor->SetDrawXInnerGridlines((state ? 1 : 0));
-        } else if (axis == Y_AXIS) {
-            _cubeAxesActor->SetDrawYInnerGridlines((state ? 1 : 0));
-        } else if (axis == Z_AXIS) {
-            _cubeAxesActor->SetDrawZInnerGridlines((state ? 1 : 0));
-        }
-        _needsRedraw = true;
-    }
-}
-
-/**
- * \brief Turn on/off rendering of single axis gridlines
- */
-void Renderer::setAxisGridpolysVisibility(Axis axis, bool state)
-{
-    if (_cubeAxesActor != NULL) {
-        if (axis == X_AXIS) {
-            _cubeAxesActor->SetDrawXGridpolys((state ? 1 : 0));
-        } else if (axis == Y_AXIS) {
-            _cubeAxesActor->SetDrawYGridpolys((state ? 1 : 0));
-        } else if (axis == Z_AXIS) {
-            _cubeAxesActor->SetDrawZGridpolys((state ? 1 : 0));
-        }
-        _needsRedraw = true;
-    }
-}
-
-/**
- * \brief Toggle label visibility for the specified axis
- */
-void Renderer::setAxisLabelVisibility(Axis axis, bool state)
-{
-    if (_cubeAxesActor != NULL) {
-        if (axis == X_AXIS) {
-            _cubeAxesActor->SetXAxisLabelVisibility((state ? 1 : 0));
-        } else if (axis == Y_AXIS) {
-            _cubeAxesActor->SetYAxisLabelVisibility((state ? 1 : 0));
-        } else if (axis == Z_AXIS) {
-            _cubeAxesActor->SetZAxisLabelVisibility((state ? 1 : 0));
-        }
-        _needsRedraw = true;
-    }
-}
-
-/**
- * \brief Toggle tick visibility for the specified axis
- */
-void Renderer::setAxisTickVisibility(Axis axis, bool state)
-{
-    if (_cubeAxesActor != NULL) {
-        if (axis == X_AXIS) {
-            _cubeAxesActor->SetXAxisTickVisibility((state ? 1 : 0));
-        } else if (axis == Y_AXIS) {
-            _cubeAxesActor->SetYAxisTickVisibility((state ? 1 : 0));
-        } else if (axis == Z_AXIS) {
-            _cubeAxesActor->SetZAxisTickVisibility((state ? 1 : 0));
-        }
-        _needsRedraw = true;
-    }
-}
-
-/**
- * \brief Toggle tick visibility for the specified axis
- */
-void Renderer::setAxisMinorTickVisibility(Axis axis, bool state)
-{
-    if (_cubeAxesActor != NULL) {
-        if (axis == X_AXIS) {
-            _cubeAxesActor->SetXAxisMinorTickVisibility((state ? 1 : 0));
-        } else if (axis == Y_AXIS) {
-            _cubeAxesActor->SetYAxisMinorTickVisibility((state ? 1 : 0));
-        } else if (axis == Z_AXIS) {
-            _cubeAxesActor->SetZAxisMinorTickVisibility((state ? 1 : 0));
-        }
-        _needsRedraw = true;
-    }
-}
-
-/**
- * \brief Set color of axis lines, ticks, labels, titles
- */
-void Renderer::setAxisColor(Axis axis, double color[3], double opacity)
-{
-    setAxisTitleColor(axis, color, opacity);
-    setAxisLabelColor(axis, color, opacity);
-    setAxisLinesColor(axis, color, opacity);
-    setAxisGridlinesColor(axis, color, opacity);
-    setAxisInnerGridlinesColor(axis, color, opacity);
-    setAxisGridpolysColor(axis, color, opacity);
-}
-
-/**
- * \brief Set color of axis title text
- */
-void Renderer::setAxisTitleColor(Axis axis, double color[3], double opacity)
-{
-    if (_cubeAxesActor != NULL) {
-        _cubeAxesActor->GetTitleTextProperty(axis)->SetColor(color);
-        _cubeAxesActor->GetTitleTextProperty(axis)->SetOpacity(opacity);
-        _needsRedraw = true;
-    }
-}
-
-/**
- * \brief Set color of axis label text
- */
-void Renderer::setAxisLabelColor(Axis axis, double color[3], double opacity)
-{
-    if (_cubeAxesActor != NULL) {
-        _cubeAxesActor->GetLabelTextProperty(axis)->SetColor(color);
-        _cubeAxesActor->GetLabelTextProperty(axis)->SetOpacity(opacity);
-        _needsRedraw = true;
-    }
-}
-
-/**
- * \brief Set color of main axis line
- */
-void Renderer::setAxisLinesColor(Axis axis, double color[3], double opacity)
-{
-    if (_cubeAxesActor != NULL) {
-        switch (axis) {
-        case X_AXIS:
-            _cubeAxesActor->GetXAxesLinesProperty()->SetColor(color);
-            _cubeAxesActor->GetXAxesLinesProperty()->SetOpacity(opacity);
-            break;
-        case Y_AXIS:
-            _cubeAxesActor->GetYAxesLinesProperty()->SetColor(color);
-            _cubeAxesActor->GetYAxesLinesProperty()->SetOpacity(opacity);
-            break;
-        case Z_AXIS:
-            _cubeAxesActor->GetZAxesLinesProperty()->SetColor(color);
-            _cubeAxesActor->GetZAxesLinesProperty()->SetOpacity(opacity);
-            break;
-        default:
-            ;
-        }
-        _needsRedraw = true;
-    }
-}
-
-/**
- * \brief Set color of axis gridlines
- */
-void Renderer::setAxisGridlinesColor(Axis axis, double color[3], double opacity)
-{
-    if (_cubeAxesActor != NULL) {
-        switch (axis) {
-        case X_AXIS:
-            _cubeAxesActor->GetXAxesGridlinesProperty()->SetColor(color);
-            _cubeAxesActor->GetXAxesGridlinesProperty()->SetOpacity(opacity);
-            break;
-        case Y_AXIS:
-            _cubeAxesActor->GetYAxesGridlinesProperty()->SetColor(color);
-            _cubeAxesActor->GetYAxesGridlinesProperty()->SetOpacity(opacity);
-            break;
-        case Z_AXIS:
-            _cubeAxesActor->GetZAxesGridlinesProperty()->SetColor(color);
-            _cubeAxesActor->GetZAxesGridlinesProperty()->SetOpacity(opacity);
-            break;
-        default:
-            ;
-        }
-        _needsRedraw = true;
-    }
-}
-
-/**
- * \brief Set color of axis inner gridlines
- */
-void Renderer::setAxisInnerGridlinesColor(Axis axis, double color[3], double opacity)
-{
-    if (_cubeAxesActor != NULL) {
-        switch (axis) {
-        case X_AXIS:
-            _cubeAxesActor->GetXAxesInnerGridlinesProperty()->SetColor(color);
-            _cubeAxesActor->GetXAxesInnerGridlinesProperty()->SetOpacity(opacity);
-            break;
-        case Y_AXIS:
-            _cubeAxesActor->GetYAxesInnerGridlinesProperty()->SetColor(color);
-            _cubeAxesActor->GetYAxesInnerGridlinesProperty()->SetOpacity(opacity);
-            break;
-        case Z_AXIS:
-            _cubeAxesActor->GetZAxesInnerGridlinesProperty()->SetColor(color);
-            _cubeAxesActor->GetZAxesInnerGridlinesProperty()->SetOpacity(opacity);
-            break;
-        default:
-            ;
-        }
-        _needsRedraw = true;
-    }
-}
-
-/**
- * \brief Set color of axis inner grid polygons
- *
- * Default opacity is 0.6
- */
-void Renderer::setAxisGridpolysColor(Axis axis, double color[3], double opacity)
-{
-    if (_cubeAxesActor != NULL) {
-        switch (axis) {
-        case X_AXIS:
-            _cubeAxesActor->GetXAxesGridpolysProperty()->SetColor(color);
-            _cubeAxesActor->GetXAxesGridpolysProperty()->SetOpacity(opacity);
-            break;
-        case Y_AXIS:
-            _cubeAxesActor->GetYAxesGridpolysProperty()->SetColor(color);
-            _cubeAxesActor->GetYAxesGridpolysProperty()->SetOpacity(opacity);
-            break;
-        case Z_AXIS:
-            _cubeAxesActor->GetZAxesGridpolysProperty()->SetColor(color);
-            _cubeAxesActor->GetZAxesGridpolysProperty()->SetOpacity(opacity);
-            break;
-        default:
-            ;
-        }
-        _needsRedraw = true;
-    }
-}
-
-/**
- * \brief Set title of the specified axis
- */
-void Renderer::setAxisTitle(Axis axis, const char *title)
-{
-    if (_cubeAxesActor != NULL) {
-        if (axis == X_AXIS) {
-            _cubeAxesActor->SetXTitle(title);
-        } else if (axis == Y_AXIS) {
-            _cubeAxesActor->SetYTitle(title);
-        } else if (axis == Z_AXIS) {
-            _cubeAxesActor->SetZTitle(title);
-        }
-        _needsRedraw = true;
-    }
-}
-
-/**
- * \brief Set units of the specified axis
- */
-void Renderer::setAxisUnits(Axis axis, const char *units)
-{
-    if (_cubeAxesActor != NULL) {
-        if (axis == X_AXIS) {
-            _cubeAxesActor->SetXUnits(units);
-        } else if (axis == Y_AXIS) {
-            _cubeAxesActor->SetYUnits(units);
-        } else if (axis == Z_AXIS) {
-            _cubeAxesActor->SetZUnits(units);
-        }
-        _needsRedraw = true;
-    }
-}
-
-/**
- * \brief Set axis title font family
- */
-void Renderer::setAxisTitleFont(Axis axis, const char *fontName)
-{
-    if (_cubeAxesActor != NULL) {
-        TRACE("Setting axis %d title font to: '%s'", axis, fontName);
-        _cubeAxesActor->GetTitleTextProperty(axis)->SetFontFamilyAsString(fontName);
-        _needsRedraw = true;
-    }
-}
-
-/**
- * \brief Set axis title font size (and optionally pixel size)
- */
-void Renderer::setAxisTitleFontSize(Axis axis, int sz)
-{
-    if (_cubeAxesActor != NULL) {
-        TRACE("Setting axis %d title font size to: %d", axis, sz);
-        _cubeAxesActor->GetTitleTextProperty(axis)->SetFontSize(sz);
-        _needsRedraw = true;
-    }
-}
-
-/**
- * \brief Set orientation (as rotation in degrees) of axis titles
- */
-void Renderer::setAxisTitleOrientation(Axis axis, double orientation)
-{
-    if (_cubeAxesActor != NULL) {
-        TRACE("Setting axis %d title orientation to: %g", axis, orientation);
-        _cubeAxesActor->GetTitleTextProperty(axis)->SetOrientation(orientation);
-        _needsRedraw = true;
-    }
-}
-
-/**
- * \brief Set axis label font family
- */
-void Renderer::setAxisLabelFont(Axis axis, const char *fontName)
-{
-    if (_cubeAxesActor != NULL) {
-        TRACE("Setting axis %d label font to: '%s'", axis, fontName);
-        _cubeAxesActor->GetLabelTextProperty(axis)->SetFontFamilyAsString(fontName);
-        _needsRedraw = true;
-    }
-}
-
-/**
- * \brief Set axis label font size (and optionally pixel size)
- */
-void Renderer::setAxisLabelFontSize(Axis axis, int sz)
-{
-    if (_cubeAxesActor != NULL) {
-        TRACE("Setting axis %d label font size to: %d", axis, sz);
-        _cubeAxesActor->GetLabelTextProperty(axis)->SetFontSize(sz);
-        _needsRedraw = true;
-    }
-}
-
-/**
- * \brief Set orientation (as rotation in degrees) of axis labels
- */
-void Renderer::setAxisLabelOrientation(Axis axis, double orientation)
-{
-    if (_cubeAxesActor != NULL) {
-        TRACE("Setting axis %d label orientation to: %g", axis, orientation);
-        _cubeAxesActor->GetLabelTextProperty(axis)->SetOrientation(orientation);
-        _needsRedraw = true;
-    }
-}
-
-/**
- * \brief Set printf style label format string
- */
-void Renderer::setAxisLabelFormat(Axis axis, const char *format)
-{
-    if (_cubeAxesActor != NULL) {
-        TRACE("Setting axis %d label format to: '%s'", axis, format);
-        if (axis == X_AXIS) {
-            _cubeAxesActor->SetXLabelFormat(format);
-            _cubeAxesActor->XAutoLabelFormatOff();
-        } else if (axis == Y_AXIS) {
-            _cubeAxesActor->SetYLabelFormat(format);
-            _cubeAxesActor->YAutoLabelFormatOff();
-        } else if (axis == Z_AXIS) {
-            _cubeAxesActor->SetZLabelFormat(format);
-            _cubeAxesActor->ZAutoLabelFormatOff();
-        }
-        _needsRedraw = true;
-    }
-}
-
-/**
- * \brief Notify graphics objects that color map has changed
- */
-void Renderer::updateColorMap(ColorMap *cmap)
-{
-    TRACE("%s", cmap->getName().c_str());
-    updateGraphicsObjectColorMap<Contour2D>(cmap);
-    updateGraphicsObjectColorMap<Contour3D>(cmap);
-    updateGraphicsObjectColorMap<Cutplane>(cmap);
-    updateGraphicsObjectColorMap<Glyphs>(cmap);
-    updateGraphicsObjectColorMap<HeightMap>(cmap);
-    updateGraphicsObjectColorMap<LIC>(cmap);
-    updateGraphicsObjectColorMap<Molecule>(cmap);
-    updateGraphicsObjectColorMap<PseudoColor>(cmap);
-    updateGraphicsObjectColorMap<Streamlines>(cmap);
-    updateGraphicsObjectColorMap<Volume>(cmap);
-    updateGraphicsObjectColorMap<Warp>(cmap);
-    TRACE("Leave");
-}
-
-/**
- * \brief Check if a ColorMap is in use by graphics objects
- */
-bool Renderer::colorMapUsed(ColorMap *cmap)
-{
-    if (graphicsObjectColorMapUsed<Contour2D>(cmap))
-        return true;
-    if (graphicsObjectColorMapUsed<Contour3D>(cmap))
-        return true;
-    if (graphicsObjectColorMapUsed<Cutplane>(cmap))
-        return true;
-    if (graphicsObjectColorMapUsed<Glyphs>(cmap))
-        return true;
-    if (graphicsObjectColorMapUsed<HeightMap>(cmap))
-        return true;
-    if (graphicsObjectColorMapUsed<LIC>(cmap))
-        return true;
-    if (graphicsObjectColorMapUsed<Molecule>(cmap))
-        return true;
-    if (graphicsObjectColorMapUsed<PseudoColor>(cmap))
-        return true;
-    if (graphicsObjectColorMapUsed<Streamlines>(cmap))
-        return true;
-    if (graphicsObjectColorMapUsed<Volume>(cmap))
-        return true;
-    if (graphicsObjectColorMapUsed<Warp>(cmap))
-        return true;
-
-    return false;
-}
-
-/**
- * \brief Add/replace a ColorMap for use in the Renderer
- */
-void Renderer::addColorMap(const ColorMapId& id, ColorMap *colorMap)
-{
-    if (colorMap != NULL) {
-        colorMap->build();
-        if (getColorMap(id) != NULL) {
-            TRACE("Replacing existing ColorMap %s", id.c_str());
-            // Copy to current colormap to avoid invalidating 
-            // pointers in graphics objects using the color map
-            *_colorMaps[id] = *colorMap;
-            delete colorMap;
-            // Notify graphics objects of change
-            updateColorMap(_colorMaps[id]);
-        } else
-            _colorMaps[id] = colorMap;
-    } else {
-        ERROR("NULL ColorMap");
-    }
-}
-
-/**
- * \brief Return the ColorMap associated with the colormap key given
- */
-ColorMap *Renderer::getColorMap(const ColorMapId& id)
-{
-    ColorMapHashmap::iterator itr = _colorMaps.find(id);
-
-    if (itr == _colorMaps.end())
-        return NULL;
-    else
-        return itr->second;
-}
-
-/**
- * \brief Remove the colormap associated with the key given
- *
- * The underlying vtkLookupTable will be deleted if it is not referenced
- * by any other objects
- */
-void Renderer::deleteColorMap(const ColorMapId& id)
-{
-    ColorMapHashmap::iterator itr;
-
-    bool doAll = false;
-
-    if (id.compare("all") == 0) {
-        itr = _colorMaps.begin();
-        doAll = true;
-    } else {
-        itr = _colorMaps.find(id);
-    }
-
-    if (itr == _colorMaps.end()) {
-        ERROR("Unknown ColorMap %s", id.c_str());
-        return;
-    }
-
-    do {
-        if (itr->second->getName().compare("default") == 0 ||
-            itr->second->getName().compare("grayDefault") == 0 ||
-            itr->second->getName().compare("volumeDefault") == 0 ||
-            itr->second->getName().compare("elementDefault") == 0) {
-            if (id.compare("all") != 0) {
-                WARN("Cannot delete a default color map");
-            }
-            continue;
-        } else if (colorMapUsed(itr->second)) {
-            WARN("Cannot delete color map '%s', it is in use", itr->second->getName().c_str());
-            continue;
-        }
-
-        TRACE("Deleting ColorMap %s", itr->second->getName().c_str());
-
-        delete itr->second;
-        itr = _colorMaps.erase(itr);
-    } while (doAll && itr != _colorMaps.end());
-}
-
-/**
- * \brief Set the number of discrete colors used in the colormap's lookup table
- *
- * Note that the number of table entries is independent of the number of 
- * control points in the color/alpha ramp
- */
-void Renderer::setColorMapNumberOfTableEntries(const ColorMapId& id, int numEntries)
-{
-    ColorMapHashmap::iterator itr;
-
-    bool doAll = false;
-
-    if (id.compare("all") == 0) {
-        itr = _colorMaps.begin();
-        doAll = true;
-    } else {
-        itr = _colorMaps.find(id);
-    }
-
-    if (itr == _colorMaps.end()) {
-        ERROR("Unknown ColorMap %s", id.c_str());
-        return;
-    }
-
-    if (numEntries < 0) {
-        numEntries = 256;
-        TRACE("Setting numEntries to default value of %d", numEntries);
-    }
-
-    do {
-        if (itr->second->getName() == "elementDefault") {
-            TRACE("Can't change number of table entries for default element color map");
-        } else {
-            itr->second->setNumberOfTableEntries(numEntries);
-            updateColorMap(itr->second);
-        }
-    } while (doAll && ++itr != _colorMaps.end());
-
-    _needsRedraw = true;
-}
-
-/**
- * \brief Render a labelled legend image for the given colormap
- *
- * The field is assumed to be the active scalar or vector field
- * based on the legendType.
- *
- * \param[in] id ColorMap name
- * \param[in] dataSetID DataSet name
- * \param[in] legendType scalar or vector field legend
- * \param[in,out] title If supplied, draw title ("#auto" means to
- * fill in field name and draw).  If blank, do not draw title.  
- * If title was blank or "#auto", will be filled with field name on
- * return
- * \param[in,out] range Data range to use in legend.  Set min > max to have
- * range computed, will be filled with valid min and max values
- * \param[in] width Pixel width of legend (aspect controls orientation)
- * \param[in] height Pixel height of legend (aspect controls orientation)
- * \param[in] opaque Flag to control if legend is rendered opaque or translucent
- * \param[in] numLabels Number of labels to render (includes min/max)
- * \param[in,out] imgData Pointer to array to fill with image bytes. Array
- * will be resized if needed.
- * \return The image is rendered into the supplied array, false is 
- * returned if the color map is not found
- */
-bool Renderer::renderColorMap(const ColorMapId& id, 
-                              const DataSetId& dataSetID,
-                              Renderer::LegendType legendType,
-                              std::string& title,
-                              double range[2],
-                              int width, int height,
-                              bool opaque,
-                              int numLabels,
-                              vtkUnsignedCharArray *imgData)
-{
-    DataSet *dataSet = NULL;
-    if (dataSetID.compare("all") == 0) {
-        if (_dataSets.empty()) {
-            WARN("No DataSets exist, can't fill title or range");
-            return renderColorMap(id, dataSetID, legendType,
-                                  NULL,
-                                  DataSet::POINT_DATA,
-                                  title, range, width, height, opaque, numLabels, imgData);
-        } else {
-            dataSet = _dataSets.begin()->second;
-        }
-    } else {
-        dataSet = getDataSet(dataSetID);
-        if (dataSet == NULL) {
-            ERROR("DataSet '%s' not found", dataSetID.c_str());
-            return false;
-        }
-    }
-
-    if (legendType == LEGEND_SCALAR) {
-        return renderColorMap(id, dataSetID, legendType,
-                              dataSet->getActiveScalarsName(),
-                              dataSet->getActiveScalarsType(),
-                              title, range, width, height, opaque, numLabels, imgData);
-    } else {
-        return renderColorMap(id, dataSetID, legendType,
-                              dataSet->getActiveVectorsName(),
-                              dataSet->getActiveVectorsType(),
-                              title, range, width, height, opaque, numLabels, imgData);
-    }
-}
-
-/**
- * \brief Render a labelled legend image for the given colormap
- *
- * The field is assumed to be point data, if the field is not found
- * as point data, cell data is used.
- *
- * \param[in] id ColorMap name
- * \param[in] dataSetID DataSet name
- * \param[in] legendType scalar or vector field legend
- * \param[in] fieldName Name of the field array this legend is for
- * \param[in,out] title If supplied, draw title ("#auto" means to
- * fill in field name and draw).  If blank, do not draw title.  
- * If title was blank or "#auto", will be filled with field name on
- * return
- * \param[in,out] range Data range to use in legend.  Set min > max to have
- * range computed, will be filled with valid min and max values
- * \param[in] width Pixel width of legend (aspect controls orientation)
- * \param[in] height Pixel height of legend (aspect controls orientation)
- * \param[in] opaque Flag to control if legend is rendered opaque or translucent
- * \param[in] numLabels Number of labels to render (includes min/max)
- * \param[in,out] imgData Pointer to array to fill with image bytes. Array
- * will be resized if needed.
- * \return The image is rendered into the supplied array, false is 
- * returned if the color map is not found
- */
-bool Renderer::renderColorMap(const ColorMapId& id, 
-                              const DataSetId& dataSetID,
-                              Renderer::LegendType legendType,
-                              const char *fieldName,
-                              std::string& title,
-                              double range[2],
-                              int width, int height,
-                              bool opaque,
-                              int numLabels,
-                              vtkUnsignedCharArray *imgData)
-{
-    DataSet *dataSet = NULL;
-    if (dataSetID.compare("all") == 0) {
-        if (_dataSets.empty()) {
-            WARN("No DataSets exist, can't fill title or range");
-            return renderColorMap(id, dataSetID, legendType,
-                                  NULL,
-                                  DataSet::POINT_DATA,
-                                  title, range, width, height, opaque, numLabels, imgData);
-        } else {
-            dataSet = _dataSets.begin()->second;
-        }
-    } else {
-        dataSet = getDataSet(dataSetID);
-        if (dataSet == NULL) {
-            ERROR("DataSet '%s' not found", dataSetID.c_str());
-            return false;
-        }
-    }
-
-    DataSet::DataAttributeType attrType;
-    int numComponents;
-
-    dataSet->getFieldInfo(fieldName, &attrType, &numComponents);
-
-    return renderColorMap(id, dataSetID, legendType,
-                          fieldName,
-                          attrType,
-                          title, range, width, height, opaque, numLabels, imgData);
-}
-
-/**
- * \brief Render a labelled legend image for the given colormap
- *
- * \param[in] id ColorMap name
- * \param[in] dataSetID DataSet name
- * \param[in] legendType scalar or vector field legend
- * \param[in] fieldName Name of the field array this legend is for
- * \param[in] type DataAttributeType of the field
- * \param[in,out] title If supplied, draw title ("#auto" means to
- * fill in field name and draw).  If blank, do not draw title.  
- * If title was blank or "#auto", will be filled with field name on
- * return
- * \param[in,out] range Data range to use in legend.  Set min > max to have
- * range computed, will be filled with valid min and max values
- * \param[in] width Pixel width of legend (aspect controls orientation)
- * \param[in] height Pixel height of legend (aspect controls orientation)
- * \param[in] opaque Flag to control if legend is rendered opaque or translucent
- * \param[in] numLabels Number of labels to render (includes min/max)
- * \param[in,out] imgData Pointer to array to fill with image bytes. Array
- * will be resized if needed.
- * \return The image is rendered into the supplied array, false is 
- * returned if the color map is not found
- */
-bool Renderer::renderColorMap(const ColorMapId& id, 
-                              const DataSetId& dataSetID,
-                              Renderer::LegendType legendType,
-                              const char *fieldName,
-                              DataSet::DataAttributeType type,
-                              std::string& title,
-                              double range[2],
-                              int width, int height,
-                              bool opaque,
-                              int numLabels,
-                              vtkUnsignedCharArray *imgData)
-{
-    TRACE("Enter");
-    ColorMap *colorMap = getColorMap(id);
-    if (colorMap == NULL)
-        return false;
-
-    if (_legendRenderWindow == NULL) {
-        _legendRenderWindow = vtkSmartPointer<vtkRenderWindow>::New();
-        _legendRenderWindow->SetMultiSamples(0);
-#ifdef USE_OFFSCREEN_RENDERING
-        _legendRenderWindow->DoubleBufferOff();
-        _legendRenderWindow->OffScreenRenderingOn();
-#else
-        _legendRenderWindow->DoubleBufferOn();
-        _legendRenderWindow->SwapBuffersOff();
-#endif
-    }
-
-    _legendRenderWindow->SetSize(width, height);
-
-    if (_legendRenderer == NULL) {
-        _legendRenderer = vtkSmartPointer<vtkRenderer>::New();
-        _legendRenderWindow->AddRenderer(_legendRenderer);
-    }
-    _legendRenderer->SetBackground(_bgColor[0], _bgColor[1], _bgColor[2]);
-
-    if (_scalarBarActor == NULL) {
-        _scalarBarActor = vtkSmartPointer<vtkScalarBarActor>::New();
-        _scalarBarActor->DrawFrameOff();
-        _scalarBarActor->DrawBackgroundOff();
-        _legendRenderer->AddViewProp(_scalarBarActor);
-    }
-
-    if (opaque) {
-        _scalarBarActor->UseOpacityOff();
-    } else {
-        _scalarBarActor->UseOpacityOn();
-    }
-
-    if (width > height) {
-        _scalarBarActor->SetOrientationToHorizontal();
-    } else {
-        _scalarBarActor->SetOrientationToVertical();
-    }
-
-    // Set viewport-relative width/height/pos
-    if (title.empty() && numLabels == 0) {
-        _scalarBarActor->SetPosition(0, 0);
-        if (width > height) {
-            // horizontal
-            _scalarBarActor->SetHeight((((double)height+1.5)/((double)height))/0.4); // VTK: floor(actorHeight * .4)
-            _scalarBarActor->SetWidth(1); // VTK: actorWidth
-        } else {
-            // vertical
-            _scalarBarActor->SetHeight((((double)height+1.5)/((double)height))/0.86); // VTK: floor(actorHeight * .86)
-            _scalarBarActor->SetWidth(((double)(width+5))/((double)width)); // VTK: actorWidth - 4 pixels
-        }
-    } else {
-        if (width > height) {
-            // horizontal
-            _scalarBarActor->SetPosition(.075, .1);
-            _scalarBarActor->SetHeight(0.8);
-            _scalarBarActor->SetWidth(0.85);
-        } else {
-            // vertical
-            _scalarBarActor->SetPosition(.1, .05);
-            _scalarBarActor->SetHeight(0.9);
-            _scalarBarActor->SetWidth(0.8);
-        }
-    }
-
-    vtkSmartPointer<vtkLookupTable> lut = colorMap->getLookupTable();
-    DataSet *dataSet = NULL;
-    bool cumulative = _useCumulativeRange;
-    if (dataSetID.compare("all") == 0) {
-        if (_dataSets.empty()) {
-            WARN("No DataSets exist, can't fill title or range");
-        } else {
-            dataSet = _dataSets.begin()->second;
-        }
-        cumulative = true;
-    } else {
-        dataSet = getDataSet(dataSetID);
-        if (dataSet == NULL) {
-            ERROR("DataSet '%s' not found", dataSetID.c_str());
-            return false;
-        }
-    }
-
-    bool drawTitle = false;
-    if (!title.empty()) {
-        drawTitle = true;
-        if (title.compare("#auto") == 0) {
-            title.clear();
-        }
-    }
-
-    bool needRange = false;
-    if (range[0] > range[1]) {
-        range[0] = 0.0;
-        range[1] = 1.0;
-        needRange = true;
-    } 
-
-    switch (legendType) {
-    case LEGEND_VECTOR_MAGNITUDE:
-        if (needRange) {
-            if (cumulative) {
-                getCumulativeDataRange(range, fieldName, type, 3);
-            } else if (dataSet != NULL) {
-                dataSet->getDataRange(range, fieldName, type);
-            }
-        }
-
-        lut->SetRange(range);
-
-        if (title.empty() && dataSet != NULL) {
-            if (fieldName != NULL) {
-                title = fieldName;
-                title.append("(mag)");
-            }
-        }
-        break;
-    case LEGEND_VECTOR_X:
-        if (needRange) {
-            if (cumulative) {
-                getCumulativeDataRange(range, fieldName, type, 3, 0);
-            } else if (dataSet != NULL) {
-                dataSet->getDataRange(range, fieldName, type, 0);
-            }
-        }
-
-        lut->SetRange(range);
-
-        if (title.empty() && dataSet != NULL) {
-            if (fieldName != NULL) {
-                title = fieldName;
-                title.append("(x)");
-            }
-        }
-        break;
-    case LEGEND_VECTOR_Y:
-        if (needRange) {
-            if (cumulative) {
-                getCumulativeDataRange(range, fieldName, type, 3, 1);
-            } else if (dataSet != NULL) {
-                dataSet->getDataRange(range, fieldName, type, 1);
-            }
-        }
-
-        lut->SetRange(range);
-
-        if (title.empty() && dataSet != NULL) {
-            if (fieldName != NULL) {
-                title = fieldName;
-                title.append("(y)");
-            }
-        }
-        break;
-    case LEGEND_VECTOR_Z:
-        if (needRange) {
-            if (cumulative) {
-                getCumulativeDataRange(range, fieldName, type, 3, 2);
-            } else if (dataSet != NULL) {
-                dataSet->getDataRange(range, fieldName, type, 1);
-            }
-        }
-
-        lut->SetRange(range);
-
-        if (title.empty() && dataSet != NULL) {
-            if (fieldName != NULL) {
-                title = fieldName;
-                title.append("(z)");
-            }
-        }
-        break;
-    case LEGEND_SCALAR:
-    default:
-        if (needRange) {
-            if (cumulative) {
-                getCumulativeDataRange(range, fieldName, type, 1);
-            } else if (dataSet != NULL) {
-                dataSet->getDataRange(range, fieldName, type);
-            }
-        }
-
-        lut->SetRange(range);
-
-        if (title.empty() && dataSet != NULL) {
-            if (fieldName != NULL)
-                title = fieldName;
-        }
-        break;
-    }
-
-    _scalarBarActor->SetLookupTable(lut);
-    _scalarBarActor->SetMaximumNumberOfColors((width > height ? width : height));
-
-    if (drawTitle) {
-        _scalarBarActor->SetTitle(title.c_str());
-    } else {
-        _scalarBarActor->SetTitle("");
-    }
-    _scalarBarActor->GetTitleTextProperty()->ItalicOff();
-    _scalarBarActor->SetNumberOfLabels(numLabels);
-    _scalarBarActor->GetLabelTextProperty()->BoldOff();
-    _scalarBarActor->GetLabelTextProperty()->ItalicOff();
-    _scalarBarActor->GetLabelTextProperty()->ShadowOff();
-
-    _legendRenderWindow->Render();
-
-#ifdef RENDER_TARGA
-    _legendRenderWindow->MakeCurrent();
-    // Must clear previous errors first.
-    while (glGetError() != GL_NO_ERROR){
-        ;
-    }
-    int bytesPerPixel = TARGA_BYTES_PER_PIXEL;
-    int size = bytesPerPixel * width * height;
-
-    if (imgData->GetMaxId() + 1 != size)
-    {
-        imgData->SetNumberOfComponents(bytesPerPixel);
-        imgData->SetNumberOfValues(size);
-    }
-    glDisable(GL_TEXTURE_2D);
-    if (_legendRenderWindow->GetDoubleBuffer()) {
-        glReadBuffer(static_cast<GLenum>(vtkOpenGLRenderWindow::SafeDownCast(_legendRenderWindow)->GetBackLeftBuffer()));
-    } else {
-        glReadBuffer(static_cast<GLenum>(vtkOpenGLRenderWindow::SafeDownCast(_legendRenderWindow)->GetFrontLeftBuffer()));
-    }
-    glPixelStorei(GL_PACK_ALIGNMENT, 1);
-    if (bytesPerPixel == 4) {
-        glReadPixels(0, 0, width, height, GL_BGRA,
-                     GL_UNSIGNED_BYTE, imgData->GetPointer(0));
-    } else {
-        glReadPixels(0, 0, width, height, GL_BGR,
-                     GL_UNSIGNED_BYTE, imgData->GetPointer(0));
-    }
-    if (glGetError() != GL_NO_ERROR) {
-        ERROR("glReadPixels");
-    }
-#else
-    _legendRenderWindow->GetPixelData(0, 0, width-1, height-1,
-                                      !_legendRenderWindow->GetDoubleBuffer(),
-                                      imgData);
-#endif
-    TRACE("Leave");
-    return true;
-}
-
-/**
- * \brief Set camera FOV based on render window height
- * 
- * Computes a field-of-view angle based on some assumptions about
- * viewer's distance to screen and pixel density
- */
-void Renderer::setViewAngle(int height)
-{
-    // Distance of eyes from screen in inches
-    double d = 20.0;
-    // Assume 72 ppi screen
-    double h = (double)height / 72.0;
-
-    double angle = vtkMath::DegreesFromRadians(2.0 * atan((h/2.0)/d));
-    _renderer->GetActiveCamera()->SetViewAngle(angle);
-
-    TRACE("Setting view angle: %g", angle);
-}
-
-/**
- * \brief Resize the render window (image size for renderings)
- */
-void Renderer::setWindowSize(int width, int height)
-{
-    if (_windowWidth == width &&
-        _windowHeight == height) {
-        TRACE("No change");
-        return;
-    }
-
-    TRACE("Setting window size to %dx%d", width, height);
-
-    //setViewAngle(height);
-
-    // FIXME: Fix up panning on aspect change
-#ifdef notdef
-    if (_cameraPan[0] != 0.0) {
-        _cameraPan[0] *= ((double)_windowWidth / width);
-    }
-    if (_cameraPan[1] != 0.0) {
-        _cameraPan[1] *= ((double)_windowHeight / height);
-    }
-#endif
-    _windowWidth = width;
-    _windowHeight = height;
-    _renderWindow->SetSize(_windowWidth, _windowHeight);
-
-    if (_cameraMode == IMAGE) {
-        if (_cameraAspect == ASPECT_WINDOW) {
-            double imgWindowAspect = getImageCameraAspect();
-            TRACE("Setting object aspect to %g", imgWindowAspect);
-            setObjectAspects(imgWindowAspect);
-            initCamera();
-        } else {
-            if (_userImgWorldDims[0] > 0) {
-                _setCameraZoomRegion(_userImgWorldOrigin[0],
-                                     _userImgWorldOrigin[1],
-                                     _userImgWorldDims[0],
-                                     _userImgWorldDims[1]);
-            } else {
-                if (isCameraMaximized()) {
-                    initCamera();
-                } else {
-                    _setCameraZoomRegion(_imgWorldOrigin[0],
-                                         _imgWorldOrigin[1],
-                                         _imgWorldDims[0],
-                                         _imgWorldDims[1]);
-                }
-            }
-        }
-    }
-    _needsRedraw = true;
-}
-
-void Renderer::setObjectAspects(double aspectRatio)
-{
-    setGraphicsObjectAspect<Arc>(aspectRatio);
-    setGraphicsObjectAspect<Arrow>(aspectRatio);
-    setGraphicsObjectAspect<Box>(aspectRatio);
-    setGraphicsObjectAspect<Cone>(aspectRatio);
-    setGraphicsObjectAspect<Contour2D>(aspectRatio);
-    setGraphicsObjectAspect<Contour3D>(aspectRatio);
-    setGraphicsObjectAspect<Cutplane>(aspectRatio);
-    setGraphicsObjectAspect<Cylinder>(aspectRatio);
-    setGraphicsObjectAspect<Disk>(aspectRatio);
-    setGraphicsObjectAspect<Glyphs>(aspectRatio);
-    setGraphicsObjectAspect<HeightMap>(aspectRatio);
-    setGraphicsObjectAspect<LIC>(aspectRatio);
-    setGraphicsObjectAspect<Line>(aspectRatio);
-    setGraphicsObjectAspect<Molecule>(aspectRatio);
-    setGraphicsObjectAspect<Outline>(aspectRatio);
-    setGraphicsObjectAspect<PolyData>(aspectRatio);
-    setGraphicsObjectAspect<Polygon>(aspectRatio);
-    setGraphicsObjectAspect<PseudoColor>(aspectRatio);
-    setGraphicsObjectAspect<Sphere>(aspectRatio);
-    setGraphicsObjectAspect<Streamlines>(aspectRatio);
-    setGraphicsObjectAspect<Volume>(aspectRatio);
-    setGraphicsObjectAspect<Warp>(aspectRatio);
-}
-
-void Renderer::setCameraAspect(Aspect aspect)
-{
-    //if (_cameraAspect == aspect)
-    //    return;
-
-    _cameraAspect = aspect;
-
-    double aspectRatio = 0.0;
-    switch (aspect) {
-    case ASPECT_SQUARE:
-        aspectRatio = 1.0;
-        break;
-    case ASPECT_WINDOW:
-        aspectRatio = 1.0;
-        if (_cameraMode == IMAGE) {
-            aspectRatio = getImageCameraAspect();
-        }
-        break;
-    case ASPECT_NATIVE:
-    default:
-        aspectRatio = 0.0;
-    }
-
-    setObjectAspects(aspectRatio);
-
-    if (_cameraMode == IMAGE)
-        _needsCameraReset = true;
-    _needsRedraw = true;
-}
-
-/**
- * \brief Change the camera type: perspective, orthographic or image view
- *
- * Perspective mode is a normal 3D camera.
- *
- * Orthogrphic mode is parallel projection.
- *
- * Image mode is an orthographic camera with fixed axes and a clipping region 
- * around the plot area, use _setCameraZoomRegion to control the displayed area
- *
- * \param[in] mode Enum specifying camera type
- */
-void Renderer::setCameraMode(CameraMode mode)
-{
-    if (_cameraMode == mode) return;
-
-    CameraMode origMode = _cameraMode;
-    _cameraMode = mode;
-    resetAxes();
-
-    vtkSmartPointer<vtkCamera> camera = _renderer->GetActiveCamera();
-    switch (mode) {
-    case ORTHO: {
-        TRACE("Set camera to Ortho mode");
-        camera->ParallelProjectionOn();
-        if (origMode == IMAGE) {
-            resetCamera(true);
-        }
-        break;
-    }
-    case PERSPECTIVE: {
-        TRACE("Set camera to Perspective mode");
-        camera->ParallelProjectionOff();
-        if (origMode == IMAGE) {
-            resetCamera(true);
-        }
-        break;
-    }
-    case IMAGE: {
-        camera->ParallelProjectionOn();
-        _setCameraZoomRegion(_imgWorldOrigin[0], _imgWorldOrigin[1],
-                             _imgWorldDims[0],_imgWorldDims[1]);
-        TRACE("Set camera to Image mode");
-        break;
-    }
-    default:
-        ERROR("Unkown camera mode: %d", mode);
-    }
-    _needsRedraw = true;
-}
-
-/**
- * \brief Get the current camera mode
- */
-Renderer::CameraMode Renderer::getCameraMode() const
-{
-    return _cameraMode;
-}
-
-/**
- * \brief Set the VTK camera parameters based on a 4x4 view matrix
- */
-void Renderer::setCameraFromMatrix(vtkCamera *camera, vtkMatrix4x4& mat)
-{
-    double d = camera->GetDistance();
-    double vu[3];
-    vu[0] = mat[1][0];
-    vu[1] = mat[1][1];
-    vu[2] = mat[1][2];
-    double trans[3];
-    trans[0] = mat[0][3];
-    trans[1] = mat[1][3];
-    trans[2] = mat[2][3];
-    mat[0][3] = 0;
-    mat[1][3] = 0;
-    mat[2][3] = 0;
-    double vpn[3] = {mat[2][0], mat[2][1], mat[2][2]};
-    double pos[3];
-    // With translation removed, we have an orthogonal matrix, 
-    // so the inverse is the transpose
-    mat.Transpose();
-    mat.MultiplyPoint(trans, pos);
-    pos[0] = -pos[0];
-    pos[1] = -pos[1];
-    pos[2] = -pos[2];
-    double fp[3];
-    fp[0] = pos[0] - vpn[0] * d;
-    fp[1] = pos[1] - vpn[1] * d;
-    fp[2] = pos[2] - vpn[2] * d;
-    camera->SetPosition(pos);
-    camera->SetFocalPoint(fp);
-    camera->SetViewUp(vu);
-}
-
-/**
- * \brief Set the orientation of the camera from a quaternion
- * rotation
- *
- * \param[in] quat A quaternion with scalar part first: w,x,y,z
- * \param[in] absolute Is rotation absolute or relative?
- */
-void Renderer::setCameraOrientation(const double quat[4], bool absolute)
-{
-    if (_cameraMode == IMAGE)
-        return;
-    vtkSmartPointer<vtkCamera> camera = _renderer->GetActiveCamera();
-    vtkSmartPointer<vtkTransform> trans = vtkSmartPointer<vtkTransform>::New();
-    vtkSmartPointer<vtkMatrix4x4> rotMat = vtkSmartPointer<vtkMatrix4x4>::New();
-
-    double q[4];
-    copyQuat(quat, q);
-
-    if (absolute) {
-        double abs[4];
-        // Save absolute rotation
-        copyQuat(q, abs);
-        // Compute relative rotation
-        quatMult(quatReciprocal(_cameraOrientation), q, q);
-        // Store absolute rotation
-        copyQuat(abs, _cameraOrientation);
-    } else {
-        // Compute new absolute rotation
-        quatMult(_cameraOrientation, q, _cameraOrientation);
-    }
-
-    quaternionToTransposeMatrix4x4(q, *rotMat);
-#ifdef DEBUG
-    TRACE("Rotation matrix:\n %g %g %g\n %g %g %g\n %g %g %g",
-          (*rotMat)[0][0], (*rotMat)[0][1], (*rotMat)[0][2],
-          (*rotMat)[1][0], (*rotMat)[1][1], (*rotMat)[1][2],
-          (*rotMat)[2][0], (*rotMat)[2][1], (*rotMat)[2][2]);
-    vtkSmartPointer<vtkMatrix4x4> camMat = vtkSmartPointer<vtkMatrix4x4>::New();
-    camMat->DeepCopy(camera->GetViewTransformMatrix());
-    TRACE("Camera matrix:\n %g %g %g %g\n %g %g %g %g\n %g %g %g %g\n %g %g %g %g",
-          (*camMat)[0][0], (*camMat)[0][1], (*camMat)[0][2], (*camMat)[0][3],
-          (*camMat)[1][0], (*camMat)[1][1], (*camMat)[1][2], (*camMat)[1][3],
-          (*camMat)[2][0], (*camMat)[2][1], (*camMat)[2][2], (*camMat)[2][3],
-          (*camMat)[3][0], (*camMat)[3][1], (*camMat)[3][2], (*camMat)[3][3]);
-    printCameraInfo(camera);
-#endif
-    trans->Translate(0, 0, -camera->GetDistance());
-    trans->Concatenate(rotMat);
-    trans->Translate(0, 0, camera->GetDistance());
-    trans->Concatenate(camera->GetViewTransformMatrix());
-    setCameraFromMatrix(camera, *trans->GetMatrix());
-
-    resetCameraClippingRange();
-    printCameraInfo(camera);
-    _needsRedraw = true;
-}
-
-/**
- * \brief Set the position and orientation of the camera
- *
- * \param[in] position x,y,z position of camera in world coordinates
- * \param[in] focalPoint x,y,z look-at point in world coordinates
- * \param[in] viewUp x,y,z up vector of camera
- */
-void Renderer::setCameraOrientationAndPosition(const double position[3],
-                                               const double focalPoint[3],
-                                               const double viewUp[3])
-{
-    vtkSmartPointer<vtkCamera> camera = _renderer->GetActiveCamera();
-    camera->SetPosition(position);
-    camera->SetFocalPoint(focalPoint);
-    camera->SetViewUp(viewUp);
-    resetCameraClippingRange();
-    _needsRedraw = true;
-}
-
-/**
- * \brief Get the position and orientation of the camera
- *
- * \param[out] position x,y,z position of camera in world coordinates
- * \param[out] focalPoint x,y,z look-at point in world coordinates
- * \param[out] viewUp x,y,z up vector of camera
- */
-void Renderer::getCameraOrientationAndPosition(double position[3],
-                                               double focalPoint[3],
-                                               double viewUp[3])
-{
-    vtkSmartPointer<vtkCamera> camera = _renderer->GetActiveCamera();
-    camera->GetPosition(position);
-    camera->GetFocalPoint(focalPoint);
-    camera->GetViewUp(viewUp);
-}
-
-void Renderer::sceneBoundsChanged()
-{
-#ifdef RESET_CAMERA_ON_SCENE_CHANGE
-    _needsCameraReset = true;
-#else
-    _needsAxesReset = true;
-    _needsCameraClippingRangeReset = true;
-#endif
-
-    _needsRedraw = true;
-}
-
-/**
- * \brief Reset pan, zoom, clipping planes and optionally rotation
- *
- * \param[in] resetOrientation Reset the camera rotation/orientation also
- */
-void Renderer::resetCamera(bool resetOrientation)
-{
-    TRACE("Enter: %d", resetOrientation ? 1 : 0);
-    vtkSmartPointer<vtkCamera> camera = _renderer->GetActiveCamera();
-    if (_cameraMode == IMAGE) {
-        initCamera();
-    } else {
-        if (resetOrientation) {
-            camera->SetPosition(0, 0, 1);
-            camera->SetFocalPoint(0, 0, 0);
-            camera->SetViewUp(0, 1, 0);
-            _cameraOrientation[0] = 1.0;
-            _cameraOrientation[1] = 0.0;
-            _cameraOrientation[2] = 0.0;
-            _cameraOrientation[3] = 0.0;
-        }
-        //setViewAngle(_windowHeight);
-        //double bounds[6];
-        //collectBounds(bounds, false);
-        //_renderer->ResetCamera(bounds);
-        if (_needsAxesReset) {
-            resetAxes();
-            _needsAxesReset = false;
-        }
-        resetVtkCamera();
-        //computeScreenWorldCoords();
-    }
-
-    printCameraInfo(camera);
-
-    _cameraZoomRatio = 1;
-    _cameraPan[0] = 0;
-    _cameraPan[1] = 0;
-
-    _needsRedraw = true;
-}
-
-void Renderer::resetVtkCamera(double *bounds)
-{
-    TRACE("Enter: bounds: %p", bounds);
-    if (bounds != NULL)
-        _renderer->ResetCamera(bounds);
-    else
-        _renderer->ResetCamera();
-    printCameraInfo(_renderer->GetActiveCamera());
-}
-
-/**
- * \brief Set the camera near/far clipping range based on current scene bounds
- */
-void Renderer::resetCameraClippingRange()
-{
-    _renderer->ResetCameraClippingRange();
-    vtkSmartPointer<vtkCamera> camera = _renderer->GetActiveCamera();
-    //double dist = camera->GetClippingRange()[0] + (camera->GetClippingRange()[1] - camera->GetClippingRange()[0])/2.0;
-    //camera->SetDistance(dist);
-    printCameraInfo(camera);
-}
-
-/**
- * \brief Perform a relative rotation to current camera orientation
- *
- * Angles are in degrees, rotation is about focal point
- */
-void Renderer::rotateCamera(double yaw, double pitch, double roll)
-{
-    if (_cameraMode == IMAGE)
-        return;
-    vtkSmartPointer<vtkCamera> camera = _renderer->GetActiveCamera();
-    camera->Azimuth(yaw); // Rotate about object
-    //camera->SetYaw(yaw); // Rotate about camera
-    camera->Elevation(pitch); // Rotate about object
-    //camera->SetPitch(pitch); // Rotate about camera
-    camera->Roll(roll); // Roll about camera view axis
-    resetCameraClippingRange();
-    //computeScreenWorldCoords();
-    _needsRedraw = true;
-}
-
-/**
- * \brief Perform a 2D translation of the camera
- *
- * x,y pan amount are specified as signed absolute pan amount in viewport
- * units -- i.e. 0 is no pan, .5 is half the viewport, 2 is twice the viewport,
- * etc.
- *
- * \param[in] x Viewport coordinate horizontal panning (positive number pans
- * camera left, object right)
- * \param[in] y Viewport coordinate vertical panning (positive number pans 
- * camera up, object down)
- * \param[in] absolute Control if pan amount is relative to current or absolute
- */
-void Renderer::panCamera(double x, double y, bool absolute)
-{
-    TRACE("Enter panCamera: %g %g, current abs: %g %g",
-          x, y, _cameraPan[0], _cameraPan[1]);
-
-    if (_cameraMode == IMAGE) {
-        _userImgWorldOrigin[0] = 0;
-        _userImgWorldOrigin[1] = 0;
-        _userImgWorldDims[0] = -1;
-        _userImgWorldDims[1] = -1;
-
-        // Reverse x rather than y, since we are panning the camera, and client
-        // expects to be panning/moving the object
-        x = -x * _screenWorldCoords[2];
-        y = y * _screenWorldCoords[3];
-
-        if (absolute) {
-            double panAbs[2];
-            panAbs[0] = x;
-            panAbs[1] = y;
-            x -= _cameraPan[0];
-            y -= _cameraPan[1];
-            _cameraPan[0] = panAbs[0];
-            _cameraPan[1] = panAbs[1];
-        } else {
-            _cameraPan[0] += x;
-            _cameraPan[1] += y;
-        }
-
-        _imgWorldOrigin[0] += x;
-        _imgWorldOrigin[1] += y;
-        _setCameraZoomRegion(_imgWorldOrigin[0], _imgWorldOrigin[1],
-                             _imgWorldDims[0], _imgWorldDims[1]);
-    } else {
-        y = -y;
-        if (absolute) {
-            double panAbs[2];
-            panAbs[0] = x;
-            panAbs[1] = y;
-            x -= _cameraPan[0];
-            y -= _cameraPan[1];
-            _cameraPan[0] = panAbs[0];
-            _cameraPan[1] = panAbs[1];
-        } else {
-            _cameraPan[0] += x;
-            _cameraPan[1] += y;
-        }
-
-        if (x != 0.0 || y != 0.0) {
-            vtkSmartPointer<vtkCamera> camera = _renderer->GetActiveCamera();
-            double viewFocus[4], focalDepth, viewPoint[3];
-            double newPickPoint[4], oldPickPoint[4], motionVector[3];
-
-            camera->GetFocalPoint(viewFocus);
-            computeWorldToDisplay(viewFocus[0], viewFocus[1], viewFocus[2], 
-                                  viewFocus);
-            focalDepth = viewFocus[2];
-
-            computeDisplayToWorld(( x * 2. + 1.) * _windowWidth / 2.0,
-                                  ( y * 2. + 1.) * _windowHeight / 2.0,
-                                  focalDepth, 
-                                  newPickPoint);
-
-            computeDisplayToWorld(_windowWidth / 2.0,
-                                  _windowHeight / 2.0,
-                                  focalDepth, 
-                                  oldPickPoint);
-
-            // Camera motion is reversed
-            motionVector[0] = oldPickPoint[0] - newPickPoint[0];
-            motionVector[1] = oldPickPoint[1] - newPickPoint[1];
-            motionVector[2] = oldPickPoint[2] - newPickPoint[2];
-
-            camera->GetFocalPoint(viewFocus);
-            camera->GetPosition(viewPoint);
-            camera->SetFocalPoint(motionVector[0] + viewFocus[0],
-                                  motionVector[1] + viewFocus[1],
-                                  motionVector[2] + viewFocus[2]);
-
-            camera->SetPosition(motionVector[0] + viewPoint[0],
-                                motionVector[1] + viewPoint[1],
-                                motionVector[2] + viewPoint[2]);
-
-            resetCameraClippingRange();
-            //computeScreenWorldCoords();
-        }
-    }
-
-    TRACE("Leave panCamera: %g %g, current abs: %g %g",
-          x, y, _cameraPan[0], _cameraPan[1]);
-
-    _needsRedraw = true;
-}
-
-/**
- * \brief Dolly camera or set orthographic scaling based on camera type
- *
- * \param[in] z Ratio to change zoom (greater than 1 is zoom in, less than 1 is zoom out)
- * \param[in] absolute Control if zoom factor is relative to current setting or absolute
- */
-void Renderer::zoomCamera(double z, bool absolute)
-{
-    vtkSmartPointer<vtkCamera> camera = _renderer->GetActiveCamera();
-    TRACE("Enter Zoom: current abs: %g, z: %g, view angle %g",
-          _cameraZoomRatio, z, camera->GetViewAngle());
-
-    if (absolute) {
-        assert(_cameraZoomRatio > 0.0);
-        double zAbs = z;
-        z *= 1.0/_cameraZoomRatio;
-        _cameraZoomRatio = zAbs;
-    } else {
-        _cameraZoomRatio *= z;
-    }
-
-    if (_cameraMode == IMAGE) {
-        _userImgWorldOrigin[0] = 0;
-        _userImgWorldOrigin[1] = 0;
-        _userImgWorldDims[0] = -1;
-        _userImgWorldDims[1] = -1;
-
-        double dx = _imgWorldDims[0];
-        double dy = _imgWorldDims[1];
-        _imgWorldDims[0] /= z;
-        _imgWorldDims[1] /= z;
-        dx -= _imgWorldDims[0];
-        dy -= _imgWorldDims[1];
-        _imgWorldOrigin[0] += dx/2.0;
-        _imgWorldOrigin[1] += dy/2.0;
-        _setCameraZoomRegion(_imgWorldOrigin[0], _imgWorldOrigin[1],
-                             _imgWorldDims[0], _imgWorldDims[1]);
-    } else {
-        // Keep ortho and perspective modes in sync
-        // Move camera forward/back for perspective camera
-        camera->Dolly(z);
-        // Change ortho parallel scale
-        camera->SetParallelScale(camera->GetParallelScale()/z);
-        resetCameraClippingRange();
-        //computeScreenWorldCoords();
-    }
-
-    TRACE("Leave Zoom: rel %g, new abs: %g, view angle %g", 
-          z, _cameraZoomRatio, camera->GetViewAngle());
-
-    _needsRedraw = true;
-}
-
-bool Renderer::setCameraZoomRegionPixels(int x, int y, int width, int height)
-{
-    if (_cameraMode != IMAGE)
-        return false;
-
-    double wx, wy, ww, wh;
-
-    y = _windowHeight - y;
-    double pxToWorldX = _screenWorldCoords[2] / (double)_windowWidth;
-    double pxToWorldY = _screenWorldCoords[3] / (double)_windowHeight;
-
-    wx = _screenWorldCoords[0] + x * pxToWorldX;
-    wy = _screenWorldCoords[1] + y * pxToWorldY;
-    ww = abs(width) *  pxToWorldX;
-    wh = abs(height) * pxToWorldY;
-    setCameraZoomRegion(wx, wy, ww, wh);
-
-    TRACE("\npx: %d %d %d %d\nworld: %g %g %g %g",
-          x, y, width, height,
-          wx, wy, ww, wh);
-
-    return true;
-}
-
-bool Renderer::setCameraZoomRegion(double x, double y, double width, double height)
-{
-    if (_cameraMode != IMAGE)
-        return false;
-
-    _userImgWorldOrigin[0] = x;
-    _userImgWorldOrigin[1] = y;
-    _userImgWorldDims[0] = width;
-    _userImgWorldDims[1] = height;
-    _setCameraZoomRegion(x, y, width, height);
-
-    return true;
-}
-
-/**
- * \brief Set the pan/zoom using a corner and dimensions in pixel coordinates
- * 
- * \param[in] x left pixel coordinate
- * \param[in] y bottom  pixel coordinate (with y=0 at top of window)
- * \param[in] width Width of zoom region in pixel coordinates
- * \param[in] height Height of zoom region in pixel coordinates
- */
-void Renderer::_setCameraZoomRegionPixels(int x, int y, int width, int height)
-{
-    if (_cameraMode != IMAGE) {
-        ERROR("Called while camera mode is not image");
-        return;
-    }
-
-    double wx, wy, ww, wh;
-
-    y = _windowHeight - y;
-    double pxToWorldX = _screenWorldCoords[2] / (double)_windowWidth;
-    double pxToWorldY = _screenWorldCoords[3] / (double)_windowHeight;
-
-    wx = _screenWorldCoords[0] + x * pxToWorldX;
-    wy = _screenWorldCoords[1] + y * pxToWorldY;
-    ww = abs(width) *  pxToWorldX;
-    wh = abs(height) * pxToWorldY;
-    _setCameraZoomRegion(wx, wy, ww, wh);
-
-    TRACE("\npx: %d %d %d %d\nworld: %g %g %g %g",
-          x, y, width, height,
-          wx, wy, ww, wh);
-}
-
-void Renderer::getImageCameraSizes(int *imgWidthPx, int *imgHeightPx,
-                                   int *_pxOffsetX, int *_pxOffsetY)
-{
-    int pxOffsetX, pxOffsetY;
-    pxOffsetX = (int)(0.17 * (double)_windowWidth);
-    pxOffsetX = (pxOffsetX > 100 ? 100 : pxOffsetX);
-    pxOffsetY = (int)(0.15 * (double)_windowHeight);
-    pxOffsetY = (pxOffsetY > 75 ? 75 : pxOffsetY);
-
-    int outerGutter = (int)(0.03 * (double)_windowWidth);
-    outerGutter = (outerGutter > 15 ? 15 : outerGutter);
-
-    *imgWidthPx = _windowWidth - pxOffsetX - outerGutter;
-    *imgHeightPx = _windowHeight - pxOffsetY - outerGutter;
-    if (_pxOffsetX != NULL) *_pxOffsetX = pxOffsetX;
-    if (_pxOffsetY != NULL) *_pxOffsetY = pxOffsetY;
-}
-
-double Renderer::getImageCameraAspect()
-{
-    int imgWidthPx, imgHeightPx;
-    getImageCameraSizes(&imgWidthPx, &imgHeightPx);
-    return ((double)imgWidthPx / (double)imgHeightPx);
-}
-
-/**
- * \brief Set the pan/zoom using a corner and dimensions in world coordinates
- * 
- * \param[in] x left world coordinate
- * \param[in] y bottom  world coordinate
- * \param[in] width Width of zoom region in world coordinates
- * \param[in] height Height of zoom region in world coordinates
- */
-void Renderer::_setCameraZoomRegion(double x, double y, double width, double height)
-{
-    if (_cameraMode != IMAGE) {
-        ERROR("Called while camera mode is not image");
-        return;
-    }
-
-    int imgWidthPx, imgHeightPx;
-    int pxOffsetX, pxOffsetY;
-
-    getImageCameraSizes(&imgWidthPx, &imgHeightPx, &pxOffsetX, &pxOffsetY);
-
-    double imgWindowAspect = (double)imgWidthPx / (double)imgHeightPx;
-
-    double pxToWorld;
-    double imgWidthWorld;
-    double imgHeightWorld;
-
-    double requestedAspect = width / height;
-
-    if (requestedAspect >= imgWindowAspect) {
-        pxToWorld = width / (double)imgWidthPx;
-        imgWidthWorld = width;
-        imgHeightWorld = (double)imgHeightPx * pxToWorld;
-    } else {
-        pxToWorld = height / (double)imgHeightPx;
-        imgWidthWorld = (double)imgWidthPx * pxToWorld;
-        imgHeightWorld =  height;
-    }
-
-    double offsetX = pxOffsetX * pxToWorld;
-    double offsetY = pxOffsetY * pxToWorld;
-    double winWidthWorld = _windowWidth * pxToWorld;
-    double winHeightWorld = _windowHeight * pxToWorld;
-
-    TRACE("Window: %d %d", _windowWidth, _windowHeight);
-    TRACE("ZoomRegion: %g %g %g %g", x, y, width, height);
-    TRACE("pxToWorld: %g", pxToWorld);
-    TRACE("offset: %g %g", offsetX, offsetY);
-
-    _imgWorldOrigin[0] = x;
-    _imgWorldOrigin[1] = y;
-    _imgWorldDims[0] = width;
-    _imgWorldDims[1] = height;
-    _imgWindowWorldDims[0] = imgWidthWorld;
-    _imgWindowWorldDims[1] = imgHeightWorld;
-
-    double camPos[2];
-    camPos[0] = _imgWorldOrigin[0] - offsetX + winWidthWorld / 2.0;
-    camPos[1] = _imgWorldOrigin[1] - offsetY + winHeightWorld / 2.0;
-
-    vtkSmartPointer<vtkCamera> camera = _renderer->GetActiveCamera();
-    camera->ParallelProjectionOn();
-    camera->SetClippingRange(1, 2);
-    // Half of world coordinate height of viewport (Documentation is wrong)
-    camera->SetParallelScale(winHeightWorld / 2.0);
-
-    if (_imgCameraPlane == PLANE_XY) {
-        // XY plane
-        camera->SetPosition(camPos[0], camPos[1], _imgCameraOffset + 1.);
-        camera->SetFocalPoint(camPos[0], camPos[1], _imgCameraOffset);
-        camera->SetViewUp(0, 1, 0);
-        // bottom
-        _cameraClipPlanes[0]->SetOrigin(0, _imgWorldOrigin[1], 0);
-        _cameraClipPlanes[0]->SetNormal(0, 1, 0);
-        // left
-        _cameraClipPlanes[1]->SetOrigin(_imgWorldOrigin[0], 0, 0);
-        _cameraClipPlanes[1]->SetNormal(1, 0, 0);
-        // top
-        _cameraClipPlanes[2]->SetOrigin(0, _imgWorldOrigin[1] + _imgWindowWorldDims[1], 0);
-        _cameraClipPlanes[2]->SetNormal(0, -1, 0);
-        // right
-        _cameraClipPlanes[3]->SetOrigin(_imgWorldOrigin[0] + _imgWindowWorldDims[0], 0, 0);
-        _cameraClipPlanes[3]->SetNormal(-1, 0, 0);
-
-        _cubeAxesActor->SetBounds(_imgWorldOrigin[0], _imgWorldOrigin[0] + _imgWindowWorldDims[0],
-                                  _imgWorldOrigin[1], _imgWorldOrigin[1] + _imgWindowWorldDims[1],
-                                  _imgCameraOffset, _imgCameraOffset);
-        _cubeAxesActor->XAxisVisibilityOn();
-        _cubeAxesActor->YAxisVisibilityOn();
-        _cubeAxesActor->ZAxisVisibilityOff();
-    } else if (_imgCameraPlane == PLANE_ZY) {
-        // ZY plane
-        camera->SetPosition(_imgCameraOffset - 1., camPos[1], camPos[0]);
-        camera->SetFocalPoint(_imgCameraOffset, camPos[1], camPos[0]);
-        camera->SetViewUp(0, 1, 0);
-        // bottom
-        _cameraClipPlanes[0]->SetOrigin(0, _imgWorldOrigin[1], 0);
-        _cameraClipPlanes[0]->SetNormal(0, 1, 0);
-        // left
-        _cameraClipPlanes[1]->SetOrigin(0, 0, _imgWorldOrigin[0]);
-        _cameraClipPlanes[1]->SetNormal(0, 0, 1);
-        // top
-        _cameraClipPlanes[2]->SetOrigin(0, _imgWorldOrigin[1] + _imgWindowWorldDims[1], 0);
-        _cameraClipPlanes[2]->SetNormal(0, -1, 0);
-        // right
-        _cameraClipPlanes[3]->SetOrigin(0, 0, _imgWorldOrigin[0] + _imgWindowWorldDims[0]);
-        _cameraClipPlanes[3]->SetNormal(0, 0, -1);
-
-        _cubeAxesActor->SetBounds(_imgCameraOffset, _imgCameraOffset, 
-                                  _imgWorldOrigin[1], _imgWorldOrigin[1] + _imgWindowWorldDims[1],
-                                  _imgWorldOrigin[0], _imgWorldOrigin[0] + _imgWindowWorldDims[0]);
-        _cubeAxesActor->XAxisVisibilityOff();
-        _cubeAxesActor->YAxisVisibilityOn();
-        _cubeAxesActor->ZAxisVisibilityOn();
-    } else {
-        // XZ plane
-        camera->SetPosition(camPos[0], _imgCameraOffset - 1., camPos[1]);
-        camera->SetFocalPoint(camPos[0], _imgCameraOffset, camPos[1]);
-        camera->SetViewUp(0, 0, 1);
-        // bottom
-        _cameraClipPlanes[0]->SetOrigin(0, 0, _imgWorldOrigin[1]);
-        _cameraClipPlanes[0]->SetNormal(0, 0, 1);
-        // left
-        _cameraClipPlanes[1]->SetOrigin(_imgWorldOrigin[0], 0, 0);
-        _cameraClipPlanes[1]->SetNormal(1, 0, 0);
-        // top
-        _cameraClipPlanes[2]->SetOrigin(0, 0, _imgWorldOrigin[1] + _imgWorldDims[1]);
-        _cameraClipPlanes[2]->SetNormal(0, 0, -1);
-        // right
-        _cameraClipPlanes[3]->SetOrigin(_imgWorldOrigin[0] + _imgWorldDims[0], 0, 0);
-        _cameraClipPlanes[3]->SetNormal(-1, 0, 0);
-
-        _cubeAxesActor->SetBounds(_imgWorldOrigin[0], _imgWorldOrigin[0] + _imgWindowWorldDims[0],
-                                  _imgCameraOffset, _imgCameraOffset,
-                                  _imgWorldOrigin[1], _imgWorldOrigin[1] + _imgWindowWorldDims[1]);
-        _cubeAxesActor->XAxisVisibilityOn();
-        _cubeAxesActor->YAxisVisibilityOff();
-        _cubeAxesActor->ZAxisVisibilityOn();
-    }
-
-    // Fix up axis ranges based on new bounds
-    setAxesRanges();
-
-    // Compute screen world coordinates
-    computeScreenWorldCoords();
-
-#ifdef DEBUG
-    printCameraInfo(camera);
-#endif
-
-    _needsRedraw = true;
-}
-
-/**
- * \brief Convert pixel/display coordinates to world coordinates based on current camera
- */
-void Renderer::computeDisplayToWorld(double x, double y, double z, double worldPt[4])
-{
-    _renderer->SetDisplayPoint(x, y, z);
-    _renderer->DisplayToWorld();
-    _renderer->GetWorldPoint(worldPt);
-    if (worldPt[3]) {
-        worldPt[0] /= worldPt[3];
-        worldPt[1] /= worldPt[3];
-        worldPt[2] /= worldPt[3];
-        worldPt[3] = 1.0;
-    }
-}
-
-/**
- * \brief Convert world coordinates to pixel/display coordinates based on current camera
- */
-void Renderer::computeWorldToDisplay(double x, double y, double z, double displayPt[3])
-{
-    _renderer->SetWorldPoint(x, y, z, 1.0);
-    _renderer->WorldToDisplay();
-    _renderer->GetDisplayPoint(displayPt);
-}
-
-/**
- * \brief Compute the world coordinate bounds of the display rectangle
- */
-void Renderer::computeScreenWorldCoords()
-{
-    // Start with viewport coords [-1,1]
-    double x0 = -1;
-    double y0 = -1;
-    double z0 = -1;
-    double x1 = 1;
-    double y1 = 1;
-    double z1 = -1;
-
-    vtkMatrix4x4 *mat = vtkMatrix4x4::New();
-    double result[4];
-
-    // get the perspective transformation from the active camera
-    mat->DeepCopy(_renderer->GetActiveCamera()->
-                  GetCompositeProjectionTransformMatrix(_renderer->GetTiledAspectRatio(),0,1));
-
-    // use the inverse matrix
-    mat->Invert();
-
-    // Transform point to world coordinates
-    result[0] = x0;
-    result[1] = y0;
-    result[2] = z0;
-    result[3] = 1.0;
-
-    mat->MultiplyPoint(result, result);
-
-    // Get the transformed vector & set WorldPoint
-    // while we are at it try to keep w at one
-    if (result[3]) {
-        x0 = result[0] / result[3];
-        y0 = result[1] / result[3];
-        z0 = result[2] / result[3];
-    }
-
-    result[0] = x1;
-    result[1] = y1;
-    result[2] = z1;
-    result[3] = 1.0;
-
-    mat->MultiplyPoint(result, result);
-
-    if (result[3]) {
-        x1 = result[0] / result[3];
-        y1 = result[1] / result[3];
-        z1 = result[2] / result[3];
-    }
-
-    mat->Delete();
-
-    if (_imgCameraPlane == PLANE_XZ) {
-        _screenWorldCoords[0] = x0;
-        _screenWorldCoords[1] = z0;
-        _screenWorldCoords[2] = x1 - x0;
-        _screenWorldCoords[3] = z1 - z0;
-    } else if (_imgCameraPlane == PLANE_ZY) {
-        _screenWorldCoords[0] = z0;
-        _screenWorldCoords[1] = y0;
-        _screenWorldCoords[2] = z1 - z0;
-        _screenWorldCoords[3] = y1 - y0;
-    } else {
-        // XY
-        _screenWorldCoords[0] = x0;
-        _screenWorldCoords[1] = y0;
-        _screenWorldCoords[2] = x1 - x0;
-        _screenWorldCoords[3] = y1 - y0;
-    }
-}
-
-/**
- * \brief Get the world coordinates of the image camera plot area
- *
- * \param[out] xywh Array to hold x,y,width,height world coordinates
- */
-void Renderer::getCameraZoomRegion(double xywh[4]) const
-{
-    xywh[0] = _imgWorldOrigin[0];
-    xywh[1] = _imgWorldOrigin[1];
-    xywh[2] = _imgWorldDims[0];
-    xywh[3] = _imgWorldDims[1];
-}
-
-/**
- * \brief Get the world origin and dimensions of the screen
- *
- * \param[out] xywh Array to hold x,y,width,height world coordinates
- */
-void Renderer::getScreenWorldCoords(double xywh[4]) const
-{
-    memcpy(xywh, _screenWorldCoords, sizeof(double)*4);
-}
-
-/**
- * \brief Compute bounding box containing the two input bounding boxes
- *
- * \param[out] boundsDest Union of the two input bounding boxes
- * \param[in] bounds1 Input bounding box
- * \param[in] bounds2 Input bounding box
- */
-void Renderer::mergeBounds(double *boundsDest,
-                           const double *bounds1, const double *bounds2)
-{
-    assert(boundsDest != NULL);
-    assert(bounds1 != NULL);
-    if (bounds2 == NULL) {
-        WARN("NULL bounds2 array");
-        return;
-    }
-    bool b1empty = (bounds1[0] > bounds1[1]);
-    bool b2empty = (bounds2[0] > bounds2[1]);
-
-    if (b1empty && b2empty)
-        return;
-    if (b1empty) {
-        memcpy(boundsDest, bounds2, sizeof(double) * 6);
-        return;
-    } else if (b2empty) {
-        memcpy(boundsDest, bounds1, sizeof(double) * 6);
-        return;
-    }
-
-    for (int i = 0; i < 6; i++) {
-        if (i % 2 == 0)
-            boundsDest[i] = min2(bounds1[i], bounds2[i]);
-        else
-            boundsDest[i] = max2(bounds1[i], bounds2[i]);
-    }
-}
-
-/**
- * \brief Collect bounds of all graphics objects
- *
- * \param[out] bounds Bounds of all scene objects
- * \param[in] onlyVisible Only collect bounds of visible objects
- */
-void Renderer::collectBounds(double *bounds, bool onlyVisible)
-{
-    bounds[0] = DBL_MAX;
-    bounds[1] = -DBL_MAX;
-    bounds[2] = DBL_MAX;
-    bounds[3] = -DBL_MAX;
-    bounds[4] = DBL_MAX;
-    bounds[5] = -DBL_MAX;
-
-    mergeGraphicsObjectBounds<Arc>(bounds, onlyVisible);
-    mergeGraphicsObjectBounds<Arrow>(bounds, onlyVisible);
-    mergeGraphicsObjectBounds<Box>(bounds, onlyVisible);
-    mergeGraphicsObjectBounds<Cone>(bounds, onlyVisible);
-    mergeGraphicsObjectBounds<Contour2D>(bounds, onlyVisible);
-    mergeGraphicsObjectBounds<Contour3D>(bounds, onlyVisible);
-    mergeGraphicsObjectBounds<Cutplane>(bounds, onlyVisible);
-    mergeGraphicsObjectBounds<Cylinder>(bounds, onlyVisible);
-    mergeGraphicsObjectBounds<Disk>(bounds, onlyVisible);
-    mergeGraphicsObjectBounds<Glyphs>(bounds, onlyVisible);
-    mergeGraphicsObjectBounds<HeightMap>(bounds, onlyVisible);
-    mergeGraphicsObjectBounds<LIC>(bounds, onlyVisible);
-    mergeGraphicsObjectBounds<Line>(bounds, onlyVisible);
-    mergeGraphicsObjectBounds<Molecule>(bounds, onlyVisible);
-    mergeGraphicsObjectBounds<Outline>(bounds, onlyVisible);
-    mergeGraphicsObjectBounds<PolyData>(bounds, onlyVisible);
-    mergeGraphicsObjectBounds<Polygon>(bounds, onlyVisible);
-    mergeGraphicsObjectBounds<PseudoColor>(bounds, onlyVisible);
-    mergeGraphicsObjectBounds<Sphere>(bounds, onlyVisible);
-    mergeGraphicsObjectBounds<Streamlines>(bounds, onlyVisible);
-    mergeGraphicsObjectBounds<Volume>(bounds, onlyVisible);
-    mergeGraphicsObjectBounds<Warp>(bounds, onlyVisible);
-
-    for (int i = 0; i < 6; i += 2) {
-        if (bounds[i+1] < bounds[i]) {
-            bounds[i] = -0.5;
-            bounds[i+1] = 0.5;
-        }
-    }
-
-    int numDims = 0;
-    if (bounds[0] != bounds[1])
-        numDims++;
-    if (bounds[2] != bounds[3])
-        numDims++;
-    if (bounds[4] != bounds[5])
-        numDims++;
-
-    if (numDims == 0) {
-        bounds[0] -= .5;
-        bounds[1] += .5;
-        bounds[2] -= .5;
-        bounds[3] += .5;
-    }
-
-    TRACE("Bounds: %g %g %g %g %g %g",
-          bounds[0],
-          bounds[1],
-          bounds[2],
-          bounds[3],
-          bounds[4],
-          bounds[5]);
-}
-
-/**
- * \brief Collect bounds of all graphics objects
- *
- * \param[out] bounds Bounds of all scene objects
- * \param[in] onlyVisible Only collect bounds of visible objects
- */
-void Renderer::collectUnscaledBounds(double *bounds, bool onlyVisible)
-{
-    bounds[0] = DBL_MAX;
-    bounds[1] = -DBL_MAX;
-    bounds[2] = DBL_MAX;
-    bounds[3] = -DBL_MAX;
-    bounds[4] = DBL_MAX;
-    bounds[5] = -DBL_MAX;
-
-    mergeGraphicsObjectUnscaledBounds<Arc>(bounds, onlyVisible);
-    mergeGraphicsObjectUnscaledBounds<Arrow>(bounds, onlyVisible);
-    mergeGraphicsObjectUnscaledBounds<Box>(bounds, onlyVisible);
-    mergeGraphicsObjectUnscaledBounds<Cone>(bounds, onlyVisible);
-    mergeGraphicsObjectUnscaledBounds<Contour2D>(bounds, onlyVisible);
-    mergeGraphicsObjectUnscaledBounds<Contour3D>(bounds, onlyVisible);
-    mergeGraphicsObjectUnscaledBounds<Cutplane>(bounds, onlyVisible);
-    mergeGraphicsObjectUnscaledBounds<Cylinder>(bounds, onlyVisible);
-    mergeGraphicsObjectUnscaledBounds<Disk>(bounds, onlyVisible);
-    mergeGraphicsObjectUnscaledBounds<Glyphs>(bounds, onlyVisible);
-    mergeGraphicsObjectUnscaledBounds<HeightMap>(bounds, onlyVisible);
-    mergeGraphicsObjectUnscaledBounds<LIC>(bounds, onlyVisible);
-    mergeGraphicsObjectUnscaledBounds<Line>(bounds, onlyVisible);
-    mergeGraphicsObjectUnscaledBounds<Molecule>(bounds, onlyVisible);
-    mergeGraphicsObjectUnscaledBounds<Outline>(bounds, onlyVisible);
-    mergeGraphicsObjectUnscaledBounds<PolyData>(bounds, onlyVisible);
-    mergeGraphicsObjectUnscaledBounds<Polygon>(bounds, onlyVisible);
-    mergeGraphicsObjectUnscaledBounds<PseudoColor>(bounds, onlyVisible);
-    mergeGraphicsObjectUnscaledBounds<Sphere>(bounds, onlyVisible);
-    mergeGraphicsObjectUnscaledBounds<Streamlines>(bounds, onlyVisible);
-    mergeGraphicsObjectUnscaledBounds<Volume>(bounds, onlyVisible);
-    mergeGraphicsObjectUnscaledBounds<Warp>(bounds, onlyVisible);
-
-    for (int i = 0; i < 6; i += 2) {
-        if (bounds[i+1] < bounds[i]) {
-            bounds[i] = -0.5;
-            bounds[i+1] = 0.5;
-        }
-    }
-
-    int numDims = 0;
-    if (bounds[0] != bounds[1])
-        numDims++;
-    if (bounds[2] != bounds[3])
-        numDims++;
-    if (bounds[4] != bounds[5])
-        numDims++;
-
-    if (numDims == 0) {
-        bounds[0] -= .5;
-        bounds[1] += .5;
-        bounds[2] -= .5;
-        bounds[3] += .5;
-    }
-
-    TRACE("Bounds: %g %g %g %g %g %g",
-          bounds[0],
-          bounds[1],
-          bounds[2],
-          bounds[3],
-          bounds[4],
-          bounds[5]);
-}
-
-/**
- * \brief Update data ranges for color-mapping and contours
- */
-void Renderer::updateFieldRanges()
-{
-    collectDataRanges();
-
-    updateGraphicsObjectFieldRanges<Contour2D>();
-    updateGraphicsObjectFieldRanges<Contour3D>();
-    updateGraphicsObjectFieldRanges<Cutplane>();
-    updateGraphicsObjectFieldRanges<Glyphs>();
-    updateGraphicsObjectFieldRanges<HeightMap>();
-    updateGraphicsObjectFieldRanges<LIC>();
-    updateGraphicsObjectFieldRanges<Molecule>();
-    updateGraphicsObjectFieldRanges<PseudoColor>();
-    updateGraphicsObjectFieldRanges<Streamlines>();
-    updateGraphicsObjectFieldRanges<Volume>();
-    updateGraphicsObjectFieldRanges<Warp>();
-}
-
-/**
- * \brief Collect cumulative data range of all DataSets
- *
- * \param[out] range Data range of all DataSets
- * \param[in] name Field name
- * \param[in] type Attribute type: e.g. POINT_DATA, CELL_DATA
- * \param[in] component Array component or -1 for magnitude
- * \param[in] onlyVisible Only collect range of visible DataSets
- */
-void Renderer::collectDataRanges(double *range, const char *name,
-                                 DataSet::DataAttributeType type,
-                                 int component, bool onlyVisible)
-{
-    range[0] = DBL_MAX;
-    range[1] = -DBL_MAX;
-
-    for (DataSetHashmap::iterator itr = _dataSets.begin();
-         itr != _dataSets.end(); ++itr) {
-        if (!onlyVisible || itr->second->getVisibility()) {
-            double r[2];
-            r[0] = DBL_MAX;
-            r[1] = -DBL_MAX;
-            itr->second->getDataRange(r, name, type, component);
-            range[0] = min2(range[0], r[0]);
-            range[1] = max2(range[1], r[1]);
-        }
-    }
-    if (range[0] == DBL_MAX)
-        range[0] = 0;
-    if (range[1] == -DBL_MAX)
-        range[1] = 1;
-    
-    TRACE("n:'%s' t:%d c:%d [%g,%g]", name, type, component,
-          range[0], range[1]);
-}
-
-/**
- * \brief Clear field range hashtables and free memory
- */
-void Renderer::clearFieldRanges()
-{
-    TRACE("Deleting Field Ranges");
-    for (FieldRangeHashmap::iterator itr = _scalarPointDataRange.begin();
-         itr != _scalarPointDataRange.end(); ++itr) {
-        delete [] itr->second;
-    }
-    _scalarPointDataRange.clear();
-    for (FieldRangeHashmap::iterator itr = _scalarCellDataRange.begin();
-         itr != _scalarCellDataRange.end(); ++itr) {
-        delete [] itr->second;
-    }
-    _scalarCellDataRange.clear();
-    for (FieldRangeHashmap::iterator itr = _vectorPointDataRange.begin();
-         itr != _vectorPointDataRange.end(); ++itr) {
-        delete [] itr->second;
-    }
-    _vectorPointDataRange.clear();
-    for (int i = 0; i < 3; i++) {
-        for (FieldRangeHashmap::iterator itr = _vectorCompPointDataRange[i].begin();
-             itr != _vectorCompPointDataRange[i].end(); ++itr) {
-            delete [] itr->second;
-        }
-        _vectorCompPointDataRange[i].clear();
-    }
-    for (FieldRangeHashmap::iterator itr = _vectorCellDataRange.begin();
-         itr != _vectorCellDataRange.end(); ++itr) {
-        delete [] itr->second;
-    }
-    _vectorCellDataRange.clear();
-    for (int i = 0; i < 3; i++) {
-        for (FieldRangeHashmap::iterator itr = _vectorCompCellDataRange[i].begin();
-             itr != _vectorCompCellDataRange[i].end(); ++itr) {
-            delete [] itr->second;
-        }
-        _vectorCompCellDataRange[i].clear();
-    }
-}
-
-/**
- * \brief Clear user-defined field range hashtables and free memory
- */
-void Renderer::clearUserFieldRanges()
-{
-    TRACE("Deleting User Field Ranges");
-    for (FieldRangeHashmap::iterator itr = _userScalarPointDataRange.begin();
-         itr != _userScalarPointDataRange.end(); ++itr) {
-        delete [] itr->second;
-    }
-    _userScalarPointDataRange.clear();
-    for (FieldRangeHashmap::iterator itr = _userScalarCellDataRange.begin();
-         itr != _userScalarCellDataRange.end(); ++itr) {
-        delete [] itr->second;
-    }
-    _userScalarCellDataRange.clear();
-    for (FieldRangeHashmap::iterator itr = _userVectorPointDataRange.begin();
-         itr != _userVectorPointDataRange.end(); ++itr) {
-        delete [] itr->second;
-    }
-    _userVectorPointDataRange.clear();
-    for (int i = 0; i < 3; i++) {
-        for (FieldRangeHashmap::iterator itr = _userVectorCompPointDataRange[i].begin();
-             itr != _userVectorCompPointDataRange[i].end(); ++itr) {
-            delete [] itr->second;
-        }
-        _userVectorCompPointDataRange[i].clear();
-    }
-    for (FieldRangeHashmap::iterator itr = _userVectorCellDataRange.begin();
-         itr != _userVectorCellDataRange.end(); ++itr) {
-        delete [] itr->second;
-    }
-    _userVectorCellDataRange.clear();
-    for (int i = 0; i < 3; i++) {
-        for (FieldRangeHashmap::iterator itr = _userVectorCompCellDataRange[i].begin();
-             itr != _userVectorCompCellDataRange[i].end(); ++itr) {
-            delete [] itr->second;
-        }
-        _userVectorCompCellDataRange[i].clear();
-    }
-}
-
-/**
- * \brief Set up hashtables for min/max values of all fields from loaded 
- * datasets
- *
- * Note that this method does not set the ranges, it just creates the table 
- * entries
- */
-void Renderer::initFieldRanges()
-{
-    clearFieldRanges();
-
-    for (DataSetHashmap::iterator itr = _dataSets.begin();
-         itr != _dataSets.end(); ++itr) {
-        DataSet *ds = itr->second;
-        std::vector<std::string> names;
-        ds->getFieldNames(names, DataSet::POINT_DATA, 1);
-        for (std::vector<std::string>::iterator itr = names.begin();
-             itr != names.end(); ++itr) {
-            FieldRangeHashmap::iterator fritr = 
-                _scalarPointDataRange.find(*itr);
-            if (fritr == _scalarPointDataRange.end()) {
-                _scalarPointDataRange[*itr] = new double[2];
-                _scalarPointDataRange[*itr][0] = 0;
-                _scalarPointDataRange[*itr][1] = 1;
-            }
-        }
-        names.clear();
-        ds->getFieldNames(names, DataSet::CELL_DATA, 1);
-        for (std::vector<std::string>::iterator itr = names.begin();
-             itr != names.end(); ++itr) {
-            FieldRangeHashmap::iterator fritr = 
-                _scalarCellDataRange.find(*itr);
-            if (fritr == _scalarCellDataRange.end()) {
-                _scalarCellDataRange[*itr] = new double[2];
-                _scalarCellDataRange[*itr][0] = 0;
-                _scalarCellDataRange[*itr][1] = 1;
-            }
-        }
-        names.clear();
-        ds->getFieldNames(names, DataSet::POINT_DATA, 3);
-        for (std::vector<std::string>::iterator itr = names.begin();
-             itr != names.end(); ++itr) {
-            FieldRangeHashmap::iterator fritr = 
-                _vectorPointDataRange.find(*itr);
-            if (fritr == _vectorPointDataRange.end()) {
-                _vectorPointDataRange[*itr] = new double[2];
-                _vectorPointDataRange[*itr][0] = 0;
-                _vectorPointDataRange[*itr][1] = 1;
-            }
-            for (int i = 0; i < 3; i++) {
-                fritr = _vectorCompPointDataRange[i].find(*itr);
-                if (fritr == _vectorCompPointDataRange[i].end()) {
-                    _vectorCompPointDataRange[i][*itr] = new double[2];
-                    _vectorCompPointDataRange[i][*itr][0] = 0;
-                    _vectorCompPointDataRange[i][*itr][1] = 1;
-                }
-            }
-        }
-        names.clear();
-        ds->getFieldNames(names, DataSet::CELL_DATA, 3);
-        for (std::vector<std::string>::iterator itr = names.begin();
-             itr != names.end(); ++itr) {
-            FieldRangeHashmap::iterator fritr = 
-                _vectorCellDataRange.find(*itr);
-            if (fritr == _vectorCellDataRange.end()) {
-                _vectorCellDataRange[*itr] = new double[2];
-                _vectorCellDataRange[*itr][0] = 0;
-                _vectorCellDataRange[*itr][1] = 1;
-            }
-            for (int i = 0; i < 3; i++) {
-                fritr = _vectorCompCellDataRange[i].find(*itr);
-                if (fritr == _vectorCompCellDataRange[i].end()) {
-                    _vectorCompCellDataRange[i][*itr] = new double[2];
-                    _vectorCompCellDataRange[i][*itr][0] = 0;
-                    _vectorCompCellDataRange[i][*itr][1] = 1;
-                }
-            }
-        }
-    }
-}
-
-/**
- * \brief Returns boolean flag indicating if cumulative data ranges 
- * should be used
- */
-bool Renderer::getUseCumulativeRange()
-{
-    return _useCumulativeRange;
-}
-
-/**
- * \brief Set explicit range to use for mapping fields
- */
-bool Renderer::setCumulativeDataRange(double *range, const char *name,
-                                      DataSet::DataAttributeType type,
-                                      int numComponents,
-                                      int component)
-{
-    if (range == NULL || name == NULL)
-        return false;
-
-    _useCumulativeRange = true;
-    bool found = false;
-
-    switch (type) {
-    case DataSet::POINT_DATA: {
-        FieldRangeHashmap::iterator itr;
-        if (numComponents == 1) {
-            itr = _userScalarPointDataRange.find(name);
-            if (itr == _userScalarPointDataRange.end()) {
-                _userScalarPointDataRange[name] = new double[2];
-                memcpy(_userScalarPointDataRange[name], range, sizeof(double)*2);
-            } else {
-                found = true;
-                memcpy(itr->second, range, sizeof(double)*2);
-            }
-        } else if (numComponents == 3) {
-            if (component == -1) {
-                itr = _userVectorPointDataRange.find(name);
-                if (itr == _userVectorPointDataRange.end()) {
-                    _userVectorPointDataRange[name] = new double[2];
-                    memcpy(itr->second, _userVectorPointDataRange[name], sizeof(double)*2);
-                } else {
-                    found = true;
-                    memcpy(itr->second, range, sizeof(double)*2);
-                }
-                return found;
-            } else if (component >= 0 && component <= 3) {
-                itr = _userVectorCompPointDataRange[component].find(name);
-                if (itr == _userVectorCompPointDataRange[component].end()) {
-                    _userVectorCompPointDataRange[component][name] = new double[2];
-                    memcpy(_userVectorCompPointDataRange[component][name], range, sizeof(double)*2);
-                } else {
-                    found = true;
-                    memcpy(itr->second, range, sizeof(double)*2);
-                }
-            }
-        }
-    }
-        break;
-    case DataSet::CELL_DATA: {
-        FieldRangeHashmap::iterator itr;
-        if (numComponents == 1) {
-            itr = _userScalarCellDataRange.find(name);
-            if (itr == _userScalarCellDataRange.end()) {
-                _userScalarCellDataRange[name] = new double[2];
-                memcpy(_userScalarCellDataRange[name], range, sizeof(double)*2);
-            } else {
-                found = true;
-                memcpy(itr->second, range, sizeof(double)*2);
-            }
-        } else if (numComponents == 3) {
-            if (component == -1) {
-                itr = _userVectorCellDataRange.find(name);
-                if (itr == _userVectorCellDataRange.end()) {
-                    _userVectorCellDataRange[name] = new double[2];
-                    memcpy(_userVectorCellDataRange[name], range, sizeof(double)*2);
-                } else {
-                    found = true;
-                    memcpy(itr->second, range, sizeof(double)*2);
-                }
-            } else if (component >= 0 && component <= 3) {
-                itr = _userVectorCompCellDataRange[component].find(name);
-                if (itr == _userVectorCompCellDataRange[component].end()) {
-                    _userVectorCompCellDataRange[component][name] = new double[2];
-                    memcpy(_userVectorCompCellDataRange[component][name], range, sizeof(double)*2);
-                } else {
-                    found = true;
-                    memcpy(itr->second, range, sizeof(double)*2);
-                }
-            }
-        }
-    }
-        break;
-    default:
-        ERROR("Bad Field Type");
-    }
-
-    // Notify graphics objects of new ranges
-    updateFieldRanges();
-    // Bounds may have changed
-    sceneBoundsChanged();
-    _needsRedraw = true;
-
-    TRACE("Field: %s found: %d range: %g %g", name, (found ? 1 : 0), range[0], range[1]);
-    return found;
-}
-
-/**
- * \brief Get the cumulative range across all DataSets for a point
- * data field if it exists, otherwise a cell data field if it exists
- *
- * \param[out] range Pointer to an array of 2 doubles
- * \param[in] name Field name
- * \param[in] numComponents Number of components in field
- * \param[in] component Index of component or -1 for magnitude/scalar
- * \return boolean indicating if field was found
- */
-bool Renderer::getCumulativeDataRange(double *range, const char *name,
-                                      int numComponents,
-                                      int component)
-{
-    bool ret;
-    if (!(ret = getCumulativeDataRange(range, name, DataSet::POINT_DATA,
-                                       numComponents, component)))
-        ret = getCumulativeDataRange(range, name, DataSet::CELL_DATA,
-                                     numComponents, component);
-    return ret;
-}
-
-/**
- * \brief Get the cumulative range across all DataSets for a field
- *
- * \param[out] range Pointer to an array of 2 doubles
- * \param[in] name Field name
- * \param[in] type DataAttributeType of field
- * \param[in] numComponents Number of components in field
- * \param[in] component Index of component or -1 for magnitude/scalar
- * \return boolean indicating if field was found
- */
-bool Renderer::getCumulativeDataRange(double *range, const char *name,
-                                      DataSet::DataAttributeType type,
-                                      int numComponents,
-                                      int component)
-{
-    if (range == NULL || name == NULL)
-        return false;
-
-    switch (type) {
-    case DataSet::POINT_DATA: {
-        FieldRangeHashmap::iterator itr;
-        if (numComponents == 1) {
-            itr = _userScalarPointDataRange.find(name);
-            if (itr == _userScalarPointDataRange.end()) {
-                itr = _scalarPointDataRange.find(name);
-                if (itr == _scalarPointDataRange.end()) {
-                    return false;
-                }
-            }
-            memcpy(range, itr->second, sizeof(double)*2);
-            return true;
-        } else if (numComponents == 3) {
-            if (component == -1) {
-                itr = _userVectorPointDataRange.find(name);
-                if (itr == _userVectorPointDataRange.end()) {
-                    itr = _vectorPointDataRange.find(name);
-                    if (itr == _vectorPointDataRange.end()) {
-                        return false;
-                    }
-                }
-                memcpy(range, itr->second, sizeof(double)*2);
-                return true;
-            } else if (component >= 0 && component <= 3) {
-                itr = _userVectorCompPointDataRange[component].find(name);
-                if (itr == _userVectorCompPointDataRange[component].end()) {
-                    itr = _vectorCompPointDataRange[component].find(name);
-                    if (itr == _vectorCompPointDataRange[component].end()) {
-                        return false;
-                    }
-                }
-                memcpy(range, itr->second, sizeof(double)*2);
-                return true;
-            }
-        }
-    }
-        break;
-    case DataSet::CELL_DATA: {
-        FieldRangeHashmap::iterator itr;
-        if (numComponents == 1) {
-            itr = _userScalarCellDataRange.find(name);
-            if (itr == _userScalarCellDataRange.end()) {
-                itr = _scalarCellDataRange.find(name);
-                if (itr == _scalarCellDataRange.end()) {
-                    return false;
-                }
-            }
-            memcpy(range, itr->second, sizeof(double)*2);
-            return true;
-        } else if (numComponents == 3) {
-            if (component == -1) {
-                itr = _userVectorCellDataRange.find(name);
-                if (itr == _userVectorCellDataRange.end()) {
-                    itr = _vectorCellDataRange.find(name);
-                    if (itr == _vectorCellDataRange.end()) {
-                        return false;
-                    }
-                }
-                memcpy(range, itr->second, sizeof(double)*2);
-                return true;
-            } else if (component >= 0 && component <= 3) {
-                itr = _userVectorCompCellDataRange[component].find(name);
-                if (itr == _userVectorCompCellDataRange[component].end()) {
-                    itr = _vectorCompCellDataRange[component].find(name);
-                    if (itr == _vectorCompCellDataRange[component].end()) {
-                        return false;
-                    }
-                }
-                memcpy(range, itr->second, sizeof(double)*2);
-                return true;
-            }
-        }
-    }
-        break;
-    default:
-        break;
-    }
-    return false;
-}
-
-void Renderer::collectDataRanges()
-{
-    for (FieldRangeHashmap::iterator itr = _scalarPointDataRange.begin();
-         itr != _scalarPointDataRange.end(); ++itr) {
-        collectDataRanges(itr->second, itr->first.c_str(),
-                          DataSet::POINT_DATA, -1,
-                          _cumulativeRangeOnlyVisible);
-    }
-    for (FieldRangeHashmap::iterator itr = _scalarCellDataRange.begin();
-         itr != _scalarCellDataRange.end(); ++itr) {
-        collectDataRanges(itr->second, itr->first.c_str(),
-                          DataSet::CELL_DATA, -1,
-                          _cumulativeRangeOnlyVisible);
-    }
-    for (FieldRangeHashmap::iterator itr = _vectorPointDataRange.begin();
-         itr != _vectorPointDataRange.end(); ++itr) {
-        collectDataRanges(itr->second, itr->first.c_str(),
-                          DataSet::POINT_DATA, -1,
-                          _cumulativeRangeOnlyVisible);
-    }
-    for (int i = 0; i < 3; i++) {
-        for (FieldRangeHashmap::iterator itr = _vectorCompPointDataRange[i].begin();
-             itr != _vectorCompPointDataRange[i].end(); ++itr) {
-            collectDataRanges(itr->second, itr->first.c_str(),
-                              DataSet::POINT_DATA, i,
-                              _cumulativeRangeOnlyVisible);
-        }
-    }
-    for (FieldRangeHashmap::iterator itr = _vectorCellDataRange.begin();
-         itr != _vectorCellDataRange.end(); ++itr) {
-        collectDataRanges(itr->second, itr->first.c_str(),
-                          DataSet::CELL_DATA, -1,
-                          _cumulativeRangeOnlyVisible);
-    }
-    for (int i = 0; i < 3; i++) {
-        for (FieldRangeHashmap::iterator itr = _vectorCompCellDataRange[i].begin();
-             itr != _vectorCompCellDataRange[i].end(); ++itr) {
-            collectDataRanges(itr->second, itr->first.c_str(),
-                              DataSet::CELL_DATA, i,
-                              _cumulativeRangeOnlyVisible);
-        }
-    }
-}
-
-/**
- * \brief Determines if AABB lies in a principal axis plane
- * and if so, returns the plane normal
- */
-bool Renderer::is2D(const double bounds[6],
-                    PrincipalPlane *plane,
-                    double *offset) const
-{
-    if (bounds[4] == bounds[5]) {
-        // Z = 0, XY plane
-        if (plane)
-            *plane = PLANE_XY;
-        if (offset)
-            *offset = bounds[4];
-        return true;
-    } else if (bounds[0] == bounds[1]) {
-        // X = 0, ZY plane
-        if (plane)
-            *plane = PLANE_ZY;
-        if (offset)
-            *offset = bounds[0];
-        return true;
-    } else if (bounds[2] == bounds[3]) {
-        // Y = 0, XZ plane
-        if (plane)
-            *plane = PLANE_XZ;
-        if (offset)
-            *offset = bounds[2];
-        return true;
-    }
-    *plane = PLANE_XY;
-    *offset = 0;
-    return false;
-}
-
-/**
- * \brief Initialize the camera zoom region to include the bounding volume given
- */
-void Renderer::initCamera(bool initCameraMode)
-{
-#ifdef WANT_TRACE
-    switch (_cameraMode) {
-    case IMAGE:
-        TRACE("Image camera");
-        break;
-    case ORTHO:
-        TRACE("Ortho camera");
-        break;
-    case PERSPECTIVE:
-        TRACE("Perspective camera");
-        break;
-    default:
-        TRACE("Unknown camera mode");
-    }
-#endif
-    // Clear user requested zoom region
-    _userImgWorldOrigin[0] = 0;
-    _userImgWorldOrigin[1] = 0;
-    _userImgWorldDims[0] = -1;
-    _userImgWorldDims[1] = -1;
-
-    double bounds[6];
-    collectBounds(bounds, false);
-    bool twod = is2D(bounds, &_imgCameraPlane, &_imgCameraOffset);
-    if (twod) {
-        if (initCameraMode) {
-            TRACE("Changing camera mode to image");
-            _cameraMode = IMAGE;
-        }
-        if (_imgCameraPlane == PLANE_ZY) {
-            _imgWorldOrigin[0] = bounds[4];
-            _imgWorldOrigin[1] = bounds[2];
-            _imgWorldDims[0] = bounds[5] - bounds[4];
-            _imgWorldDims[1] = bounds[3] - bounds[2];
-        } else if (_imgCameraPlane == PLANE_XZ) {
-            _imgWorldOrigin[0] = bounds[0];
-            _imgWorldOrigin[1] = bounds[4];
-            _imgWorldDims[0] = bounds[1] - bounds[0];
-            _imgWorldDims[1] = bounds[5] - bounds[4];
-        } else {
-            _imgWorldOrigin[0] = bounds[0];
-            _imgWorldOrigin[1] = bounds[2];
-            _imgWorldDims[0] = bounds[1] - bounds[0];
-            _imgWorldDims[1] = bounds[3] - bounds[2];
-        }
-    } else {
-        _imgWorldOrigin[0] = bounds[0];
-        _imgWorldOrigin[1] = bounds[2];
-        _imgWorldDims[0] = bounds[1] - bounds[0];
-        _imgWorldDims[1] = bounds[3] - bounds[2];
-    }
-
-    _cameraPan[0] = 0;
-    _cameraPan[1] = 0;
-    _cameraZoomRatio = 1;
-
-    switch (_cameraMode) {
-    case IMAGE:
-        //_renderer->ResetCamera(bounds);
-        _setCameraZoomRegion(_imgWorldOrigin[0], _imgWorldOrigin[1],
-                             _imgWorldDims[0], _imgWorldDims[1]);
-        resetAxes(bounds);
-        break;
-    case ORTHO:
-        _renderer->GetActiveCamera()->ParallelProjectionOn();
-        resetAxes(bounds);
-        //_renderer->ResetCamera(bounds);
-        resetVtkCamera();
-        //computeScreenWorldCoords();
-        break;
-    case PERSPECTIVE:
-        _renderer->GetActiveCamera()->ParallelProjectionOff();
-        resetAxes(bounds);
-        //_renderer->ResetCamera(bounds);
-        resetVtkCamera();
-        //computeScreenWorldCoords();
-        break;
-    default:
-        ERROR("Unknown camera mode");
-    }
-
-#ifdef WANT_TRACE
-    printCameraInfo(_renderer->GetActiveCamera());
-#endif
-}
-
-#if 0
-/**
- * \brief Print debugging info about a vtkCamera
- */
-void Renderer::printCameraInfo(vtkCamera *camera)
-{
-    TRACE("pscale: %g, angle: %g, d: %g pos: %g %g %g, fpt: %g %g %g, vup: %g %g %g, clip: %g %g",
-          camera->GetParallelScale(),
-          camera->GetViewAngle(),
-          camera->GetDistance(),
-          camera->GetPosition()[0],
-          camera->GetPosition()[1],
-          camera->GetPosition()[2], 
-          camera->GetFocalPoint()[0],
-          camera->GetFocalPoint()[1],
-          camera->GetFocalPoint()[2],
-          camera->GetViewUp()[0],
-          camera->GetViewUp()[1],
-          camera->GetViewUp()[2],
-          camera->GetClippingRange()[0],
-          camera->GetClippingRange()[1]);
-}
-#endif
-
-/**
- * \brief Set the RGB background color to render into the image
- */
-void Renderer::setBackgroundColor(float color[3])
-{
-    _bgColor[0] = color[0];
-    _bgColor[1] = color[1];
-    _bgColor[2] = color[2];
-    _renderer->SetBackground(_bgColor[0], _bgColor[1], _bgColor[2]);
-    _needsRedraw = true;
-}
-
-/**
- * \brief Set the opacity of the specified DataSet's associated graphics objects
- */
-void Renderer::setDataSetOpacity(const DataSetId& id, double opacity)
-{
-    DataSetHashmap::iterator itr;
-
-    bool doAll = false;
-
-    if (id.compare("all") == 0) {
-        itr = _dataSets.begin();
-        if (itr == _dataSets.end())
-            return;
-        doAll = true;
-    } else {
-        itr = _dataSets.find(id);
-    }
-    if (itr == _dataSets.end()) {
-        ERROR("Unknown dataset %s", id.c_str());
-        return;
-    }
-
-    do {
-        itr->second->setOpacity(opacity);
-    } while (doAll && ++itr != _dataSets.end());
-
-    if (id.compare("all") == 0 || getGraphicsObject<Contour2D>(id) != NULL)
-        setGraphicsObjectOpacity<Contour2D>(id, opacity);
-    if (id.compare("all") == 0 || getGraphicsObject<Contour3D>(id) != NULL)
-        setGraphicsObjectOpacity<Contour3D>(id, opacity);
-    if (id.compare("all") == 0 || getGraphicsObject<Cutplane>(id) != NULL)
-        setGraphicsObjectOpacity<Cutplane>(id, opacity);
-    if (id.compare("all") == 0 || getGraphicsObject<Glyphs>(id) != NULL)
-        setGraphicsObjectOpacity<Glyphs>(id, opacity);
-    if (id.compare("all") == 0 || getGraphicsObject<HeightMap>(id) != NULL)
-        setGraphicsObjectOpacity<HeightMap>(id, opacity);
-    if (id.compare("all") == 0 || getGraphicsObject<LIC>(id) != NULL)
-        setGraphicsObjectOpacity<LIC>(id, opacity);
-    if (id.compare("all") == 0 || getGraphicsObject<Molecule>(id) != NULL)
-        setGraphicsObjectOpacity<Molecule>(id, opacity);
-    if (id.compare("all") == 0 || getGraphicsObject<Outline>(id) != NULL)
-        setGraphicsObjectOpacity<Outline>(id, opacity);
-    if (id.compare("all") == 0 || getGraphicsObject<PolyData>(id) != NULL)
-        setGraphicsObjectOpacity<PolyData>(id, opacity);
-    if (id.compare("all") == 0 || getGraphicsObject<PseudoColor>(id) != NULL)
-        setGraphicsObjectOpacity<PseudoColor>(id, opacity);
-    if (id.compare("all") == 0 || getGraphicsObject<Streamlines>(id) != NULL)
-        setGraphicsObjectOpacity<Streamlines>(id, opacity);
-    if (id.compare("all") == 0 || getGraphicsObject<Volume>(id) != NULL)
-        setGraphicsObjectOpacity<Volume>(id, opacity);
-    if (id.compare("all") == 0 || getGraphicsObject<Warp>(id) != NULL)
-        setGraphicsObjectOpacity<Warp>(id, opacity);
-
-    _needsRedraw = true;
-}
-
-/**
- * \brief Turn on/off rendering of the specified DataSet's associated graphics objects
- */
-void Renderer::setDataSetVisibility(const DataSetId& id, bool state)
-{
-    DataSetHashmap::iterator itr;
-
-    bool doAll = false;
-
-    if (id.compare("all") == 0) {
-        itr = _dataSets.begin();
-        doAll = true;
-        if (itr == _dataSets.end())
-            return;
-    } else {
-        itr = _dataSets.find(id);
-    }
-    if (itr == _dataSets.end()) {
-        ERROR("Unknown dataset %s", id.c_str());
-        return;
-    }
-
-    do {
-        itr->second->setVisibility(state);
-    } while (doAll && ++itr != _dataSets.end());
-
-    if (id.compare("all") == 0 || getGraphicsObject<Contour2D>(id) != NULL)
-        setGraphicsObjectVisibility<Contour2D>(id, state);
-    if (id.compare("all") == 0 || getGraphicsObject<Contour3D>(id) != NULL)
-        setGraphicsObjectVisibility<Contour3D>(id, state);
-    if (id.compare("all") == 0 || getGraphicsObject<Cutplane>(id) != NULL)
-        setGraphicsObjectVisibility<Cutplane>(id, state);
-    if (id.compare("all") == 0 || getGraphicsObject<Glyphs>(id) != NULL)
-        setGraphicsObjectVisibility<Glyphs>(id, state);
-    if (id.compare("all") == 0 || getGraphicsObject<HeightMap>(id) != NULL)
-        setGraphicsObjectVisibility<HeightMap>(id, state);
-    if (id.compare("all") == 0 || getGraphicsObject<LIC>(id) != NULL)
-        setGraphicsObjectVisibility<LIC>(id, state);
-    if (id.compare("all") == 0 || getGraphicsObject<Molecule>(id) != NULL)
-        setGraphicsObjectVisibility<Molecule>(id, state);
-    if (id.compare("all") == 0 || getGraphicsObject<Outline>(id) != NULL)
-        setGraphicsObjectVisibility<Outline>(id, state);
-    if (id.compare("all") == 0 || getGraphicsObject<PolyData>(id) != NULL)
-        setGraphicsObjectVisibility<PolyData>(id, state);
-    if (id.compare("all") == 0 || getGraphicsObject<PseudoColor>(id) != NULL)
-        setGraphicsObjectVisibility<PseudoColor>(id, state);
-    if (id.compare("all") == 0 || getGraphicsObject<Streamlines>(id) != NULL)
-        setGraphicsObjectVisibility<Streamlines>(id, state);
-    if (id.compare("all") == 0 || getGraphicsObject<Volume>(id) != NULL)
-        setGraphicsObjectVisibility<Volume>(id, state);
-    if (id.compare("all") == 0 || getGraphicsObject<Warp>(id) != NULL)
-        setGraphicsObjectVisibility<Warp>(id, state);
-
-    _needsRedraw = true;
-}
-
-/**
- * \brief Set a user clipping plane
- *
- * TODO: Fix clip plane positions after a change in actor bounds
- */
-void Renderer::setClipPlane(Axis axis, double ratio, int direction)
-{
-    double bounds[6];
-    collectBounds(bounds, false);
-
-    switch (axis) {
-    case X_AXIS:
-        if (direction > 0) {
-            if (ratio > 0.0) {
-                if (_userClipPlanes[0] == NULL) {
-                    _userClipPlanes[0] = vtkSmartPointer<vtkPlane>::New();
-                    _userClipPlanes[0]->SetNormal(1, 0, 0);
-                }
-                _userClipPlanes[0]->SetOrigin(bounds[0] + (bounds[1]-bounds[0])*ratio, 0, 0);
-            } else {
-                _userClipPlanes[0] = NULL;
-            }
-        } else {
-            if (ratio < 1.0) {
-                if (_userClipPlanes[1] == NULL) {
-                    _userClipPlanes[1] = vtkSmartPointer<vtkPlane>::New();
-                    _userClipPlanes[1]->SetNormal(-1, 0, 0);
-                }
-                _userClipPlanes[1]->SetOrigin(bounds[0] + (bounds[1]-bounds[0])*ratio, 0, 0);
-            } else {
-                _userClipPlanes[1] = NULL;
-            }
-        }
-        break;
-    case Y_AXIS:
-        if (direction > 0) {
-            if (ratio > 0.0) {
-                if (_userClipPlanes[2] == NULL) {
-                    _userClipPlanes[2] = vtkSmartPointer<vtkPlane>::New();
-                    _userClipPlanes[2]->SetNormal(0, 1, 0);
-                }
-                _userClipPlanes[2]->SetOrigin(0, bounds[2] + (bounds[3]-bounds[2])*ratio, 0);
-            } else {
-                _userClipPlanes[2] = NULL;
-            }
-        } else {
-            if (ratio < 1.0) {
-                if (_userClipPlanes[3] == NULL) {
-                    _userClipPlanes[3] = vtkSmartPointer<vtkPlane>::New();
-                    _userClipPlanes[3]->SetNormal(0, -1, 0);
-                }
-                _userClipPlanes[3]->SetOrigin(0, bounds[2] + (bounds[3]-bounds[2])*ratio, 0);
-            } else {
-                _userClipPlanes[3] = NULL;
-            }
-        }
-        break;
-    case Z_AXIS:
-        if (direction > 0) {
-            if (ratio > 0.0) {
-                if (_userClipPlanes[4] == NULL) {
-                    _userClipPlanes[4] = vtkSmartPointer<vtkPlane>::New();
-                    _userClipPlanes[4]->SetNormal(0, 0, 1);
-                }
-                _userClipPlanes[4]->SetOrigin(0, 0, bounds[4] + (bounds[5]-bounds[4])*ratio);
-            } else {
-                _userClipPlanes[4] = NULL;
-            }
-        } else {
-            if (ratio < 1.0) {
-                if (_userClipPlanes[5] == NULL) {
-                    _userClipPlanes[5] = vtkSmartPointer<vtkPlane>::New();
-                    _userClipPlanes[5]->SetNormal(0, 0, -1);
-                }
-                _userClipPlanes[5]->SetOrigin(0, 0, bounds[4] + (bounds[5]-bounds[4])*ratio);
-            } else {
-                _userClipPlanes[5] = NULL;
-            }
-        }
-        break;
-    default:
-        ;
-    }
-
-    _needsRedraw = true;
-}
-
-/**
- * \brief Set up clipping planes for image camera mode if needed
- */
-void Renderer::setCameraClippingPlanes()
-{
-    /* XXX: Note that there appears to be a bug with setting the 
-     * clipping plane collection to NULL in the VTK Mappers -- 
-     * the old clip planes are still applied.  The workaround here 
-     * is to keep the PlaneCollection and add/remove the planes 
-     * to/from the PlaneCollection as needed.
-     */
-    if (_cameraMode == IMAGE) {
-        if (_activeClipPlanes->GetNumberOfItems() == 0) {
-            for (int i = 0; i < 4; i++)
-                _activeClipPlanes->AddItem(_cameraClipPlanes[i]);
-        }
-    } else {
-        if (_activeClipPlanes->GetNumberOfItems() > 0)
-            _activeClipPlanes->RemoveAllItems();
-        for (int i = 0; i < 6; i++) {
-            if (_userClipPlanes[i] != NULL) {
-                _activeClipPlanes->AddItem(_userClipPlanes[i]);
-            }
-        }
-    }
-
-    /* Ensure all Mappers are using the PlaneCollection
-     * This will not change the state or timestamp of 
-     * Mappers already using the PlaneCollection
-     */
-    setGraphicsObjectClippingPlanes<Arc>(_activeClipPlanes);
-    setGraphicsObjectClippingPlanes<Arrow>(_activeClipPlanes);
-    setGraphicsObjectClippingPlanes<Box>(_activeClipPlanes);
-    setGraphicsObjectClippingPlanes<Cone>(_activeClipPlanes);
-    setGraphicsObjectClippingPlanes<Contour2D>(_activeClipPlanes);
-    setGraphicsObjectClippingPlanes<Contour3D>(_activeClipPlanes);
-    setGraphicsObjectClippingPlanes<Cutplane>(_activeClipPlanes);
-    setGraphicsObjectClippingPlanes<Cylinder>(_activeClipPlanes);
-    setGraphicsObjectClippingPlanes<Disk>(_activeClipPlanes);
-    setGraphicsObjectClippingPlanes<Glyphs>(_activeClipPlanes);
-    setGraphicsObjectClippingPlanes<Group>(_activeClipPlanes);
-    setGraphicsObjectClippingPlanes<HeightMap>(_activeClipPlanes);
-    setGraphicsObjectClippingPlanes<LIC>(_activeClipPlanes);
-    setGraphicsObjectClippingPlanes<Line>(_activeClipPlanes);
-    setGraphicsObjectClippingPlanes<Molecule>(_activeClipPlanes);
-    setGraphicsObjectClippingPlanes<Outline>(_activeClipPlanes);
-    setGraphicsObjectClippingPlanes<PolyData>(_activeClipPlanes);
-    setGraphicsObjectClippingPlanes<Polygon>(_activeClipPlanes);
-    setGraphicsObjectClippingPlanes<PseudoColor>(_activeClipPlanes);
-    setGraphicsObjectClippingPlanes<Sphere>(_activeClipPlanes);
-    setGraphicsObjectClippingPlanes<Streamlines>(_activeClipPlanes);
-    setGraphicsObjectClippingPlanes<Volume>(_activeClipPlanes);
-    setGraphicsObjectClippingPlanes<Warp>(_activeClipPlanes);
-}
-
-/**
- * \brief Control the use of two sided lighting
- */
-void Renderer::setUseTwoSidedLighting(bool state)
-{
-    _renderer->SetTwoSidedLighting(state ? 1 : 0);
-    _needsRedraw = true;
-}
-
-/**
- * \brief Control the use of the depth peeling algorithm for transparency
- */
-void Renderer::setUseDepthPeeling(bool state)
-{
-    _renderer->SetUseDepthPeeling(state ? 1 : 0);
-    _needsRedraw = true;
-}
-
-/**
- * \brief Sets flag to trigger rendering next time render() is called
- */
-void Renderer::eventuallyRender()
-{
-    _needsRedraw = true;
-}
-
-/**
- * \brief Cause the rendering to render a new image if needed
- *
- * The _needsRedraw flag indicates if a state change has occured since
- * the last rendered frame
- */
-bool Renderer::render()
-{
-    TRACE("Enter: redraw: %d axesReset: %d cameraReset: %d clippingRangeReset: %d",
-          _needsRedraw ? 1 : 0, _needsAxesReset ? 1 : 0, _needsCameraReset ? 1 : 0, _needsCameraClippingRangeReset ? 1 : 0);
-    if (_needsRedraw) {
-         if (_needsAxesReset) {
-            resetAxes();
-            _needsAxesReset = false;
-        }
-        if (_needsCameraReset) {
-            initCamera();
-            _needsCameraReset = false;
-            _needsCameraClippingRangeReset = false;
-        } else if (_needsCameraClippingRangeReset && _cameraMode != IMAGE) {
-            resetCameraClippingRange();
-            _needsCameraClippingRangeReset = false;
-        }
-        setCameraClippingPlanes();
-        _renderWindow->Render();
-        _needsRedraw = false;
-        return true;
-    } else
-        return false;
-}
-
-/// Get the pixel width of the render window/image
-int Renderer::getWindowWidth() const
-{
-    return _windowWidth;
-}
-
-/// Get the pixel height of the render window/image
-int Renderer::getWindowHeight() const
-{
-    return _windowHeight;
-}
-
-/**
- * \brief Read back the rendered framebuffer image
- */
-void Renderer::getRenderedFrame(vtkUnsignedCharArray *imgData)
-{
-#ifdef RENDER_TARGA
-    _renderWindow->MakeCurrent();
-    // Must clear previous errors first.
-    while (glGetError() != GL_NO_ERROR){
-        ;
-    }
-    int bytesPerPixel = TARGA_BYTES_PER_PIXEL;
-    int size = bytesPerPixel * _windowWidth * _windowHeight;
-
-    if (imgData->GetMaxId() + 1 != size)
-    {
-        imgData->SetNumberOfComponents(bytesPerPixel);
-        imgData->SetNumberOfValues(size);
-    }
-    glDisable(GL_TEXTURE_2D);
-    if (_renderWindow->GetDoubleBuffer()) {
-        glReadBuffer(static_cast<GLenum>(vtkOpenGLRenderWindow::SafeDownCast(_renderWindow)->GetBackLeftBuffer()));
-    } else {
-        glReadBuffer(static_cast<GLenum>(vtkOpenGLRenderWindow::SafeDownCast(_renderWindow)->GetFrontLeftBuffer()));
-    }
-    glPixelStorei(GL_PACK_ALIGNMENT, 1);
-#ifdef WANT_TRACE
-    struct timeval t1, t2;
-    glFinish();
-    gettimeofday(&t1, 0);
-#endif
-    if (bytesPerPixel == 4) {
-        glReadPixels(0, 0, _windowWidth, _windowHeight, GL_BGRA,
-                     GL_UNSIGNED_BYTE, imgData->GetPointer(0));
-    } else {
-        glReadPixels(0, 0, _windowWidth, _windowHeight, GL_BGR,
-                     GL_UNSIGNED_BYTE, imgData->GetPointer(0));
-    }
-#ifdef WANT_TRACE
-    gettimeofday(&t2, 0);
-    static unsigned int numFrames = 0;
-    static double accum = 0;
-    numFrames++;
-    accum += MSECS_ELAPSED(t1, t2);
-#endif
-    TRACE("Readback time: %g ms", MSECS_ELAPSED(t1, t2));
-    TRACE("Readback avg: %g ms", accum/numFrames);
-    if (glGetError() != GL_NO_ERROR) {
-        ERROR("glReadPixels");
-    }
-#else
-    _renderWindow->GetPixelData(0, 0, _windowWidth-1, _windowHeight-1,
-                                !_renderWindow->GetDoubleBuffer(), imgData);
-#endif
-    TRACE("Image data size: %d", imgData->GetSize());
-}
-
-/**
- * \brief Get nearest data value given display coordinates x,y
- *
- * FIXME: This doesn't work when actors are scaled
- *
- * Note: no interpolation is performed on data
- */
-bool Renderer::getScalarValueAtPixel(const DataSetId& id, int x, int y, double *value)
-{
-    vtkSmartPointer<vtkCoordinate> coord = vtkSmartPointer<vtkCoordinate>::New();
-    coord->SetCoordinateSystemToDisplay();
-    coord->SetValue(x, _windowHeight - y, 0);
-    double *worldCoords = coord->GetComputedWorldValue(_renderer);
-
-    TRACE("Pixel coords: %d, %d\nWorld coords: %g, %g, %g", x, y,
-          worldCoords[0], 
-          worldCoords[1], 
-          worldCoords[2]);
-
-    return getScalarValue(id, worldCoords[0], worldCoords[1], worldCoords[2], value);
-}
-
-/**
- * \brief Get nearest data value given world coordinates x,y,z
- *
- * Note: no interpolation is performed on data
- */
-bool Renderer::getScalarValue(const DataSetId& id, double x, double y, double z, double *value)
-{
-    DataSet *ds = getDataSet(id);
-    if (ds == NULL)
-        return false;
-
-    return ds->getScalarValue(x, y, z, value);
-}
-
-/**
- * \brief Get nearest data value given display coordinates x,y
- *
- * Note: no interpolation is performed on data
- */
-bool Renderer::getVectorValueAtPixel(const DataSetId& id, int x, int y, double vector[3])
-{
-    vtkSmartPointer<vtkCoordinate> coord = vtkSmartPointer<vtkCoordinate>::New();
-    coord->SetCoordinateSystemToDisplay();
-    coord->SetValue(x, _windowHeight - y, 0);
-    double *worldCoords = coord->GetComputedWorldValue(_renderer);
-
-    TRACE("Pixel coords: %d, %d\nWorld coords: %g, %g, %g", x, y,
-          worldCoords[0], 
-          worldCoords[1], 
-          worldCoords[2]);
-
-    return getVectorValue(id, worldCoords[0], worldCoords[1], worldCoords[2], vector);
-}
-
-/**
- * \brief Get nearest data value given world coordinates x,y,z
- *
- * Note: no interpolation is performed on data
- */
-bool Renderer::getVectorValue(const DataSetId& id, double x, double y, double z, double vector[3])
-{
-    DataSet *ds = getDataSet(id);
-    if (ds == NULL)
-        return false;
-
-    return ds->getVectorValue(x, y, z, vector);
-}
Index: unk/packages/vizservers/vtkvis/RpVtkRenderer.h
===================================================================
--- /trunk/packages/vizservers/vtkvis/RpVtkRenderer.h	(revision 3615)
+++ 	(revision )
@@ -1,996 +1,0 @@
-/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
-/*
- * Copyright (C) 2004-2012  HUBzero Foundation, LLC
- *
- * Author: Leif Delgass <ldelgass@purdue.edu>
- */
-
-#ifndef VTKVIS_RENDERER_H
-#define VTKVIS_RENDERER_H
-
-#include <string>
-#include <vector>
-#include <tr1/unordered_map>
-#include <typeinfo>
-
-#include <vtkSmartPointer.h>
-#ifdef USE_CUSTOM_AXES
-#include "vtkRpCubeAxesActor.h"
-#else
-#include <vtkCubeAxesActor.h>
-#endif
-#include <vtkScalarBarActor.h>
-#include <vtkRenderer.h>
-#include <vtkRenderWindow.h>
-#include <vtkUnsignedCharArray.h>
-
-#include "ColorMap.h"
-#include "RpTypes.h"
-#include "RpVtkDataSet.h"
-#include "RpArc.h"
-#include "RpArrow.h"
-#include "RpBox.h"
-#include "RpCone.h"
-#include "RpContour2D.h"
-#include "RpContour3D.h"
-#include "RpCutplane.h"
-#include "RpCylinder.h"
-#include "RpDisk.h"
-#include "RpGlyphs.h"
-#include "RpGroup.h"
-#include "RpHeightMap.h"
-#include "RpLIC.h"
-#include "RpLine.h"
-#include "RpMolecule.h"
-#include "RpOutline.h"
-#include "RpPolyData.h"
-#include "RpPolygon.h"
-#include "RpPseudoColor.h"
-#include "RpSphere.h"
-#include "RpStreamlines.h"
-#include "RpVolume.h"
-#include "RpWarp.h"
-#include "Trace.h"
-
-// Controls if TGA format is sent to client
-//#define RENDER_TARGA
-#define TARGA_BYTES_PER_PIXEL 3
-
-namespace VtkVis {
-
-/**
- * \brief VTK Renderer
- */
-class Renderer
-{
-public:
-    Renderer();
-    virtual ~Renderer();
-
-    enum AxisRangeMode {
-        RANGE_AUTO = 0,
-        RANGE_SCALE_BOUNDS,
-        RANGE_EXPLICIT
-    };
-
-    enum AxesFlyMode {
-        FLY_OUTER_EDGES = 0,
-        FLY_CLOSEST_TRIAD,
-        FLY_FURTHEST_TRIAD,
-        FLY_STATIC_EDGES,
-        FLY_STATIC_TRIAD
-    };
-
-    enum AxesTickPosition {
-        TICKS_INSIDE,
-        TICKS_OUTSIDE,
-        TICKS_BOTH
-    };
-
-    enum CameraMode {
-        PERSPECTIVE,
-        ORTHO,
-        IMAGE
-    };
-
-    enum Aspect {
-        ASPECT_NATIVE,
-        ASPECT_SQUARE,
-        ASPECT_WINDOW
-    };
-
-    enum LegendType {
-        LEGEND_SCALAR,
-        LEGEND_VECTOR_MAGNITUDE,
-        LEGEND_VECTOR_X,
-        LEGEND_VECTOR_Y,
-        LEGEND_VECTOR_Z
-    };
-
-    typedef std::string DataSetId;
-    typedef std::string ColorMapId;
-    typedef std::string FieldId;
-
-    // Data sets
-
-    void addDataSet(const DataSetId& id);
-
-    void deleteDataSet(const DataSetId& id);
-
-    DataSet *getDataSet(const DataSetId& id);
-
-    void getDataSetNames(std::vector<std::string>& names);
-
-    bool setData(const DataSetId& id, char *data, int nbytes);
-
-    bool setDataFile(const DataSetId& id, const char *filename);
-
-    bool setDataSetActiveScalars(const DataSetId& id, const char *scalarName);
-
-    bool setDataSetActiveVectors(const DataSetId& id, const char *vectorName);
-
-    bool getScalarValueAtPixel(const DataSetId& id, int x, int y, double *value);
-
-    bool getScalarValue(const DataSetId& id, double x, double y, double z, double *value);
-
-    bool getVectorValueAtPixel(const DataSetId& id, int x, int y, double vector[3]);
-
-    bool getVectorValue(const DataSetId& id, double x, double y, double z, double vector[3]);
-
-    void setDataSetOpacity(const DataSetId& id, double opacity);
-
-    void setDataSetVisibility(const DataSetId& id, bool state);
-
-    void setUseCumulativeDataRange(bool state, bool onlyVisible = false);
-
-    bool getUseCumulativeRange();
-
-    bool setCumulativeDataRange(double *range, const char *name,
-                                DataSet::DataAttributeType type,
-                                int numComponents,
-                                int component = -1);
-
-    bool getCumulativeDataRange(double *range, const char *name,
-                                int numComponents,
-                                int component = -1);
-
-    bool getCumulativeDataRange(double *range, const char *name,
-                                DataSet::DataAttributeType type,
-                                int numComponents,
-                                int component = -1);
-
-    // Render window
-
-    /// Get the VTK render window object this Renderer uses
-    vtkRenderWindow *getRenderWindow()
-    {
-        return _renderWindow;
-    }
-
-    void setWindowSize(int width, int height);
-
-    int getWindowWidth() const;
-
-    int getWindowHeight() const;
-
-    // Camera controls
-
-    void setViewAngle(int height);
-
-    /// Return the VTK camera object this Renderer uses
-    vtkCamera *getVtkCamera()
-    {
-        if (_renderer != NULL)
-            return _renderer->GetActiveCamera();
-        else
-            return NULL;
-    }
-
-    bool isCameraMaximized()
-    {
-        return (_cameraZoomRatio == 1.0 &&
-                _cameraPan[0] == 0.0 &&
-                _cameraPan[1] == 0.0);
-    }
-
-    void getImageCameraSizes(int *imgWidthPx, int *imgHeightPx,
-                             int *_pxOffsetX = NULL, int *_pxOffsetY = NULL);
-
-    double getImageCameraAspect();
-
-    void setCameraMode(CameraMode mode);
-
-    CameraMode getCameraMode() const;
-
-    void setCameraAspect(Aspect aspect);
-
-    void resetVtkCamera(double *bounds = NULL);
-
-    void resetCamera(bool resetOrientation = true);
-
-    void resetCameraClippingRange();
-
-    bool setCameraZoomRegionPixels(int x, int y, int width, int height);
-
-    bool setCameraZoomRegion(double x, double y, double width, double height);
-
-    void getCameraZoomRegion(double xywh[4]) const;
-
-    void getScreenWorldCoords(double xywh[4]) const;
-
-    void rotateCamera(double yaw, double pitch, double roll);
-
-    void setCameraOrientation(const double quat[4], bool absolute = true);
-
-    void panCamera(double x, double y, bool absolute = true);
-
-    void zoomCamera(double z, bool absolute = true);
-
-    void setCameraOrientationAndPosition(const double position[3],
-                                         const double focalPoint[3],
-                                         const double viewUp[3]);
-
-    void getCameraOrientationAndPosition(double position[3],
-                                         double focalPoint[3],
-                                         double viewUp[3]);
-
-    void eventuallyResetCamera()
-    {
-        _needsCameraReset = true;
-    }
-
-    bool needsCameraReset()
-    {
-        return _needsCameraReset;
-    }
-
-    void eventuallyResetCameraClippingRange()
-    {
-        _needsCameraClippingRangeReset = true;
-    }
-
-    bool needsCameraClippingRangeReset()
-    {
-        return _needsCameraClippingRangeReset;
-    }
-
-    // Rendering an image
-
-    void setBackgroundColor(float color[3]);
-
-    void setClipPlane(Axis axis, double ratio, int direction);
-
-    void setUseTwoSidedLighting(bool state);
-
-    void setUseDepthPeeling(bool state);
-
-    void eventuallyRender();
-
-    bool render();
-
-    void getRenderedFrame(vtkUnsignedCharArray *imgData);
-
-    // Axes
-
-    void setAxesOrigin(double x, double y, double z, bool useCustom = true);
-
-    void setAxesAutoBounds(bool state);
-
-    void setAxesBounds(double min, double max);
-
-    void setAxesAutoRange(bool state);
-
-    void setAxisBounds(Axis axis, double min, double max);
-
-    void setAxesScale(double scale);
-
-    void setAxesRange(double min, double max);
-
-    void setAxesLabelPowerScaling(int xPow, int yPow, int zPow, bool useCustom = true);
-
-    void setAxisAutoBounds(Axis axis, bool state);
-
-    void setAxisAutoRange(Axis axis, bool state);
-
-    void setAxisScale(Axis axis, double scale);
-
-    void setAxisRange(Axis axis, double min, double max);
-
-    void setAxesFlyMode(AxesFlyMode mode);
-
-    void setAxesVisibility(bool state);
-
-    void setAxesGridVisibility(bool state);
-
-    void setAxesInnerGridVisibility(bool state);
-
-    void setAxesGridpolysVisibility(bool state);
-
-    void setAxesLabelVisibility(bool state);
-
-    void setAxesTickVisibility(bool state);
-
-    void setAxesMinorTickVisibility(bool state);
-
-    void setAxesTickPosition(AxesTickPosition pos);
-
-    void setAxesColor(double color[3], double opacity = 1.0);
-
-    void setAxesTitleColor(double color[3], double opacity = 1.0);
-
-    void setAxesLabelColor(double color[3], double opacity = 1.0);
-
-    void setAxesLinesColor(double color[3], double opacity = 1.0);
-
-    void setAxesGridlinesColor(double color[3], double opacity = 1.0);
-
-    void setAxesInnerGridlinesColor(double color[3], double opacity = 1.0);
-
-    void setAxesGridpolysColor(double color[3], double opacity = 1.0);
-
-    void setAxesLabelScaling(bool autoScale, int xpow, int ypow, int zpow);
-
-    void setAxesPixelFontSize(double screenSize);
-
-    void setAxesTitleFont(const char *fontName);
-
-    void setAxesTitleFontSize(int sz);
-
-    void setAxesTitleOrientation(double orientation);
-
-    void setAxesLabelFont(const char *fontName);
-
-    void setAxesLabelFontSize(int sz);
-
-    void setAxesLabelOrientation(double orientation);
-
-    void setAxesLabelFormat(const char *format);
-
-    void setAxisVisibility(Axis axis, bool state);
-
-    void setAxisGridVisibility(Axis axis, bool state);
-
-    void setAxisInnerGridVisibility(Axis axis, bool state);
-
-    void setAxisGridpolysVisibility(Axis axis, bool state);
-
-    void setAxisLabelVisibility(Axis axis, bool state);
-
-    void setAxisTickVisibility(Axis axis, bool state);
-
-    void setAxisMinorTickVisibility(Axis axis, bool state);
-
-    void setAxisColor(Axis axis, double color[3], double opacity = 1.0);
-
-    void setAxisTitleColor(Axis axis, double color[3], double opacity = 1.0);
-
-    void setAxisLabelColor(Axis axis, double color[3], double opacity = 1.0);
-
-    void setAxisLinesColor(Axis axis, double color[3], double opacity = 1.0);
-
-    void setAxisGridlinesColor(Axis axis, double color[3], double opacity = 1.0);
-
-    void setAxisInnerGridlinesColor(Axis axis, double color[3], double opacity = 1.0);
-
-    void setAxisGridpolysColor(Axis axis, double color[3], double opacity = 1.0);
-
-    void setAxisTitle(Axis axis, const char *title);
-
-    void setAxisUnits(Axis axis, const char *units);
-
-    void setAxisTitleFont(Axis axis, const char *fontName);
-
-    void setAxisTitleFontSize(Axis axis, int sz);
-
-    void setAxisTitleOrientation(Axis axis, double orientation);
-
-    void setAxisLabelFont(Axis axis, const char *fontName);
-
-    void setAxisLabelFontSize(Axis axis, int sz);
-
-    void setAxisLabelOrientation(Axis axis, double orientation);
-
-    void setAxisLabelFormat(Axis axis, const char *format);
-
-    void eventuallyResetAxes()
-    {
-        _needsAxesReset = true;
-    }
-
-    bool needsAxesReset()
-    {
-        return _needsAxesReset;
-    }
-
-    // Colormaps
-
-    void addColorMap(const ColorMapId& id, ColorMap *colorMap);
-
-    void deleteColorMap(const ColorMapId& id);
-
-    ColorMap *getColorMap(const ColorMapId& id);
-
-    void setColorMapNumberOfTableEntries(const ColorMapId& id, int numEntries);
-
-    bool renderColorMap(const ColorMapId& id, 
-                        const DataSetId& dataSetID,
-                        LegendType legendType,
-                        const char *fieldName,
-                        DataSet::DataAttributeType type,
-                        std::string& title,
-                        double range[2],
-                        int width, int height,
-                        bool opaque,
-                        int numLabels,
-                        vtkUnsignedCharArray *imgData);
-
-    bool renderColorMap(const ColorMapId& id, 
-                        const DataSetId& dataSetID,
-                        LegendType legendType,
-                        const char *fieldName,
-                        std::string& title,
-                        double range[2],
-                        int width, int height,
-                        bool opaque,
-                        int numLabels,
-                        vtkUnsignedCharArray *imgData);
-
-    bool renderColorMap(const ColorMapId& id, 
-                        const DataSetId& dataSetID,
-                        LegendType legendType,
-                        std::string& title,
-                        double range[2],
-                        int width, int height,
-                        bool opaque,
-                        int numLabels,
-                        vtkUnsignedCharArray *imgData);
-
-    // Generic VtkGraphicsObject methods
-
-    template<class GraphicsObject>
-    GraphicsObject *getGraphicsObject(const DataSetId& id);
-
-    template<class GraphicsObject>
-    bool addGraphicsObject(const DataSetId& id);
-
-    template<class GraphicsObject>
-    void deleteGraphicsObject(const DataSetId& id);
-
-    template<class GraphicsObject>
-    void deleteAllGraphicsObjects();
-
-    template<class GraphicsObject>
-    void mergeGraphicsObjectBounds(double *bounds, bool onlyVisible);
-
-    template<class GraphicsObject>
-    void mergeGraphicsObjectUnscaledBounds(double *bounds, bool onlyVisible);
-
-    template<class GraphicsObject>
-    void updateGraphicsObjectFieldRanges();
-
-    template<class GraphicsObject>
-    void setGraphicsObjectClippingPlanes(vtkPlaneCollection *planes);
-
-    template<class GraphicsObject>
-    void setGraphicsObjectAspect(double aspectRatio);
-
-    template<class GraphicsObject>
-    void setGraphicsObjectInterpolateBeforeMapping(const DataSetId& id, bool state);
-
-    template<class GraphicsObject>
-    void setGraphicsObjectColorMap(const DataSetId& id, const ColorMapId& colorMapId);
-
-    template<class GraphicsObject>
-    void updateGraphicsObjectColorMap(ColorMap *cmap);
-
-    template<class GraphicsObject>
-    bool graphicsObjectColorMapUsed(ColorMap *cmap);
-
-    template<class GraphicsObject>
-    void setGraphicsObjectVolumeSlice(const DataSetId& id, Axis axis, double ratio);
-
-    //   Prop/Prop3D properties
-
-    template<class GraphicsObject>
-    void setGraphicsObjectOrientation(const DataSetId& id, double quat[4]);
-
-    template<class GraphicsObject>
-    void setGraphicsObjectOrientation(const DataSetId& id, double angle, double axis[3]);
-
-    template<class GraphicsObject>
-    void setGraphicsObjectPosition(const DataSetId& id, double pos[3]);
-
-    template<class GraphicsObject>
-    void setGraphicsObjectAspect(const DataSetId& id, double aspect);
-
-    template<class GraphicsObject>
-    void setGraphicsObjectScale(const DataSetId& id, double scale[3]);
-
-    template<class GraphicsObject>
-    void setGraphicsObjectTransform(const DataSetId& id, vtkMatrix4x4 *trans);
-
-    template<class GraphicsObject>
-    void setGraphicsObjectVisibility(const DataSetId& id, bool state);
-
-    //   Actor properties
-
-    template<class GraphicsObject>
-    void setGraphicsObjectColor(const DataSetId& id, float color[3]);
-
-    template<class GraphicsObject>
-    void setGraphicsObjectEdgeVisibility(const DataSetId& id, bool state);
-
-    template<class GraphicsObject>
-    void setGraphicsObjectEdgeColor(const DataSetId& id, float color[3]);
-
-    template<class GraphicsObject>
-    void setGraphicsObjectEdgeWidth(const DataSetId& id, float edgeWidth);
-
-    template<class GraphicsObject>
-    void setGraphicsObjectAmbient(const DataSetId& id, double coeff);
-
-    template<class GraphicsObject>
-    void setGraphicsObjectDiffuse(const DataSetId& id, double coeff);
-
-    template<class GraphicsObject>
-    void setGraphicsObjectSpecular(const DataSetId& id, double coeff, double power);
-
-    template<class GraphicsObject>
-    void setGraphicsObjectLighting(const DataSetId& id, bool state);
-
-    template<class GraphicsObject>
-    void setGraphicsObjectOpacity(const DataSetId& id, double opacity);
-
-    template<class GraphicsObject>
-    void setGraphicsObjectPointSize(const DataSetId& id, float size);
-
-    template<class GraphicsObject>
-    void setGraphicsObjectWireframe(const DataSetId& id, bool state);
-
-    // Arcs
-
-    bool addArc(const DataSetId& id, double pt1[3], double pt2[3]);
-
-    void setArcResolution(const DataSetId& id, int res);
-
-    // Arrows
-
-    bool addArrow(const DataSetId& id, double tipRadius, double shaftRadius, double tipLength);
-
-    void setArrowResolution(const DataSetId& id, int resTip, int resShaft);
-
-    // Cones
-
-    bool addCone(const DataSetId& id, double radius, double height, bool cap);
-
-    void setConeResolution(const DataSetId& id, int res);
-
-    // 2D Contour plots
-
-    bool addContour2D(const DataSetId& id, int numContours);
-
-    bool addContour2D(const DataSetId& id, const std::vector<double>& contours);
-
-    void setContour2DContourField(const DataSetId& id, const char *fieldName);
-
-    void setContour2DNumContours(const DataSetId& id, int numContours);
-
-    void setContour2DContourList(const DataSetId& id, const std::vector<double>& contours);
-
-    void setContour2DColorMode(const DataSetId& id,
-                               Contour2D::ColorMode mode,
-                               const char *name, double range[2] = NULL);
-
-    void setContour2DColorMode(const DataSetId& id,
-                               Contour2D::ColorMode mode,
-                               DataSet::DataAttributeType type,
-                               const char *name, double range[2] = NULL);
-
-    // 3D Contour (isosurface) plots
-
-    bool addContour3D(const DataSetId& id, int numContours);
-
-    bool addContour3D(const DataSetId& id, const std::vector<double>& contours);
-
-    void setContour3DContourField(const DataSetId& id, const char *fieldName);
-
-    void setContour3DNumContours(const DataSetId& id, int numContours);
-
-    void setContour3DContourList(const DataSetId& id, const std::vector<double>& contours);
-
-    void setContour3DColorMode(const DataSetId& id,
-                               Contour3D::ColorMode mode,
-                               const char *name, double range[2] = NULL);
-
-    void setContour3DColorMode(const DataSetId& id,
-                               Contour3D::ColorMode mode,
-                               DataSet::DataAttributeType type,
-                               const char *name, double range[2] = NULL);
-
-    // Cutplanes
-
-    void setCutplaneOutlineVisibility(const DataSetId& id, bool state);
-
-    void setCutplaneSliceVisibility(const DataSetId& id, Axis axis, bool state);
-
-    void setCutplaneColorMode(const DataSetId& id,
-                              Cutplane::ColorMode mode,
-                              const char *name, double range[2] = NULL);
-
-    void setCutplaneColorMode(const DataSetId& id,
-                              Cutplane::ColorMode mode,
-                              DataSet::DataAttributeType type,
-                              const char *name, double range[2] = NULL);
-
-    // Cylinders
-
-    bool addCylinder(const DataSetId& id, double radius, double height, bool cap);
-
-    void setCylinderResolution(const DataSetId& id, int res);
-
-    // Disks
-
-    bool addDisk(const DataSetId& id, double innerRadius, double outerRadius);
-
-    void setDiskResolution(const DataSetId& id, int resRadial, int resCircum);
-
-    // Glyphs
-
-    bool addGlyphs(const DataSetId& id, Glyphs::GlyphShape shape);
-
-    void setGlyphsShape(const DataSetId& id, Glyphs::GlyphShape shape);
-
-    void setGlyphsOrientMode(const DataSetId& id, bool state, const char *name);
-
-    void setGlyphsColorMode(const DataSetId& id,
-                            Glyphs::ColorMode mode,
-                            const char *name,
-                            double range[2] = NULL);
-
-    void setGlyphsScalingMode(const DataSetId& id,
-                              Glyphs::ScalingMode mode,
-                              const char *name,
-                              double range[2] = NULL);
-
-    void setGlyphsNormalizeScale(const DataSetId& id, bool normalize);
-
-    void setGlyphsScaleFactor(const DataSetId& id, double scale);
-
-    // Height maps
-
-    bool addHeightMap(const DataSetId& id, int numContours, double heightScale);
-
-    bool addHeightMap(const DataSetId& id, const std::vector<double>& contours, double heightScale);
-
-    void setHeightMapHeightScale(const DataSetId& id, double scale);
-
-    void setHeightMapNumContours(const DataSetId& id, int numContours);
-
-    void setHeightMapContourList(const DataSetId& id, const std::vector<double>& contours);
-
-    void setHeightMapContourSurfaceVisibility(const DataSetId& id, bool state);
-
-    void setHeightMapContourLineVisibility(const DataSetId& id, bool state);
-
-    void setHeightMapContourLineColorMapEnabled(const DataSetId& id, bool mode);
-
-    void setHeightMapContourEdgeColor(const DataSetId& id, float color[3]);
-
-    void setHeightMapContourEdgeWidth(const DataSetId& id, float edgeWidth);
-
-    void setHeightMapColorMode(const DataSetId& id,
-                               HeightMap::ColorMode mode,
-                               const char *name, double range[2] = NULL);
-
-    void setHeightMapColorMode(const DataSetId& id,
-                               HeightMap::ColorMode mode,
-                               DataSet::DataAttributeType type,
-                               const char *name, double range[2] = NULL);
-
-
-    // Lines
-
-    bool addLine(const DataSetId& id, double pt1[3], double pt2[3]);
-
-    // Molecules
-
-    void setMoleculeAtomRadiusScale(const DataSetId& id, double scale);
-
-    void setMoleculeBondRadiusScale(const DataSetId& id, double scale);
-
-    void setMoleculeAtomScaling(const DataSetId& id, Molecule::AtomScaling scaling);
-
-    void setMoleculeAtomVisibility(const DataSetId& id, bool state);
-
-    void setMoleculeAtomLabelVisibility(const DataSetId& id, bool state);
-
-    void setMoleculeBondVisibility(const DataSetId& id, bool state);
-
-    void setMoleculeBondStyle(const DataSetId& id, Molecule::BondStyle style);
-
-    void setMoleculeBondColorMode(const DataSetId& id, Molecule::BondColorMode mode);
-
-    void setMoleculeBondColor(const DataSetId& id, float color[3]);
-
-    void setMoleculeColorMode(const DataSetId& id,
-                              Molecule::ColorMode mode,
-                              const char *name, double range[2] = NULL);
-
-    void setMoleculeColorMode(const DataSetId& id,
-                              Molecule::ColorMode mode,
-                              DataSet::DataAttributeType type,
-                              const char *name, double range[2] = NULL);
-
-    // N-sided Regular Polygons
-
-    bool addPolygon(const DataSetId& id, int numSides);
-
-    // Color-mapped surfaces
-
-    void setPseudoColorColorMode(const DataSetId& id,
-                                 PseudoColor::ColorMode mode,
-                                 const char *name, double range[2] = NULL);
-
-    void setPseudoColorColorMode(const DataSetId& id,
-                                 PseudoColor::ColorMode mode,
-                                 DataSet::DataAttributeType type,
-                                 const char *name, double range[2] = NULL);
-
-    // Spheres
-
-    void setSphereSection(const DataSetId& id, double thetaStart, double thetaEnd,
-                          double phiStart, double phiEnd);
-
-    void setSphereResolution(const DataSetId& id, int thetaRes, int phiRes);
-
-    // Streamlines
-
-    void setStreamlinesNumberOfSeedPoints(const DataSetId& id, int numPoints);
-
-    void setStreamlinesSeedToMeshPoints(const DataSetId& id);
-
-    void setStreamlinesSeedToFilledMesh(const DataSetId& id, int numPoints);
-
-    bool setStreamlinesSeedToMeshPoints(const DataSetId& id,
-                                        char *data, size_t nbytes);
-
-    bool setStreamlinesSeedToFilledMesh(const DataSetId& id,
-                                        char *data, size_t nbytes,
-                                        int numPoints);
-
-    void setStreamlinesSeedToRake(const DataSetId& id,
-                                  double start[3], double end[3],
-                                  int numPoints);
-
-    void setStreamlinesSeedToDisk(const DataSetId& id,
-                                  double center[3], double normal[3],
-                                  double radius, double innerRadius,
-                                  int numPoints);
-
-    void setStreamlinesSeedToPolygon(const DataSetId& id,
-                                     double center[3], double normal[3],
-                                     double angle, double radius,
-                                     int numSides);
-
-    void setStreamlinesSeedToFilledPolygon(const DataSetId& id,
-                                           double center[3], double normal[3],
-                                           double angle, double radius,
-                                           int numSides, int numPoints);
-
-    void setStreamlinesLength(const DataSetId& id, double length);
-
-    void setStreamlinesTypeToLines(const DataSetId& id);
-
-    void setStreamlinesTypeToTubes(const DataSetId& id, int numSides, double radius);
-
-    void setStreamlinesTypeToRibbons(const DataSetId& id, double width, double angle);
-
-    void setStreamlinesSeedVisibility(const DataSetId& id, bool state);
-
-    void setStreamlinesColorMode(const DataSetId& id,
-                                 Streamlines::ColorMode mode,
-                                 const char *name, double range[2] = NULL);
-
-    void setStreamlinesColorMode(const DataSetId& id,
-                                 Streamlines::ColorMode mode,
-                                 DataSet::DataAttributeType type,
-                                 const char *name, double range[2] = NULL);
-
-    void setStreamlinesSeedColor(const DataSetId& id, float color[3]);
-
-    // Volumes
-
-    void setVolumeSampleDistance(const DataSetId& id, double distance);
-
-    // Warps
-
-    void setWarpColorMode(const DataSetId& id,
-                          Warp::ColorMode mode,
-                          const char *name, double range[2] = NULL);
-
-    void setWarpColorMode(const DataSetId& id,
-                          Warp::ColorMode mode,
-                          DataSet::DataAttributeType type,
-                          const char *name, double range[2] = NULL);
-
-
-    void setWarpWarpScale(const DataSetId& id, double scale);
-
-private:
-    typedef std::tr1::unordered_map<DataSetId, DataSet *> DataSetHashmap;
-    typedef std::tr1::unordered_map<FieldId, double *> FieldRangeHashmap;
-    typedef std::tr1::unordered_map<ColorMapId, ColorMap *> ColorMapHashmap;
-
-    typedef std::tr1::unordered_map<DataSetId, Arc *> ArcHashmap;
-    typedef std::tr1::unordered_map<DataSetId, Arrow *> ArrowHashmap;
-    typedef std::tr1::unordered_map<DataSetId, Box *> BoxHashmap;
-    typedef std::tr1::unordered_map<DataSetId, Cone *> ConeHashmap;
-    typedef std::tr1::unordered_map<DataSetId, Contour2D *> Contour2DHashmap;
-    typedef std::tr1::unordered_map<DataSetId, Contour3D *> Contour3DHashmap;
-    typedef std::tr1::unordered_map<DataSetId, Cutplane *> CutplaneHashmap;
-    typedef std::tr1::unordered_map<DataSetId, Cylinder *> CylinderHashmap;
-    typedef std::tr1::unordered_map<DataSetId, Disk *> DiskHashmap;
-    typedef std::tr1::unordered_map<DataSetId, Glyphs *> GlyphsHashmap;
-    typedef std::tr1::unordered_map<DataSetId, Group *> GroupHashmap;
-    typedef std::tr1::unordered_map<DataSetId, HeightMap *> HeightMapHashmap;
-    typedef std::tr1::unordered_map<DataSetId, LIC *> LICHashmap;
-    typedef std::tr1::unordered_map<DataSetId, Line *> LineHashmap;
-    typedef std::tr1::unordered_map<DataSetId, Molecule *> MoleculeHashmap;
-    typedef std::tr1::unordered_map<DataSetId, Outline *> OutlineHashmap;
-    typedef std::tr1::unordered_map<DataSetId, PolyData *> PolyDataHashmap;
-    typedef std::tr1::unordered_map<DataSetId, Polygon *> PolygonHashmap;
-    typedef std::tr1::unordered_map<DataSetId, PseudoColor *> PseudoColorHashmap;
-    typedef std::tr1::unordered_map<DataSetId, Sphere *> SphereHashmap;
-    typedef std::tr1::unordered_map<DataSetId, Streamlines *> StreamlinesHashmap;
-    typedef std::tr1::unordered_map<DataSetId, Volume *> VolumeHashmap;
-    typedef std::tr1::unordered_map<DataSetId, Warp *> WarpHashmap;
-
-    void _setCameraZoomRegionPixels(int x, int y, int width, int height);
-
-    void _setCameraZoomRegion(double x, double y, double width, double height);
-
-    //static void printCameraInfo(vtkCamera *camera);
-
-    static void setCameraFromMatrix(vtkCamera *camera, vtkMatrix4x4 &mat);
-
-    static void mergeBounds(double *boundsDest, const double *bounds1, const double *bounds2);
-
-    template<class GraphicsObject>
-    std::tr1::unordered_map<DataSetId, GraphicsObject *>&getGraphicsObjectHashmap();
-
-    void setObjectAspects(double aspectRatio);
-
-    void collectBounds(double *bounds, bool onlyVisible);
-
-    void collectUnscaledBounds(double *bounds, bool onlyVisible);
-
-    void collectDataRanges();
-
-    void collectDataRanges(double *range, const char *name,
-                           DataSet::DataAttributeType type,
-                           int component, bool onlyVisible);
-
-    void clearFieldRanges();
-
-    void clearUserFieldRanges();
-
-    void initFieldRanges();
-
-    void updateFieldRanges();
-
-    void updateColorMap(ColorMap *cmap);
-
-    bool colorMapUsed(ColorMap *cmap);
-
-    void computeDisplayToWorld(double x, double y, double z, double worldPt[4]);
-
-    void computeWorldToDisplay(double x, double y, double z, double displayPt[3]);
-
-    void computeScreenWorldCoords();
-
-    bool is2D(const double bounds[6],
-              PrincipalPlane *plane,
-              double *offset) const;
-
-    void initCamera(bool initCameraMode = false);
-
-    void sceneBoundsChanged();
-
-    void initAxes();
-
-    void resetAxes(double bounds[6] = NULL);
-
-    void setAxesBounds(double bounds[6] = NULL);
-
-    void setAxesRanges();
-
-    void computeAxesScale();
-
-    void setCameraClippingPlanes();
-
-    bool _needsRedraw;
-    bool _needsAxesReset;
-    bool _needsCameraClippingRangeReset;
-    bool _needsCameraReset;
-
-    int _windowWidth, _windowHeight;
-    CameraMode _cameraMode;
-    Aspect _cameraAspect;
-    double _imgWorldOrigin[2];
-    double _imgWorldDims[2];
-    double _imgWindowWorldDims[2];
-    double _userImgWorldOrigin[2];
-    double _userImgWorldDims[2];
-    PrincipalPlane _imgCameraPlane;
-    double _imgCameraOffset;
-    double _screenWorldCoords[4];
-    double _cameraOrientation[4];
-    double _cameraZoomRatio;
-    double _cameraPan[2];
-    float _bgColor[3];
-    bool _useCumulativeRange;
-    bool _cumulativeRangeOnlyVisible;
-
-    FieldRangeHashmap _scalarPointDataRange;
-    FieldRangeHashmap _vectorPointDataRange;
-    FieldRangeHashmap _vectorCompPointDataRange[3];
-    FieldRangeHashmap _scalarCellDataRange;
-    FieldRangeHashmap _vectorCellDataRange;
-    FieldRangeHashmap _vectorCompCellDataRange[3];
-
-    FieldRangeHashmap _userScalarPointDataRange;
-    FieldRangeHashmap _userVectorPointDataRange;
-    FieldRangeHashmap _userVectorCompPointDataRange[3];
-    FieldRangeHashmap _userScalarCellDataRange;
-    FieldRangeHashmap _userVectorCellDataRange;
-    FieldRangeHashmap _userVectorCompCellDataRange[3];
-
-    bool _axesAutoBounds[3];
-    double _axesUserBounds[6];
-    AxisRangeMode _axesRangeMode[3];
-    double _axesScale[3];
-
-    ColorMapHashmap _colorMaps;
-    DataSetHashmap _dataSets;
-    ArcHashmap _arcs;
-    ArrowHashmap _arrows;
-    BoxHashmap _boxes;
-    ConeHashmap _cones;
-    Contour2DHashmap _contour2Ds;
-    Contour3DHashmap _contour3Ds;
-    CutplaneHashmap _cutplanes;
-    CylinderHashmap _cylinders;
-    DiskHashmap _disks;
-    GlyphsHashmap _glyphs;
-    GroupHashmap _groups;
-    HeightMapHashmap _heightMaps;
-    LICHashmap _lics;
-    LineHashmap _lines;
-    MoleculeHashmap _molecules;
-    OutlineHashmap _outlines;
-    PolyDataHashmap _polyDatas;
-    PolygonHashmap _polygons;
-    PseudoColorHashmap _pseudoColors;
-    SphereHashmap _spheres;
-    StreamlinesHashmap _streamlines;
-    VolumeHashmap _volumes;
-    WarpHashmap _warps;
-
-    vtkSmartPointer<vtkPlane> _cameraClipPlanes[4];
-    vtkSmartPointer<vtkPlane> _userClipPlanes[6];
-    vtkSmartPointer<vtkPlaneCollection> _activeClipPlanes;
-#ifdef USE_CUSTOM_AXES
-    vtkSmartPointer<vtkRpCubeAxesActor> _cubeAxesActor;
-#else
-    vtkSmartPointer<vtkCubeAxesActor> _cubeAxesActor;
-#endif
-    vtkSmartPointer<vtkScalarBarActor> _scalarBarActor;
-    vtkSmartPointer<vtkRenderer> _renderer;
-    vtkSmartPointer<vtkRenderer> _legendRenderer;
-    vtkSmartPointer<vtkRenderWindow> _renderWindow;
-    vtkSmartPointer<vtkRenderWindow> _legendRenderWindow;
-};
-
-}
-
-#endif
Index: unk/packages/vizservers/vtkvis/RpVtkRendererCmd.cpp
===================================================================
--- /trunk/packages/vizservers/vtkvis/RpVtkRendererCmd.cpp	(revision 3615)
+++ 	(revision )
@@ -1,10206 +1,0 @@
-/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
-/*
- * Copyright (C) 2004-2012  HUBzero Foundation, LLC
- *
- * Author: Leif Delgass <ldelgass@purdue.edu>
- */
-
-#include <cstdlib>
-#include <cstdio>
-#include <cstring>
-#include <cfloat>
-#include <cerrno>
-#include <string>
-#include <sstream>
-#include <unistd.h>
-#include <sys/select.h>
-#include <sys/uio.h>
-#include <tcl.h>
-
-#include "Trace.h"
-#include "CmdProc.h"
-#include "ReadBuffer.h"
-#include "RpTypes.h"
-#include "RpVtkRendererCmd.h"
-#include "RpVtkRenderServer.h"
-#include "RpVtkRenderer.h"
-#include "RpVtkRendererGraphicsObjs.h"
-#include "PPMWriter.h"
-#include "TGAWriter.h"
-#ifdef USE_THREADS
-#include "ResponseQueue.h"
-#endif
-
-using namespace VtkVis;
-
-static int lastCmdStatus;
-
-#ifdef USE_THREADS
-void
-VtkVis::queueResponse(ClientData clientData,
-                      const void *bytes, size_t len, 
-                      Response::AllocationType allocType,
-                      Response::ResponseType type)
-{
-    ResponseQueue *queue = (ResponseQueue *)clientData;
-
-    Response *response = new Response(type);
-    response->setMessage((unsigned char *)bytes, len, allocType);
-    queue->enqueue(response);
-}
-#else
-
-static ssize_t
-SocketWrite(const void *bytes, size_t len)
-{
-    size_t ofs = 0;
-    ssize_t bytesWritten;
-    while ((bytesWritten = write(g_fdOut, (const char *)bytes + ofs, len - ofs)) > 0) {
-        ofs += bytesWritten;
-        if (ofs == len)
-            break;
-    }
-    if (bytesWritten < 0) {
-        ERROR("write: %s", strerror(errno));
-    }
-    return bytesWritten;
-}
-
-#endif  /*USE_THREADS*/
-
-static bool
-SocketRead(char *bytes, size_t len)
-{
-    ReadBuffer::BufferStatus status;
-    status = g_inBufPtr->followingData((unsigned char *)bytes, len);
-    TRACE("followingData status: %d", status);
-    return (status == ReadBuffer::OK);
-}
-
-static int
-ExecuteCommand(Tcl_Interp *interp, Tcl_DString *dsPtr) 
-{
-    int result;
-#ifdef WANT_TRACE
-    char *str = Tcl_DStringValue(dsPtr);
-    std::string cmd(str);
-    cmd.erase(cmd.find_last_not_of(" \n\r\t")+1);
-    TRACE("command %lu: '%s'", g_stats.nCommands+1, cmd.c_str());
-#endif
-    lastCmdStatus = TCL_OK;
-    result = Tcl_EvalEx(interp, Tcl_DStringValue(dsPtr), 
-                        Tcl_DStringLength(dsPtr), 
-                        TCL_EVAL_DIRECT | TCL_EVAL_GLOBAL);
-    Tcl_DStringSetLength(dsPtr, 0);
-    if (lastCmdStatus == TCL_BREAK) {
-        return TCL_BREAK;
-    }
-    lastCmdStatus = result;
-    if (result != TCL_OK) {
-        TRACE("Error: %d", result);
-    }
-    return result;
-}
-
-static int
-GetBooleanFromObj(Tcl_Interp *interp, Tcl_Obj *objPtr, bool *boolPtr)
-{
-    int value;
-
-    if (Tcl_GetBooleanFromObj(interp, objPtr, &value) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    *boolPtr = (bool)value;
-    return TCL_OK;
-}
-
-static int
-GetFloatFromObj(Tcl_Interp *interp, Tcl_Obj *objPtr, float *valuePtr)
-{
-    double value;
-
-    if (Tcl_GetDoubleFromObj(interp, objPtr, &value) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    *valuePtr = (float)value;
-    return TCL_OK;
-}
-
-static int
-ArcAddOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-         Tcl_Obj *const *objv)
-{
-    double pt1[3];
-    double pt2[3];
-    if (Tcl_GetDoubleFromObj(interp, objv[2], &pt1[0]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[3], &pt1[1]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[4], &pt1[2]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[5], &pt2[0]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[6], &pt2[1]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[7], &pt2[2]) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    const char *name = Tcl_GetString(objv[8]);
-    if (!g_renderer->addArc(name, pt1, pt2)) {
-        Tcl_AppendResult(interp, "Failed to create arc", (char*)NULL);
-        return TCL_ERROR;
-    }
-    return TCL_OK;
-}
-
-static int
-ArcDeleteOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-             Tcl_Obj *const *objv)
-{
-    if (objc == 3) {
-        const char *name = Tcl_GetString(objv[2]);
-        g_renderer->deleteGraphicsObject<Arc>(name);
-    } else {
-        g_renderer->deleteGraphicsObject<Arc>("all");
-    }
-    return TCL_OK;
-}
-
-static int
-ArcColorOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-           Tcl_Obj *const *objv)
-{
-    float color[3];
-    if (GetFloatFromObj(interp, objv[2], &color[0]) != TCL_OK ||
-        GetFloatFromObj(interp, objv[3], &color[1]) != TCL_OK ||
-        GetFloatFromObj(interp, objv[4], &color[2]) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 6) {
-        const char *name = Tcl_GetString(objv[5]);
-        g_renderer->setGraphicsObjectColor<Arc>(name, color);
-    } else {
-        g_renderer->setGraphicsObjectColor<Arc>("all", color);
-    }
-    return TCL_OK;
-}
-
-static int
-ArcLineWidthOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-               Tcl_Obj *const *objv)
-{
-    float width;
-    if (GetFloatFromObj(interp, objv[2], &width) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 4) {
-        const char *name = Tcl_GetString(objv[3]);
-        g_renderer->setGraphicsObjectEdgeWidth<Arc>(name, width);
-    } else {
-        g_renderer->setGraphicsObjectEdgeWidth<Arc>("all", width);
-    }
-    return TCL_OK;
-}
-
-static int
-ArcOpacityOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-             Tcl_Obj *const *objv)
-{
-    double opacity;
-    if (Tcl_GetDoubleFromObj(interp, objv[2], &opacity) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 4) {
-        const char *name = Tcl_GetString(objv[3]);
-        g_renderer->setGraphicsObjectOpacity<Arc>(name, opacity);
-    } else {
-        g_renderer->setGraphicsObjectOpacity<Arc>("all", opacity);
-    }
-    return TCL_OK;
-}
-
-static int
-ArcOrientOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-            Tcl_Obj *const *objv)
-{
-    double quat[4];
-    if (Tcl_GetDoubleFromObj(interp, objv[2], &quat[0]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[3], &quat[1]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[4], &quat[2]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[5], &quat[3]) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 7) {
-        const char *name = Tcl_GetString(objv[6]);
-        g_renderer->setGraphicsObjectOrientation<Arc>(name, quat);
-    } else {
-        g_renderer->setGraphicsObjectOrientation<Arc>("all", quat);
-    }
-    return TCL_OK;
-}
-
-static int
-ArcPositionOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-              Tcl_Obj *const *objv)
-{
-    double pos[3];
-    if (Tcl_GetDoubleFromObj(interp, objv[2], &pos[0]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[3], &pos[1]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[4], &pos[2]) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 6) {
-        const char *name = Tcl_GetString(objv[5]);
-        g_renderer->setGraphicsObjectPosition<Arc>(name, pos);
-    } else {
-        g_renderer->setGraphicsObjectPosition<Arc>("all", pos);
-    }
-    return TCL_OK;
-}
-
-static int
-ArcResolutionOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                Tcl_Obj *const *objv)
-{
-    int res;
-    if (Tcl_GetIntFromObj(interp, objv[2], &res) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 4) {
-        const char *name = Tcl_GetString(objv[3]);
-        g_renderer->setArcResolution(name, res);
-    } else {
-        g_renderer->setArcResolution("all", res);
-    }
-    return TCL_OK;
-}
-
-static int
-ArcScaleOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-            Tcl_Obj *const *objv)
-{
-    double scale[3];
-    if (Tcl_GetDoubleFromObj(interp, objv[2], &scale[0]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[3], &scale[1]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[4], &scale[2]) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 6) {
-        const char *name = Tcl_GetString(objv[5]);
-        g_renderer->setGraphicsObjectScale<Arc>(name, scale);
-    } else {
-        g_renderer->setGraphicsObjectScale<Arc>("all", scale);
-    }
-    return TCL_OK;
-}
-
-static int
-ArcVisibleOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-             Tcl_Obj *const *objv)
-{
-    bool state;
-    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 4) {
-        const char *name = Tcl_GetString(objv[3]);
-        g_renderer->setGraphicsObjectVisibility<Arc>(name, state);
-    } else {
-        g_renderer->setGraphicsObjectVisibility<Arc>("all", state);
-    }
-    return TCL_OK;
-}
-
-static Rappture::CmdSpec arcOps[] = {
-    {"add",       1, ArcAddOp, 9, 9, "x1 y1 z1 x2 y2 z2 name"},
-    {"color",     1, ArcColorOp, 5, 6, "r g b ?name?"},
-    {"delete",    1, ArcDeleteOp, 2, 3, "?name?"},
-    {"linecolor", 5, ArcColorOp, 5, 6, "r g b ?name?"},
-    {"linewidth", 5, ArcLineWidthOp, 3, 4, "width ?name?"},
-    {"opacity",   2, ArcOpacityOp, 3, 4, "value ?name?"},
-    {"orient",    2, ArcOrientOp, 6, 7, "qw qx qy qz ?name?"},
-    {"pos",       2, ArcPositionOp, 5, 6, "x y z ?name?"},
-    {"resolution",1, ArcResolutionOp, 3, 4, "res ?name?"},
-    {"scale",     2, ArcScaleOp, 5, 6, "sx sy sz ?name?"},
-    {"visible",   1, ArcVisibleOp, 3, 4, "bool ?name?"}
-};
-static int nArcOps = NumCmdSpecs(arcOps);
-
-static int
-ArcCmd(ClientData clientData, Tcl_Interp *interp, int objc, 
-       Tcl_Obj *const *objv)
-{
-    Tcl_ObjCmdProc *proc;
-
-    proc = Rappture::GetOpFromObj(interp, nArcOps, arcOps,
-                                  Rappture::CMDSPEC_ARG1, objc, objv, 0);
-    if (proc == NULL) {
-        return TCL_ERROR;
-    }
-    return (*proc) (clientData, interp, objc, objv);
-}
-
-static int
-ArrowAddOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-           Tcl_Obj *const *objv)
-{
-    double tipRadius, shaftRadius, tipLength;
-    if (Tcl_GetDoubleFromObj(interp, objv[2], &tipRadius) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[3], &shaftRadius) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[4], &tipLength) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    const char *name = Tcl_GetString(objv[5]);
-    if (!g_renderer->addArrow(name, tipRadius, shaftRadius, tipLength)) {
-        Tcl_AppendResult(interp, "Failed to create arrow", (char*)NULL);
-        return TCL_ERROR;
-    }
-    return TCL_OK;
-}
-
-static int
-ArrowDeleteOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-              Tcl_Obj *const *objv)
-{
-    if (objc == 3) {
-        const char *name = Tcl_GetString(objv[2]);
-        g_renderer->deleteGraphicsObject<Arrow>(name);
-    } else {
-        g_renderer->deleteGraphicsObject<Arrow>("all");
-    }
-    return TCL_OK;
-}
-
-static int
-ArrowColorOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-             Tcl_Obj *const *objv)
-{
-    float color[3];
-    if (GetFloatFromObj(interp, objv[2], &color[0]) != TCL_OK ||
-        GetFloatFromObj(interp, objv[3], &color[1]) != TCL_OK ||
-        GetFloatFromObj(interp, objv[4], &color[2]) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 6) {
-        const char *name = Tcl_GetString(objv[5]);
-        g_renderer->setGraphicsObjectColor<Arrow>(name, color);
-    } else {
-        g_renderer->setGraphicsObjectColor<Arrow>("all", color);
-    }
-    return TCL_OK;
-}
-
-static int
-ArrowEdgeVisibilityOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                      Tcl_Obj *const *objv)
-{
-    bool state;
-    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 4) {
-        const char *name = Tcl_GetString(objv[3]);
-        g_renderer->setGraphicsObjectEdgeVisibility<Arrow>(name, state);
-    } else {
-        g_renderer->setGraphicsObjectEdgeVisibility<Arrow>("all", state);
-    }
-    return TCL_OK;
-}
-
-static int
-ArrowLightingOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                Tcl_Obj *const *objv)
-{
-    bool state;
-    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 4) {
-        const char *name = Tcl_GetString(objv[3]);
-        g_renderer->setGraphicsObjectLighting<Arrow>(name, state);
-    } else {
-        g_renderer->setGraphicsObjectLighting<Arrow>("all", state);
-    }
-    return TCL_OK;
-}
-
-static int
-ArrowLineColorOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                 Tcl_Obj *const *objv)
-{
-    float color[3];
-    if (GetFloatFromObj(interp, objv[2], &color[0]) != TCL_OK ||
-        GetFloatFromObj(interp, objv[3], &color[1]) != TCL_OK ||
-        GetFloatFromObj(interp, objv[4], &color[2]) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 6) {
-        const char *name = Tcl_GetString(objv[5]);
-        g_renderer->setGraphicsObjectEdgeColor<Arrow>(name, color);
-    } else {
-        g_renderer->setGraphicsObjectEdgeColor<Arrow>("all", color);
-    }
-    return TCL_OK;
-}
-
-static int
-ArrowLineWidthOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                 Tcl_Obj *const *objv)
-{
-    float width;
-    if (GetFloatFromObj(interp, objv[2], &width) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 4) {
-        const char *name = Tcl_GetString(objv[3]);
-        g_renderer->setGraphicsObjectEdgeWidth<Arrow>(name, width);
-    } else {
-        g_renderer->setGraphicsObjectEdgeWidth<Arrow>("all", width);
-    }
-    return TCL_OK;
-}
-
-static int
-ArrowMaterialOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                Tcl_Obj *const *objv)
-{
-    double ambient, diffuse, specCoeff, specPower;
-    if (Tcl_GetDoubleFromObj(interp, objv[2], &ambient) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[3], &diffuse) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[4], &specCoeff) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[5], &specPower) != TCL_OK) {
-        return TCL_ERROR;
-    }
-
-    if (objc == 7) {
-        const char *name = Tcl_GetString(objv[6]);
-        g_renderer->setGraphicsObjectAmbient<Arrow>(name, ambient);
-        g_renderer->setGraphicsObjectDiffuse<Arrow>(name, diffuse);
-        g_renderer->setGraphicsObjectSpecular<Arrow>(name, specCoeff, specPower);
-    } else {
-        g_renderer->setGraphicsObjectAmbient<Arrow>("all", ambient);
-        g_renderer->setGraphicsObjectDiffuse<Arrow>("all", diffuse);
-        g_renderer->setGraphicsObjectSpecular<Arrow>("all", specCoeff, specPower);
-    }
-    return TCL_OK;
-}
-
-static int
-ArrowOpacityOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-               Tcl_Obj *const *objv)
-{
-    double opacity;
-    if (Tcl_GetDoubleFromObj(interp, objv[2], &opacity) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 4) {
-        const char *name = Tcl_GetString(objv[3]);
-        g_renderer->setGraphicsObjectOpacity<Arrow>(name, opacity);
-    } else {
-        g_renderer->setGraphicsObjectOpacity<Arrow>("all", opacity);
-    }
-    return TCL_OK;
-}
-
-static int
-ArrowOrientOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-              Tcl_Obj *const *objv)
-{
-    double quat[4];
-    if (Tcl_GetDoubleFromObj(interp, objv[2], &quat[0]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[3], &quat[1]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[4], &quat[2]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[5], &quat[3]) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 7) {
-        const char *name = Tcl_GetString(objv[6]);
-        g_renderer->setGraphicsObjectOrientation<Arrow>(name, quat);
-    } else {
-        g_renderer->setGraphicsObjectOrientation<Arrow>("all", quat);
-    }
-    return TCL_OK;
-}
-
-static int
-ArrowPositionOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                Tcl_Obj *const *objv)
-{
-    double pos[3];
-    if (Tcl_GetDoubleFromObj(interp, objv[2], &pos[0]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[3], &pos[1]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[4], &pos[2]) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 6) {
-        const char *name = Tcl_GetString(objv[5]);
-        g_renderer->setGraphicsObjectPosition<Arrow>(name, pos);
-    } else {
-        g_renderer->setGraphicsObjectPosition<Arrow>("all", pos);
-    }
-    return TCL_OK;
-}
-
-static int
-ArrowResolutionOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                  Tcl_Obj *const *objv)
-{
-    int tipRes, shaftRes;
-    if (Tcl_GetIntFromObj(interp, objv[2], &tipRes) != TCL_OK ||
-        Tcl_GetIntFromObj(interp, objv[3], &shaftRes) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 4) {
-        const char *name = Tcl_GetString(objv[4]);
-        g_renderer->setArrowResolution(name, tipRes, shaftRes);
-    } else {
-        g_renderer->setArrowResolution("all", tipRes, shaftRes);
-    }
-    return TCL_OK;
-}
-
-static int
-ArrowScaleOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-             Tcl_Obj *const *objv)
-{
-    double scale[3];
-    if (Tcl_GetDoubleFromObj(interp, objv[2], &scale[0]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[3], &scale[1]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[4], &scale[2]) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 6) {
-        const char *name = Tcl_GetString(objv[5]);
-        g_renderer->setGraphicsObjectScale<Arrow>(name, scale);
-    } else {
-        g_renderer->setGraphicsObjectScale<Arrow>("all", scale);
-    }
-    return TCL_OK;
-}
-
-static int
-ArrowVisibleOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-               Tcl_Obj *const *objv)
-{
-    bool state;
-    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 4) {
-        const char *name = Tcl_GetString(objv[3]);
-        g_renderer->setGraphicsObjectVisibility<Arrow>(name, state);
-    } else {
-        g_renderer->setGraphicsObjectVisibility<Arrow>("all", state);
-    }
-    return TCL_OK;
-}
-
-static int
-ArrowWireframeOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                 Tcl_Obj *const *objv)
-{
-    bool state;
-    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 4) {
-        const char *name = Tcl_GetString(objv[3]);
-        g_renderer->setGraphicsObjectWireframe<Arrow>(name, state);
-    } else {
-        g_renderer->setGraphicsObjectWireframe<Arrow>("all", state);
-    }
-    return TCL_OK;
-}
-
-static Rappture::CmdSpec arrowOps[] = {
-    {"add",       1, ArrowAddOp, 6, 6, "tipRadius shaftRadius tipLength name"},
-    {"color",     1, ArrowColorOp, 5, 6, "r g b ?name?"},
-    {"delete",    1, ArrowDeleteOp, 2, 3, "?name?"},
-    {"edges",     1, ArrowEdgeVisibilityOp, 3, 4, "bool ?name?"},
-    {"lighting",  3, ArrowLightingOp, 3, 4, "bool ?name?"},
-    {"linecolor", 5, ArrowLineColorOp, 5, 6, "r g b ?name?"},
-    {"linewidth", 5, ArrowLineWidthOp, 3, 4, "width ?name?"},
-    {"material",  1, ArrowMaterialOp, 6, 7, "ambientCoeff diffuseCoeff specularCoeff specularPower ?name?"},
-    {"opacity",   2, ArrowOpacityOp, 3, 4, "value ?name?"},
-    {"orient",    2, ArrowOrientOp, 6, 7, "qw qx qy qz ?name?"},
-    {"pos",       2, ArrowPositionOp, 5, 6, "x y z ?name?"},
-    {"resolution",1, ArrowResolutionOp, 4, 5, "tipRes shaftRes ?name?"},
-    {"scale",     1, ArrowScaleOp, 5, 6, "sx sy sz ?name?"},
-    {"visible",   1, ArrowVisibleOp, 3, 4, "bool ?name?"},
-    {"wireframe", 1, ArrowWireframeOp, 3, 4, "bool ?name?"}
-};
-static int nArrowOps = NumCmdSpecs(arrowOps);
-
-static int
-ArrowCmd(ClientData clientData, Tcl_Interp *interp, int objc, 
-       Tcl_Obj *const *objv)
-{
-    Tcl_ObjCmdProc *proc;
-
-    proc = Rappture::GetOpFromObj(interp, nArrowOps, arrowOps,
-                                  Rappture::CMDSPEC_ARG1, objc, objv, 0);
-    if (proc == NULL) {
-        return TCL_ERROR;
-    }
-    return (*proc) (clientData, interp, objc, objv);
-}
-
-static int
-AxisAutoBoundsOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                 Tcl_Obj *const *objv)
-{
-    bool enableAuto;
-    if (GetBooleanFromObj(interp, objv[3], &enableAuto) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    const char *string = Tcl_GetString(objv[2]);
-    char c = string[0];
-    if ((c == 'x') && (strcmp(string, "x") == 0)) {
-        g_renderer->setAxisAutoBounds(X_AXIS, enableAuto);
-    } else if ((c == 'y') && (strcmp(string, "y") == 0)) {
-        g_renderer->setAxisAutoBounds(Y_AXIS, enableAuto);
-    } else if ((c == 'z') && (strcmp(string, "z") == 0)) {
-        g_renderer->setAxisAutoBounds(Z_AXIS, enableAuto);
-    } else if ((c == 'a') && (strcmp(string, "all") == 0)) {
-        g_renderer->setAxesAutoBounds(enableAuto);
-    } else {
-        Tcl_AppendResult(interp, "bad axis option \"", string,
-                         "\": should be axisName", (char*)NULL);
-        return TCL_ERROR;
-    }
-    return TCL_OK;
-}
-
-static int
-AxisAutoRangeOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                Tcl_Obj *const *objv)
-{
-    bool enableAuto;
-    if (GetBooleanFromObj(interp, objv[3], &enableAuto) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    const char *string = Tcl_GetString(objv[2]);
-    char c = string[0];
-    if ((c == 'x') && (strcmp(string, "x") == 0)) {
-        g_renderer->setAxisAutoRange(X_AXIS, enableAuto);
-    } else if ((c == 'y') && (strcmp(string, "y") == 0)) {
-        g_renderer->setAxisAutoRange(Y_AXIS, enableAuto);
-    } else if ((c == 'z') && (strcmp(string, "z") == 0)) {
-        g_renderer->setAxisAutoRange(Z_AXIS, enableAuto);
-    } else if ((c == 'a') && (strcmp(string, "all") == 0)) {
-        g_renderer->setAxesAutoRange(enableAuto);
-    } else {
-        Tcl_AppendResult(interp, "bad axis option \"", string,
-                         "\": should be axisName", (char*)NULL);
-        return TCL_ERROR;
-    }
-    return TCL_OK;
-}
-
-static int
-AxisColorOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-            Tcl_Obj *const *objv)
-{
-    double color[3];
-    if (Tcl_GetDoubleFromObj(interp, objv[3], &color[0]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[4], &color[1]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[5], &color[2]) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    double opacity = 1.0;
-    if (objc > 6) {
-        if (Tcl_GetDoubleFromObj(interp, objv[6], &opacity) != TCL_OK) {
-            return TCL_ERROR;
-        }
-    }
-    const char *string = Tcl_GetString(objv[2]);
-    char c = string[0];
-    if ((c == 'x') && (strcmp(string, "x") == 0)) {
-        g_renderer->setAxisColor(X_AXIS, color, opacity);
-    } else if ((c == 'y') && (strcmp(string, "y") == 0)) {
-        g_renderer->setAxisColor(Y_AXIS, color, opacity);
-    } else if ((c == 'z') && (strcmp(string, "z") == 0)) {
-        g_renderer->setAxisColor(Z_AXIS, color, opacity);
-    } else if ((c == 'a') && (strcmp(string, "all") == 0)) {
-        g_renderer->setAxesColor(color, opacity);
-    } else {
-        Tcl_AppendResult(interp, "bad axis option \"", string,
-                         "\": should be axisName", (char*)NULL);
-        return TCL_ERROR;
-    }
-    return TCL_OK;
-}
-
-static int
-AxisBoundsOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-             Tcl_Obj *const *objv)
-{
-    double min, max;
-    if (Tcl_GetDoubleFromObj(interp, objv[3], &min) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[4], &max) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    const char *string = Tcl_GetString(objv[2]);
-    char c = string[0];
-    if ((c == 'x') && (strcmp(string, "x") == 0)) {
-        g_renderer->setAxisBounds(X_AXIS, min, max);
-    } else if ((c == 'y') && (strcmp(string, "y") == 0)) {
-        g_renderer->setAxisBounds(Y_AXIS, min, max);
-    } else if ((c == 'z') && (strcmp(string, "z") == 0)) {
-        g_renderer->setAxisBounds(Z_AXIS, min, max);
-    } else if ((c == 'a') && (strcmp(string, "all") == 0)) {
-        g_renderer->setAxesBounds(min, max);
-    } else {
-        Tcl_AppendResult(interp, "bad axis option \"", string,
-                         "\": should be axisName", (char*)NULL);
-        return TCL_ERROR;
-    }
-    return TCL_OK;
-}
-
-static int
-AxisExponentOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-               Tcl_Obj *const *objv)
-{
-    int xPow, yPow, zPow;
-    bool useCustom = true;
-    if (Tcl_GetIntFromObj(interp, objv[2], &xPow) != TCL_OK ||
-        Tcl_GetIntFromObj(interp, objv[3], &yPow) != TCL_OK ||
-        Tcl_GetIntFromObj(interp, objv[4], &zPow) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc > 5) {
-        if (GetBooleanFromObj(interp, objv[5], &useCustom) != TCL_OK) {
-            return TCL_ERROR;
-        }
-        g_renderer->setAxesLabelPowerScaling(xPow, yPow, zPow, useCustom);
-    } else {
-        g_renderer->setAxesLabelPowerScaling(xPow, yPow, zPow);
-    }
-    return TCL_OK;
-}
-
-static int
-AxisFlyModeOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-              Tcl_Obj *const *objv)
-{
-    const char *string = Tcl_GetString(objv[2]);
-    char c = string[0];
-    Renderer::AxesFlyMode mode;
-    if ((c == 's') && (strcmp(string, "static_edges") == 0)) {
-        mode = Renderer::FLY_STATIC_EDGES;
-    } else if ((c == 's') && (strcmp(string, "static_triad") == 0)) {
-        mode = Renderer::FLY_STATIC_TRIAD;
-    } else if ((c == 'o') && (strcmp(string, "outer_edges") == 0)) {
-        mode = Renderer::FLY_OUTER_EDGES;
-    } else if ((c == 'f') && (strcmp(string, "furthest_triad") == 0)) {
-        mode = Renderer::FLY_FURTHEST_TRIAD;
-    } else if ((c == 'c') && (strcmp(string, "closest_triad") == 0)) {
-        mode = Renderer::FLY_CLOSEST_TRIAD;
-    } else {
-        Tcl_AppendResult(interp, "bad axis flymode option \"", string,
-                         "\": should be static_edges, static_triad, outer_edges, furthest_triad, or closest_triad", (char*)NULL);
-        return TCL_ERROR;
-    }
-    g_renderer->setAxesFlyMode(mode);
-    return TCL_OK;
-}
-
-static int
-AxisFontSizeOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-               Tcl_Obj *const *objv)
-{
-    double screenSize;
-    if (Tcl_GetDoubleFromObj(interp, objv[2], &screenSize) != TCL_OK) {
-        return TCL_ERROR;
-    }
-
-    g_renderer->setAxesPixelFontSize(screenSize);
-    return TCL_OK;
-}
-
-static int
-AxisGridOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-           Tcl_Obj *const *objv)
-{
-    bool visible;
-    if (GetBooleanFromObj(interp, objv[3], &visible) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    const char *string = Tcl_GetString(objv[2]);
-    char c = string[0];
-    if ((c == 'x') && (strcmp(string, "x") == 0)) {
-        g_renderer->setAxisGridVisibility(X_AXIS, visible);
-    } else if ((c == 'y') && (strcmp(string, "y") == 0)) {
-        g_renderer->setAxisGridVisibility(Y_AXIS, visible);
-    } else if ((c == 'z') && (strcmp(string, "z") == 0)) {
-        g_renderer->setAxisGridVisibility(Z_AXIS, visible);
-    } else if ((c == 'a') && (strcmp(string, "all") == 0)) {
-        g_renderer->setAxesGridVisibility(visible);
-    } else {
-        Tcl_AppendResult(interp, "bad axis option \"", string,
-                         "\": should be axisName", (char*)NULL);
-        return TCL_ERROR;
-    }
-    return TCL_OK;
-}
-
-static int
-AxisGridColorOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                Tcl_Obj *const *objv)
-{
-    double color[3];
-    if (Tcl_GetDoubleFromObj(interp, objv[3], &color[0]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[4], &color[1]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[5], &color[2]) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    double opacity = 1.0;
-    if (objc > 6) {
-        if (Tcl_GetDoubleFromObj(interp, objv[6], &opacity) != TCL_OK) {
-            return TCL_ERROR;
-        }
-    }
-    const char *string = Tcl_GetString(objv[2]);
-    char c = string[0];
-    if ((c == 'x') && (strcmp(string, "x") == 0)) {
-        g_renderer->setAxisGridlinesColor(X_AXIS, color, opacity);
-    } else if ((c == 'y') && (strcmp(string, "y") == 0)) {
-        g_renderer->setAxisGridlinesColor(Y_AXIS, color, opacity);
-    } else if ((c == 'z') && (strcmp(string, "z") == 0)) {
-        g_renderer->setAxisGridlinesColor(Z_AXIS, color, opacity);
-    } else if ((c == 'a') && (strcmp(string, "all") == 0)) {
-        g_renderer->setAxesGridlinesColor(color, opacity);
-    } else {
-        Tcl_AppendResult(interp, "bad axis option \"", string,
-                         "\": should be axisName", (char*)NULL);
-        return TCL_ERROR;
-    }
-    return TCL_OK;
-}
-
-static int
-AxisGridpolysOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                Tcl_Obj *const *objv)
-{
-    bool visible;
-    if (GetBooleanFromObj(interp, objv[3], &visible) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    const char *string = Tcl_GetString(objv[2]);
-    char c = string[0];
-    if ((c == 'x') && (strcmp(string, "x") == 0)) {
-        g_renderer->setAxisGridpolysVisibility(X_AXIS, visible);
-    } else if ((c == 'y') && (strcmp(string, "y") == 0)) {
-        g_renderer->setAxisGridpolysVisibility(Y_AXIS, visible);
-    } else if ((c == 'z') && (strcmp(string, "z") == 0)) {
-        g_renderer->setAxisGridpolysVisibility(Z_AXIS, visible);
-    } else if ((c == 'a') && (strcmp(string, "all") == 0)) {
-        g_renderer->setAxesGridpolysVisibility(visible);
-    } else {
-        Tcl_AppendResult(interp, "bad axis option \"", string,
-                         "\": should be axisName", (char*)NULL);
-        return TCL_ERROR;
-    }
-    return TCL_OK;
-}
-
-static int
-AxisGridpolysColorOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                     Tcl_Obj *const *objv)
-{
-    double color[3];
-    if (Tcl_GetDoubleFromObj(interp, objv[3], &color[0]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[4], &color[1]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[5], &color[2]) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    double opacity = 1.0;
-    if (objc > 6) {
-        if (Tcl_GetDoubleFromObj(interp, objv[6], &opacity) != TCL_OK) {
-            return TCL_ERROR;
-        }
-    }
-    const char *string = Tcl_GetString(objv[2]);
-    char c = string[0];
-    if ((c == 'x') && (strcmp(string, "x") == 0)) {
-        g_renderer->setAxisGridpolysColor(X_AXIS, color, opacity);
-    } else if ((c == 'y') && (strcmp(string, "y") == 0)) {
-        g_renderer->setAxisGridpolysColor(Y_AXIS, color, opacity);
-    } else if ((c == 'z') && (strcmp(string, "z") == 0)) {
-        g_renderer->setAxisGridpolysColor(Z_AXIS, color, opacity);
-    } else if ((c == 'a') && (strcmp(string, "all") == 0)) {
-        g_renderer->setAxesGridpolysColor(color, opacity);
-    } else {
-        Tcl_AppendResult(interp, "bad axis option \"", string,
-                         "\": should be axisName", (char*)NULL);
-        return TCL_ERROR;
-    }
-    return TCL_OK;
-}
-
-static int
-AxisInnerGridOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                Tcl_Obj *const *objv)
-{
-    bool visible;
-    if (GetBooleanFromObj(interp, objv[3], &visible) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    const char *string = Tcl_GetString(objv[2]);
-    char c = string[0];
-    if ((c == 'x') && (strcmp(string, "x") == 0)) {
-        g_renderer->setAxisInnerGridVisibility(X_AXIS, visible);
-    } else if ((c == 'y') && (strcmp(string, "y") == 0)) {
-        g_renderer->setAxisInnerGridVisibility(Y_AXIS, visible);
-    } else if ((c == 'z') && (strcmp(string, "z") == 0)) {
-        g_renderer->setAxisInnerGridVisibility(Z_AXIS, visible);
-    } else if ((c == 'a') && (strcmp(string, "all") == 0)) {
-        g_renderer->setAxesInnerGridVisibility(visible);
-    } else {
-        Tcl_AppendResult(interp, "bad axis option \"", string,
-                         "\": should be axisName", (char*)NULL);
-        return TCL_ERROR;
-    }
-    return TCL_OK;
-}
-
-static int
-AxisInnerGridColorOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                     Tcl_Obj *const *objv)
-{
-    double color[3];
-    if (Tcl_GetDoubleFromObj(interp, objv[3], &color[0]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[4], &color[1]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[5], &color[2]) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    double opacity = 1.0;
-    if (objc > 6) {
-        if (Tcl_GetDoubleFromObj(interp, objv[6], &opacity) != TCL_OK) {
-            return TCL_ERROR;
-        }
-    }
-    const char *string = Tcl_GetString(objv[2]);
-    char c = string[0];
-    if ((c == 'x') && (strcmp(string, "x") == 0)) {
-        g_renderer->setAxisInnerGridlinesColor(X_AXIS, color, opacity);
-    } else if ((c == 'y') && (strcmp(string, "y") == 0)) {
-        g_renderer->setAxisInnerGridlinesColor(Y_AXIS, color, opacity);
-    } else if ((c == 'z') && (strcmp(string, "z") == 0)) {
-        g_renderer->setAxisInnerGridlinesColor(Z_AXIS, color, opacity);
-    } else if ((c == 'a') && (strcmp(string, "all") == 0)) {
-        g_renderer->setAxesInnerGridlinesColor(color, opacity);
-    } else {
-        Tcl_AppendResult(interp, "bad axis option \"", string,
-                         "\": should be axisName", (char*)NULL);
-        return TCL_ERROR;
-    }
-    return TCL_OK;
-}
-
-static int
-AxisLabelColorOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                 Tcl_Obj *const *objv)
-{
-    double color[3];
-    if (Tcl_GetDoubleFromObj(interp, objv[3], &color[0]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[4], &color[1]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[5], &color[2]) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    double opacity = 1.0;
-    if (objc > 6) {
-        if (Tcl_GetDoubleFromObj(interp, objv[6], &opacity) != TCL_OK) {
-            return TCL_ERROR;
-        }
-    }
-    const char *string = Tcl_GetString(objv[2]);
-    char c = string[0];
-    if ((c == 'x') && (strcmp(string, "x") == 0)) {
-        g_renderer->setAxisLabelColor(X_AXIS, color, opacity);
-    } else if ((c == 'y') && (strcmp(string, "y") == 0)) {
-        g_renderer->setAxisLabelColor(Y_AXIS, color, opacity);
-    } else if ((c == 'z') && (strcmp(string, "z") == 0)) {
-        g_renderer->setAxisLabelColor(Z_AXIS, color, opacity);
-    } else if ((c == 'a') && (strcmp(string, "all") == 0)) {
-        g_renderer->setAxesLabelColor(color, opacity);
-    } else {
-        Tcl_AppendResult(interp, "bad axis option \"", string,
-                         "\": should be axisName", (char*)NULL);
-        return TCL_ERROR;
-    }
-    return TCL_OK;
-}
-
-static int
-AxisLabelFontOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                Tcl_Obj *const *objv)
-{
-    const char *fontName = Tcl_GetString(objv[3]);
-
-    const char *string = Tcl_GetString(objv[2]);
-    char c = string[0];
-    if ((c == 'x') && (strcmp(string, "x") == 0)) {
-        g_renderer->setAxisLabelFont(X_AXIS, fontName);
-    } else if ((c == 'y') && (strcmp(string, "y") == 0)) {
-        g_renderer->setAxisLabelFont(Y_AXIS, fontName);
-    } else if ((c == 'z') && (strcmp(string, "z") == 0)) {
-        g_renderer->setAxisLabelFont(Z_AXIS, fontName);
-    } else if ((c == 'a') && (strcmp(string, "all") == 0)) {
-        g_renderer->setAxesLabelFont(fontName);
-    } else {
-        Tcl_AppendResult(interp, "bad axis option \"", string,
-                         "\": should be axisName", (char*)NULL);
-        return TCL_ERROR;
-    }
-    return TCL_OK;
-}
-
-static int
-AxisLabelFormatOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                  Tcl_Obj *const *objv)
-{
-    const char *format = Tcl_GetString(objv[3]);
-
-    const char *string = Tcl_GetString(objv[2]);
-    char c = string[0];
-    if ((c == 'x') && (strcmp(string, "x") == 0)) {
-        g_renderer->setAxisLabelFormat(X_AXIS, format);
-    } else if ((c == 'y') && (strcmp(string, "y") == 0)) {
-        g_renderer->setAxisLabelFormat(Y_AXIS, format);
-    } else if ((c == 'z') && (strcmp(string, "z") == 0)) {
-        g_renderer->setAxisLabelFormat(Z_AXIS, format);
-    } else if ((c == 'a') && (strcmp(string, "all") == 0)) {
-        g_renderer->setAxesLabelFormat(format);
-    } else {
-        Tcl_AppendResult(interp, "bad axis option \"", string,
-                         "\": should be axisName", (char*)NULL);
-        return TCL_ERROR;
-    }
-    return TCL_OK;
-}
-
-static int
-AxisLabelFontSizeOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                    Tcl_Obj *const *objv)
-{
-    int fontSize;
-    if (Tcl_GetIntFromObj(interp, objv[3], &fontSize) != TCL_OK) {
-        return TCL_ERROR;
-    }
-
-    const char *string = Tcl_GetString(objv[2]);
-    char c = string[0];
-    if ((c == 'x') && (strcmp(string, "x") == 0)) {
-        g_renderer->setAxisLabelFontSize(X_AXIS, fontSize);
-    } else if ((c == 'y') && (strcmp(string, "y") == 0)) {
-        g_renderer->setAxisLabelFontSize(Y_AXIS, fontSize);
-    } else if ((c == 'z') && (strcmp(string, "z") == 0)) {
-        g_renderer->setAxisLabelFontSize(Z_AXIS, fontSize);
-    } else if ((c == 'a') && (strcmp(string, "all") == 0)) {
-        g_renderer->setAxesLabelFontSize(fontSize);
-    } else {
-        Tcl_AppendResult(interp, "bad axis option \"", string,
-                         "\": should be axisName", (char*)NULL);
-        return TCL_ERROR;
-    }
-    return TCL_OK;
-}
-
-static int
-AxisLabelOrientationOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                       Tcl_Obj *const *objv)
-{
-    double rot;
-    if (Tcl_GetDoubleFromObj(interp, objv[3], &rot) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    const char *string = Tcl_GetString(objv[2]);
-    char c = string[0];
-    if ((c == 'x') && (strcmp(string, "x") == 0)) {
-        g_renderer->setAxisLabelOrientation(X_AXIS, rot);
-    } else if ((c == 'y') && (strcmp(string, "y") == 0)) {
-        g_renderer->setAxisLabelOrientation(Y_AXIS, rot);
-    } else if ((c == 'z') && (strcmp(string, "z") == 0)) {
-        g_renderer->setAxisLabelOrientation(Z_AXIS, rot);
-    } else if ((c == 'a') && (strcmp(string, "all") == 0)) {
-        g_renderer->setAxesLabelOrientation(rot);
-    } else {
-        Tcl_AppendResult(interp, "bad axis option \"", string,
-                         "\": should be axisName", (char*)NULL);
-        return TCL_ERROR;
-    }
-    return TCL_OK;
-}
-
-static int
-AxisLabelScaleOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                 Tcl_Obj *const *objv)
-{
-    bool autoScale;
-    int xpow, ypow, zpow;
-    if (GetBooleanFromObj(interp, objv[3], &autoScale) != TCL_OK ||
-        Tcl_GetIntFromObj(interp, objv[4], &xpow) != TCL_OK ||
-        Tcl_GetIntFromObj(interp, objv[5], &ypow) != TCL_OK ||
-        Tcl_GetIntFromObj(interp, objv[6], &zpow) != TCL_OK) {
-        return TCL_ERROR;
-    }
-
-    g_renderer->setAxesLabelScaling(autoScale, xpow, ypow, zpow);
-    return TCL_OK;
-}
-
-static int
-AxisLabelsVisibleOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                    Tcl_Obj *const *objv)
-{
-    bool visible;
-    if (GetBooleanFromObj(interp, objv[3], &visible) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    const char *string = Tcl_GetString(objv[2]);
-    char c = string[0];
-    if ((c == 'x') && (strcmp(string, "x") == 0)) {
-        g_renderer->setAxisLabelVisibility(X_AXIS, visible);
-    } else if ((c == 'y') && (strcmp(string, "y") == 0)) {
-        g_renderer->setAxisLabelVisibility(Y_AXIS, visible);
-    } else if ((c == 'z') && (strcmp(string, "z") == 0)) {
-        g_renderer->setAxisLabelVisibility(Z_AXIS, visible);
-    } else if ((c == 'a') && (strcmp(string, "all") == 0)) {
-        g_renderer->setAxesLabelVisibility(visible);
-    } else {
-        Tcl_AppendResult(interp, "bad axis option \"", string,
-                         "\": should be axisName", (char*)NULL);
-        return TCL_ERROR;
-    }
-    return TCL_OK;
-}
-
-static int
-AxisLineColorOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                Tcl_Obj *const *objv)
-{
-    double color[3];
-    if (Tcl_GetDoubleFromObj(interp, objv[3], &color[0]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[4], &color[1]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[5], &color[2]) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    double opacity = 1.0;
-    if (objc > 6) {
-        if (Tcl_GetDoubleFromObj(interp, objv[6], &opacity) != TCL_OK) {
-            return TCL_ERROR;
-        }
-    }
-    const char *string = Tcl_GetString(objv[2]);
-    char c = string[0];
-    if ((c == 'x') && (strcmp(string, "x") == 0)) {
-        g_renderer->setAxisLinesColor(X_AXIS, color, opacity);
-    } else if ((c == 'y') && (strcmp(string, "y") == 0)) {
-        g_renderer->setAxisLinesColor(Y_AXIS, color, opacity);
-    } else if ((c == 'z') && (strcmp(string, "z") == 0)) {
-        g_renderer->setAxisLinesColor(Z_AXIS, color, opacity);
-    } else if ((c == 'a') && (strcmp(string, "all") == 0)) {
-        g_renderer->setAxesLinesColor(color, opacity);
-    } else {
-        Tcl_AppendResult(interp, "bad axis option \"", string,
-                         "\": should be axisName", (char*)NULL);
-        return TCL_ERROR;
-    }
-    return TCL_OK;
-}
-
-static int
-AxisNameOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-           Tcl_Obj *const *objv)
-{
-    const char *title = Tcl_GetString(objv[3]);
-    if (strlen(title) > 30) {
-        Tcl_AppendResult(interp, "axis name \"", title,
-                         "\" is too long", (char*)NULL);
-        return TCL_ERROR;
-    }
-    const char *string = Tcl_GetString(objv[2]);
-    char c = string[0];
-    if ((c == 'x') && (strcmp(string, "x") == 0)) {
-        g_renderer->setAxisTitle(X_AXIS, title);
-    } else if ((c == 'y') && (strcmp(string, "y") == 0)) {
-        g_renderer->setAxisTitle(Y_AXIS, title);
-    } else if ((c == 'z') && (strcmp(string, "z") == 0)) {
-        g_renderer->setAxisTitle(Z_AXIS, title);
-    } else {
-        Tcl_AppendResult(interp, "bad axis option \"", string,
-                         "\": should be axisName", (char*)NULL);
-        return TCL_ERROR;
-    }
-    return TCL_OK;
-}
-
-static int
-AxisOriginOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-             Tcl_Obj *const *objv)
-{
-    double x, y, z;
-    bool useCustom = true;
-    if (Tcl_GetDoubleFromObj(interp, objv[2], &x) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[3], &y) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[4], &z) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc > 5) {
-        if (GetBooleanFromObj(interp, objv[5], &useCustom) != TCL_OK) {
-            return TCL_ERROR;
-        }
-        g_renderer->setAxesOrigin(x, y, z, useCustom);
-    } else {
-        g_renderer->setAxesOrigin(x, y, z);
-    }
-    return TCL_OK;
-}
-
-static int
-AxisRangeOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-            Tcl_Obj *const *objv)
-{
-    double min, max;
-    if (Tcl_GetDoubleFromObj(interp, objv[3], &min) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[4], &max) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    const char *string = Tcl_GetString(objv[2]);
-    char c = string[0];
-    if ((c == 'x') && (strcmp(string, "x") == 0)) {
-        g_renderer->setAxisRange(X_AXIS, min, max);
-    } else if ((c == 'y') && (strcmp(string, "y") == 0)) {
-        g_renderer->setAxisRange(Y_AXIS, min, max);
-    } else if ((c == 'z') && (strcmp(string, "z") == 0)) {
-        g_renderer->setAxisRange(Z_AXIS, min, max);
-    } else if ((c == 'a') && (strcmp(string, "all") == 0)) {
-        g_renderer->setAxesRange(min, max);
-    } else {
-        Tcl_AppendResult(interp, "bad axis option \"", string,
-                         "\": should be axisName", (char*)NULL);
-        return TCL_ERROR;
-    }
-    return TCL_OK;
-}
-
-static int
-AxisScaleOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-            Tcl_Obj *const *objv)
-{
-    double scale;
-    if (Tcl_GetDoubleFromObj(interp, objv[3], &scale) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    const char *string = Tcl_GetString(objv[2]);
-    char c = string[0];
-    if ((c == 'x') && (strcmp(string, "x") == 0)) {
-        g_renderer->setAxisScale(X_AXIS, scale);
-    } else if ((c == 'y') && (strcmp(string, "y") == 0)) {
-        g_renderer->setAxisScale(Y_AXIS, scale);
-    } else if ((c == 'z') && (strcmp(string, "z") == 0)) {
-        g_renderer->setAxisScale(Z_AXIS, scale);
-    } else if ((c == 'a') && (strcmp(string, "all") == 0)) {
-        g_renderer->setAxesScale(scale);
-    } else {
-        Tcl_AppendResult(interp, "bad axis option \"", string,
-                         "\": should be axisName", (char*)NULL);
-        return TCL_ERROR;
-    }
-    return TCL_OK;
-}
-
-static int
-AxisTicksVisibleOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                   Tcl_Obj *const *objv)
-{
-    bool visible;
-    if (GetBooleanFromObj(interp, objv[3], &visible) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    const char *string = Tcl_GetString(objv[2]);
-    char c = string[0];
-    if ((c == 'x') && (strcmp(string, "x") == 0)) {
-        g_renderer->setAxisTickVisibility(X_AXIS, visible);
-    } else if ((c == 'y') && (strcmp(string, "y") == 0)) {
-        g_renderer->setAxisTickVisibility(Y_AXIS, visible);
-    } else if ((c == 'z') && (strcmp(string, "z") == 0)) {
-        g_renderer->setAxisTickVisibility(Z_AXIS, visible);
-    } else if ((c == 'a') && (strcmp(string, "all") == 0)) {
-        g_renderer->setAxesTickVisibility(visible);
-    } else {
-        Tcl_AppendResult(interp, "bad axis option \"", string,
-                         "\": should be axisName", (char*)NULL);
-        return TCL_ERROR;
-    }
-    return TCL_OK;
-}
-
-static int
-AxisMinorTicksVisibleOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                        Tcl_Obj *const *objv)
-{
-    bool visible;
-    if (GetBooleanFromObj(interp, objv[3], &visible) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    const char *string = Tcl_GetString(objv[2]);
-    char c = string[0];
-    if ((c == 'x') && (strcmp(string, "x") == 0)) {
-        g_renderer->setAxisMinorTickVisibility(X_AXIS, visible);
-    } else if ((c == 'y') && (strcmp(string, "y") == 0)) {
-        g_renderer->setAxisMinorTickVisibility(Y_AXIS, visible);
-    } else if ((c == 'z') && (strcmp(string, "z") == 0)) {
-        g_renderer->setAxisMinorTickVisibility(Z_AXIS, visible);
-    } else if ((c == 'a') && (strcmp(string, "all") == 0)) {
-        g_renderer->setAxesMinorTickVisibility(visible);
-    } else {
-        Tcl_AppendResult(interp, "bad axis option \"", string,
-                         "\": should be axisName", (char*)NULL);
-        return TCL_ERROR;
-    }
-    return TCL_OK;
-}
-
-static int
-AxisTickPositionOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                   Tcl_Obj *const *objv)
-{
-    const char *string = Tcl_GetString(objv[2]);
-    char c = string[0];
-    if ((c == 'i') && (strcmp(string, "inside") == 0)) {
-        g_renderer->setAxesTickPosition(Renderer::TICKS_INSIDE);
-    } else if ((c == 'o') && (strcmp(string, "outside") == 0)) {
-        g_renderer->setAxesTickPosition(Renderer::TICKS_OUTSIDE);
-    } else if ((c == 'b') && (strcmp(string, "both") == 0)) {
-        g_renderer->setAxesTickPosition(Renderer::TICKS_BOTH);
-    } else {
-        Tcl_AppendResult(interp, "bad axis option \"", string,
-                         "\": should be inside, outside or both", (char*)NULL);
-        return TCL_ERROR;
-    }
-    return TCL_OK;
-}
-
-static int
-AxisTitleColorOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                 Tcl_Obj *const *objv)
-{
-    double color[3];
-    if (Tcl_GetDoubleFromObj(interp, objv[3], &color[0]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[4], &color[1]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[5], &color[2]) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    double opacity = 1.0;
-    if (objc > 6) {
-        if (Tcl_GetDoubleFromObj(interp, objv[6], &opacity) != TCL_OK) {
-            return TCL_ERROR;
-        }
-    }
-    const char *string = Tcl_GetString(objv[2]);
-    char c = string[0];
-    if ((c == 'x') && (strcmp(string, "x") == 0)) {
-        g_renderer->setAxisTitleColor(X_AXIS, color, opacity);
-    } else if ((c == 'y') && (strcmp(string, "y") == 0)) {
-        g_renderer->setAxisTitleColor(Y_AXIS, color, opacity);
-    } else if ((c == 'z') && (strcmp(string, "z") == 0)) {
-        g_renderer->setAxisTitleColor(Z_AXIS, color, opacity);
-    } else if ((c == 'a') && (strcmp(string, "all") == 0)) {
-        g_renderer->setAxesTitleColor(color, opacity);
-    } else {
-        Tcl_AppendResult(interp, "bad axis option \"", string,
-                         "\": should be axisName", (char*)NULL);
-        return TCL_ERROR;
-    }
-    return TCL_OK;
-}
-
-static int
-AxisTitleFontOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                Tcl_Obj *const *objv)
-{
-    const char *fontName = Tcl_GetString(objv[3]);
-
-    const char *string = Tcl_GetString(objv[2]);
-    char c = string[0];
-    if ((c == 'x') && (strcmp(string, "x") == 0)) {
-        g_renderer->setAxisTitleFont(X_AXIS, fontName);
-    } else if ((c == 'y') && (strcmp(string, "y") == 0)) {
-        g_renderer->setAxisTitleFont(Y_AXIS, fontName);
-    } else if ((c == 'z') && (strcmp(string, "z") == 0)) {
-        g_renderer->setAxisTitleFont(Z_AXIS, fontName);
-    } else if ((c == 'a') && (strcmp(string, "all") == 0)) {
-        g_renderer->setAxesTitleFont(fontName);
-    } else {
-        Tcl_AppendResult(interp, "bad axis option \"", string,
-                         "\": should be axisName", (char*)NULL);
-        return TCL_ERROR;
-    }
-    return TCL_OK;
-}
-
-static int
-AxisTitleFontSizeOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                    Tcl_Obj *const *objv)
-{
-    int fontSize;
-    if (Tcl_GetIntFromObj(interp, objv[3], &fontSize) != TCL_OK) {
-        return TCL_ERROR;
-    }
-
-    const char *string = Tcl_GetString(objv[2]);
-    char c = string[0];
-    if ((c == 'x') && (strcmp(string, "x") == 0)) {
-        g_renderer->setAxisTitleFontSize(X_AXIS, fontSize);
-    } else if ((c == 'y') && (strcmp(string, "y") == 0)) {
-        g_renderer->setAxisTitleFontSize(Y_AXIS, fontSize);
-    } else if ((c == 'z') && (strcmp(string, "z") == 0)) {
-        g_renderer->setAxisTitleFontSize(Z_AXIS, fontSize);
-    } else if ((c == 'a') && (strcmp(string, "all") == 0)) {
-        g_renderer->setAxesTitleFontSize(fontSize);
-    } else {
-        Tcl_AppendResult(interp, "bad axis option \"", string,
-                         "\": should be axisName", (char*)NULL);
-        return TCL_ERROR;
-    }
-    return TCL_OK;
-}
-
-static int
-AxisTitleOrientationOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                       Tcl_Obj *const *objv)
-{
-    double rot;
-    if (Tcl_GetDoubleFromObj(interp, objv[3], &rot) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    const char *string = Tcl_GetString(objv[2]);
-    char c = string[0];
-    if ((c == 'x') && (strcmp(string, "x") == 0)) {
-        g_renderer->setAxisTitleOrientation(X_AXIS, rot);
-    } else if ((c == 'y') && (strcmp(string, "y") == 0)) {
-        g_renderer->setAxisTitleOrientation(Y_AXIS, rot);
-    } else if ((c == 'z') && (strcmp(string, "z") == 0)) {
-        g_renderer->setAxisTitleOrientation(Z_AXIS, rot);
-    } else if ((c == 'a') && (strcmp(string, "all") == 0)) {
-        g_renderer->setAxesTitleOrientation(rot);
-    } else {
-        Tcl_AppendResult(interp, "bad axis option \"", string,
-                         "\": should be axisName", (char*)NULL);
-        return TCL_ERROR;
-    }
-    return TCL_OK;
-}
-
-static int
-AxisUnitsOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-            Tcl_Obj *const *objv)
-{
-    const char *units = Tcl_GetString(objv[3]);
-    if (strlen(units) > 10) {
-        Tcl_AppendResult(interp, "axis units name \"", units,
-                         "\" is too long", (char*)NULL);
-        return TCL_ERROR;
-    }
-    const char *string = Tcl_GetString(objv[2]);
-    char c = string[0];
-    if ((c == 'x') && (strcmp(string, "x") == 0)) {
-        g_renderer->setAxisUnits(X_AXIS, units);
-    } else if ((c == 'y') && (strcmp(string, "y") == 0)) {
-        g_renderer->setAxisUnits(Y_AXIS, units);
-    } else if ((c == 'z') && (strcmp(string, "z") == 0)) {
-        g_renderer->setAxisUnits(Z_AXIS, units);
-    } else if ((c == 'a') && (strcmp(string, "all") == 0)) {
-        g_renderer->setAxisUnits(X_AXIS, units);
-        g_renderer->setAxisUnits(Y_AXIS, units);
-        g_renderer->setAxisUnits(Z_AXIS, units);
-    } else {
-        Tcl_AppendResult(interp, "bad axis option \"", string,
-                         "\": should be axisName", (char*)NULL);
-        return TCL_ERROR;
-    }
-    return TCL_OK;
-}
-
-static int
-AxisVisibleOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-              Tcl_Obj *const *objv)
-{
-    bool visible;
-    if (GetBooleanFromObj(interp, objv[3], &visible) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    const char *string = Tcl_GetString(objv[2]);
-    char c = string[0];
-    if ((c == 'x') && (strcmp(string, "x") == 0)) {
-        g_renderer->setAxisVisibility(X_AXIS, visible);
-    } else if ((c == 'y') && (strcmp(string, "y") == 0)) {
-        g_renderer->setAxisVisibility(Y_AXIS, visible);
-    } else if ((c == 'z') && (strcmp(string, "z") == 0)) {
-        g_renderer->setAxisVisibility(Z_AXIS, visible);
-    } else if ((c == 'a') && (strcmp(string, "all") == 0)) {
-        g_renderer->setAxesVisibility(visible);
-    } else {
-        Tcl_AppendResult(interp, "bad axis option \"", string,
-                         "\": should be axisName", (char*)NULL);
-        return TCL_ERROR;
-    }
-    return TCL_OK;
-}
-
-static Rappture::CmdSpec axisOps[] = {
-    {"autobounds", 5, AxisAutoBoundsOp, 4, 4, "axis bool"},
-    {"autorange",  5, AxisAutoRangeOp, 4, 4, "axis bool"},
-    {"bounds",     1, AxisBoundsOp, 5, 5, "axis min max"},
-    {"color",      1, AxisColorOp, 6, 7, "axis r g b ?opacity?"},
-    {"exp",        1, AxisExponentOp, 5, 6, "xPow yPow zPow ?useCustom?"},
-    {"flymode",    2, AxisFlyModeOp, 3, 3, "mode"},
-    {"fontsz",     2, AxisFontSizeOp, 3, 3, "fontPixelSize"},
-    {"gpcolor",    3, AxisGridpolysColorOp, 6, 7, "axis r g b ?opacity?"},
-    {"gpolys",     3, AxisGridpolysOp, 4, 4, "axis bool"},
-    {"grcolor",    3, AxisGridColorOp, 6, 7, "axis r g b ?opacity?"},
-    {"grid",       3, AxisGridOp, 4, 4, "axis bool"},
-    {"igcolor",    3, AxisInnerGridColorOp, 6, 7, "axis r g b ?opacity?"},
-    {"igrid",      3, AxisInnerGridOp, 4, 4, "axis bool"},
-    {"labels",     2, AxisLabelsVisibleOp, 4, 4, "axis bool"},
-    {"lcolor",     2, AxisLabelColorOp, 6, 7, "axis r g b ?opacity?"},
-    {"lfont",      4, AxisLabelFontOp, 4, 4, "axis font"},
-    {"lformat",    4, AxisLabelFormatOp, 4, 4, "axis format"},
-    {"lfsize",     3, AxisLabelFontSizeOp, 4, 4, "axis fontSize"},
-    {"linecolor",  2, AxisLineColorOp, 6, 7, "axis r g b ?opacity?"},
-    {"lrot",       2, AxisLabelOrientationOp, 4, 4, "axis rot"},
-    {"lscale",     2, AxisLabelScaleOp, 7, 7, "axis bool xpow ypow zpow"},
-    {"minticks",   1, AxisMinorTicksVisibleOp, 4, 4, "axis bool"},
-    {"name",       1, AxisNameOp, 4, 4, "axis title"},
-    {"origin",     1, AxisOriginOp, 5, 6, "x y z ?useCustom?"},
-    {"range",      1, AxisRangeOp, 5, 5, "axis min max"},
-    {"scale",      1, AxisScaleOp, 4, 4, "axis scale"},
-    {"tcolor",     2, AxisTitleColorOp, 6, 7, "axis r g b ?opacity?"},
-    {"tfont",      3, AxisTitleFontOp, 4, 4, "axis font"},
-    {"tfsize",     3, AxisTitleFontSizeOp, 4, 4, "axis fontSize"},
-    {"tickpos",    5, AxisTickPositionOp, 3, 3, "position"},
-    {"ticks",      5, AxisTicksVisibleOp, 4, 4, "axis bool"},
-    {"trot",       2, AxisTitleOrientationOp, 4, 4, "axis rot"},
-    {"units",      1, AxisUnitsOp, 4, 4, "axis units"},
-    {"visible",    1, AxisVisibleOp, 4, 4, "axis bool"}
-};
-static int nAxisOps = NumCmdSpecs(axisOps);
-
-static int
-AxisCmd(ClientData clientData, Tcl_Interp *interp, int objc, 
-        Tcl_Obj *const *objv)
-{
-    Tcl_ObjCmdProc *proc;
-
-    proc = Rappture::GetOpFromObj(interp, nAxisOps, axisOps,
-                                  Rappture::CMDSPEC_ARG1, objc, objv, 0);
-    if (proc == NULL) {
-        return TCL_ERROR;
-    }
-    return (*proc) (clientData, interp, objc, objv);
-}
-
-static int
-BoxAddOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-         Tcl_Obj *const *objv)
-{
-    const char *name = Tcl_GetString(objv[2]);
-    if (!g_renderer->addGraphicsObject<Box>(name)) {
-        Tcl_AppendResult(interp, "Failed to create box", (char*)NULL);
-        return TCL_ERROR;
-    }
-    return TCL_OK;
-}
-
-static int
-BoxDeleteOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-            Tcl_Obj *const *objv)
-{
-    if (objc == 3) {
-        const char *name = Tcl_GetString(objv[2]);
-        g_renderer->deleteGraphicsObject<Box>(name);
-    } else {
-        g_renderer->deleteGraphicsObject<Box>("all");
-    }
-    return TCL_OK;
-}
-
-static int
-BoxColorOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-           Tcl_Obj *const *objv)
-{
-    float color[3];
-    if (GetFloatFromObj(interp, objv[2], &color[0]) != TCL_OK ||
-        GetFloatFromObj(interp, objv[3], &color[1]) != TCL_OK ||
-        GetFloatFromObj(interp, objv[4], &color[2]) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 6) {
-        const char *name = Tcl_GetString(objv[5]);
-        g_renderer->setGraphicsObjectColor<Box>(name, color);
-    } else {
-        g_renderer->setGraphicsObjectColor<Box>("all", color);
-    }
-    return TCL_OK;
-}
-
-static int
-BoxEdgeVisibilityOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                    Tcl_Obj *const *objv)
-{
-    bool state;
-    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 4) {
-        const char *name = Tcl_GetString(objv[3]);
-        g_renderer->setGraphicsObjectEdgeVisibility<Box>(name, state);
-    } else {
-        g_renderer->setGraphicsObjectEdgeVisibility<Box>("all", state);
-    }
-    return TCL_OK;
-}
-
-static int
-BoxLightingOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-              Tcl_Obj *const *objv)
-{
-    bool state;
-    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 4) {
-        const char *name = Tcl_GetString(objv[3]);
-        g_renderer->setGraphicsObjectLighting<Box>(name, state);
-    } else {
-        g_renderer->setGraphicsObjectLighting<Box>("all", state);
-    }
-    return TCL_OK;
-}
-
-static int
-BoxLineColorOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-               Tcl_Obj *const *objv)
-{
-    float color[3];
-    if (GetFloatFromObj(interp, objv[2], &color[0]) != TCL_OK ||
-        GetFloatFromObj(interp, objv[3], &color[1]) != TCL_OK ||
-        GetFloatFromObj(interp, objv[4], &color[2]) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 6) {
-        const char *name = Tcl_GetString(objv[5]);
-        g_renderer->setGraphicsObjectEdgeColor<Box>(name, color);
-    } else {
-        g_renderer->setGraphicsObjectEdgeColor<Box>("all", color);
-    }
-    return TCL_OK;
-}
-
-static int
-BoxLineWidthOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-               Tcl_Obj *const *objv)
-{
-    float width;
-    if (GetFloatFromObj(interp, objv[2], &width) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 4) {
-        const char *name = Tcl_GetString(objv[3]);
-        g_renderer->setGraphicsObjectEdgeWidth<Box>(name, width);
-    } else {
-        g_renderer->setGraphicsObjectEdgeWidth<Box>("all", width);
-    }
-    return TCL_OK;
-}
-
-static int
-BoxMaterialOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-              Tcl_Obj *const *objv)
-{
-    double ambient, diffuse, specCoeff, specPower;
-    if (Tcl_GetDoubleFromObj(interp, objv[2], &ambient) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[3], &diffuse) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[4], &specCoeff) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[5], &specPower) != TCL_OK) {
-        return TCL_ERROR;
-    }
-
-    if (objc == 7) {
-        const char *name = Tcl_GetString(objv[6]);
-        g_renderer->setGraphicsObjectAmbient<Box>(name, ambient);
-        g_renderer->setGraphicsObjectDiffuse<Box>(name, diffuse);
-        g_renderer->setGraphicsObjectSpecular<Box>(name, specCoeff, specPower);
-    } else {
-        g_renderer->setGraphicsObjectAmbient<Box>("all", ambient);
-        g_renderer->setGraphicsObjectDiffuse<Box>("all", diffuse);
-        g_renderer->setGraphicsObjectSpecular<Box>("all", specCoeff, specPower);
-    }
-    return TCL_OK;
-}
-
-static int
-BoxOpacityOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-             Tcl_Obj *const *objv)
-{
-    double opacity;
-    if (Tcl_GetDoubleFromObj(interp, objv[2], &opacity) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 4) {
-        const char *name = Tcl_GetString(objv[3]);
-        g_renderer->setGraphicsObjectOpacity<Box>(name, opacity);
-    } else {
-        g_renderer->setGraphicsObjectOpacity<Box>("all", opacity);
-    }
-    return TCL_OK;
-}
-
-static int
-BoxOrientOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-            Tcl_Obj *const *objv)
-{
-    double quat[4];
-    if (Tcl_GetDoubleFromObj(interp, objv[2], &quat[0]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[3], &quat[1]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[4], &quat[2]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[5], &quat[3]) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 7) {
-        const char *name = Tcl_GetString(objv[6]);
-        g_renderer->setGraphicsObjectOrientation<Box>(name, quat);
-    } else {
-        g_renderer->setGraphicsObjectOrientation<Box>("all", quat);
-    }
-    return TCL_OK;
-}
-
-static int
-BoxPositionOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-              Tcl_Obj *const *objv)
-{
-    double pos[3];
-    if (Tcl_GetDoubleFromObj(interp, objv[2], &pos[0]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[3], &pos[1]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[4], &pos[2]) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 6) {
-        const char *name = Tcl_GetString(objv[5]);
-        g_renderer->setGraphicsObjectPosition<Box>(name, pos);
-    } else {
-        g_renderer->setGraphicsObjectPosition<Box>("all", pos);
-    }
-    return TCL_OK;
-}
-
-static int
-BoxScaleOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-           Tcl_Obj *const *objv)
-{
-    double scale[3];
-    if (Tcl_GetDoubleFromObj(interp, objv[2], &scale[0]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[3], &scale[1]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[4], &scale[2]) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 6) {
-        const char *name = Tcl_GetString(objv[5]);
-        g_renderer->setGraphicsObjectScale<Box>(name, scale);
-    } else {
-        g_renderer->setGraphicsObjectScale<Box>("all", scale);
-    }
-    return TCL_OK;
-}
-
-static int
-BoxVisibleOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-             Tcl_Obj *const *objv)
-{
-    bool state;
-    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 4) {
-        const char *name = Tcl_GetString(objv[3]);
-        g_renderer->setGraphicsObjectVisibility<Box>(name, state);
-    } else {
-        g_renderer->setGraphicsObjectVisibility<Box>("all", state);
-    }
-    return TCL_OK;
-}
-
-static int
-BoxWireframeOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-               Tcl_Obj *const *objv)
-{
-    bool state;
-    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 4) {
-        const char *name = Tcl_GetString(objv[3]);
-        g_renderer->setGraphicsObjectWireframe<Box>(name, state);
-    } else {
-        g_renderer->setGraphicsObjectWireframe<Box>("all", state);
-    }
-    return TCL_OK;
-}
-
-static Rappture::CmdSpec boxOps[] = {
-    {"add",       1, BoxAddOp, 3, 3, "name"},
-    {"color",     1, BoxColorOp, 5, 6, "r g b ?name?"},
-    {"delete",    1, BoxDeleteOp, 2, 3, "?name?"},
-    {"edges",     1, BoxEdgeVisibilityOp, 3, 4, "bool ?name?"},
-    {"lighting",  3, BoxLightingOp, 3, 4, "bool ?name?"},
-    {"linecolor", 5, BoxLineColorOp, 5, 6, "r g b ?name?"},
-    {"linewidth", 5, BoxLineWidthOp, 3, 4, "width ?name?"},
-    {"material",  1, BoxMaterialOp, 6, 7, "ambientCoeff diffuseCoeff specularCoeff specularPower ?name?"},
-    {"opacity",   2, BoxOpacityOp, 3, 4, "value ?name?"},
-    {"orient",    2, BoxOrientOp, 6, 7, "qw qx qy qz ?name?"},
-    {"pos",       2, BoxPositionOp, 5, 6, "x y z ?name?"},
-    {"scale",     1, BoxScaleOp, 5, 6, "sx sy sz ?name?"},
-    {"visible",   1, BoxVisibleOp, 3, 4, "bool ?name?"},
-    {"wireframe", 1, BoxWireframeOp, 3, 4, "bool ?name?"}
-};
-static int nBoxOps = NumCmdSpecs(boxOps);
-
-static int
-BoxCmd(ClientData clientData, Tcl_Interp *interp, int objc, 
-       Tcl_Obj *const *objv)
-{
-    Tcl_ObjCmdProc *proc;
-
-    proc = Rappture::GetOpFromObj(interp, nBoxOps, boxOps,
-                                  Rappture::CMDSPEC_ARG1, objc, objv, 0);
-    if (proc == NULL) {
-        return TCL_ERROR;
-    }
-    return (*proc) (clientData, interp, objc, objv);
-}
-
-static int
-CameraAspectOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-               Tcl_Obj *const *objv)
-{
-    Renderer::Aspect aspect;
-    const char *string = Tcl_GetString(objv[2]);
-    if ((strcmp(string, "native") == 0)) {
-        aspect = Renderer::ASPECT_NATIVE;
-    } else if ((strcmp(string, "square") == 0)) {
-        aspect = Renderer::ASPECT_SQUARE;
-    } else if ((strcmp(string, "window") == 0)) {
-        aspect = Renderer::ASPECT_WINDOW;
-    } else {
-        Tcl_AppendResult(interp, "bad camera aspect option \"", string,
-                         "\": should be native, square or window", (char*)NULL);
-        return TCL_ERROR;
-    }
-    g_renderer->setCameraAspect(aspect);
-    return TCL_OK;
-}
-
-static int
-CameraModeOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-             Tcl_Obj *const *objv)
-{
-    Renderer::CameraMode mode;
-    const char *string = Tcl_GetString(objv[2]);
-    if ((strcmp(string, "persp") == 0)) {
-        mode = Renderer::PERSPECTIVE;
-    } else if ((strcmp(string, "ortho") == 0)) {
-        mode = Renderer::ORTHO;
-    } else if ((strcmp(string, "image") == 0)) {
-        mode = Renderer::IMAGE;
-    } else {
-        Tcl_AppendResult(interp, "bad camera mode option \"", string,
-                         "\": should be persp, ortho or image", (char*)NULL);
-        return TCL_ERROR;
-    }
-    g_renderer->setCameraMode(mode);
-    return TCL_OK;
-}
-
-static int
-CameraGetOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-            Tcl_Obj *const *objv)
-{
-    double pos[3];
-    double focalPt[3];
-    double viewUp[3];
-
-    g_renderer->getCameraOrientationAndPosition(pos, focalPt, viewUp);
-
-    char buf[256];
-    snprintf(buf, sizeof(buf), "nv>camera set %.12e %.12e %.12e %.12e %.12e %.12e %.12e %.12e %.12e\n", 
-             pos[0], pos[1], pos[2], focalPt[0], focalPt[1], focalPt[2], viewUp[0], viewUp[1], viewUp[2]);
-
-#ifdef USE_THREADS
-    queueResponse(clientData, buf, strlen(buf), Response::VOLATILE);
-#else 
-    ssize_t bytesWritten = SocketWrite(buf, strlen(buf));
-    if (bytesWritten < 0) {
-        return TCL_ERROR;
-    }
-#endif
-    return TCL_OK;
-}
-
-static int
-CameraOrientOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-               Tcl_Obj *const *objv)
-{
-    double quat[4];
-
-    if (Tcl_GetDoubleFromObj(interp, objv[2], &quat[0]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[3], &quat[1]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[4], &quat[2]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[5], &quat[3]) != TCL_OK) {
-        return TCL_ERROR;
-    }
-
-    g_renderer->setCameraOrientation(quat);
-    return TCL_OK;
-}
-
-static int
-CameraOrthoOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-              Tcl_Obj *const *objv)
-{
-    const char *string = Tcl_GetString(objv[2]);
-
-    if (string[0] == 'p' && strcmp(string, "pixel") == 0) {
-        int x, y, width, height;
-        if (Tcl_GetIntFromObj(interp, objv[3], &x) != TCL_OK ||
-            Tcl_GetIntFromObj(interp, objv[4], &y) != TCL_OK ||
-            Tcl_GetIntFromObj(interp, objv[5], &width) != TCL_OK ||
-            Tcl_GetIntFromObj(interp, objv[6], &height) != TCL_OK) {
-            return TCL_ERROR;
-        }
-        if (!g_renderer->setCameraZoomRegionPixels(x, y, width, height)) {
-            Tcl_AppendResult(interp, "Camera mode is not image", (char*)NULL);
-            return TCL_ERROR;
-        }
-    } else if (string[0] == 'w' && strcmp(string, "world") == 0) {
-        double x, y, width, height;
-        if (Tcl_GetDoubleFromObj(interp, objv[3], &x) != TCL_OK ||
-            Tcl_GetDoubleFromObj(interp, objv[4], &y) != TCL_OK ||
-            Tcl_GetDoubleFromObj(interp, objv[5], &width) != TCL_OK ||
-            Tcl_GetDoubleFromObj(interp, objv[6], &height) != TCL_OK) {
-            return TCL_ERROR;
-        }
-        if (!g_renderer->setCameraZoomRegion(x, y, width, height)) {
-            Tcl_AppendResult(interp, "Camera mode is not image", (char*)NULL);
-            return TCL_ERROR;
-        }
-    } else {
-        Tcl_AppendResult(interp, "bad camera ortho option \"", string,
-                         "\": should be pixel or world", (char*)NULL);
-        return TCL_ERROR;
-    }
-
-    return TCL_OK;
-}
-
-static int
-CameraPanOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-            Tcl_Obj *const *objv)
-{
-    double x, y;
-
-    if (Tcl_GetDoubleFromObj(interp, objv[2], &x) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[3], &y) != TCL_OK) {
-        return TCL_ERROR;
-    }
-
-    g_renderer->panCamera(x, y);
-    return TCL_OK;
-}
-
-static int
-CameraResetOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-              Tcl_Obj *const *objv)
-{
-    if (objc == 3) {
-        const char *string = Tcl_GetString(objv[2]);
-        char c = string[0];
-        if ((c != 'a') || (strcmp(string, "all") != 0)) {
-            Tcl_AppendResult(interp, "bad camera reset option \"", string,
-                         "\": should be all", (char*)NULL);
-            return TCL_ERROR;
-        }
-        g_renderer->resetCamera(true);
-    } else {
-        g_renderer->resetCamera(false);
-    }
-    return TCL_OK;
-}
-
-static int
-CameraRotateOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-               Tcl_Obj *const *objv)
-{
-    double yaw, pitch, roll;
-
-    if (Tcl_GetDoubleFromObj(interp, objv[2], &yaw) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[3], &pitch) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[4], &roll) != TCL_OK) {
-        return TCL_ERROR;
-    }
-
-    g_renderer->rotateCamera(yaw, pitch, roll);
-    return TCL_OK;
-}
-
-static int
-CameraSetOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-            Tcl_Obj *const *objv)
-{
-    double pos[3];
-    double focalPt[3];
-    double viewUp[3];
-
-    if (Tcl_GetDoubleFromObj(interp, objv[2], &pos[0]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[3], &pos[1]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[4], &pos[2]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[5], &focalPt[0]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[6], &focalPt[1]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[7], &focalPt[2]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[8], &viewUp[0]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[9], &viewUp[1]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[10], &viewUp[2]) != TCL_OK) {
-        return TCL_ERROR;
-    }
-
-    g_renderer->setCameraOrientationAndPosition(pos, focalPt, viewUp);
-    return TCL_OK;
-}
-
-static int
-CameraZoomOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-            Tcl_Obj *const *objv)
-{
-    double z;
-
-    if (Tcl_GetDoubleFromObj(interp, objv[2], &z) != TCL_OK) {
-        return TCL_ERROR;
-    }
-
-    g_renderer->zoomCamera(z);
-    return TCL_OK;
-}
-
-static Rappture::CmdSpec cameraOps[] = {
-    {"aspect", 1, CameraAspectOp, 3, 3, "aspect"},
-    {"get",    1, CameraGetOp, 2, 2, ""},
-    {"mode",   1, CameraModeOp, 3, 3, "mode"},
-    {"orient", 3, CameraOrientOp, 6, 6, "qw qx qy qz"},
-    {"ortho",  1, CameraOrthoOp, 7, 7, "coordMode x y width height"},
-    {"pan",    1, CameraPanOp, 4, 4, "panX panY"},
-    {"reset",  2, CameraResetOp, 2, 3, "?all?"},
-    {"rotate", 2, CameraRotateOp, 5, 5, "angle angle angle"},
-    {"set",    1, CameraSetOp, 11, 11, "posX posY posZ focalPtX focalPtY focalPtZ viewUpX viewUpY viewUpZ"},
-    {"zoom",   1, CameraZoomOp, 3, 3, "zoomAmount"}
-};
-static int nCameraOps = NumCmdSpecs(cameraOps);
-
-static int
-CameraCmd(ClientData clientData, Tcl_Interp *interp, int objc, 
-          Tcl_Obj *const *objv)
-{
-    Tcl_ObjCmdProc *proc;
-
-    proc = Rappture::GetOpFromObj(interp, nCameraOps, cameraOps,
-                                  Rappture::CMDSPEC_ARG1, objc, objv, 0);
-    if (proc == NULL) {
-        return TCL_ERROR;
-    }
-    return (*proc) (clientData, interp, objc, objv);
-}
-
-static int
-ClientInfoCmd(ClientData clientData, Tcl_Interp *interp, int objc, 
-              Tcl_Obj *const *objv)
-{
-    Tcl_DString ds;
-    Tcl_Obj *objPtr, *listObjPtr, **items;
-    int numItems;
-    char buf[BUFSIZ];
-    const char *string;
-    int length;
-    int result;
-    static bool first = true;
-
-    /* Use the initial client key value pairs as the parts for a generating
-     * a unique file name. */
-    int fd = VtkVis::getStatsFile(interp, objv[1]);
-    if (fd < 0) {
-	Tcl_AppendResult(interp, "can't open stats file: ", 
-                         Tcl_PosixError(interp), (char *)NULL);
-	return TCL_ERROR;
-    }
-    listObjPtr = Tcl_NewListObj(0, (Tcl_Obj **)NULL);
-    Tcl_IncrRefCount(listObjPtr);
-    if (first) {
-        first = false;
-        objPtr = Tcl_NewStringObj("render_start", 12);
-        Tcl_ListObjAppendElement(interp, listObjPtr, objPtr);
-        /* server */
-        objPtr = Tcl_NewStringObj("server", 6);
-        Tcl_ListObjAppendElement(interp, listObjPtr, objPtr);
-        objPtr = Tcl_NewStringObj("vtkvis", 6);
-        Tcl_ListObjAppendElement(interp, listObjPtr, objPtr);
-        /* pid */
-        objPtr = Tcl_NewStringObj("pid", 3);
-        Tcl_ListObjAppendElement(interp, listObjPtr, objPtr);
-        Tcl_ListObjAppendElement(interp, listObjPtr, Tcl_NewIntObj(getpid()));
-        /* machine */
-        objPtr = Tcl_NewStringObj("machine", 7);
-        Tcl_ListObjAppendElement(interp, listObjPtr, objPtr);
-        gethostname(buf, BUFSIZ-1);
-        buf[BUFSIZ-1] = '\0';
-        objPtr = Tcl_NewStringObj(buf, -1);
-        Tcl_ListObjAppendElement(interp, listObjPtr, objPtr);
-    } else {
-        objPtr = Tcl_NewStringObj("render_info", 11);
-        Tcl_ListObjAppendElement(interp, listObjPtr, objPtr);
-    }
-    /* date */
-    Tcl_ListObjAppendElement(interp, listObjPtr, Tcl_NewStringObj("date", 4));
-    strcpy(buf, ctime(&VtkVis::g_stats.start.tv_sec));
-    buf[strlen(buf) - 1] = '\0';
-    Tcl_ListObjAppendElement(interp, listObjPtr, Tcl_NewStringObj(buf, -1));
-    /* date_secs */
-    Tcl_ListObjAppendElement(interp, listObjPtr, 
-                             Tcl_NewStringObj("date_secs", 9));
-    Tcl_ListObjAppendElement(interp, listObjPtr, 
-                             Tcl_NewLongObj(VtkVis::g_stats.start.tv_sec));
-    /* Client arguments. */
-    if (Tcl_ListObjGetElements(interp, objv[1], &numItems, &items) != TCL_OK) {
-	return TCL_ERROR;
-    }
-    for (int i = 0; i < numItems; i++) {
-        Tcl_ListObjAppendElement(interp, listObjPtr, items[i]);
-    }
-    Tcl_DStringInit(&ds);
-    string = Tcl_GetStringFromObj(listObjPtr, &length);
-    Tcl_DStringAppend(&ds, string, length);
-    Tcl_DStringAppend(&ds, "\n", 1);
-    result = VtkVis::writeToStatsFile(fd, Tcl_DStringValue(&ds), 
-                                      Tcl_DStringLength(&ds));
-    Tcl_DStringFree(&ds);
-    Tcl_DecrRefCount(listObjPtr);
-    return result;
-}
-
-static int
-ColorMapAddOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-              Tcl_Obj *const *objv)
-{
-    const char *name = Tcl_GetString(objv[2]);
-    int cmapc, omapc;
-    Tcl_Obj **cmapv = NULL;
-    Tcl_Obj **omapv = NULL;
-
-    if (Tcl_ListObjGetElements(interp, objv[3], &cmapc, &cmapv) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if ((cmapc % 4) != 0) {
-        Tcl_AppendResult(interp, "wrong # elements in colormap: should be ",
-                         "{ value r g b ... }", (char*)NULL);
-        return TCL_ERROR;
-    }
-
-    ColorMap *colorMap = new ColorMap(name);
-    colorMap->setNumberOfTableEntries(256);
-
-    for (int i = 0; i < cmapc; i += 4) {
-        double val[4];
-        for (int j = 0; j < 4; j++) {
-            if (Tcl_GetDoubleFromObj(interp, cmapv[i+j], &val[j]) != TCL_OK) {
-                delete colorMap;
-                return TCL_ERROR;
-            }
-            if ((val[j] < 0.0) || (val[j] > 1.0)) {
-                Tcl_AppendResult(interp, "bad colormap value \"",
-                                 Tcl_GetString(cmapv[i+j]),
-                                 "\": should be in the range [0,1]", (char*)NULL);
-                delete colorMap;
-                return TCL_ERROR;
-            }
-        }
-        ColorMap::ControlPoint cp;
-        cp.value = val[0];
-        for (int c = 0; c < 3; c++) {
-            cp.color[c] = val[c+1];
-        }
-        colorMap->addControlPoint(cp);
-    }
-
-    if (Tcl_ListObjGetElements(interp, objv[4], &omapc, &omapv) != TCL_OK) {
-        delete colorMap;
-        return TCL_ERROR;
-    }
-    if ((omapc % 2) != 0) {
-        Tcl_AppendResult(interp, "wrong # elements in opacitymap: should be ",
-                         "{ value alpha ... }", (char*)NULL);
-        delete colorMap;
-        return TCL_ERROR;
-    }
-    for (int i = 0; i < omapc; i += 2) {
-        double val[2];
-        for (int j = 0; j < 2; j++) {
-            if (Tcl_GetDoubleFromObj(interp, omapv[i+j], &val[j]) != TCL_OK) {
-                delete colorMap;
-                return TCL_ERROR;
-            }
-            if ((val[j] < 0.0) || (val[j] > 1.0)) {
-                Tcl_AppendResult(interp, "bad opacitymap value \"",
-                                 Tcl_GetString(omapv[i+j]),
-                                 "\": should be in the range [0,1]", (char*)NULL);
-                delete colorMap;
-                return TCL_ERROR;
-            }
-        }
-        ColorMap::OpacityControlPoint ocp;
-        ocp.value = val[0];
-        ocp.alpha = val[1];
-        colorMap->addOpacityControlPoint(ocp);
-    }
-
-    colorMap->build();
-    g_renderer->addColorMap(name, colorMap);
-    return TCL_OK;
-}
-
-static int
-ColorMapDeleteOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                 Tcl_Obj *const *objv)
-{
-    if (objc == 3) {
-        const char *name = Tcl_GetString(objv[2]);
-        g_renderer->deleteColorMap(name);
-    } else {
-        g_renderer->deleteColorMap("all");
-    }
-    return TCL_OK;
-}
-
-static int
-ColorMapNumTableEntriesOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                          Tcl_Obj *const *objv)
-{
-    int numEntries;
-    if (Tcl_GetIntFromObj(interp, objv[2], &numEntries) != TCL_OK) {
-        const char *str = Tcl_GetString(objv[2]);
-        if (strcmp(str, "default") == 0) {
-            numEntries = -1;
-        } else {
-            Tcl_AppendResult(interp, "bad colormap resolution value \"", str,
-                             "\": should be a positive integer or \"default\"", (char*)NULL);
-            return TCL_ERROR;
-        }
-    } else if (numEntries < 1) {
-        Tcl_AppendResult(interp, "bad colormap resolution value \"", Tcl_GetString(objv[2]),
-                         "\": should be a positive integer or \"default\"", (char*)NULL);
-        return TCL_ERROR;
-    }
-    if (objc == 4) {
-        const char *name = Tcl_GetString(objv[3]);
-
-        g_renderer->setColorMapNumberOfTableEntries(name, numEntries);
-    } else {
-        g_renderer->setColorMapNumberOfTableEntries("all", numEntries);
-    }
-    return TCL_OK;
-}
-
-static Rappture::CmdSpec colorMapOps[] = {
-    {"add",    1, ColorMapAddOp,             5, 5, "colorMapName colormap alphamap"},
-    {"delete", 1, ColorMapDeleteOp,          2, 3, "?colorMapName?"},
-    {"res",    1, ColorMapNumTableEntriesOp, 3, 4, "numTableEntries ?colorMapName?"}
-};
-static int nColorMapOps = NumCmdSpecs(colorMapOps);
-
-static int
-ColorMapCmd(ClientData clientData, Tcl_Interp *interp, int objc, 
-            Tcl_Obj *const *objv)
-{
-    Tcl_ObjCmdProc *proc;
-
-    proc = Rappture::GetOpFromObj(interp, nColorMapOps, colorMapOps,
-                                  Rappture::CMDSPEC_ARG1, objc, objv, 0);
-    if (proc == NULL) {
-        return TCL_ERROR;
-    }
-    return (*proc) (clientData, interp, objc, objv);
-}
-
-static int
-ConeAddOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-          Tcl_Obj *const *objv)
-{
-    double radius, height;
-    bool cap;
-    if (Tcl_GetDoubleFromObj(interp, objv[2], &radius) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[3], &height) != TCL_OK ||
-        GetBooleanFromObj(interp, objv[4], &cap) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    const char *name = Tcl_GetString(objv[5]);
-    if (!g_renderer->addCone(name, radius, height, cap)) {
-        Tcl_AppendResult(interp, "Failed to create cone", (char*)NULL);
-        return TCL_ERROR;
-    }
-    return TCL_OK;
-}
-
-static int
-ConeDeleteOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-             Tcl_Obj *const *objv)
-{
-    if (objc == 3) {
-        const char *name = Tcl_GetString(objv[2]);
-        g_renderer->deleteGraphicsObject<Cone>(name);
-    } else {
-        g_renderer->deleteGraphicsObject<Cone>("all");
-    }
-    return TCL_OK;
-}
-
-static int
-ConeColorOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-            Tcl_Obj *const *objv)
-{
-    float color[3];
-    if (GetFloatFromObj(interp, objv[2], &color[0]) != TCL_OK ||
-        GetFloatFromObj(interp, objv[3], &color[1]) != TCL_OK ||
-        GetFloatFromObj(interp, objv[4], &color[2]) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 6) {
-        const char *name = Tcl_GetString(objv[5]);
-        g_renderer->setGraphicsObjectColor<Cone>(name, color);
-    } else {
-        g_renderer->setGraphicsObjectColor<Cone>("all", color);
-    }
-    return TCL_OK;
-}
-
-static int
-ConeEdgeVisibilityOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                     Tcl_Obj *const *objv)
-{
-    bool state;
-    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 4) {
-        const char *name = Tcl_GetString(objv[3]);
-        g_renderer->setGraphicsObjectEdgeVisibility<Cone>(name, state);
-    } else {
-        g_renderer->setGraphicsObjectEdgeVisibility<Cone>("all", state);
-    }
-    return TCL_OK;
-}
-
-static int
-ConeLightingOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-               Tcl_Obj *const *objv)
-{
-    bool state;
-    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 4) {
-        const char *name = Tcl_GetString(objv[3]);
-        g_renderer->setGraphicsObjectLighting<Cone>(name, state);
-    } else {
-        g_renderer->setGraphicsObjectLighting<Cone>("all", state);
-    }
-    return TCL_OK;
-}
-
-static int
-ConeLineColorOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                Tcl_Obj *const *objv)
-{
-    float color[3];
-    if (GetFloatFromObj(interp, objv[2], &color[0]) != TCL_OK ||
-        GetFloatFromObj(interp, objv[3], &color[1]) != TCL_OK ||
-        GetFloatFromObj(interp, objv[4], &color[2]) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 6) {
-        const char *name = Tcl_GetString(objv[5]);
-        g_renderer->setGraphicsObjectEdgeColor<Cone>(name, color);
-    } else {
-        g_renderer->setGraphicsObjectEdgeColor<Cone>("all", color);
-    }
-    return TCL_OK;
-}
-
-static int
-ConeLineWidthOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                Tcl_Obj *const *objv)
-{
-    float width;
-    if (GetFloatFromObj(interp, objv[2], &width) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 4) {
-        const char *name = Tcl_GetString(objv[3]);
-        g_renderer->setGraphicsObjectEdgeWidth<Cone>(name, width);
-    } else {
-        g_renderer->setGraphicsObjectEdgeWidth<Cone>("all", width);
-    }
-    return TCL_OK;
-}
-
-static int
-ConeMaterialOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-               Tcl_Obj *const *objv)
-{
-    double ambient, diffuse, specCoeff, specPower;
-    if (Tcl_GetDoubleFromObj(interp, objv[2], &ambient) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[3], &diffuse) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[4], &specCoeff) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[5], &specPower) != TCL_OK) {
-        return TCL_ERROR;
-    }
-
-    if (objc == 7) {
-        const char *name = Tcl_GetString(objv[6]);
-        g_renderer->setGraphicsObjectAmbient<Cone>(name, ambient);
-        g_renderer->setGraphicsObjectDiffuse<Cone>(name, diffuse);
-        g_renderer->setGraphicsObjectSpecular<Cone>(name, specCoeff, specPower);
-    } else {
-        g_renderer->setGraphicsObjectAmbient<Cone>("all", ambient);
-        g_renderer->setGraphicsObjectDiffuse<Cone>("all", diffuse);
-        g_renderer->setGraphicsObjectSpecular<Cone>("all", specCoeff, specPower);
-    }
-    return TCL_OK;
-}
-
-static int
-ConeOpacityOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-              Tcl_Obj *const *objv)
-{
-    double opacity;
-    if (Tcl_GetDoubleFromObj(interp, objv[2], &opacity) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 4) {
-        const char *name = Tcl_GetString(objv[3]);
-        g_renderer->setGraphicsObjectOpacity<Cone>(name, opacity);
-    } else {
-        g_renderer->setGraphicsObjectOpacity<Cone>("all", opacity);
-    }
-    return TCL_OK;
-}
-
-static int
-ConeOrientOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-             Tcl_Obj *const *objv)
-{
-    double quat[4];
-    if (Tcl_GetDoubleFromObj(interp, objv[2], &quat[0]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[3], &quat[1]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[4], &quat[2]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[5], &quat[3]) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 7) {
-        const char *name = Tcl_GetString(objv[6]);
-        g_renderer->setGraphicsObjectOrientation<Cone>(name, quat);
-    } else {
-        g_renderer->setGraphicsObjectOrientation<Cone>("all", quat);
-    }
-    return TCL_OK;
-}
-
-static int
-ConePositionOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-               Tcl_Obj *const *objv)
-{
-    double pos[3];
-    if (Tcl_GetDoubleFromObj(interp, objv[2], &pos[0]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[3], &pos[1]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[4], &pos[2]) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 6) {
-        const char *name = Tcl_GetString(objv[5]);
-        g_renderer->setGraphicsObjectPosition<Cone>(name, pos);
-    } else {
-        g_renderer->setGraphicsObjectPosition<Cone>("all", pos);
-    }
-    return TCL_OK;
-}
-
-static int
-ConeResolutionOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                 Tcl_Obj *const *objv)
-{
-    int res;
-    if (Tcl_GetIntFromObj(interp, objv[2], &res) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 4) {
-        const char *name = Tcl_GetString(objv[3]);
-        g_renderer->setConeResolution(name, res);
-    } else {
-        g_renderer->setConeResolution("all", res);
-    }
-    return TCL_OK;
-}
-
-static int
-ConeScaleOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-            Tcl_Obj *const *objv)
-{
-    double scale[3];
-    if (Tcl_GetDoubleFromObj(interp, objv[2], &scale[0]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[3], &scale[1]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[4], &scale[2]) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 6) {
-        const char *name = Tcl_GetString(objv[5]);
-        g_renderer->setGraphicsObjectScale<Cone>(name, scale);
-    } else {
-        g_renderer->setGraphicsObjectScale<Cone>("all", scale);
-    }
-    return TCL_OK;
-}
-
-static int
-ConeVisibleOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-              Tcl_Obj *const *objv)
-{
-    bool state;
-    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 4) {
-        const char *name = Tcl_GetString(objv[3]);
-        g_renderer->setGraphicsObjectVisibility<Cone>(name, state);
-    } else {
-        g_renderer->setGraphicsObjectVisibility<Cone>("all", state);
-    }
-    return TCL_OK;
-}
-
-static int
-ConeWireframeOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                Tcl_Obj *const *objv)
-{
-    bool state;
-    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 4) {
-        const char *name = Tcl_GetString(objv[3]);
-        g_renderer->setGraphicsObjectWireframe<Cone>(name, state);
-    } else {
-        g_renderer->setGraphicsObjectWireframe<Cone>("all", state);
-    }
-    return TCL_OK;
-}
-
-static Rappture::CmdSpec coneOps[] = {
-    {"add",       1, ConeAddOp, 6, 6, "radius height cap name"},
-    {"color",     1, ConeColorOp, 5, 6, "r g b ?name?"},
-    {"delete",    1, ConeDeleteOp, 2, 3, "?name?"},
-    {"edges",     1, ConeEdgeVisibilityOp, 3, 4, "bool ?name?"},
-    {"lighting",  3, ConeLightingOp, 3, 4, "bool ?name?"},
-    {"linecolor", 5, ConeLineColorOp, 5, 6, "r g b ?name?"},
-    {"linewidth", 5, ConeLineWidthOp, 3, 4, "width ?name?"},
-    {"material",  1, ConeMaterialOp, 6, 7, "ambientCoeff diffuseCoeff specularCoeff specularPower ?name?"},
-    {"opacity",   2, ConeOpacityOp, 3, 4, "value ?name?"},
-    {"orient",    2, ConeOrientOp, 6, 7, "qw qx qy qz ?name?"},
-    {"pos",       2, ConePositionOp, 5, 6, "x y z ?name?"},
-    {"resolution",1, ConeResolutionOp, 3, 4, "res ?name?"},
-    {"scale",     1, ConeScaleOp, 5, 6, "sx sy sz ?name?"},
-    {"visible",   1, ConeVisibleOp, 3, 4, "bool ?name?"},
-    {"wireframe", 1, ConeWireframeOp, 3, 4, "bool ?name?"}
-};
-static int nConeOps = NumCmdSpecs(coneOps);
-
-static int
-ConeCmd(ClientData clientData, Tcl_Interp *interp, int objc, 
-       Tcl_Obj *const *objv)
-{
-    Tcl_ObjCmdProc *proc;
-
-    proc = Rappture::GetOpFromObj(interp, nConeOps, coneOps,
-                                  Rappture::CMDSPEC_ARG1, objc, objv, 0);
-    if (proc == NULL) {
-        return TCL_ERROR;
-    }
-    return (*proc) (clientData, interp, objc, objv);
-}
-
-static int
-Contour2DAddContourListOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                          Tcl_Obj *const *objv)
-{
-    std::vector<double> contourList;
-
-    int clistc;
-    Tcl_Obj **clistv;
-
-    if (Tcl_ListObjGetElements(interp, objv[3], &clistc, &clistv) != TCL_OK) {
-        return TCL_ERROR;
-    }
-
-    for (int i = 0; i < clistc; i++) {
-        double val;
-        if (Tcl_GetDoubleFromObj(interp, clistv[i], &val) != TCL_OK) {
-            return TCL_ERROR;
-        }
-        contourList.push_back(val);
-    }
-
-    if (objc == 5) {
-        const char *name = Tcl_GetString(objv[4]);
-        if (!g_renderer->addContour2D(name, contourList)) {
-            Tcl_AppendResult(interp, "Failed to create contour2d", (char*)NULL);
-            return TCL_ERROR;
-        }
-    } else {
-        if (!g_renderer->addContour2D("all", contourList)) {
-            Tcl_AppendResult(interp, "Failed to create contour2d for one or more data sets", (char*)NULL);
-            return TCL_ERROR;
-        }
-    }
-    return TCL_OK;
-}
-
-static int
-Contour2DAddNumContoursOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                          Tcl_Obj *const *objv)
-{
-    int numContours;
-    if (Tcl_GetIntFromObj(interp, objv[3], &numContours) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 5) {
-        const char *name = Tcl_GetString(objv[4]);
-        if (!g_renderer->addContour2D(name, numContours)) {
-            Tcl_AppendResult(interp, "Failed to create contour2d", (char*)NULL);
-            return TCL_ERROR;
-        }
-    } else {
-       if (!g_renderer->addContour2D("all", numContours)) {
-            Tcl_AppendResult(interp, "Failed to create contour2d for one or more data sets", (char*)NULL);
-            return TCL_ERROR;
-       }
-    }
-    return TCL_OK;
-}
-
-static Rappture::CmdSpec contour2dAddOps[] = {
-    {"contourlist", 1, Contour2DAddContourListOp, 4, 5, "contourList ?dataSetName?"},
-    {"numcontours", 1, Contour2DAddNumContoursOp, 4, 5, "numContours ?dataSetName?"}
-};
-static int nContour2dAddOps = NumCmdSpecs(contour2dAddOps);
-
-static int
-Contour2DAddOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-               Tcl_Obj *const *objv)
-{
-    Tcl_ObjCmdProc *proc;
-
-    proc = Rappture::GetOpFromObj(interp, nContour2dAddOps, contour2dAddOps,
-                                  Rappture::CMDSPEC_ARG2, objc, objv, 0);
-    if (proc == NULL) {
-        return TCL_ERROR;
-    }
-    return (*proc) (clientData, interp, objc, objv);
-}
-
-static int
-Contour2DDeleteOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                  Tcl_Obj *const *objv)
-{
-    if (objc == 3) {
-        const char *name = Tcl_GetString(objv[2]);
-        g_renderer->deleteGraphicsObject<Contour2D>(name);
-    } else {
-        g_renderer->deleteGraphicsObject<Contour2D>("all");
-    }
-    return TCL_OK;
-}
-
-static int
-Contour2DColorMapOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                    Tcl_Obj *const *objv)
-{
-    const char *colorMapName = Tcl_GetString(objv[2]);
-    if (objc == 4) {
-        const char *dataSetName = Tcl_GetString(objv[3]);
-        g_renderer->setGraphicsObjectColorMap<Contour2D>(dataSetName, colorMapName);
-    } else {
-        g_renderer->setGraphicsObjectColorMap<Contour2D>("all", colorMapName);
-    }
-    return TCL_OK;
-}
-
-static int
-Contour2DColorModeOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                     Tcl_Obj *const *objv)
-{
-    Contour2D::ColorMode mode;
-    const char *str = Tcl_GetString(objv[2]);
-    if (str[0] == 'c' && strcmp(str, "ccolor") == 0) {
-        mode = Contour2D::COLOR_CONSTANT;
-    } else if (str[0] == 's' && strcmp(str, "scalar") == 0) {
-        mode = Contour2D::COLOR_BY_SCALAR;
-    } else if (str[0] == 'v' && strcmp(str, "vmag") == 0) {
-        mode = Contour2D::COLOR_BY_VECTOR_MAGNITUDE;
-    } else if (str[0] == 'v' && strcmp(str, "vx") == 0) {
-        mode = Contour2D::COLOR_BY_VECTOR_X;
-    } else if (str[0] == 'v' && strcmp(str, "vy") == 0) {
-        mode = Contour2D::COLOR_BY_VECTOR_Y;
-    } else if (str[0] == 'v' && strcmp(str, "vz") == 0) {
-        mode = Contour2D::COLOR_BY_VECTOR_Z;
-    } else {
-        Tcl_AppendResult(interp, "bad color mode option \"", str,
-                         "\": should be one of: 'scalar', 'vmag', 'vx', 'vy', 'vz', 'ccolor'", (char*)NULL);
-        return TCL_ERROR;
-    }
-    const char *fieldName = Tcl_GetString(objv[3]);
-    if (mode == Contour2D::COLOR_CONSTANT) {
-        fieldName = NULL;
-    }
-    if (objc == 5) {
-        const char *name = Tcl_GetString(objv[4]);
-        g_renderer->setContour2DColorMode(name, mode, fieldName);
-    } else {
-        g_renderer->setContour2DColorMode("all", mode, fieldName);
-    }
-    return TCL_OK;
-}
-
-static int
-Contour2DContourListOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                       Tcl_Obj *const *objv)
-{
-    std::vector<double> contourList;
-
-    int clistc;
-    Tcl_Obj **clistv;
-
-    if (Tcl_ListObjGetElements(interp, objv[2], &clistc, &clistv) != TCL_OK) {
-        return TCL_ERROR;
-    }
-
-    for (int i = 0; i < clistc; i++) {
-        double val;
-        if (Tcl_GetDoubleFromObj(interp, clistv[i], &val) != TCL_OK) {
-            return TCL_ERROR;
-        }
-        contourList.push_back(val);
-    }
-
-    if (objc == 4) {
-        const char *name = Tcl_GetString(objv[3]);
-        g_renderer->setContour2DContourList(name, contourList);
-    } else {
-        g_renderer->setContour2DContourList("all", contourList);
-    }
-    return TCL_OK;
-}
-
-static int
-Contour2DLightingOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                    Tcl_Obj *const *objv)
-{
-    bool state;
-    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 4) {
-        const char *name = Tcl_GetString(objv[3]);
-        g_renderer->setGraphicsObjectLighting<Contour2D>(name, state);
-    } else {
-        g_renderer->setGraphicsObjectLighting<Contour2D>("all", state);
-    }
-    return TCL_OK;
-}
-
-static int
-Contour2DLineColorOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                     Tcl_Obj *const *objv)
-{
-    float color[3];
-    if (GetFloatFromObj(interp, objv[2], &color[0]) != TCL_OK ||
-        GetFloatFromObj(interp, objv[3], &color[1]) != TCL_OK ||
-        GetFloatFromObj(interp, objv[4], &color[2]) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 6) {
-        const char *name = Tcl_GetString(objv[5]);
-        g_renderer->setGraphicsObjectColor<Contour2D>(name, color);
-    } else {
-        g_renderer->setGraphicsObjectColor<Contour2D>("all", color);
-    }
-    return TCL_OK;
-}
-
-static int
-Contour2DLineWidthOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                     Tcl_Obj *const *objv)
-{
-    float width;
-    if (GetFloatFromObj(interp, objv[2], &width) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 4) {
-        const char *name = Tcl_GetString(objv[3]);
-        g_renderer->setGraphicsObjectEdgeWidth<Contour2D>(name, width);
-    } else {
-        g_renderer->setGraphicsObjectEdgeWidth<Contour2D>("all", width);
-    }
-    return TCL_OK;
-}
-
-
-static int
-Contour2DNumContoursOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                       Tcl_Obj *const *objv)
-{
-    int numContours;
-
-    if (Tcl_GetIntFromObj(interp, objv[2], &numContours) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 4) {
-        const char *name = Tcl_GetString(objv[3]);
-        g_renderer->setContour2DNumContours(name, numContours);
-    } else {
-        g_renderer->setContour2DNumContours("all", numContours);
-    }
-    return TCL_OK;
-}
-
-static int
-Contour2DOpacityOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                   Tcl_Obj *const *objv)
-{
-    double opacity;
-    if (Tcl_GetDoubleFromObj(interp, objv[2], &opacity) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 4) {
-        const char *name = Tcl_GetString(objv[3]);
-        g_renderer->setGraphicsObjectOpacity<Contour2D>(name, opacity);
-    } else {
-        g_renderer->setGraphicsObjectOpacity<Contour2D>("all", opacity);
-    }
-    return TCL_OK;
-}
-
-static int
-Contour2DOrientOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                  Tcl_Obj *const *objv)
-{
-    double quat[4];
-    if (Tcl_GetDoubleFromObj(interp, objv[2], &quat[0]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[3], &quat[1]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[4], &quat[2]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[5], &quat[3]) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 7) {
-        const char *name = Tcl_GetString(objv[6]);
-        g_renderer->setGraphicsObjectOrientation<Contour2D>(name, quat);
-    } else {
-        g_renderer->setGraphicsObjectOrientation<Contour2D>("all", quat);
-    }
-    return TCL_OK;
-}
-
-static int
-Contour2DPositionOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                    Tcl_Obj *const *objv)
-{
-    double pos[3];
-    if (Tcl_GetDoubleFromObj(interp, objv[2], &pos[0]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[3], &pos[1]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[4], &pos[2]) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 6) {
-        const char *name = Tcl_GetString(objv[5]);
-        g_renderer->setGraphicsObjectPosition<Contour2D>(name, pos);
-    } else {
-        g_renderer->setGraphicsObjectPosition<Contour2D>("all", pos);
-    }
-    return TCL_OK;
-}
-
-static int
-Contour2DScaleOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                 Tcl_Obj *const *objv)
-{
-    double scale[3];
-    if (Tcl_GetDoubleFromObj(interp, objv[2], &scale[0]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[3], &scale[1]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[4], &scale[2]) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 6) {
-        const char *name = Tcl_GetString(objv[5]);
-        g_renderer->setGraphicsObjectScale<Contour2D>(name, scale);
-    } else {
-        g_renderer->setGraphicsObjectScale<Contour2D>("all", scale);
-    }
-    return TCL_OK;
-}
-
-static int
-Contour2DVisibleOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                   Tcl_Obj *const *objv)
-{
-    bool state;
-    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 4) {
-        const char *name = Tcl_GetString(objv[3]);
-        g_renderer->setGraphicsObjectVisibility<Contour2D>(name, state);
-    } else {
-        g_renderer->setGraphicsObjectVisibility<Contour2D>("all", state);
-    }
-    return TCL_OK;
-}
-
-static Rappture::CmdSpec contour2dOps[] = {
-    {"add",          1, Contour2DAddOp, 4, 5, "oper value ?dataSetName?"},
-    {"ccolor",       2, Contour2DLineColorOp, 5, 6, "r g b ?dataSetName?"},
-    {"colormap",     7, Contour2DColorMapOp, 3, 4, "colorMapName ?dataSetName?"},
-    {"colormode",    7, Contour2DColorModeOp, 4, 5, "mode fieldName ?dataSetName?"},
-    {"contourlist",  3, Contour2DContourListOp, 3, 4, "contourList ?dataSetName?"},
-    {"delete",       1, Contour2DDeleteOp, 2, 3, "?dataSetName?"},
-    {"lighting",     3, Contour2DLightingOp, 3, 4, "bool ?dataSetName?"},
-    {"linecolor",    5, Contour2DLineColorOp, 5, 6, "r g b ?dataSetName?"},
-    {"linewidth",    5, Contour2DLineWidthOp, 3, 4, "width ?dataSetName?"},
-    {"numcontours",  1, Contour2DNumContoursOp, 3, 4, "numContours ?dataSetName?"},
-    {"opacity",      2, Contour2DOpacityOp, 3, 4, "value ?dataSetName?"},
-    {"orient",       2, Contour2DOrientOp, 6, 7, "qw qx qy qz ?dataSetName?"},
-    {"pos",          1, Contour2DPositionOp, 5, 6, "x y z ?dataSetName?"},
-    {"scale",        1, Contour2DScaleOp, 5, 6, "sx sy sz ?dataSetName?"},
-    {"visible",      1, Contour2DVisibleOp, 3, 4, "bool ?dataSetName?"}
-};
-static int nContour2dOps = NumCmdSpecs(contour2dOps);
-
-static int
-Contour2DCmd(ClientData clientData, Tcl_Interp *interp, int objc, 
-             Tcl_Obj *const *objv)
-{
-    Tcl_ObjCmdProc *proc;
-
-    proc = Rappture::GetOpFromObj(interp, nContour2dOps, contour2dOps,
-                                  Rappture::CMDSPEC_ARG1, objc, objv, 0);
-    if (proc == NULL) {
-        return TCL_ERROR;
-    }
-    return (*proc) (clientData, interp, objc, objv);
-}
-
-static int
-Contour3DAddContourListOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                          Tcl_Obj *const *objv)
-{
-    std::vector<double> contourList;
-
-    int clistc;
-    Tcl_Obj **clistv;
-
-    if (Tcl_ListObjGetElements(interp, objv[3], &clistc, &clistv) != TCL_OK) {
-        return TCL_ERROR;
-    }
-
-    for (int i = 0; i < clistc; i++) {
-        double val;
-        if (Tcl_GetDoubleFromObj(interp, clistv[i], &val) != TCL_OK) {
-            return TCL_ERROR;
-        }
-        contourList.push_back(val);
-    }
-
-    if (objc == 5) {
-        const char *name = Tcl_GetString(objv[4]);
-        if (!g_renderer->addContour3D(name, contourList)) {
-            Tcl_AppendResult(interp, "Failed to create contour3d", (char*)NULL);
-            return TCL_ERROR;
-        }
-    } else {
-        if (!g_renderer->addContour3D("all", contourList)) {
-            Tcl_AppendResult(interp, "Failed to create contour3d for one or more data sets", (char*)NULL);
-            return TCL_ERROR;
-        }
-    }
-    return TCL_OK;
-}
-
-static int
-Contour3DAddNumContoursOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                          Tcl_Obj *const *objv)
-{
-    int numContours;
-    if (Tcl_GetIntFromObj(interp, objv[3], &numContours) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 5) {
-        const char *name = Tcl_GetString(objv[4]);
-        if (!g_renderer->addContour3D(name, numContours)) {
-            Tcl_AppendResult(interp, "Failed to create contour3d", (char*)NULL);
-            return TCL_ERROR;
-        }
-    } else {
-        if (!g_renderer->addContour3D("all", numContours)) {
-            Tcl_AppendResult(interp, "Failed to create contour3d for one or more data sets", (char*)NULL);
-            return TCL_ERROR;
-        }
-    }
-    return TCL_OK;
-}
-
-static Rappture::CmdSpec contour3dAddOps[] = {
-    {"contourlist", 1, Contour3DAddContourListOp, 4, 5, "contourList ?dataSetName?"},
-    {"numcontours", 1, Contour3DAddNumContoursOp, 4, 5, "numContours ?dataSetName?"}
-};
-static int nContour3dAddOps = NumCmdSpecs(contour3dAddOps);
-
-static int
-Contour3DAddOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-               Tcl_Obj *const *objv)
-{
-    Tcl_ObjCmdProc *proc;
-
-    proc = Rappture::GetOpFromObj(interp, nContour3dAddOps, contour3dAddOps,
-                                  Rappture::CMDSPEC_ARG2, objc, objv, 0);
-    if (proc == NULL) {
-        return TCL_ERROR;
-    }
-    return (*proc) (clientData, interp, objc, objv);
-}
-
-static int
-Contour3DColorOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                 Tcl_Obj *const *objv)
-{
-    float color[3];
-    if (GetFloatFromObj(interp, objv[2], &color[0]) != TCL_OK ||
-        GetFloatFromObj(interp, objv[3], &color[1]) != TCL_OK ||
-        GetFloatFromObj(interp, objv[4], &color[2]) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 6) {
-        const char *name = Tcl_GetString(objv[5]);
-        g_renderer->setGraphicsObjectColor<Contour3D>(name, color);
-    } else {
-        g_renderer->setGraphicsObjectColor<Contour3D>("all", color);
-    }
-    return TCL_OK;
-}
-
-static int
-Contour3DColorMapOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                    Tcl_Obj *const *objv)
-{
-    const char *colorMapName = Tcl_GetString(objv[2]);
-    if (objc == 4) {
-        const char *dataSetName = Tcl_GetString(objv[3]);
-        g_renderer->setGraphicsObjectColorMap<Contour3D>(dataSetName, colorMapName);
-    } else {
-        g_renderer->setGraphicsObjectColorMap<Contour3D>("all", colorMapName);
-    }
-    return TCL_OK;
-}
-
-static int
-Contour3DColorModeOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                     Tcl_Obj *const *objv)
-{
-    Contour3D::ColorMode mode;
-    const char *str = Tcl_GetString(objv[2]);
-    if (str[0] == 'c' && strcmp(str, "ccolor") == 0) {
-        mode = Contour3D::COLOR_CONSTANT;
-    } else if (str[0] == 's' && strcmp(str, "scalar") == 0) {
-        mode = Contour3D::COLOR_BY_SCALAR;
-    } else if (str[0] == 'v' && strcmp(str, "vmag") == 0) {
-        mode = Contour3D::COLOR_BY_VECTOR_MAGNITUDE;
-    } else if (str[0] == 'v' && strcmp(str, "vx") == 0) {
-        mode = Contour3D::COLOR_BY_VECTOR_X;
-    } else if (str[0] == 'v' && strcmp(str, "vy") == 0) {
-        mode = Contour3D::COLOR_BY_VECTOR_Y;
-    } else if (str[0] == 'v' && strcmp(str, "vz") == 0) {
-        mode = Contour3D::COLOR_BY_VECTOR_Z;
-    } else {
-        Tcl_AppendResult(interp, "bad color mode option \"", str,
-                         "\": should be one of: 'scalar', 'vmag', 'vx', 'vy', 'vz', 'ccolor'", (char*)NULL);
-        return TCL_ERROR;
-    }
-    const char *fieldName = Tcl_GetString(objv[3]);
-    if (mode == Contour3D::COLOR_CONSTANT) {
-        fieldName = NULL;
-    }
-    if (objc == 5) {
-        const char *name = Tcl_GetString(objv[4]);
-        g_renderer->setContour3DColorMode(name, mode, fieldName);
-    } else {
-        g_renderer->setContour3DColorMode("all", mode, fieldName);
-    }
-    return TCL_OK;
-}
-
-static int
-Contour3DContourFieldOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                        Tcl_Obj *const *objv)
-{
-    const char *fieldName = Tcl_GetString(objv[2]);
-    if (objc == 4) {
-        const char *dataSetName = Tcl_GetString(objv[3]);
-        g_renderer->setContour3DContourField(dataSetName, fieldName);
-    } else {
-        g_renderer->setContour3DContourField("all", fieldName);
-    }
-    return TCL_OK;
-}
-
-static int
-Contour3DContourListOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                       Tcl_Obj *const *objv)
-{
-    std::vector<double> contourList;
-
-    int clistc;
-    Tcl_Obj **clistv;
-
-    if (Tcl_ListObjGetElements(interp, objv[2], &clistc, &clistv) != TCL_OK) {
-        return TCL_ERROR;
-    }
-
-    for (int i = 0; i < clistc; i++) {
-        double val;
-        if (Tcl_GetDoubleFromObj(interp, clistv[i], &val) != TCL_OK) {
-            return TCL_ERROR;
-        }
-        contourList.push_back(val);
-    }
-
-    if (objc == 4) {
-        const char *name = Tcl_GetString(objv[3]);
-        g_renderer->setContour3DContourList(name, contourList);
-    } else {
-        g_renderer->setContour3DContourList("all", contourList);
-    }
-    return TCL_OK;
-}
-
-static int
-Contour3DDeleteOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                  Tcl_Obj *const *objv)
-{
-    if (objc == 3) {
-        const char *name = Tcl_GetString(objv[2]);
-        g_renderer->deleteGraphicsObject<Contour3D>(name);
-    } else {
-        g_renderer->deleteGraphicsObject<Contour3D>("all");
-    }
-    return TCL_OK;
-}
-
-static int
-Contour3DEdgeVisibilityOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                          Tcl_Obj *const *objv)
-{
-    bool state;
-    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 4) {
-        const char *name = Tcl_GetString(objv[3]);
-        g_renderer->setGraphicsObjectEdgeVisibility<Contour3D>(name, state);
-    } else {
-        g_renderer->setGraphicsObjectEdgeVisibility<Contour3D>("all", state);
-    }
-    return TCL_OK;
-}
-
-static int
-Contour3DLightingOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                    Tcl_Obj *const *objv)
-{
-    bool state;
-    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 4) {
-        const char *name = Tcl_GetString(objv[3]);
-        g_renderer->setGraphicsObjectLighting<Contour3D>(name, state);
-    } else {
-        g_renderer->setGraphicsObjectLighting<Contour3D>("all", state);
-    }
-    return TCL_OK;
-}
-
-static int
-Contour3DLineColorOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                     Tcl_Obj *const *objv)
-{
-    float color[3];
-    if (GetFloatFromObj(interp, objv[2], &color[0]) != TCL_OK ||
-        GetFloatFromObj(interp, objv[3], &color[1]) != TCL_OK ||
-        GetFloatFromObj(interp, objv[4], &color[2]) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 6) {
-        const char *name = Tcl_GetString(objv[5]);
-        g_renderer->setGraphicsObjectEdgeColor<Contour3D>(name, color);
-    } else {
-        g_renderer->setGraphicsObjectEdgeColor<Contour3D>("all", color);
-    }
-    return TCL_OK;
-}
-
-static int
-Contour3DLineWidthOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                     Tcl_Obj *const *objv)
-{
-    float width;
-    if (GetFloatFromObj(interp, objv[2], &width) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 4) {
-        const char *name = Tcl_GetString(objv[3]);
-        g_renderer->setGraphicsObjectEdgeWidth<Contour3D>(name, width);
-    } else {
-        g_renderer->setGraphicsObjectEdgeWidth<Contour3D>("all", width);
-    }
-    return TCL_OK;
-}
-
-static int
-Contour3DNumContoursOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                       Tcl_Obj *const *objv)
-{
-    int numContours;
-
-    if (Tcl_GetIntFromObj(interp, objv[2], &numContours) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 4) {
-        const char *name = Tcl_GetString(objv[3]);
-        g_renderer->setContour3DNumContours(name, numContours);
-    } else {
-        g_renderer->setContour3DNumContours("all", numContours);
-    }
-    return TCL_OK;
-}
-
-static int
-Contour3DOpacityOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                   Tcl_Obj *const *objv)
-{
-    double opacity;
-    if (Tcl_GetDoubleFromObj(interp, objv[2], &opacity) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 4) {
-        const char *name = Tcl_GetString(objv[3]);
-        g_renderer->setGraphicsObjectOpacity<Contour3D>(name, opacity);
-    } else {
-        g_renderer->setGraphicsObjectOpacity<Contour3D>("all", opacity);
-    }
-    return TCL_OK;
-}
-
-static int
-Contour3DOrientOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                  Tcl_Obj *const *objv)
-{
-    double quat[4];
-    if (Tcl_GetDoubleFromObj(interp, objv[2], &quat[0]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[3], &quat[1]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[4], &quat[2]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[5], &quat[3]) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 7) {
-        const char *name = Tcl_GetString(objv[6]);
-        g_renderer->setGraphicsObjectOrientation<Contour3D>(name, quat);
-    } else {
-        g_renderer->setGraphicsObjectOrientation<Contour3D>("all", quat);
-    }
-    return TCL_OK;
-}
-
-static int
-Contour3DPositionOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                    Tcl_Obj *const *objv)
-{
-    double pos[3];
-    if (Tcl_GetDoubleFromObj(interp, objv[2], &pos[0]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[3], &pos[1]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[4], &pos[2]) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 6) {
-        const char *name = Tcl_GetString(objv[5]);
-        g_renderer->setGraphicsObjectPosition<Contour3D>(name, pos);
-    } else {
-        g_renderer->setGraphicsObjectPosition<Contour3D>("all", pos);
-    }
-    return TCL_OK;
-}
-
-static int
-Contour3DScaleOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                 Tcl_Obj *const *objv)
-{
-    double scale[3];
-    if (Tcl_GetDoubleFromObj(interp, objv[2], &scale[0]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[3], &scale[1]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[4], &scale[2]) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 6) {
-        const char *name = Tcl_GetString(objv[5]);
-        g_renderer->setGraphicsObjectScale<Contour3D>(name, scale);
-    } else {
-        g_renderer->setGraphicsObjectScale<Contour3D>("all", scale);
-    }
-    return TCL_OK;
-}
-
-static int
-Contour3DVisibleOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                   Tcl_Obj *const *objv)
-{
-    bool state;
-    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 4) {
-        const char *name = Tcl_GetString(objv[3]);
-        g_renderer->setGraphicsObjectVisibility<Contour3D>(name, state);
-    } else {
-        g_renderer->setGraphicsObjectVisibility<Contour3D>("all", state);
-    }
-    return TCL_OK;
-}
-
-static int
-Contour3DWireframeOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                     Tcl_Obj *const *objv)
-{
-    bool state;
-    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 4) {
-        const char *name = Tcl_GetString(objv[3]);
-        g_renderer->setGraphicsObjectWireframe<Contour3D>(name, state);
-    } else {
-        g_renderer->setGraphicsObjectWireframe<Contour3D>("all", state);
-    }
-    return TCL_OK;
-}
-
-static Rappture::CmdSpec contour3dOps[] = {
-    {"add",          1, Contour3DAddOp, 4, 5, "oper value ?dataSetName?"},
-    {"ccolor",       2, Contour3DColorOp, 5, 6, "r g b ?dataSetName?"},
-    {"colormap",     7, Contour3DColorMapOp, 3, 4, "colorMapName ?dataSetName?"},
-    {"colormode",    7, Contour3DColorModeOp, 4, 5, "mode fieldName ?dataSetName?"},
-    {"contourfield", 8, Contour3DContourFieldOp, 3, 4, "fieldName ?dataSetName?"},
-    {"contourlist",  8, Contour3DContourListOp, 3, 4, "contourList ?dataSetName?"},
-    {"delete",       1, Contour3DDeleteOp, 2, 3, "?dataSetName?"},
-    {"edges",        1, Contour3DEdgeVisibilityOp, 3, 4, "bool ?dataSetName?"},
-    {"lighting",     3, Contour3DLightingOp, 3, 4, "bool ?dataSetName?"},
-    {"linecolor",    5, Contour3DLineColorOp, 5, 6, "r g b ?dataSetName?"},
-    {"linewidth",    5, Contour3DLineWidthOp, 3, 4, "width ?dataSetName?"},
-    {"numcontours",  1, Contour3DNumContoursOp, 3, 4, "numContours ?dataSetName?"},
-    {"opacity",      2, Contour3DOpacityOp, 3, 4, "value ?dataSetName?"},
-    {"orient",       2, Contour3DOrientOp, 6, 7, "qw qx qy qz ?dataSetName?"},
-    {"pos",          1, Contour3DPositionOp, 5, 6, "x y z ?dataSetName?"},
-    {"scale",        1, Contour3DScaleOp, 5, 6, "sx sy sz ?dataSetName?"},
-    {"visible",      1, Contour3DVisibleOp, 3, 4, "bool ?dataSetName?"},
-    {"wireframe",    1, Contour3DWireframeOp, 3, 4, "bool ?dataSetName?"}
-};
-static int nContour3dOps = NumCmdSpecs(contour3dOps);
-
-static int
-Contour3DCmd(ClientData clientData, Tcl_Interp *interp, int objc, 
-             Tcl_Obj *const *objv)
-{
-    Tcl_ObjCmdProc *proc;
-
-    proc = Rappture::GetOpFromObj(interp, nContour3dOps, contour3dOps,
-                                  Rappture::CMDSPEC_ARG1, objc, objv, 0);
-    if (proc == NULL) {
-        return TCL_ERROR;
-    }
-    return (*proc) (clientData, interp, objc, objv);
-}
-
-static int
-CutplaneAddOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-              Tcl_Obj *const *objv)
-{
-    if (objc == 3) {
-        const char *name = Tcl_GetString(objv[2]);
-        if (!g_renderer->addGraphicsObject<Cutplane>(name)) {
-            Tcl_AppendResult(interp, "Failed to create cutplane", (char*)NULL);
-            return TCL_ERROR;
-        }
-    } else {
-        if (!g_renderer->addGraphicsObject<Cutplane>("all")) {
-            Tcl_AppendResult(interp, "Failed to create cutplane for one or more data sets", (char*)NULL);
-            return TCL_ERROR;
-        }
-    }
-    return TCL_OK;
-}
-
-static int
-CutplaneColorOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                Tcl_Obj *const *objv)
-{
-    float color[3];
-    if (GetFloatFromObj(interp, objv[2], &color[0]) != TCL_OK ||
-        GetFloatFromObj(interp, objv[3], &color[1]) != TCL_OK ||
-        GetFloatFromObj(interp, objv[4], &color[2]) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 6) {
-        const char *name = Tcl_GetString(objv[5]);
-        g_renderer->setGraphicsObjectColor<Cutplane>(name, color);
-    } else {
-        g_renderer->setGraphicsObjectColor<Cutplane>("all", color);
-    }
-    return TCL_OK;
-}
-
-static int
-CutplaneColorMapOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                   Tcl_Obj *const *objv)
-{
-    const char *colorMapName = Tcl_GetString(objv[2]);
-    if (objc == 4) {
-        const char *dataSetName = Tcl_GetString(objv[3]);
-        g_renderer->setGraphicsObjectColorMap<Cutplane>(dataSetName, colorMapName);
-    } else {
-        g_renderer->setGraphicsObjectColorMap<Cutplane>("all", colorMapName);
-    }
-    return TCL_OK;
-}
-
-static int
-CutplaneColorModeOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                    Tcl_Obj *const *objv)
-{
-    Cutplane::ColorMode mode;
-    const char *str = Tcl_GetString(objv[2]);
-    if (str[0] == 's' && strcmp(str, "scalar") == 0) {
-        mode = Cutplane::COLOR_BY_SCALAR;
-    } else if (str[0] == 'v' && strcmp(str, "vmag") == 0) {
-        mode = Cutplane::COLOR_BY_VECTOR_MAGNITUDE;
-    } else if (str[0] == 'v' && strcmp(str, "vx") == 0) {
-        mode = Cutplane::COLOR_BY_VECTOR_X;
-    } else if (str[0] == 'v' && strcmp(str, "vy") == 0) {
-        mode = Cutplane::COLOR_BY_VECTOR_Y;
-    } else if (str[0] == 'v' && strcmp(str, "vz") == 0) {
-        mode = Cutplane::COLOR_BY_VECTOR_Z;
-    } else {
-        Tcl_AppendResult(interp, "bad color mode option \"", str,
-                         "\": should be one of: 'scalar', 'vmag', 'vx', 'vy', 'vz'", (char*)NULL);
-        return TCL_ERROR;
-    }
-    const char *fieldName = Tcl_GetString(objv[3]);
-    if (objc == 5) {
-        const char *name = Tcl_GetString(objv[4]);
-        g_renderer->setCutplaneColorMode(name, mode, fieldName);
-    } else {
-        g_renderer->setCutplaneColorMode("all", mode, fieldName);
-    }
-    return TCL_OK;
-}
-
-static int
-CutplaneDeleteOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                 Tcl_Obj *const *objv)
-{
-    if (objc == 3) {
-        const char *name = Tcl_GetString(objv[2]);
-        g_renderer->deleteGraphicsObject<Cutplane>(name);
-    } else {
-        g_renderer->deleteGraphicsObject<Cutplane>("all");
-    }
-    return TCL_OK;
-}
-
-static int
-CutplaneEdgeVisibilityOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                         Tcl_Obj *const *objv)
-{
-    bool state;
-    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 4) {
-        const char *name = Tcl_GetString(objv[3]);
-        g_renderer->setGraphicsObjectEdgeVisibility<Cutplane>(name, state);
-    } else {
-        g_renderer->setGraphicsObjectEdgeVisibility<Cutplane>("all", state);
-    }
-    return TCL_OK;
-}
-
-static int
-CutplaneLightingOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                   Tcl_Obj *const *objv)
-{
-    bool state;
-    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 4) {
-        const char *name = Tcl_GetString(objv[3]);
-        g_renderer->setGraphicsObjectLighting<Cutplane>(name, state);
-    } else {
-        g_renderer->setGraphicsObjectLighting<Cutplane>("all", state);
-    }
-    return TCL_OK;
-}
-
-static int
-CutplaneLineColorOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                    Tcl_Obj *const *objv)
-{
-    float color[3];
-    if (GetFloatFromObj(interp, objv[2], &color[0]) != TCL_OK ||
-        GetFloatFromObj(interp, objv[3], &color[1]) != TCL_OK ||
-        GetFloatFromObj(interp, objv[4], &color[2]) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 6) {
-        const char *name = Tcl_GetString(objv[5]);
-        g_renderer->setGraphicsObjectEdgeColor<Cutplane>(name, color);
-    } else {
-        g_renderer->setGraphicsObjectEdgeColor<Cutplane>("all", color);
-    }
-    return TCL_OK;
-}
-
-static int
-CutplaneLineWidthOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                    Tcl_Obj *const *objv)
-{
-    float width;
-    if (GetFloatFromObj(interp, objv[2], &width) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 4) {
-        const char *name = Tcl_GetString(objv[3]);
-        g_renderer->setGraphicsObjectEdgeWidth<Cutplane>(name, width);
-    } else {
-        g_renderer->setGraphicsObjectEdgeWidth<Cutplane>("all", width);
-    }
-    return TCL_OK;
-}
-
-static int
-CutplaneOpacityOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                  Tcl_Obj *const *objv)
-{
-    double opacity;
-    if (Tcl_GetDoubleFromObj(interp, objv[2], &opacity) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 4) {
-        const char *name = Tcl_GetString(objv[3]);
-        g_renderer->setGraphicsObjectOpacity<Cutplane>(name, opacity);
-    } else {
-        g_renderer->setGraphicsObjectOpacity<Cutplane>("all", opacity);
-    }
-    return TCL_OK;
-}
-
-static int
-CutplaneOrientOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                 Tcl_Obj *const *objv)
-{
-    double quat[4];
-    if (Tcl_GetDoubleFromObj(interp, objv[2], &quat[0]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[3], &quat[1]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[4], &quat[2]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[5], &quat[3]) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 7) {
-        const char *name = Tcl_GetString(objv[6]);
-        g_renderer->setGraphicsObjectOrientation<Cutplane>(name, quat);
-    } else {
-        g_renderer->setGraphicsObjectOrientation<Cutplane>("all", quat);
-    }
-    return TCL_OK;
-}
-
-static int
-CutplaneOutlineOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                  Tcl_Obj *const *objv)
-{
-    bool state;
-    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 4) {
-        const char *name = Tcl_GetString(objv[3]);
-        g_renderer->setCutplaneOutlineVisibility(name, state);
-    } else {
-        g_renderer->setCutplaneOutlineVisibility("all", state);
-    }
-    return TCL_OK;
-}
-
-static int
-CutplanePositionOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                   Tcl_Obj *const *objv)
-{
-    double pos[3];
-    if (Tcl_GetDoubleFromObj(interp, objv[2], &pos[0]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[3], &pos[1]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[4], &pos[2]) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 6) {
-        const char *name = Tcl_GetString(objv[5]);
-        g_renderer->setGraphicsObjectPosition<Cutplane>(name, pos);
-    } else {
-        g_renderer->setGraphicsObjectPosition<Cutplane>("all", pos);
-    }
-    return TCL_OK;
-}
-
-static int
-CutplanePreInterpOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                    Tcl_Obj *const *objv)
-{
-    bool state;
-    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 4) {
-        const char *name = Tcl_GetString(objv[3]);
-        g_renderer->setGraphicsObjectInterpolateBeforeMapping<Cutplane>(name, state);
-    } else {
-        g_renderer->setGraphicsObjectInterpolateBeforeMapping<Cutplane>("all", state);
-    }
-    return TCL_OK;
-}
-
-static int
-CutplaneScaleOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                Tcl_Obj *const *objv)
-{
-    double scale[3];
-    if (Tcl_GetDoubleFromObj(interp, objv[2], &scale[0]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[3], &scale[1]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[4], &scale[2]) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 6) {
-        const char *name = Tcl_GetString(objv[5]);
-        g_renderer->setGraphicsObjectScale<Cutplane>(name, scale);
-    } else {
-        g_renderer->setGraphicsObjectScale<Cutplane>("all", scale);
-    }
-    return TCL_OK;
-}
-
-static int
-CutplaneSliceVisibilityOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                          Tcl_Obj *const *objv)
-{
-    bool state;
-    if (GetBooleanFromObj(interp, objv[3], &state) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    const char *string = Tcl_GetString(objv[2]);
-    char c = string[0];
-    Axis axis;
-    if ((c == 'x') && (strcmp(string, "x") == 0)) {
-        axis = X_AXIS;
-    } else if ((c == 'y') && (strcmp(string, "y") == 0)) {
-        axis = Y_AXIS;
-    } else if ((c == 'z') && (strcmp(string, "z") == 0)) {
-        axis = Z_AXIS;
-    } else {
-        Tcl_AppendResult(interp, "bad axis option \"", string,
-                         "\": should be axisName bool", (char*)NULL);
-        return TCL_ERROR;
-    }
-    if (objc == 5) {
-        const char *name = Tcl_GetString(objv[4]);
-        g_renderer->setCutplaneSliceVisibility(name, axis, state);
-    } else {
-        g_renderer->setCutplaneSliceVisibility("all", axis, state);
-    }
-    return TCL_OK;
-}
-
-static int
-CutplaneVisibleOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                  Tcl_Obj *const *objv)
-{
-    bool state;
-    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 4) {
-        const char *name = Tcl_GetString(objv[3]);
-        g_renderer->setGraphicsObjectVisibility<Cutplane>(name, state);
-    } else {
-        g_renderer->setGraphicsObjectVisibility<Cutplane>("all", state);
-    }
-    return TCL_OK;
-}
-
-static int
-CutplaneVolumeSliceOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                      Tcl_Obj *const *objv)
-{
-    double ratio;
-    if (Tcl_GetDoubleFromObj(interp, objv[3], &ratio) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    const char *string = Tcl_GetString(objv[2]);
-    char c = string[0];
-    Axis axis;
-    if ((c == 'x') && (strcmp(string, "x") == 0)) {
-        axis = X_AXIS;
-    } else if ((c == 'y') && (strcmp(string, "y") == 0)) {
-        axis = Y_AXIS;
-    } else if ((c == 'z') && (strcmp(string, "z") == 0)) {
-        axis = Z_AXIS;
-    } else {
-        Tcl_AppendResult(interp, "bad axis option \"", string,
-                         "\": should be axisName ratio", (char*)NULL);
-        return TCL_ERROR;
-    }
-    if (objc == 5) {
-        const char *name = Tcl_GetString(objv[4]);
-        g_renderer->setGraphicsObjectVolumeSlice<Cutplane>(name, axis, ratio);
-    } else {
-        g_renderer->setGraphicsObjectVolumeSlice<Cutplane>("all", axis, ratio);
-    }
-    return TCL_OK;
-}
-
-static int
-CutplaneWireframeOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                    Tcl_Obj *const *objv)
-{
-    bool state;
-    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 4) {
-        const char *name = Tcl_GetString(objv[3]);
-        g_renderer->setGraphicsObjectWireframe<Cutplane>(name, state);
-    } else {
-        g_renderer->setGraphicsObjectWireframe<Cutplane>("all", state);
-    }
-    return TCL_OK;
-}
-
-static Rappture::CmdSpec cutplaneOps[] = {
-    {"add",          2, CutplaneAddOp, 2, 3, "oper value ?dataSetName?"},
-    {"axis",         2, CutplaneSliceVisibilityOp, 4, 5, "axis bool ?dataSetName?"},
-    {"ccolor",       2, CutplaneColorOp, 5, 6, "r g b ?dataSetName?"},
-    {"colormap",     7, CutplaneColorMapOp, 3, 4, "colorMapName ?dataSetName?"},
-    {"colormode",    7, CutplaneColorModeOp, 4, 5, "mode fieldName ?dataSetName?"},
-    {"delete",       1, CutplaneDeleteOp, 2, 3, "?dataSetName?"},
-    {"edges",        1, CutplaneEdgeVisibilityOp, 3, 4, "bool ?dataSetName?"},
-    {"lighting",     3, CutplaneLightingOp, 3, 4, "bool ?dataSetName?"},
-    {"linecolor",    5, CutplaneLineColorOp, 5, 6, "r g b ?dataSetName?"},
-    {"linewidth",    5, CutplaneLineWidthOp, 3, 4, "width ?dataSetName?"},
-    {"opacity",      2, CutplaneOpacityOp, 3, 4, "value ?dataSetName?"},
-    {"orient",       2, CutplaneOrientOp, 6, 7, "qw qx qy qz ?dataSetName?"},
-    {"outline",      2, CutplaneOutlineOp, 3, 4, "bool ?dataSetName?"},
-    {"pos",          2, CutplanePositionOp, 5, 6, "x y z ?dataSetName?"},
-    {"preinterp",    2, CutplanePreInterpOp, 3, 4, "bool ?dataSetName?"},
-    {"scale",        2, CutplaneScaleOp, 5, 6, "sx sy sz ?dataSetName?"},
-    {"slice",        2, CutplaneVolumeSliceOp, 4, 5, "axis ratio ?dataSetName?"},
-    {"visible",      1, CutplaneVisibleOp, 3, 4, "bool ?dataSetName?"},
-    {"wireframe",    1, CutplaneWireframeOp, 3, 4, "bool ?dataSetName?"}
-};
-static int nCutplaneOps = NumCmdSpecs(cutplaneOps);
-
-static int
-CutplaneCmd(ClientData clientData, Tcl_Interp *interp, int objc, 
-             Tcl_Obj *const *objv)
-{
-    Tcl_ObjCmdProc *proc;
-
-    proc = Rappture::GetOpFromObj(interp, nCutplaneOps, cutplaneOps,
-                                  Rappture::CMDSPEC_ARG1, objc, objv, 0);
-    if (proc == NULL) {
-        return TCL_ERROR;
-    }
-    return (*proc) (clientData, interp, objc, objv);
-}
-
-static int
-CylinderAddOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-              Tcl_Obj *const *objv)
-{
-    double radius, height;
-    bool cap = true;
-    if (Tcl_GetDoubleFromObj(interp, objv[2], &radius) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[3], &height) != TCL_OK ||
-        GetBooleanFromObj(interp, objv[4], &cap) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    const char *name = Tcl_GetString(objv[5]);
-    if (!g_renderer->addCylinder(name, radius, height, cap)) {
-        Tcl_AppendResult(interp, "Failed to create cylinder", (char*)NULL);
-        return TCL_ERROR;
-    }
-    return TCL_OK;
-}
-
-static int
-CylinderDeleteOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                 Tcl_Obj *const *objv)
-{
-    if (objc == 3) {
-        const char *name = Tcl_GetString(objv[2]);
-        g_renderer->deleteGraphicsObject<Cylinder>(name);
-    } else {
-        g_renderer->deleteGraphicsObject<Cylinder>("all");
-    }
-    return TCL_OK;
-}
-
-static int
-CylinderColorOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                Tcl_Obj *const *objv)
-{
-    float color[3];
-    if (GetFloatFromObj(interp, objv[2], &color[0]) != TCL_OK ||
-        GetFloatFromObj(interp, objv[3], &color[1]) != TCL_OK ||
-        GetFloatFromObj(interp, objv[4], &color[2]) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 6) {
-        const char *name = Tcl_GetString(objv[5]);
-        g_renderer->setGraphicsObjectColor<Cylinder>(name, color);
-    } else {
-        g_renderer->setGraphicsObjectColor<Cylinder>("all", color);
-    }
-    return TCL_OK;
-}
-
-static int
-CylinderEdgeVisibilityOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                         Tcl_Obj *const *objv)
-{
-    bool state;
-    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 4) {
-        const char *name = Tcl_GetString(objv[3]);
-        g_renderer->setGraphicsObjectEdgeVisibility<Cylinder>(name, state);
-    } else {
-        g_renderer->setGraphicsObjectEdgeVisibility<Cylinder>("all", state);
-    }
-    return TCL_OK;
-}
-
-static int
-CylinderLightingOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                   Tcl_Obj *const *objv)
-{
-    bool state;
-    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 4) {
-        const char *name = Tcl_GetString(objv[3]);
-        g_renderer->setGraphicsObjectLighting<Cylinder>(name, state);
-    } else {
-        g_renderer->setGraphicsObjectLighting<Cylinder>("all", state);
-    }
-    return TCL_OK;
-}
-
-static int
-CylinderLineColorOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                    Tcl_Obj *const *objv)
-{
-    float color[3];
-    if (GetFloatFromObj(interp, objv[2], &color[0]) != TCL_OK ||
-        GetFloatFromObj(interp, objv[3], &color[1]) != TCL_OK ||
-        GetFloatFromObj(interp, objv[4], &color[2]) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 6) {
-        const char *name = Tcl_GetString(objv[5]);
-        g_renderer->setGraphicsObjectEdgeColor<Cylinder>(name, color);
-    } else {
-        g_renderer->setGraphicsObjectEdgeColor<Cylinder>("all", color);
-    }
-    return TCL_OK;
-}
-
-static int
-CylinderLineWidthOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                    Tcl_Obj *const *objv)
-{
-    float width;
-    if (GetFloatFromObj(interp, objv[2], &width) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 4) {
-        const char *name = Tcl_GetString(objv[3]);
-        g_renderer->setGraphicsObjectEdgeWidth<Cylinder>(name, width);
-    } else {
-        g_renderer->setGraphicsObjectEdgeWidth<Cylinder>("all", width);
-    }
-    return TCL_OK;
-}
-
-static int
-CylinderMaterialOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                   Tcl_Obj *const *objv)
-{
-    double ambient, diffuse, specCoeff, specPower;
-    if (Tcl_GetDoubleFromObj(interp, objv[2], &ambient) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[3], &diffuse) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[4], &specCoeff) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[5], &specPower) != TCL_OK) {
-        return TCL_ERROR;
-    }
-
-    if (objc == 7) {
-        const char *name = Tcl_GetString(objv[6]);
-        g_renderer->setGraphicsObjectAmbient<Cylinder>(name, ambient);
-        g_renderer->setGraphicsObjectDiffuse<Cylinder>(name, diffuse);
-        g_renderer->setGraphicsObjectSpecular<Cylinder>(name, specCoeff, specPower);
-    } else {
-        g_renderer->setGraphicsObjectAmbient<Cylinder>("all", ambient);
-        g_renderer->setGraphicsObjectDiffuse<Cylinder>("all", diffuse);
-        g_renderer->setGraphicsObjectSpecular<Cylinder>("all", specCoeff, specPower);
-    }
-    return TCL_OK;
-}
-
-static int
-CylinderOpacityOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                  Tcl_Obj *const *objv)
-{
-    double opacity;
-    if (Tcl_GetDoubleFromObj(interp, objv[2], &opacity) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 4) {
-        const char *name = Tcl_GetString(objv[3]);
-        g_renderer->setGraphicsObjectOpacity<Cylinder>(name, opacity);
-    } else {
-        g_renderer->setGraphicsObjectOpacity<Cylinder>("all", opacity);
-    }
-    return TCL_OK;
-}
-
-static int
-CylinderOrientOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                 Tcl_Obj *const *objv)
-{
-    double quat[4];
-    if (Tcl_GetDoubleFromObj(interp, objv[2], &quat[0]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[3], &quat[1]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[4], &quat[2]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[5], &quat[3]) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 7) {
-        const char *name = Tcl_GetString(objv[6]);
-        g_renderer->setGraphicsObjectOrientation<Cylinder>(name, quat);
-    } else {
-        g_renderer->setGraphicsObjectOrientation<Cylinder>("all", quat);
-    }
-    return TCL_OK;
-}
-
-static int
-CylinderPositionOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                   Tcl_Obj *const *objv)
-{
-    double pos[3];
-    if (Tcl_GetDoubleFromObj(interp, objv[2], &pos[0]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[3], &pos[1]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[4], &pos[2]) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 6) {
-        const char *name = Tcl_GetString(objv[5]);
-        g_renderer->setGraphicsObjectPosition<Cylinder>(name, pos);
-    } else {
-        g_renderer->setGraphicsObjectPosition<Cylinder>("all", pos);
-    }
-    return TCL_OK;
-}
-
-static int
-CylinderResolutionOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                     Tcl_Obj *const *objv)
-{
-    int res;
-    if (Tcl_GetIntFromObj(interp, objv[2], &res) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 4) {
-        const char *name = Tcl_GetString(objv[3]);
-        g_renderer->setCylinderResolution(name, res);
-    } else {
-        g_renderer->setCylinderResolution("all", res);
-    }
-    return TCL_OK;
-}
-
-static int
-CylinderScaleOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                Tcl_Obj *const *objv)
-{
-    double scale[3];
-    if (Tcl_GetDoubleFromObj(interp, objv[2], &scale[0]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[3], &scale[1]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[4], &scale[2]) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 6) {
-        const char *name = Tcl_GetString(objv[5]);
-        g_renderer->setGraphicsObjectScale<Cylinder>(name, scale);
-    } else {
-        g_renderer->setGraphicsObjectScale<Cylinder>("all", scale);
-    }
-    return TCL_OK;
-}
-
-static int
-CylinderVisibleOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                  Tcl_Obj *const *objv)
-{
-    bool state;
-    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 4) {
-        const char *name = Tcl_GetString(objv[3]);
-        g_renderer->setGraphicsObjectVisibility<Cylinder>(name, state);
-    } else {
-        g_renderer->setGraphicsObjectVisibility<Cylinder>("all", state);
-    }
-    return TCL_OK;
-}
-
-static int
-CylinderWireframeOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                    Tcl_Obj *const *objv)
-{
-    bool state;
-    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 4) {
-        const char *name = Tcl_GetString(objv[3]);
-        g_renderer->setGraphicsObjectWireframe<Cylinder>(name, state);
-    } else {
-        g_renderer->setGraphicsObjectWireframe<Cylinder>("all", state);
-    }
-    return TCL_OK;
-}
-
-static Rappture::CmdSpec cylinderOps[] = {
-    {"add",       1, CylinderAddOp, 6, 6, " radius height cap name"},
-    {"color",     1, CylinderColorOp, 5, 6, "r g b ?name?"},
-    {"delete",    1, CylinderDeleteOp, 2, 3, "?name?"},
-    {"edges",     1, CylinderEdgeVisibilityOp, 3, 4, "bool ?name?"},
-    {"lighting",  3, CylinderLightingOp, 3, 4, "bool ?name?"},
-    {"linecolor", 5, CylinderLineColorOp, 5, 6, "r g b ?name?"},
-    {"linewidth", 5, CylinderLineWidthOp, 3, 4, "width ?name?"},
-    {"material",  1, CylinderMaterialOp, 6, 7, "ambientCoeff diffuseCoeff specularCoeff specularPower ?name?"},
-    {"opacity",   2, CylinderOpacityOp, 3, 4, "value ?name?"},
-    {"orient",    2, CylinderOrientOp, 6, 7, "qw qx qy qz ?name?"},
-    {"pos",       2, CylinderPositionOp, 5, 6, "x y z ?name?"},
-    {"resolution",1, CylinderResolutionOp, 3, 4, "res ?name?"},
-    {"scale",     1, CylinderScaleOp, 5, 6, "sx sy sz ?name?"},
-    {"visible",   1, CylinderVisibleOp, 3, 4, "bool ?name?"},
-    {"wireframe", 1, CylinderWireframeOp, 3, 4, "bool ?name?"}
-};
-static int nCylinderOps = NumCmdSpecs(cylinderOps);
-
-static int
-CylinderCmd(ClientData clientData, Tcl_Interp *interp, int objc, 
-       Tcl_Obj *const *objv)
-{
-    Tcl_ObjCmdProc *proc;
-
-    proc = Rappture::GetOpFromObj(interp, nCylinderOps, cylinderOps,
-                                  Rappture::CMDSPEC_ARG1, objc, objv, 0);
-    if (proc == NULL) {
-        return TCL_ERROR;
-    }
-    return (*proc) (clientData, interp, objc, objv);
-}
-
-static int
-DataSetActiveScalarsOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                       Tcl_Obj *const *objv)
-{
-    const char *scalarName = Tcl_GetString(objv[2]);
-    if (objc == 4) {
-        const char *name = Tcl_GetString(objv[3]);
-        if (!g_renderer->setDataSetActiveScalars(name, scalarName)) {
-            Tcl_AppendResult(interp, "scalar \"", scalarName,
-                         "\" not found", (char*)NULL);
-            return TCL_ERROR;
-        }
-    } else {
-        if (!g_renderer->setDataSetActiveScalars("all", scalarName)) {
-            Tcl_AppendResult(interp, "scalar \"", scalarName,
-                         "\" not found in one or more data sets", (char*)NULL);
-            return TCL_ERROR;
-        }
-    }
-    return TCL_OK;
-}
-
-static int
-DataSetActiveVectorsOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                       Tcl_Obj *const *objv)
-{
-    const char *vectorName = Tcl_GetString(objv[2]);
-    if (objc == 4) {
-        const char *name = Tcl_GetString(objv[3]);
-        if (!g_renderer->setDataSetActiveVectors(name, vectorName)) {
-            Tcl_AppendResult(interp, "vector \"", vectorName,
-                         "\" not found", (char*)NULL);
-            return TCL_ERROR;
-        }
-    } else {
-        if (!g_renderer->setDataSetActiveVectors("all", vectorName)) {
-            Tcl_AppendResult(interp, "vector \"", vectorName,
-                         "\" not found in one or more data sets", (char*)NULL);
-            return TCL_ERROR;
-        }
-    }
-    return TCL_OK;
-}
-
-static int
-DataSetAddOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-             Tcl_Obj *const *objv)
-{
-    const char *name = Tcl_GetString(objv[2]);
-    const char *string = Tcl_GetString(objv[3]);
-    char c = string[0];
-    if ((c != 'd') || (strcmp(string, "data") != 0)) {
-        Tcl_AppendResult(interp, "bad dataset option \"", string,
-                         "\": should be data", (char*)NULL);
-        return TCL_ERROR;
-    }
-    string = Tcl_GetString(objv[4]);
-    c = string[0];
-    if ((c != 'f') || (strcmp(string, "follows") != 0)) {
-        Tcl_AppendResult(interp, "bad dataset option \"", string,
-                         "\": should be follows", (char*)NULL);
-        return TCL_ERROR;
-    }
-    int nbytes = 0;
-    if (Tcl_GetIntFromObj(interp, objv[5], &nbytes) != TCL_OK ||
-        nbytes < 0) {
-        return TCL_ERROR;
-    }
-    char *data = (char *)malloc(nbytes);
-    if (!SocketRead(data, nbytes)) {
-        free(data);
-        return TCL_ERROR;
-    }
-    g_renderer->addDataSet(name);
-    if (!g_renderer->setData(name, data, nbytes)) {
-        USER_ERROR("Failed to load data for dataset \"%s\"", name);
-        free(data);
-        return TCL_ERROR;
-    }
-    g_stats.nDataSets++;
-    g_stats.nDataBytes += nbytes;
-    free(data);
-    return TCL_OK;
-}
-
-static int
-DataSetDeleteOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                Tcl_Obj *const *objv)
-{
-    if (objc == 3) {
-        const char *name = Tcl_GetString(objv[2]);
-        TRACE("Deleting dataset %s", name);
-        g_renderer->deleteDataSet(name);
-    } else {
-        g_renderer->deleteDataSet("all");
-    }
-    return TCL_OK;
-}
-
-static int
-DataSetGetScalarPixelOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                        Tcl_Obj *const *objv)
-{
-    const char *name = Tcl_GetString(objv[5]);
-    int x, y;
-    if (Tcl_GetIntFromObj(interp, objv[3], &x) != TCL_OK ||
-        Tcl_GetIntFromObj(interp, objv[4], &y) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    double value;
-    if (!g_renderer->getScalarValueAtPixel(name, x, y, &value)) {
-        Tcl_AppendResult(interp, "Pixel out of dataset bounds or no scalar data available", (char*)NULL);
-        return TCL_ERROR;
-    }
-
-    char buf[256];
-    int length;
-
-    length = snprintf(buf, sizeof(buf), "nv>dataset scalar pixel %d %d %g %s\n",
-                      x, y, value, name);
-
-#ifdef USE_THREADS
-    queueResponse(clientData, buf, length, Response::VOLATILE);
-#else
-    ssize_t bytesWritten = SocketWrite(buf, length);
-
-    if (bytesWritten < 0) {
-        return TCL_ERROR;
-    }
-#endif
-    return TCL_OK;
-}
-
-static int
-DataSetGetScalarWorldOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                        Tcl_Obj *const *objv)
-{
-    const char *name = Tcl_GetString(objv[6]);
-    double x, y, z;
-    if (Tcl_GetDoubleFromObj(interp, objv[3], &x) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[4], &y) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[5], &z) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    double value;
-    if (!g_renderer->getScalarValue(name, x, y, z, &value)) {
-        Tcl_AppendResult(interp, "Coordinate out of dataset bounds or no scalar data available", (char*)NULL);
-        return TCL_ERROR;
-    }
-
-    char buf[256];
-    int length;
-
-    length = snprintf(buf, sizeof(buf), 
-                      "nv>dataset scalar world %g %g %g %g %s\n",
-                      x, y, z, value, name);
-
-#ifdef USE_THREADS
-    queueResponse(clientData, buf, length, Response::VOLATILE);
-#else 
-    ssize_t bytesWritten = SocketWrite(buf, length);
-    if (bytesWritten < 0) {
-        return TCL_ERROR;
-    }
-#endif
-    return TCL_OK;
-}
-
-static Rappture::CmdSpec dataSetGetScalarOps[] = {
-    {"pixel", 1, DataSetGetScalarPixelOp, 6, 6, "x y dataSetName"},
-    {"world", 1, DataSetGetScalarWorldOp, 7, 7, "x y z dataSetName"}
-};
-static int nDataSetGetScalarOps = NumCmdSpecs(dataSetGetScalarOps);
-
-static int
-DataSetGetScalarOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                   Tcl_Obj *const *objv)
-{
-    Tcl_ObjCmdProc *proc;
-
-    proc = Rappture::GetOpFromObj(interp, nDataSetGetScalarOps, dataSetGetScalarOps,
-                                  Rappture::CMDSPEC_ARG2, objc, objv, 0);
-    if (proc == NULL) {
-        return TCL_ERROR;
-    }
-    return (*proc) (clientData, interp, objc, objv);
-}
-
-static int
-DataSetGetVectorPixelOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                        Tcl_Obj *const *objv)
-{
-    const char *name = Tcl_GetString(objv[5]);
-    int x, y;
-    if (Tcl_GetIntFromObj(interp, objv[3], &x) != TCL_OK ||
-        Tcl_GetIntFromObj(interp, objv[4], &y) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    double value[3];
-    if (!g_renderer->getVectorValueAtPixel(name, x, y, value)) {
-        Tcl_AppendResult(interp, "Pixel out of dataset bounds or no vector data available", (char*)NULL);
-        return TCL_ERROR;
-    }
-
-    char buf[256];
-    int length; 
-    length = snprintf(buf, sizeof(buf), 
-                      "nv>dataset vector pixel %d %d %g %g %g %s\n",
-                      x, y,
-                      value[0], value[1], value[2], name);
-
-#ifdef USE_THREADS
-    queueResponse(clientData, buf, length, Response::VOLATILE);
-#else 
-    ssize_t bytesWritten = SocketWrite(buf, length);
-
-    if (bytesWritten < 0) {
-        return TCL_ERROR;
-    }
-#endif /*USE_THREADS*/
-    return TCL_OK;
-}
-
-static int
-DataSetGetVectorWorldOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                        Tcl_Obj *const *objv)
-{
-    const char *name = Tcl_GetString(objv[6]);
-    double x, y, z;
-    if (Tcl_GetDoubleFromObj(interp, objv[3], &x) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[4], &y) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[5], &z) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    double value[3];
-    if (!g_renderer->getVectorValue(name, x, y, z, value)) {
-        Tcl_AppendResult(interp, "Coordinate out of dataset bounds or no vector data available", (char*)NULL);
-        return TCL_ERROR;
-    }
-
-    char buf[256];
-    int length;
-    length = snprintf(buf, sizeof(buf), 
-                      "nv>dataset vector world %g %g %g %g %g %g %s\n",
-                      x, y, z,
-                      value[0], value[1], value[2], name);
-#ifdef USE_THREADS
-    queueResponse(clientData, buf, length, Response::VOLATILE);
-#else 
-    ssize_t bytesWritten = SocketWrite(buf, length);
-
-    if (bytesWritten < 0) {
-        return TCL_ERROR;
-    }
-#endif /*USE_THREADS*/
-    return TCL_OK;
-}
-
-static Rappture::CmdSpec dataSetGetVectorOps[] = {
-    {"pixel", 1, DataSetGetVectorPixelOp, 6, 6, "x y dataSetName"},
-    {"world", 1, DataSetGetVectorWorldOp, 7, 7, "x y z dataSetName"}
-};
-static int nDataSetGetVectorOps = NumCmdSpecs(dataSetGetVectorOps);
-
-static int
-DataSetGetVectorOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                   Tcl_Obj *const *objv)
-{
-    Tcl_ObjCmdProc *proc;
-
-    proc = Rappture::GetOpFromObj(interp, nDataSetGetVectorOps, dataSetGetVectorOps,
-                                  Rappture::CMDSPEC_ARG2, objc, objv, 0);
-    if (proc == NULL) {
-        return TCL_ERROR;
-    }
-    return (*proc) (clientData, interp, objc, objv);
-}
-
-static int
-DataSetMapRangeOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                  Tcl_Obj *const *objv)
-{
-    const char *value = Tcl_GetString(objv[2]);
-    if (strcmp(value, "all") == 0) {
-        g_renderer->setUseCumulativeDataRange(true);
-    } else if (strcmp(value, "explicit") == 0) {
-        if (objc < 6 || objc > 9) {
-            Tcl_AppendResult(interp, "wrong number of arguments for explicit maprange", (char*)NULL);
-            return TCL_ERROR;
-        }
-        double range[2];
-        if (Tcl_GetDoubleFromObj(interp, objv[3], &range[0]) != TCL_OK ||
-            Tcl_GetDoubleFromObj(interp, objv[4], &range[1]) != TCL_OK) {
-            return TCL_ERROR;
-        }
-        const char *fieldName = Tcl_GetString(objv[5]);
-
-        DataSet::DataAttributeType type = DataSet::POINT_DATA;
-        int numComponents = 1;
-        int component = -1;
-        if (objc > 6) {
-            const char *fieldType = Tcl_GetString(objv[6]);
-            if (strcmp(fieldType, "point_data") == 0) {
-                type = DataSet::POINT_DATA;
-            } else if (strcmp(fieldType, "cell_data") == 0) {
-                type = DataSet::CELL_DATA;
-            } else if (strcmp(fieldType, "field_data") == 0) {
-                type = DataSet::FIELD_DATA;
-            } else {
-                Tcl_AppendResult(interp, "bad field type option \"", fieldType,
-                                 "\": should be point_data, cell_data or field_data", (char*)NULL);
-                return TCL_ERROR;
-            }
-            if (objc > 7) {
-                if (Tcl_GetIntFromObj(interp, objv[7], &numComponents) != TCL_OK) {
-                    return TCL_ERROR;
-                }
-                if (objc == 9) {
-                    if (Tcl_GetIntFromObj(interp, objv[8], &component) != TCL_OK) {
-                        return TCL_ERROR;
-                    }
-                }
-            }
-        }
-        g_renderer->setCumulativeDataRange(range, fieldName, type, numComponents, component);
-    } else if (strcmp(value, "separate") == 0) {
-        g_renderer->setUseCumulativeDataRange(false);
-    } else if (strcmp(value, "visible") == 0) {
-        g_renderer->setUseCumulativeDataRange(true, true);
-    } else {
-        Tcl_AppendResult(interp, "bad maprange option \"", value,
-                         "\": should be all, explicit, separate or visible", (char*)NULL);
-        return TCL_ERROR;
-    }
-    return TCL_OK;
-}
-
-static int
-DataSetNamesOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-               Tcl_Obj *const *objv)
-{
-    std::vector<std::string> dataSets;
-    g_renderer->getDataSetNames(dataSets);
-    std::ostringstream oss;
-    size_t len = 0;
-    oss << "nv>dataset names {";
-    len += 18;
-    for (size_t i = 0; i < dataSets.size(); i++) {
-        oss << "\"" << dataSets[i] << "\"";
-        len += 2 + dataSets[i].length();
-        if (i < dataSets.size() - 1) {
-            oss << " ";
-            len++;
-        }
-    }
-    oss << "}\n";
-    len += 2;
-#ifdef USE_THREADS
-    queueResponse(clientData, oss.str().c_str(), len, Response::VOLATILE);
-#else 
-    ssize_t bytesWritten = SocketWrite(oss.str().c_str(), len);
-
-    if (bytesWritten < 0) {
-        return TCL_ERROR;
-    }
-#endif /*USE_THREADS*/
-    return TCL_OK;
-}
-
-static int
-DataSetOpacityOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                 Tcl_Obj *const *objv)
-{
-    double opacity;
-    if (Tcl_GetDoubleFromObj(interp, objv[2], &opacity) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 4) {
-        const char *name = Tcl_GetString(objv[3]);
-        g_renderer->setDataSetOpacity(name, opacity);
-    } else {
-        g_renderer->setDataSetOpacity("all", opacity);
-    }
-    return TCL_OK;
-}
-
-static int
-DataSetVisibleOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                 Tcl_Obj *const *objv)
-{
-    bool state;
-    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 4) {
-        const char *name = Tcl_GetString(objv[3]);
-        g_renderer->setDataSetVisibility(name, state);
-    } else {
-        g_renderer->setDataSetVisibility("all", state);
-    }
-    return TCL_OK;
-}
-
-static Rappture::CmdSpec dataSetOps[] = {
-    {"add",       1, DataSetAddOp, 6, 6, "name data follows nBytes"},
-    {"delete",    1, DataSetDeleteOp, 2, 3, "?name?"},
-    {"getscalar", 4, DataSetGetScalarOp, 6, 7, "oper x y ?z? name"},
-    {"getvector", 4, DataSetGetVectorOp, 6, 7, "oper x y ?z? name"},
-    {"maprange",  1, DataSetMapRangeOp, 3, 9, "value ?min? ?max? ?fieldName? ?fieldType? ?fieldNumComp? ?compIdx?"},
-    {"names",     1, DataSetNamesOp, 2, 2, ""},
-    {"opacity",   2, DataSetOpacityOp, 3, 4, "value ?name?"},
-    {"scalar",    1, DataSetActiveScalarsOp, 3, 4, "scalarName ?name?"},
-    {"vector",    2, DataSetActiveVectorsOp, 3, 4, "vectorName ?name?"},
-    {"visible",   2, DataSetVisibleOp, 3, 4, "bool ?name?"}
-};
-static int nDataSetOps = NumCmdSpecs(dataSetOps);
-
-static int
-DataSetCmd(ClientData clientData, Tcl_Interp *interp, int objc, 
-           Tcl_Obj *const *objv)
-{
-    Tcl_ObjCmdProc *proc;
-
-    proc = Rappture::GetOpFromObj(interp, nDataSetOps, dataSetOps,
-                                  Rappture::CMDSPEC_ARG1, objc, objv, 0);
-    if (proc == NULL) {
-        return TCL_ERROR;
-    }
-    return (*proc) (clientData, interp, objc, objv);
-}
-
-static int
-DiskAddOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-          Tcl_Obj *const *objv)
-{
-    double innerRadius, outerRadius;
-    if (Tcl_GetDoubleFromObj(interp, objv[2], &innerRadius) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[3], &outerRadius) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    const char *name = Tcl_GetString(objv[4]);
-    if (!g_renderer->addDisk(name, innerRadius, outerRadius)) {
-        Tcl_AppendResult(interp, "Failed to create disk", (char*)NULL);
-        return TCL_ERROR;
-    }
-    return TCL_OK;
-}
-
-static int
-DiskDeleteOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-             Tcl_Obj *const *objv)
-{
-    if (objc == 3) {
-        const char *name = Tcl_GetString(objv[2]);
-        g_renderer->deleteGraphicsObject<Disk>(name);
-    } else {
-        g_renderer->deleteGraphicsObject<Disk>("all");
-    }
-    return TCL_OK;
-}
-
-static int
-DiskColorOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-            Tcl_Obj *const *objv)
-{
-    float color[3];
-    if (GetFloatFromObj(interp, objv[2], &color[0]) != TCL_OK ||
-        GetFloatFromObj(interp, objv[3], &color[1]) != TCL_OK ||
-        GetFloatFromObj(interp, objv[4], &color[2]) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 6) {
-        const char *name = Tcl_GetString(objv[5]);
-        g_renderer->setGraphicsObjectColor<Disk>(name, color);
-    } else {
-        g_renderer->setGraphicsObjectColor<Disk>("all", color);
-    }
-    return TCL_OK;
-}
-
-static int
-DiskEdgeVisibilityOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                     Tcl_Obj *const *objv)
-{
-    bool state;
-    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 4) {
-        const char *name = Tcl_GetString(objv[3]);
-        g_renderer->setGraphicsObjectEdgeVisibility<Disk>(name, state);
-    } else {
-        g_renderer->setGraphicsObjectEdgeVisibility<Disk>("all", state);
-    }
-    return TCL_OK;
-}
-
-static int
-DiskLightingOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-               Tcl_Obj *const *objv)
-{
-    bool state;
-    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 4) {
-        const char *name = Tcl_GetString(objv[3]);
-        g_renderer->setGraphicsObjectLighting<Disk>(name, state);
-    } else {
-        g_renderer->setGraphicsObjectLighting<Disk>("all", state);
-    }
-    return TCL_OK;
-}
-
-static int
-DiskLineColorOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                Tcl_Obj *const *objv)
-{
-    float color[3];
-    if (GetFloatFromObj(interp, objv[2], &color[0]) != TCL_OK ||
-        GetFloatFromObj(interp, objv[3], &color[1]) != TCL_OK ||
-        GetFloatFromObj(interp, objv[4], &color[2]) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 6) {
-        const char *name = Tcl_GetString(objv[5]);
-        g_renderer->setGraphicsObjectEdgeColor<Disk>(name, color);
-    } else {
-        g_renderer->setGraphicsObjectEdgeColor<Disk>("all", color);
-    }
-    return TCL_OK;
-}
-
-static int
-DiskLineWidthOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                Tcl_Obj *const *objv)
-{
-    float width;
-    if (GetFloatFromObj(interp, objv[2], &width) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 4) {
-        const char *name = Tcl_GetString(objv[3]);
-        g_renderer->setGraphicsObjectEdgeWidth<Disk>(name, width);
-    } else {
-        g_renderer->setGraphicsObjectEdgeWidth<Disk>("all", width);
-    }
-    return TCL_OK;
-}
-
-static int
-DiskMaterialOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-               Tcl_Obj *const *objv)
-{
-    double ambient, diffuse, specCoeff, specPower;
-    if (Tcl_GetDoubleFromObj(interp, objv[2], &ambient) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[3], &diffuse) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[4], &specCoeff) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[5], &specPower) != TCL_OK) {
-        return TCL_ERROR;
-    }
-
-    if (objc == 7) {
-        const char *name = Tcl_GetString(objv[6]);
-        g_renderer->setGraphicsObjectAmbient<Disk>(name, ambient);
-        g_renderer->setGraphicsObjectDiffuse<Disk>(name, diffuse);
-        g_renderer->setGraphicsObjectSpecular<Disk>(name, specCoeff, specPower);
-    } else {
-        g_renderer->setGraphicsObjectAmbient<Disk>("all", ambient);
-        g_renderer->setGraphicsObjectDiffuse<Disk>("all", diffuse);
-        g_renderer->setGraphicsObjectSpecular<Disk>("all", specCoeff, specPower);
-    }
-    return TCL_OK;
-}
-
-static int
-DiskOpacityOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-              Tcl_Obj *const *objv)
-{
-    double opacity;
-    if (Tcl_GetDoubleFromObj(interp, objv[2], &opacity) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 4) {
-        const char *name = Tcl_GetString(objv[3]);
-        g_renderer->setGraphicsObjectOpacity<Disk>(name, opacity);
-    } else {
-        g_renderer->setGraphicsObjectOpacity<Disk>("all", opacity);
-    }
-    return TCL_OK;
-}
-
-static int
-DiskOrientOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-             Tcl_Obj *const *objv)
-{
-    double quat[4];
-    if (Tcl_GetDoubleFromObj(interp, objv[2], &quat[0]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[3], &quat[1]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[4], &quat[2]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[5], &quat[3]) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 7) {
-        const char *name = Tcl_GetString(objv[6]);
-        g_renderer->setGraphicsObjectOrientation<Disk>(name, quat);
-    } else {
-        g_renderer->setGraphicsObjectOrientation<Disk>("all", quat);
-    }
-    return TCL_OK;
-}
-
-static int
-DiskPositionOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-               Tcl_Obj *const *objv)
-{
-    double pos[3];
-    if (Tcl_GetDoubleFromObj(interp, objv[2], &pos[0]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[3], &pos[1]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[4], &pos[2]) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 6) {
-        const char *name = Tcl_GetString(objv[5]);
-        g_renderer->setGraphicsObjectPosition<Disk>(name, pos);
-    } else {
-        g_renderer->setGraphicsObjectPosition<Disk>("all", pos);
-    }
-    return TCL_OK;
-}
-
-static int
-DiskResolutionOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                 Tcl_Obj *const *objv)
-{
-    int radial, circum;
-    if (Tcl_GetIntFromObj(interp, objv[2], &radial) != TCL_OK ||
-        Tcl_GetIntFromObj(interp, objv[3], &circum) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 5) {
-        const char *name = Tcl_GetString(objv[4]);
-        g_renderer->setDiskResolution(name, radial, circum);
-    } else {
-        g_renderer->setDiskResolution("all", radial, circum);
-    }
-    return TCL_OK;
-}
-
-static int
-DiskScaleOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-            Tcl_Obj *const *objv)
-{
-    double scale[3];
-    if (Tcl_GetDoubleFromObj(interp, objv[2], &scale[0]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[3], &scale[1]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[4], &scale[2]) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 6) {
-        const char *name = Tcl_GetString(objv[5]);
-        g_renderer->setGraphicsObjectScale<Disk>(name, scale);
-    } else {
-        g_renderer->setGraphicsObjectScale<Disk>("all", scale);
-    }
-    return TCL_OK;
-}
-
-static int
-DiskVisibleOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-              Tcl_Obj *const *objv)
-{
-    bool state;
-    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 4) {
-        const char *name = Tcl_GetString(objv[3]);
-        g_renderer->setGraphicsObjectVisibility<Disk>(name, state);
-    } else {
-        g_renderer->setGraphicsObjectVisibility<Disk>("all", state);
-    }
-    return TCL_OK;
-}
-
-static int
-DiskWireframeOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                Tcl_Obj *const *objv)
-{
-    bool state;
-    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 4) {
-        const char *name = Tcl_GetString(objv[3]);
-        g_renderer->setGraphicsObjectWireframe<Disk>(name, state);
-    } else {
-        g_renderer->setGraphicsObjectWireframe<Disk>("all", state);
-    }
-    return TCL_OK;
-}
-
-static Rappture::CmdSpec diskOps[] = {
-    {"add",       1, DiskAddOp, 5, 5, "innerRadius outerRadius name"},
-    {"color",     1, DiskColorOp, 5, 6, "r g b ?name?"},
-    {"delete",    1, DiskDeleteOp, 2, 3, "?name?"},
-    {"edges",     1, DiskEdgeVisibilityOp, 3, 4, "bool ?name?"},
-    {"lighting",  3, DiskLightingOp, 3, 4, "bool ?name?"},
-    {"linecolor", 5, DiskLineColorOp, 5, 6, "r g b ?name?"},
-    {"linewidth", 5, DiskLineWidthOp, 3, 4, "width ?name?"},
-    {"material",  1, DiskMaterialOp, 6, 7, "ambientCoeff diffuseCoeff specularCoeff specularPower ?name?"},
-    {"opacity",   2, DiskOpacityOp, 3, 4, "value ?name?"},
-    {"orient",    2, DiskOrientOp, 6, 7, "qw qx qy qz ?name?"},
-    {"pos",       2, DiskPositionOp, 5, 6, "x y z ?name?"},
-    {"resolution",1, DiskResolutionOp, 4, 5, "resRadial resCircum ?name?"},
-    {"scale",     1, DiskScaleOp, 5, 6, "sx sy sz ?name?"},
-    {"visible",   1, DiskVisibleOp, 3, 4, "bool ?name?"},
-    {"wireframe", 1, DiskWireframeOp, 3, 4, "bool ?name?"}
-};
-static int nDiskOps = NumCmdSpecs(diskOps);
-
-static int
-DiskCmd(ClientData clientData, Tcl_Interp *interp, int objc, 
-        Tcl_Obj *const *objv)
-{
-    Tcl_ObjCmdProc *proc;
-
-    proc = Rappture::GetOpFromObj(interp, nDiskOps, diskOps,
-                                  Rappture::CMDSPEC_ARG1, objc, objv, 0);
-    if (proc == NULL) {
-        return TCL_ERROR;
-    }
-    return (*proc) (clientData, interp, objc, objv);
-}
-
-static int
-GlyphsAddOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-            Tcl_Obj *const *objv)
-{
-    Glyphs::GlyphShape shape;
-
-    const char *shapeOpt = Tcl_GetString(objv[2]);
-    if (shapeOpt[0] == 'a' && strcmp(shapeOpt, "arrow") == 0) {
-        shape = Glyphs::ARROW;
-    } else if (shapeOpt[0] == 'c' && strcmp(shapeOpt, "cone") == 0) {
-        shape = Glyphs::CONE;
-    } else if (shapeOpt[0] == 'c' && strcmp(shapeOpt, "cube") == 0) {
-        shape = Glyphs::CUBE;
-    } else if (shapeOpt[0] == 'c' && strcmp(shapeOpt, "cylinder") == 0) {
-        shape = Glyphs::CYLINDER;
-    } else if (shapeOpt[0] == 'd' && strcmp(shapeOpt, "dodecahedron") == 0) {
-        shape = Glyphs::DODECAHEDRON;
-    } else if (shapeOpt[0] == 'i' && strcmp(shapeOpt, "icosahedron") == 0) {
-        shape = Glyphs::ICOSAHEDRON;
-    } else if (shapeOpt[0] == 'l' && strcmp(shapeOpt, "line") == 0) {
-        shape = Glyphs::LINE;
-    } else if (shapeOpt[0] == 'o' && strcmp(shapeOpt, "octahedron") == 0) {
-        shape = Glyphs::OCTAHEDRON;
-    } else if (shapeOpt[0] == 's' && strcmp(shapeOpt, "sphere") == 0) {
-        shape = Glyphs::SPHERE;
-    } else if (shapeOpt[0] == 't' && strcmp(shapeOpt, "tetrahedron") == 0) {
-        shape = Glyphs::TETRAHEDRON;
-    } else {
-        Tcl_AppendResult(interp, "bad shape option \"", shapeOpt,
-                         "\": should be one of: 'arrow', 'cone', 'cube', 'cylinder', 'dodecahedron', 'icosahedron', 'octahedron', 'sphere', 'tetrahedron'", (char*)NULL);
-        return TCL_ERROR;
-    }
-
-    if (objc == 4) {
-        const char *name = Tcl_GetString(objv[3]);
-        if (!g_renderer->addGlyphs(name, shape)) {
-            Tcl_AppendResult(interp, "Failed to create glyphs", (char*)NULL);
-            return TCL_ERROR;
-        }
-    } else {
-        if (!g_renderer->addGlyphs("all", shape)) {
-            Tcl_AppendResult(interp, "Failed to create glyphs for one or more data sets", (char*)NULL);
-            return TCL_ERROR;
-        }
-    }
-    return TCL_OK;
-}
-
-static int
-GlyphsColorOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-              Tcl_Obj *const *objv)
-{
-    float color[3];
-    if (GetFloatFromObj(interp, objv[2], &color[0]) != TCL_OK ||
-        GetFloatFromObj(interp, objv[3], &color[1]) != TCL_OK ||
-        GetFloatFromObj(interp, objv[4], &color[2]) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 6) {
-        const char *name = Tcl_GetString(objv[5]);
-        g_renderer->setGraphicsObjectColor<Glyphs>(name, color);
-    } else {
-        g_renderer->setGraphicsObjectColor<Glyphs>("all", color);
-    }
-    return TCL_OK;
-}
-
-static int
-GlyphsColorMapOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                 Tcl_Obj *const *objv)
-{
-    const char *colorMapName = Tcl_GetString(objv[2]);
-    if (objc == 4) {
-        const char *dataSetName = Tcl_GetString(objv[3]);
-        g_renderer->setGraphicsObjectColorMap<Glyphs>(dataSetName, colorMapName);
-    } else {
-        g_renderer->setGraphicsObjectColorMap<Glyphs>("all", colorMapName);
-    }
-    return TCL_OK;
-}
-
-static int
-GlyphsColorModeOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                  Tcl_Obj *const *objv)
-{
-    Glyphs::ColorMode mode;
-    const char *str = Tcl_GetString(objv[2]);
-    if (str[0] == 'c' && strcmp(str, "ccolor") == 0) {
-        mode = Glyphs::COLOR_CONSTANT;
-    } else if (str[0] == 's' && strcmp(str, "scalar") == 0) {
-        mode = Glyphs::COLOR_BY_SCALAR;
-    } else if (str[0] == 'v' && strcmp(str, "vmag") == 0) {
-        mode = Glyphs::COLOR_BY_VECTOR_MAGNITUDE;
-    } else if (str[0] == 'v' && strcmp(str, "vx") == 0) {
-        mode = Glyphs::COLOR_BY_VECTOR_X;
-    } else if (str[0] == 'v' && strcmp(str, "vy") == 0) {
-        mode = Glyphs::COLOR_BY_VECTOR_Y;
-    } else if (str[0] == 'v' && strcmp(str, "vz") == 0) {
-        mode = Glyphs::COLOR_BY_VECTOR_Z;
-    } else {
-        Tcl_AppendResult(interp, "bad color mode option \"", str,
-                         "\": should be one of: 'scalar', 'vmag', 'vx', 'vy', 'vz', 'ccolor'", (char*)NULL);
-        return TCL_ERROR;
-    }
-    const char *fieldName = Tcl_GetString(objv[3]);
-    if (mode == Glyphs::COLOR_CONSTANT) {
-        fieldName = NULL;
-    }
-    if (objc == 5) {
-        const char *name = Tcl_GetString(objv[4]);
-        g_renderer->setGlyphsColorMode(name, mode, fieldName);
-    } else {
-        g_renderer->setGlyphsColorMode("all", mode, fieldName);
-    }
-    return TCL_OK;
-}
-
-static int
-GlyphsDeleteOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-               Tcl_Obj *const *objv)
-{
-    if (objc == 3) {
-        const char *name = Tcl_GetString(objv[2]);
-        g_renderer->deleteGraphicsObject<Glyphs>(name);
-    } else {
-        g_renderer->deleteGraphicsObject<Glyphs>("all");
-    }
-    return TCL_OK;
-}
-
-static int
-GlyphsEdgeVisibilityOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                       Tcl_Obj *const *objv)
-{
-    bool state;
-    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 4) {
-        const char *name = Tcl_GetString(objv[3]);
-        g_renderer->setGraphicsObjectEdgeVisibility<Glyphs>(name, state);
-    } else {
-        g_renderer->setGraphicsObjectEdgeVisibility<Glyphs>("all", state);
-    }
-    return TCL_OK;
-}
-
-static int
-GlyphsLightingOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                 Tcl_Obj *const *objv)
-{
-    bool state;
-    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 4) {
-        const char *name = Tcl_GetString(objv[3]);
-        g_renderer->setGraphicsObjectLighting<Glyphs>(name, state);
-    } else {
-        g_renderer->setGraphicsObjectLighting<Glyphs>("all", state);
-    }
-    return TCL_OK;
-}
-
-static int
-GlyphsLineColorOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                  Tcl_Obj *const *objv)
-{
-    float color[3];
-    if (GetFloatFromObj(interp, objv[2], &color[0]) != TCL_OK ||
-        GetFloatFromObj(interp, objv[3], &color[1]) != TCL_OK ||
-        GetFloatFromObj(interp, objv[4], &color[2]) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 6) {
-        const char *name = Tcl_GetString(objv[5]);
-        g_renderer->setGraphicsObjectEdgeColor<Glyphs>(name, color);
-    } else {
-        g_renderer->setGraphicsObjectEdgeColor<Glyphs>("all", color);
-    }
-    return TCL_OK;
-}
-
-static int
-GlyphsLineWidthOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                  Tcl_Obj *const *objv)
-{
-    float width;
-    if (GetFloatFromObj(interp, objv[2], &width) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 4) {
-        const char *name = Tcl_GetString(objv[3]);
-        g_renderer->setGraphicsObjectEdgeWidth<Glyphs>(name, width);
-    } else {
-        g_renderer->setGraphicsObjectEdgeWidth<Glyphs>("all", width);
-    }
-    return TCL_OK;
-}
-
-static int
-GlyphsNormalizeScaleOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                       Tcl_Obj *const *objv)
-{
-    bool normalize;
-    if (GetBooleanFromObj(interp, objv[2], &normalize) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 4) {
-        const char *name = Tcl_GetString(objv[3]);
-        g_renderer->setGlyphsNormalizeScale(name, normalize);
-    } else {
-        g_renderer->setGlyphsNormalizeScale("all", normalize);
-    }
-    return TCL_OK;
-}
-
-static int
-GlyphsOpacityOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                Tcl_Obj *const *objv)
-{
-    double opacity;
-    if (Tcl_GetDoubleFromObj(interp, objv[2], &opacity) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 4) {
-        const char *name = Tcl_GetString(objv[3]);
-        g_renderer->setGraphicsObjectOpacity<Glyphs>(name, opacity);
-    } else {
-        g_renderer->setGraphicsObjectOpacity<Glyphs>("all", opacity);
-    }
-    return TCL_OK;
-}
-
-static int
-GlyphsOrientOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-               Tcl_Obj *const *objv)
-{
-    double quat[4];
-    if (Tcl_GetDoubleFromObj(interp, objv[2], &quat[0]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[3], &quat[1]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[4], &quat[2]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[5], &quat[3]) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 7) {
-        const char *name = Tcl_GetString(objv[6]);
-        g_renderer->setGraphicsObjectOrientation<Glyphs>(name, quat);
-    } else {
-        g_renderer->setGraphicsObjectOrientation<Glyphs>("all", quat);
-    }
-    return TCL_OK;
-}
-
-static int
-GlyphsOrientGlyphsOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                     Tcl_Obj *const *objv)
-{
-    bool state;
-    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    const char *fieldName = Tcl_GetString(objv[3]);
-    if (objc == 5) {
-        const char *name = Tcl_GetString(objv[4]);
-        g_renderer->setGlyphsOrientMode(name, state, fieldName);
-    } else {
-        g_renderer->setGlyphsOrientMode("all", state, fieldName);
-    }
-    return TCL_OK;
-}
-
-static int
-GlyphsPositionOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                 Tcl_Obj *const *objv)
-{
-    double pos[3];
-    if (Tcl_GetDoubleFromObj(interp, objv[2], &pos[0]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[3], &pos[1]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[4], &pos[2]) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 6) {
-        const char *name = Tcl_GetString(objv[5]);
-        g_renderer->setGraphicsObjectPosition<Glyphs>(name, pos);
-    } else {
-        g_renderer->setGraphicsObjectPosition<Glyphs>("all", pos);
-    }
-    return TCL_OK;
-}
-
-static int
-GlyphsScaleOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-              Tcl_Obj *const *objv)
-{
-    double scale[3];
-    if (Tcl_GetDoubleFromObj(interp, objv[2], &scale[0]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[3], &scale[1]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[4], &scale[2]) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 6) {
-        const char *name = Tcl_GetString(objv[5]);
-        g_renderer->setGraphicsObjectScale<Glyphs>(name, scale);
-    } else {
-        g_renderer->setGraphicsObjectScale<Glyphs>("all", scale);
-    }
-    return TCL_OK;
-}
-
-static int
-GlyphsScaleFactorOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                    Tcl_Obj *const *objv)
-{
-    double scale;
-    if (Tcl_GetDoubleFromObj(interp, objv[2], &scale) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 4) {
-        const char *name = Tcl_GetString(objv[3]);
-        g_renderer->setGlyphsScaleFactor(name, scale);
-    } else {
-        g_renderer->setGlyphsScaleFactor("all", scale);
-    }
-    return TCL_OK;
-}
-
-static int
-GlyphsScalingModeOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                    Tcl_Obj *const *objv)
-{
-    Glyphs::ScalingMode mode;
-    const char *str = Tcl_GetString(objv[2]);
-    if (str[0] == 's' && strcmp(str, "scalar") == 0) {
-        mode = Glyphs::SCALE_BY_SCALAR;
-    } else if (str[0] == 'v' && strcmp(str, "vmag") == 0) {
-        mode = Glyphs::SCALE_BY_VECTOR_MAGNITUDE;
-    } else if (str[0] == 'v' && strcmp(str, "vcomp") == 0) {
-        mode = Glyphs::SCALE_BY_VECTOR_COMPONENTS;
-    } else if (str[0] == 'o' && strcmp(str, "off") == 0) {
-        mode = Glyphs::SCALING_OFF;
-    } else {
-        Tcl_AppendResult(interp, "bad scaling mode option \"", str,
-                         "\": should be one of: 'scalar', 'vmag', 'vcomp', 'off'", (char*)NULL);
-        return TCL_ERROR;
-    }
-    const char *fieldName = Tcl_GetString(objv[3]);
-    if (objc == 5) {
-        const char *name = Tcl_GetString(objv[4]);
-        g_renderer->setGlyphsScalingMode(name, mode, fieldName);
-    } else {
-        g_renderer->setGlyphsScalingMode("all", mode, fieldName);
-    }
-    return TCL_OK;
-}
-
-static int
-GlyphsShapeOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-              Tcl_Obj *const *objv)
-{
-    Glyphs::GlyphShape shape;
-
-    const char *shapeOpt = Tcl_GetString(objv[2]);
-    if (shapeOpt[0] == 'a' && strcmp(shapeOpt, "arrow") == 0) {
-        shape = Glyphs::ARROW;
-    } else if (shapeOpt[0] == 'c' && strcmp(shapeOpt, "cone") == 0) {
-        shape = Glyphs::CONE;
-    } else if (shapeOpt[0] == 'c' && strcmp(shapeOpt, "cube") == 0) {
-        shape = Glyphs::CUBE;
-    } else if (shapeOpt[0] == 'c' && strcmp(shapeOpt, "cylinder") == 0) {
-        shape = Glyphs::CYLINDER;
-    } else if (shapeOpt[0] == 'd' && strcmp(shapeOpt, "dodecahedron") == 0) {
-        shape = Glyphs::DODECAHEDRON;
-    } else if (shapeOpt[0] == 'i' && strcmp(shapeOpt, "icosahedron") == 0) {
-        shape = Glyphs::ICOSAHEDRON;
-    } else if (shapeOpt[0] == 'l' && strcmp(shapeOpt, "line") == 0) {
-        shape = Glyphs::LINE;
-    } else if (shapeOpt[0] == 'o' && strcmp(shapeOpt, "octahedron") == 0) {
-        shape = Glyphs::OCTAHEDRON;
-    } else if (shapeOpt[0] == 's' && strcmp(shapeOpt, "sphere") == 0) {
-        shape = Glyphs::SPHERE;
-    } else if (shapeOpt[0] == 't' && strcmp(shapeOpt, "tetrahedron") == 0) {
-        shape = Glyphs::TETRAHEDRON;
-    } else {
-        Tcl_AppendResult(interp, "bad shape option \"", shapeOpt,
-                         "\": should be one of: 'arrow', 'cone', 'cube', 'cylinder', 'dodecahedron', 'icosahedron', 'line', 'octahedron', 'sphere', 'tetrahedron'", (char*)NULL);
-        return TCL_ERROR;
-    }
-
-    if (objc == 4) {
-        const char *name = Tcl_GetString(objv[3]);
-        g_renderer->setGlyphsShape(name, shape);
-    } else {
-        g_renderer->setGlyphsShape("all", shape);
-    }
-    return TCL_OK;
-}
-
-static int
-GlyphsVisibleOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                Tcl_Obj *const *objv)
-{
-    bool state;
-    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 4) {
-        const char *name = Tcl_GetString(objv[3]);
-        g_renderer->setGraphicsObjectVisibility<Glyphs>(name, state);
-    } else {
-        g_renderer->setGraphicsObjectVisibility<Glyphs>("all", state);
-    }
-    return TCL_OK;
-}
-
-static int
-GlyphsWireframeOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                  Tcl_Obj *const *objv)
-{
-    bool state;
-    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 4) {
-        const char *name = Tcl_GetString(objv[3]);
-        g_renderer->setGraphicsObjectWireframe<Glyphs>(name, state);
-    } else {
-        g_renderer->setGraphicsObjectWireframe<Glyphs>("all", state);
-    }
-    return TCL_OK;
-}
-
-static Rappture::CmdSpec glyphsOps[] = {
-    {"add",          1, GlyphsAddOp, 3, 4, "shape ?dataSetName?"},
-    {"ccolor",       2, GlyphsColorOp, 5, 6, "r g b ?dataSetName?"},
-    {"colormap",     7, GlyphsColorMapOp, 3, 4, "colorMapName ?dataSetName?"},
-    {"colormode",    7, GlyphsColorModeOp, 4, 5, "mode fieldName ?dataSetName?"},
-    {"delete",       1, GlyphsDeleteOp, 2, 3, "?dataSetName?"},
-    {"edges",        1, GlyphsEdgeVisibilityOp, 3, 4, "bool ?dataSetName?"},
-    {"gorient",      2, GlyphsOrientGlyphsOp, 4, 5, "bool fieldName ?dataSetName?"},
-    {"gscale",       2, GlyphsScaleFactorOp, 3, 4, "scaleFactor ?dataSetName?"},
-    {"lighting",     3, GlyphsLightingOp, 3, 4, "bool ?dataSetName?"},
-    {"linecolor",    5, GlyphsLineColorOp, 5, 6, "r g b ?dataSetName?"},
-    {"linewidth",    5, GlyphsLineWidthOp, 3, 4, "width ?dataSetName?"},
-    {"normscale",    1, GlyphsNormalizeScaleOp, 3, 4, "bool ?dataSetName?"},
-    {"opacity",      2, GlyphsOpacityOp, 3, 4, "value ?dataSetName?"},
-    {"orient",       2, GlyphsOrientOp, 6, 7, "qw qx qy qz ?dataSetName?"},
-    {"pos",          1, GlyphsPositionOp, 5, 6, "x y z ?dataSetName?"},
-    {"scale",        2, GlyphsScaleOp, 5, 6, "sx sy sz ?dataSetName?"},
-    {"shape",        2, GlyphsShapeOp, 3, 4, "shapeVal ?dataSetName?"},
-    {"smode",        2, GlyphsScalingModeOp, 4, 5, "mode fieldName ?dataSetName?"},
-    {"visible",      1, GlyphsVisibleOp, 3, 4, "bool ?dataSetName?"},
-    {"wireframe",    1, GlyphsWireframeOp, 3, 4, "bool ?dataSetName?"}
-};
-static int nGlyphsOps = NumCmdSpecs(glyphsOps);
-
-static int
-GlyphsCmd(ClientData clientData, Tcl_Interp *interp, int objc, 
-          Tcl_Obj *const *objv)
-{
-    Tcl_ObjCmdProc *proc;
-
-    proc = Rappture::GetOpFromObj(interp, nGlyphsOps, glyphsOps,
-                                  Rappture::CMDSPEC_ARG1, objc, objv, 0);
-    if (proc == NULL) {
-        return TCL_ERROR;
-    }
-    return (*proc) (clientData, interp, objc, objv);
-}
-
-static int
-HeightMapAddContourListOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                          Tcl_Obj *const *objv)
-{
-    std::vector<double> contourList;
-    double heightScale;
-
-    int clistc;
-    Tcl_Obj **clistv;
-
-    if (Tcl_ListObjGetElements(interp, objv[3], &clistc, &clistv) != TCL_OK) {
-        return TCL_ERROR;
-    }
-
-    for (int i = 0; i < clistc; i++) {
-        double val;
-        if (Tcl_GetDoubleFromObj(interp, clistv[i], &val) != TCL_OK) {
-            return TCL_ERROR;
-        }
-        contourList.push_back(val);
-    }
-
-    if (Tcl_GetDoubleFromObj(interp, objv[4], &heightScale) != TCL_OK) {
-        return TCL_ERROR;
-    }
-
-    if (objc == 6) {
-        const char *name = Tcl_GetString(objv[5]);
-        if (!g_renderer->addHeightMap(name, contourList, heightScale)) {
-            Tcl_AppendResult(interp, "Failed to create heightmap", (char*)NULL);
-            return TCL_ERROR;
-        }
-    } else {
-        if (!g_renderer->addHeightMap("all", contourList, heightScale)) {
-            Tcl_AppendResult(interp, "Failed to create heightmap for one or more data sets", (char*)NULL);
-            return TCL_ERROR;
-        }
-    }
-    return TCL_OK;
-}
-
-static int
-HeightMapAddNumContoursOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                          Tcl_Obj *const *objv)
-{
-    int numContours;
-    double heightScale;
-    if (Tcl_GetIntFromObj(interp, objv[3], &numContours) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (Tcl_GetDoubleFromObj(interp, objv[4], &heightScale) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 6) {
-        const char *name = Tcl_GetString(objv[5]);
-        if (!g_renderer->addHeightMap(name, numContours, heightScale)) {
-            Tcl_AppendResult(interp, "Failed to create heightmap", (char*)NULL);
-            return TCL_ERROR;
-        }
-    } else {
-        if (!g_renderer->addHeightMap("all", numContours, heightScale)) {
-            Tcl_AppendResult(interp, "Failed to create heightmap for one or more data sets", (char*)NULL);
-            return TCL_ERROR;
-        }
-    }
-    return TCL_OK;
-}
-
-static Rappture::CmdSpec heightmapAddOps[] = {
-    {"contourlist", 1, HeightMapAddContourListOp, 5, 6, "contourList heightscale ?dataSetName?"},
-    {"numcontours", 1, HeightMapAddNumContoursOp, 5, 6, "numContours heightscale ?dataSetName?"}
-};
-static int nHeightmapAddOps = NumCmdSpecs(heightmapAddOps);
-
-static int
-HeightMapAddOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-               Tcl_Obj *const *objv)
-{
-    Tcl_ObjCmdProc *proc;
-
-    proc = Rappture::GetOpFromObj(interp, nHeightmapAddOps, heightmapAddOps,
-                                  Rappture::CMDSPEC_ARG2, objc, objv, 0);
-    if (proc == NULL) {
-        return TCL_ERROR;
-    }
-    return (*proc) (clientData, interp, objc, objv);
-}
-
-static int
-HeightMapAspectOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                  Tcl_Obj *const *objv)
-{
-    double aspect;
-    if (Tcl_GetDoubleFromObj(interp, objv[2], &aspect) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 4) {
-        const char *name = Tcl_GetString(objv[3]);
-        g_renderer->setGraphicsObjectAspect<HeightMap>(name, aspect);
-    } else {
-        g_renderer->setGraphicsObjectAspect<HeightMap>("all", aspect);
-    }
-    return TCL_OK;
-}
-
-static int
-HeightMapColorOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                 Tcl_Obj *const *objv)
-{
-    float color[3];
-    if (GetFloatFromObj(interp, objv[2], &color[0]) != TCL_OK ||
-        GetFloatFromObj(interp, objv[3], &color[1]) != TCL_OK ||
-        GetFloatFromObj(interp, objv[4], &color[2]) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 6) {
-        const char *name = Tcl_GetString(objv[5]);
-        g_renderer->setGraphicsObjectColor<HeightMap>(name, color);
-    } else {
-        g_renderer->setGraphicsObjectColor<HeightMap>("all", color);
-    }
-    return TCL_OK;
-}
-
-static int
-HeightMapColorMapOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                    Tcl_Obj *const *objv)
-{
-    const char *colorMapName = Tcl_GetString(objv[2]);
-    if (objc == 4) {
-        const char *dataSetName = Tcl_GetString(objv[3]);
-        g_renderer->setGraphicsObjectColorMap<HeightMap>(dataSetName, colorMapName);
-    } else {
-        g_renderer->setGraphicsObjectColorMap<HeightMap>("all", colorMapName);
-    }
-    return TCL_OK;
-}
-
-static int
-HeightMapColorModeOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                     Tcl_Obj *const *objv)
-{
-    HeightMap::ColorMode mode;
-    const char *str = Tcl_GetString(objv[2]);
-    if (str[0] == 'c' && strcmp(str, "ccolor") == 0) {
-        mode = HeightMap::COLOR_CONSTANT;
-    } else if (str[0] == 's' && strcmp(str, "scalar") == 0) {
-        mode = HeightMap::COLOR_BY_SCALAR;
-    } else if (str[0] == 'v' && strcmp(str, "vmag") == 0) {
-        mode = HeightMap::COLOR_BY_VECTOR_MAGNITUDE;
-    } else if (str[0] == 'v' && strcmp(str, "vx") == 0) {
-        mode = HeightMap::COLOR_BY_VECTOR_X;
-    } else if (str[0] == 'v' && strcmp(str, "vy") == 0) {
-        mode = HeightMap::COLOR_BY_VECTOR_Y;
-    } else if (str[0] == 'v' && strcmp(str, "vz") == 0) {
-        mode = HeightMap::COLOR_BY_VECTOR_Z;
-    } else {
-        Tcl_AppendResult(interp, "bad color mode option \"", str,
-                         "\": should be one of: 'scalar', 'vmag', 'vx', 'vy', 'vz', 'ccolor'", (char*)NULL);
-        return TCL_ERROR;
-    }
-    const char *fieldName = Tcl_GetString(objv[3]);
-    if (mode == HeightMap::COLOR_CONSTANT) {
-        fieldName = NULL;
-    }
-    if (objc == 5) {
-        const char *name = Tcl_GetString(objv[4]);
-        g_renderer->setHeightMapColorMode(name, mode, fieldName);
-    } else {
-        g_renderer->setHeightMapColorMode("all", mode, fieldName);
-    }
-    return TCL_OK;
-}
-
-static int
-HeightMapContourLineColorMapOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                               Tcl_Obj *const *objv)
-{
-    bool state;
-    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 4) {
-        const char *name = Tcl_GetString(objv[3]);
-        g_renderer->setHeightMapContourLineColorMapEnabled(name, state);
-    } else {
-        g_renderer->setHeightMapContourLineColorMapEnabled("all", state);
-    }
-    return TCL_OK;
-}
-
-static int
-HeightMapContourLineColorOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                            Tcl_Obj *const *objv)
-{
-    float color[3];
-    if (GetFloatFromObj(interp, objv[2], &color[0]) != TCL_OK ||
-        GetFloatFromObj(interp, objv[3], &color[1]) != TCL_OK ||
-        GetFloatFromObj(interp, objv[4], &color[2]) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 6) {
-        const char *name = Tcl_GetString(objv[5]);
-        g_renderer->setHeightMapContourEdgeColor(name, color);
-    } else {
-        g_renderer->setHeightMapContourEdgeColor("all", color);
-    }
-    return TCL_OK;
-}
-
-static int
-HeightMapContourLineWidthOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                            Tcl_Obj *const *objv)
-{
-    float width;
-    if (GetFloatFromObj(interp, objv[2], &width) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 4) {
-        const char *name = Tcl_GetString(objv[3]);
-        g_renderer->setHeightMapContourEdgeWidth(name, width);
-    } else {
-        g_renderer->setHeightMapContourEdgeWidth("all", width);
-    }
-    return TCL_OK;
-}
-
-static int
-HeightMapContourListOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                       Tcl_Obj *const *objv)
-{
-    std::vector<double> contourList;
-
-    int clistc;
-    Tcl_Obj **clistv;
-
-    if (Tcl_ListObjGetElements(interp, objv[2], &clistc, &clistv) != TCL_OK) {
-        return TCL_ERROR;
-    }
-
-    for (int i = 0; i < clistc; i++) {
-        double val;
-        if (Tcl_GetDoubleFromObj(interp, clistv[i], &val) != TCL_OK) {
-            return TCL_ERROR;
-        }
-        contourList.push_back(val);
-    }
-
-    if (objc == 4) {
-        const char *name = Tcl_GetString(objv[3]);
-        g_renderer->setHeightMapContourList(name, contourList);
-    } else {
-        g_renderer->setHeightMapContourList("all", contourList);
-    }
-    return TCL_OK;
-}
-
-static int
-HeightMapContourLineVisibleOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                              Tcl_Obj *const *objv)
-{
-    bool state;
-    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 4) {
-        const char *name = Tcl_GetString(objv[3]);
-        g_renderer->setHeightMapContourLineVisibility(name, state);
-    } else {
-        g_renderer->setHeightMapContourLineVisibility("all", state);
-    }
-    return TCL_OK;
-}
-
-static int
-HeightMapContourSurfaceVisibleOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                                 Tcl_Obj *const *objv)
-{
-    bool state;
-    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 4) {
-        const char *name = Tcl_GetString(objv[3]);
-        g_renderer->setHeightMapContourSurfaceVisibility(name, state);
-    } else {
-        g_renderer->setHeightMapContourSurfaceVisibility("all", state);
-    }
-    return TCL_OK;
-}
-
-static int
-HeightMapDeleteOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                  Tcl_Obj *const *objv)
-{
-    if (objc == 3) {
-        const char *name = Tcl_GetString(objv[2]);
-        g_renderer->deleteGraphicsObject<HeightMap>(name);
-    } else {
-        g_renderer->deleteGraphicsObject<HeightMap>("all");
-    }
-    return TCL_OK;
-}
-
-static int
-HeightMapEdgeVisibilityOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                          Tcl_Obj *const *objv)
-{
-    bool state;
-    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 4) {
-        const char *name = Tcl_GetString(objv[3]);
-        g_renderer->setGraphicsObjectEdgeVisibility<HeightMap>(name, state);
-    } else {
-        g_renderer->setGraphicsObjectEdgeVisibility<HeightMap>("all", state);
-    }
-    return TCL_OK;
-}
-
-static int
-HeightMapHeightScaleOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                       Tcl_Obj *const *objv)
-{
-    double scale;
-    if (Tcl_GetDoubleFromObj(interp, objv[2], &scale) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 4) {
-        const char *name = Tcl_GetString(objv[3]);
-        g_renderer->setHeightMapHeightScale(name, scale);
-    } else {
-        g_renderer->setHeightMapHeightScale("all", scale);
-    }
-    return TCL_OK;
-}
-
-static int
-HeightMapLightingOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                    Tcl_Obj *const *objv)
-{
-    bool state;
-    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 4) {
-        const char *name = Tcl_GetString(objv[3]);
-        g_renderer->setGraphicsObjectLighting<HeightMap>(name, state);
-    } else {
-        g_renderer->setGraphicsObjectLighting<HeightMap>("all", state);
-    }
-    return TCL_OK;
-}
-
-static int
-HeightMapLineColorOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                     Tcl_Obj *const *objv)
-{
-    float color[3];
-    if (GetFloatFromObj(interp, objv[2], &color[0]) != TCL_OK ||
-        GetFloatFromObj(interp, objv[3], &color[1]) != TCL_OK ||
-        GetFloatFromObj(interp, objv[4], &color[2]) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 6) {
-        const char *name = Tcl_GetString(objv[5]);
-        g_renderer->setGraphicsObjectEdgeColor<HeightMap>(name, color);
-    } else {
-        g_renderer->setGraphicsObjectEdgeColor<HeightMap>("all", color);
-    }
-    return TCL_OK;
-}
-
-static int
-HeightMapLineWidthOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                     Tcl_Obj *const *objv)
-{
-    float width;
-    if (GetFloatFromObj(interp, objv[2], &width) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 4) {
-        const char *name = Tcl_GetString(objv[3]);
-        g_renderer->setGraphicsObjectEdgeWidth<HeightMap>(name, width);
-    } else {
-        g_renderer->setGraphicsObjectEdgeWidth<HeightMap>("all", width);
-    }
-    return TCL_OK;
-}
-
-static int
-HeightMapNumContoursOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                       Tcl_Obj *const *objv)
-{
-    int numContours;
-
-    if (Tcl_GetIntFromObj(interp, objv[2], &numContours) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 4) {
-        const char *name = Tcl_GetString(objv[3]);
-        g_renderer->setHeightMapNumContours(name, numContours);
-    } else {
-        g_renderer->setHeightMapNumContours("all", numContours);
-    }
-    return TCL_OK;
-}
-
-static int
-HeightMapOpacityOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                   Tcl_Obj *const *objv)
-{
-    double opacity;
-    if (Tcl_GetDoubleFromObj(interp, objv[2], &opacity) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 4) {
-        const char *name = Tcl_GetString(objv[3]);
-        g_renderer->setGraphicsObjectOpacity<HeightMap>(name, opacity);
-    } else {
-        g_renderer->setGraphicsObjectOpacity<HeightMap>("all", opacity);
-    }
-    return TCL_OK;
-}
-
-static int
-HeightMapOrientOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                  Tcl_Obj *const *objv)
-{
-    double quat[4];
-    if (Tcl_GetDoubleFromObj(interp, objv[2], &quat[0]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[3], &quat[1]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[4], &quat[2]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[5], &quat[3]) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 7) {
-        const char *name = Tcl_GetString(objv[6]);
-        g_renderer->setGraphicsObjectOrientation<HeightMap>(name, quat);
-    } else {
-        g_renderer->setGraphicsObjectOrientation<HeightMap>("all", quat);
-    }
-    return TCL_OK;
-}
-
-static int
-HeightMapPositionOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                    Tcl_Obj *const *objv)
-{
-    double pos[3];
-    if (Tcl_GetDoubleFromObj(interp, objv[2], &pos[0]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[3], &pos[1]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[4], &pos[2]) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 6) {
-        const char *name = Tcl_GetString(objv[5]);
-        g_renderer->setGraphicsObjectPosition<HeightMap>(name, pos);
-    } else {
-        g_renderer->setGraphicsObjectPosition<HeightMap>("all", pos);
-    }
-    return TCL_OK;
-}
-
-static int
-HeightMapPreInterpOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                     Tcl_Obj *const *objv)
-{
-    bool state;
-    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 4) {
-        const char *name = Tcl_GetString(objv[3]);
-        g_renderer->setGraphicsObjectInterpolateBeforeMapping<HeightMap>(name, state);
-    } else {
-        g_renderer->setGraphicsObjectInterpolateBeforeMapping<HeightMap>("all", state);
-    }
-    return TCL_OK;
-}
-
-static int
-HeightMapScaleOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                 Tcl_Obj *const *objv)
-{
-    double scale[3];
-    if (Tcl_GetDoubleFromObj(interp, objv[2], &scale[0]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[3], &scale[1]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[4], &scale[2]) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 6) {
-        const char *name = Tcl_GetString(objv[5]);
-        g_renderer->setGraphicsObjectScale<HeightMap>(name, scale);
-    } else {
-        g_renderer->setGraphicsObjectScale<HeightMap>("all", scale);
-    }
-    return TCL_OK;
-}
-
-static int
-HeightMapVisibleOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                   Tcl_Obj *const *objv)
-{
-    bool state;
-    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 4) {
-        const char *name = Tcl_GetString(objv[3]);
-        g_renderer->setGraphicsObjectVisibility<HeightMap>(name, state);
-    } else {
-        g_renderer->setGraphicsObjectVisibility<HeightMap>("all", state);
-    }
-    return TCL_OK;
-}
-
-static int
-HeightMapVolumeSliceOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                       Tcl_Obj *const *objv)
-{
-    double ratio;
-    if (Tcl_GetDoubleFromObj(interp, objv[3], &ratio) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    const char *string = Tcl_GetString(objv[2]);
-    char c = string[0];
-    Axis axis;
-    if ((c == 'x') && (strcmp(string, "x") == 0)) {
-        axis = X_AXIS;
-    } else if ((c == 'y') && (strcmp(string, "y") == 0)) {
-        axis = Y_AXIS;
-    } else if ((c == 'z') && (strcmp(string, "z") == 0)) {
-        axis = Z_AXIS;
-    } else {
-        Tcl_AppendResult(interp, "bad axis option \"", string,
-                         "\": should be axisName ratio", (char*)NULL);
-        return TCL_ERROR;
-    }
-    if (objc == 5) {
-        const char *name = Tcl_GetString(objv[4]);
-        g_renderer->setGraphicsObjectVolumeSlice<HeightMap>(name, axis, ratio);
-    } else {
-        g_renderer->setGraphicsObjectVolumeSlice<HeightMap>("all", axis, ratio);
-    }
-    return TCL_OK;
-}
-
-static int
-HeightMapWireframeOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                     Tcl_Obj *const *objv)
-{
-    bool state;
-    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 4) {
-        const char *name = Tcl_GetString(objv[3]);
-        g_renderer->setGraphicsObjectWireframe<HeightMap>(name, state);
-    } else {
-        g_renderer->setGraphicsObjectWireframe<HeightMap>("all", state);
-    }
-    return TCL_OK;
-}
-
-static Rappture::CmdSpec heightmapOps[] = {
-    {"add",          2, HeightMapAddOp, 5, 6, "oper value heightscale ?dataSetName?"},
-    {"aspect",       2, HeightMapAspectOp, 3, 4, "aspect ?dataSetName?"},
-    {"ccolor",       2, HeightMapColorOp, 5, 6, "r g b ?dataSetName?"},
-    {"colormap",     7, HeightMapColorMapOp, 3, 4, "colorMapName ?dataSetName?"},
-    {"colormode",    7, HeightMapColorModeOp, 4, 5, "mode fieldName ?dataSetName?"},
-    {"contourlist",  3, HeightMapContourListOp, 3, 4, "contourList ?dataSetName?"},
-    {"delete",       1, HeightMapDeleteOp, 2, 3, "?dataSetName?"},
-    {"edges",        1, HeightMapEdgeVisibilityOp, 3, 4, "bool ?dataSetName?"},
-    {"heightscale",  1, HeightMapHeightScaleOp, 3, 4, "value ?dataSetName?"},
-    {"isolinecmap",  9, HeightMapContourLineColorMapOp, 3, 4, "bool ?dataSetName?"},
-    {"isolinecolor", 9, HeightMapContourLineColorOp, 5, 6, "r g b ?dataSetName?"},
-    {"isolines",     8, HeightMapContourLineVisibleOp, 3, 4, "bool ?dataSetName?"},
-    {"isolinewidth", 8, HeightMapContourLineWidthOp, 3, 4, "width ?dataSetName?"},
-    {"lighting",     3, HeightMapLightingOp, 3, 4, "bool ?dataSetName?"},
-    {"linecolor",    5, HeightMapLineColorOp, 5, 6, "r g b ?dataSetName?"},
-    {"linewidth",    5, HeightMapLineWidthOp, 3, 4, "width ?dataSetName?"},
-    {"numcontours",  1, HeightMapNumContoursOp, 3, 4, "numContours ?dataSetName?"},
-    {"opacity",      2, HeightMapOpacityOp, 3, 4, "value ?dataSetName?"},
-    {"orient",       2, HeightMapOrientOp, 6, 7, "qw qx qy qz ?dataSetName?"},
-    {"pos",          2, HeightMapPositionOp, 5, 6, "x y z ?dataSetName?"},
-    {"preinterp",    2, HeightMapPreInterpOp, 3, 4, "bool ?dataSetName?"},
-    {"scale",        2, HeightMapScaleOp, 5, 6, "sx sy sz ?dataSetName?"},
-    {"slice",        2, HeightMapVolumeSliceOp, 4, 5, "axis ratio ?dataSetName?"},
-    {"surface",      2, HeightMapContourSurfaceVisibleOp, 3, 4, "bool ?dataSetName?"},
-    {"visible",      1, HeightMapVisibleOp, 3, 4, "bool ?dataSetName?"},
-    {"wireframe",    1, HeightMapWireframeOp, 3, 4, "bool ?dataSetName?"}
-};
-static int nHeightmapOps = NumCmdSpecs(heightmapOps);
-
-static int
-HeightMapCmd(ClientData clientData, Tcl_Interp *interp, int objc, 
-             Tcl_Obj *const *objv)
-{
-    Tcl_ObjCmdProc *proc;
-
-    proc = Rappture::GetOpFromObj(interp, nHeightmapOps, heightmapOps,
-                                  Rappture::CMDSPEC_ARG1, objc, objv, 0);
-    if (proc == NULL) {
-        return TCL_ERROR;
-    }
-    return (*proc) (clientData, interp, objc, objv);
-}
-
-static int
-ImageFlushCmd(ClientData clientData, Tcl_Interp *interp, int objc, 
-              Tcl_Obj *const *objv)
-{
-    lastCmdStatus = TCL_BREAK;
-    return TCL_OK;
-}
-
-static int
-LegendCmd(ClientData clientData, Tcl_Interp *interp, int objc, 
-          Tcl_Obj *const *objv)
-{
-    if (objc < 8) {
-        Tcl_AppendResult(interp, "wrong # args: should be \"",
-                Tcl_GetString(objv[0]), " colormapName legendType fieldName title width height numLabels ?dataSetName?\"", (char*)NULL);
-        return TCL_ERROR;
-    }
-    const char *colorMapName = Tcl_GetString(objv[1]);
-    const char *typeStr = Tcl_GetString(objv[2]);
-    Renderer::LegendType legendType;
-    if (typeStr[0] == 's' && strcmp(typeStr, "scalar") == 0) {
-        legendType = Renderer::LEGEND_SCALAR;
-    } else if (typeStr[0] == 'v' && strcmp(typeStr, "vmag") == 0) {
-        legendType = Renderer::LEGEND_VECTOR_MAGNITUDE;
-    } else if (typeStr[0] == 'v' && strcmp(typeStr, "vx") == 0) {
-        legendType = Renderer::LEGEND_VECTOR_X;
-    } else if (typeStr[0] == 'v' && strcmp(typeStr, "vy") == 0) {
-        legendType = Renderer::LEGEND_VECTOR_Y;
-    } else if (typeStr[0] == 'v' && strcmp(typeStr, "vz") == 0) {
-        legendType = Renderer::LEGEND_VECTOR_Z;
-    } else {
-        Tcl_AppendResult(interp, "Bad legendType option \"",
-                         typeStr, "\", should be one of 'scalar', 'vmag', 'vx', 'vy', 'vz'", (char*)NULL);
-        return TCL_ERROR;
-    }
-
-    const char *fieldName = Tcl_GetString(objv[3]);
-
-    std::string title(Tcl_GetString(objv[4]));
-    int width, height, numLabels;
-
-    if (Tcl_GetIntFromObj(interp, objv[5], &width) != TCL_OK ||
-        Tcl_GetIntFromObj(interp, objv[6], &height) != TCL_OK ||
-        Tcl_GetIntFromObj(interp, objv[7], &numLabels) != TCL_OK) {
-        return TCL_ERROR;
-    }
-
-    vtkSmartPointer<vtkUnsignedCharArray> imgData = 
-        vtkSmartPointer<vtkUnsignedCharArray>::New();
-
-    double range[2];
-    range[0] = DBL_MAX;
-    range[1] = -DBL_MAX;
-
-    if (objc == 9) {
-        const char *dataSetName = Tcl_GetString(objv[8]);
-        if (!g_renderer->renderColorMap(colorMapName, dataSetName, legendType, fieldName, title,
-                                        range, width, height, true, numLabels, imgData)) {
-            Tcl_AppendResult(interp, "Color map \"",
-                             colorMapName, "\" or dataset \"",
-                             dataSetName, "\" was not found", (char*)NULL);
-            return TCL_ERROR;
-        }
-    } else {
-        if (!g_renderer->renderColorMap(colorMapName, "all", legendType, fieldName, title,
-                                        range, width, height, true, numLabels, imgData)) {
-            Tcl_AppendResult(interp, "Color map \"",
-                             colorMapName, "\" was not found", (char*)NULL);
-            return TCL_ERROR;
-        }
-    }
-
-#ifdef DEBUG
-# ifdef RENDER_TARGA
-    writeTGAFile("/tmp/legend.tga", imgData->GetPointer(0), width, height,
-                 TARGA_BYTES_PER_PIXEL);
-# else
-    writeTGAFile("/tmp/legend.tga", imgData->GetPointer(0), width, height,
-                 TARGA_BYTES_PER_PIXEL, true);
-# endif
-#else
-    char cmd[256];
-    snprintf(cmd, sizeof(cmd), "nv>legend {%s} {%s} %g %g",
-             colorMapName, title.c_str(), range[0], range[1]);
-
-# ifdef USE_THREADS
-#  ifdef RENDER_TARGA
-    ResponseQueue *queue = (ResponseQueue *)clientData;
-    queueTGA(queue, cmd, imgData->GetPointer(0), width, height,
-             TARGA_BYTES_PER_PIXEL);
-#  else
-    ResponseQueue *queue = (ResponseQueue *)clientData;
-    queuePPM(queue, cmd, imgData->GetPointer(0), width, height);
-#  endif
-# else
-#  ifdef RENDER_TARGA
-    writeTGA(g_fdOut, cmd, imgData->GetPointer(0), width, height,
-             TARGA_BYTES_PER_PIXEL);
-#  else
-    writePPM(g_fdOut, cmd, imgData->GetPointer(0), width, height);
-#  endif
-# endif // USE_THREADS
-#endif // DEBUG
-    return TCL_OK;
-}
-
-static int
-LICAddOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-         Tcl_Obj *const *objv)
-{
-    if (objc == 3) {
-        const char *name = Tcl_GetString(objv[2]);
-        if (!g_renderer->addGraphicsObject<LIC>(name)) {
-            Tcl_AppendResult(interp, "Failed to create lic", (char*)NULL);
-            return TCL_ERROR;
-        }
-    } else {
-        if (!g_renderer->addGraphicsObject<LIC>("all")) {
-            Tcl_AppendResult(interp, "Failed to create lic for one or more data sets", (char*)NULL);
-            return TCL_ERROR;
-        }
-    }
-    return TCL_OK;
-}
-
-static int
-LICColorMapOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-              Tcl_Obj *const *objv)
-{
-    const char *colorMapName = Tcl_GetString(objv[2]);
-    if (objc == 4) {
-        const char *dataSetName = Tcl_GetString(objv[3]);
-        g_renderer->setGraphicsObjectColorMap<LIC>(dataSetName, colorMapName);
-    } else {
-        g_renderer->setGraphicsObjectColorMap<LIC>("all", colorMapName);
-    }
-    return TCL_OK;
-}
-
-static int
-LICDeleteOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-            Tcl_Obj *const *objv)
-{
-    if (objc == 3) {
-        const char *name = Tcl_GetString(objv[2]);
-        g_renderer->deleteGraphicsObject<LIC>(name);
-    } else {
-        g_renderer->deleteGraphicsObject<LIC>("all");
-    }
-    return TCL_OK;
-}
-
-static int
-LICEdgeVisibilityOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                    Tcl_Obj *const *objv)
-{
-    bool state;
-    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 4) {
-        const char *name = Tcl_GetString(objv[3]);
-        g_renderer->setGraphicsObjectEdgeVisibility<LIC>(name, state);
-    } else {
-        g_renderer->setGraphicsObjectEdgeVisibility<LIC>("all", state);
-    }
-    return TCL_OK;
-}
-
-static int
-LICLightingOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-              Tcl_Obj *const *objv)
-{
-    bool state;
-    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 4) {
-        const char *name = Tcl_GetString(objv[3]);
-        g_renderer->setGraphicsObjectLighting<LIC>(name, state);
-    } else {
-        g_renderer->setGraphicsObjectLighting<LIC>("all", state);
-    }
-    return TCL_OK;
-}
-
-static int
-LICLineColorOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-               Tcl_Obj *const *objv)
-{
-    float color[3];
-    if (GetFloatFromObj(interp, objv[2], &color[0]) != TCL_OK ||
-        GetFloatFromObj(interp, objv[3], &color[1]) != TCL_OK ||
-        GetFloatFromObj(interp, objv[4], &color[2]) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 6) {
-        const char *name = Tcl_GetString(objv[5]);
-        g_renderer->setGraphicsObjectEdgeColor<LIC>(name, color);
-    } else {
-        g_renderer->setGraphicsObjectEdgeColor<LIC>("all", color);
-    }
-    return TCL_OK;
-}
-
-static int
-LICLineWidthOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-               Tcl_Obj *const *objv)
-{
-    float width;
-    if (GetFloatFromObj(interp, objv[2], &width) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 4) {
-        const char *name = Tcl_GetString(objv[3]);
-        g_renderer->setGraphicsObjectEdgeWidth<LIC>(name, width);
-    } else {
-        g_renderer->setGraphicsObjectEdgeWidth<LIC>("all", width);
-    }
-    return TCL_OK;
-}
-
-static int
-LICOpacityOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-             Tcl_Obj *const *objv)
-{
-    double opacity;
-    if (Tcl_GetDoubleFromObj(interp, objv[2], &opacity) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 4) {
-        const char *name = Tcl_GetString(objv[3]);
-        g_renderer->setGraphicsObjectOpacity<LIC>(name, opacity);
-    } else {
-        g_renderer->setGraphicsObjectOpacity<LIC>("all", opacity);
-    }
-    return TCL_OK;
-}
-
-static int
-LICOrientOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-            Tcl_Obj *const *objv)
-{
-    double quat[4];
-    if (Tcl_GetDoubleFromObj(interp, objv[2], &quat[0]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[3], &quat[1]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[4], &quat[2]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[5], &quat[3]) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 7) {
-        const char *name = Tcl_GetString(objv[6]);
-        g_renderer->setGraphicsObjectOrientation<LIC>(name, quat);
-    } else {
-        g_renderer->setGraphicsObjectOrientation<LIC>("all", quat);
-    }
-    return TCL_OK;
-}
-
-static int
-LICPositionOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-              Tcl_Obj *const *objv)
-{
-    double pos[3];
-    if (Tcl_GetDoubleFromObj(interp, objv[2], &pos[0]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[3], &pos[1]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[4], &pos[2]) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 6) {
-        const char *name = Tcl_GetString(objv[5]);
-        g_renderer->setGraphicsObjectPosition<LIC>(name, pos);
-    } else {
-        g_renderer->setGraphicsObjectPosition<LIC>("all", pos);
-    }
-    return TCL_OK;
-}
-
-static int
-LICPreInterpOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-               Tcl_Obj *const *objv)
-{
-    bool state;
-    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 4) {
-        const char *name = Tcl_GetString(objv[3]);
-        g_renderer->setGraphicsObjectInterpolateBeforeMapping<LIC>(name, state);
-    } else {
-        g_renderer->setGraphicsObjectInterpolateBeforeMapping<LIC>("all", state);
-    }
-    return TCL_OK;
-}
-
-static int
-LICScaleOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-           Tcl_Obj *const *objv)
-{
-    double scale[3];
-    if (Tcl_GetDoubleFromObj(interp, objv[2], &scale[0]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[3], &scale[1]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[4], &scale[2]) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 6) {
-        const char *name = Tcl_GetString(objv[5]);
-        g_renderer->setGraphicsObjectScale<LIC>(name, scale);
-    } else {
-        g_renderer->setGraphicsObjectScale<LIC>("all", scale);
-    }
-    return TCL_OK;
-}
-
-static int
-LICVisibleOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-             Tcl_Obj *const *objv)
-{
-    bool state;
-    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 4) {
-        const char *name = Tcl_GetString(objv[3]);
-        g_renderer->setGraphicsObjectVisibility<LIC>(name, state);
-    } else {
-        g_renderer->setGraphicsObjectVisibility<LIC>("all", state);
-    }
-    return TCL_OK;
-}
-
-static int
-LICVolumeSliceOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                 Tcl_Obj *const *objv)
-{
-    double ratio;
-    if (Tcl_GetDoubleFromObj(interp, objv[3], &ratio) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    const char *string = Tcl_GetString(objv[2]);
-    char c = string[0];
-    Axis axis;
-    if ((c == 'x') && (strcmp(string, "x") == 0)) {
-        axis = X_AXIS;
-    } else if ((c == 'y') && (strcmp(string, "y") == 0)) {
-        axis = Y_AXIS;
-    } else if ((c == 'z') && (strcmp(string, "z") == 0)) {
-        axis = Z_AXIS;
-    } else {
-        Tcl_AppendResult(interp, "bad axis option \"", string,
-                         "\": should be axisName ratio", (char*)NULL);
-        return TCL_ERROR;
-    }
-    if (objc == 5) {
-        const char *name = Tcl_GetString(objv[4]);
-        g_renderer->setGraphicsObjectVolumeSlice<LIC>(name, axis, ratio);
-    } else {
-        g_renderer->setGraphicsObjectVolumeSlice<LIC>("all", axis, ratio);
-    }
-    return TCL_OK;
-}
-
-static Rappture::CmdSpec licOps[] = {
-    {"add",          1, LICAddOp, 2, 3, "?dataSetName?"},
-    {"colormap",     1, LICColorMapOp, 3, 4, "colorMapName ?dataSetName?"},
-    {"delete",       1, LICDeleteOp, 2, 3, "?dataSetName?"},
-    {"edges",        1, LICEdgeVisibilityOp, 3, 4, "bool ?dataSetName?"},
-    {"lighting",     3, LICLightingOp, 3, 4, "bool ?dataSetName?"},
-    {"linecolor",    5, LICLineColorOp, 5, 6, "r g b ?dataSetName?"},
-    {"linewidth",    5, LICLineWidthOp, 3, 4, "width ?dataSetName?"},
-    {"opacity",      2, LICOpacityOp, 3, 4, "value ?dataSetName?"},
-    {"orient",       2, LICOrientOp, 6, 7, "qw qx qy qz ?dataSetName?"},
-    {"pos",          2, LICPositionOp, 5, 6, "x y z ?dataSetName?"},
-    {"preinterp",    2, LICPreInterpOp, 3, 4, "bool ?dataSetName?"},
-    {"scale",        2, LICScaleOp, 5, 6, "sx sy sz ?dataSetName?"},
-    {"slice",        2, LICVolumeSliceOp, 4, 5, "axis ratio ?dataSetName?"},
-    {"visible",      1, LICVisibleOp, 3, 4, "bool ?dataSetName?"}
-};
-static int nLICOps = NumCmdSpecs(licOps);
-
-static int
-LICCmd(ClientData clientData, Tcl_Interp *interp, int objc, 
-       Tcl_Obj *const *objv)
-{
-    Tcl_ObjCmdProc *proc;
-
-    proc = Rappture::GetOpFromObj(interp, nLICOps, licOps,
-                                  Rappture::CMDSPEC_ARG1, objc, objv, 0);
-    if (proc == NULL) {
-        return TCL_ERROR;
-    }
-    return (*proc) (clientData, interp, objc, objv);
-}
-
-static int
-LineAddOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-          Tcl_Obj *const *objv)
-{
-    double pt1[3];
-    double pt2[3];
-    if (Tcl_GetDoubleFromObj(interp, objv[2], &pt1[0]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[3], &pt1[1]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[4], &pt1[2]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[5], &pt2[0]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[6], &pt2[1]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[7], &pt2[2]) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    const char *name = Tcl_GetString(objv[8]);
-    if (!g_renderer->addLine(name, pt1, pt2)) {
-        Tcl_AppendResult(interp, "Failed to create line", (char*)NULL);
-        return TCL_ERROR;
-    }
-    return TCL_OK;
-}
-
-static int
-LineDeleteOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-             Tcl_Obj *const *objv)
-{
-    if (objc == 3) {
-        const char *name = Tcl_GetString(objv[2]);
-        g_renderer->deleteGraphicsObject<Line>(name);
-    } else {
-        g_renderer->deleteGraphicsObject<Line>("all");
-    }
-    return TCL_OK;
-}
-
-static int
-LineColorOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-            Tcl_Obj *const *objv)
-{
-    float color[3];
-    if (GetFloatFromObj(interp, objv[2], &color[0]) != TCL_OK ||
-        GetFloatFromObj(interp, objv[3], &color[1]) != TCL_OK ||
-        GetFloatFromObj(interp, objv[4], &color[2]) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 6) {
-        const char *name = Tcl_GetString(objv[5]);
-        g_renderer->setGraphicsObjectColor<Line>(name, color);
-    } else {
-        g_renderer->setGraphicsObjectColor<Line>("all", color);
-    }
-    return TCL_OK;
-}
-
-static int
-LineLineWidthOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                Tcl_Obj *const *objv)
-{
-    float width;
-    if (GetFloatFromObj(interp, objv[2], &width) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 4) {
-        const char *name = Tcl_GetString(objv[3]);
-        g_renderer->setGraphicsObjectEdgeWidth<Line>(name, width);
-    } else {
-        g_renderer->setGraphicsObjectEdgeWidth<Line>("all", width);
-    }
-    return TCL_OK;
-}
-
-static int
-LineOpacityOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-              Tcl_Obj *const *objv)
-{
-    double opacity;
-    if (Tcl_GetDoubleFromObj(interp, objv[2], &opacity) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 4) {
-        const char *name = Tcl_GetString(objv[3]);
-        g_renderer->setGraphicsObjectOpacity<Line>(name, opacity);
-    } else {
-        g_renderer->setGraphicsObjectOpacity<Line>("all", opacity);
-    }
-    return TCL_OK;
-}
-
-static int
-LineOrientOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-             Tcl_Obj *const *objv)
-{
-    double quat[4];
-    if (Tcl_GetDoubleFromObj(interp, objv[2], &quat[0]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[3], &quat[1]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[4], &quat[2]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[5], &quat[3]) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 7) {
-        const char *name = Tcl_GetString(objv[6]);
-        g_renderer->setGraphicsObjectOrientation<Line>(name, quat);
-    } else {
-        g_renderer->setGraphicsObjectOrientation<Line>("all", quat);
-    }
-    return TCL_OK;
-}
-
-static int
-LinePositionOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-               Tcl_Obj *const *objv)
-{
-    double pos[3];
-    if (Tcl_GetDoubleFromObj(interp, objv[2], &pos[0]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[3], &pos[1]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[4], &pos[2]) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 6) {
-        const char *name = Tcl_GetString(objv[5]);
-        g_renderer->setGraphicsObjectPosition<Line>(name, pos);
-    } else {
-        g_renderer->setGraphicsObjectPosition<Line>("all", pos);
-    }
-    return TCL_OK;
-}
-
-static int
-LineScaleOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-            Tcl_Obj *const *objv)
-{
-    double scale[3];
-    if (Tcl_GetDoubleFromObj(interp, objv[2], &scale[0]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[3], &scale[1]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[4], &scale[2]) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 6) {
-        const char *name = Tcl_GetString(objv[5]);
-        g_renderer->setGraphicsObjectScale<Line>(name, scale);
-    } else {
-        g_renderer->setGraphicsObjectScale<Line>("all", scale);
-    }
-    return TCL_OK;
-}
-
-static int
-LineVisibleOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-              Tcl_Obj *const *objv)
-{
-    bool state;
-    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 4) {
-        const char *name = Tcl_GetString(objv[3]);
-        g_renderer->setGraphicsObjectVisibility<Line>(name, state);
-    } else {
-        g_renderer->setGraphicsObjectVisibility<Line>("all", state);
-    }
-    return TCL_OK;
-}
-
-static Rappture::CmdSpec lineOps[] = {
-    {"add",       1, LineAddOp, 9, 9, "x1 y1 z1 x2 y2 z2 name"},
-    {"color",     1, LineColorOp, 5, 6, "r g b ?name?"},
-    {"delete",    1, LineDeleteOp, 2, 3, "?name?"},
-    {"linecolor", 5, LineColorOp, 5, 6, "r g b ?name?"},
-    {"linewidth", 5, LineLineWidthOp, 3, 4, "width ?name?"},
-    {"opacity",   2, LineOpacityOp, 3, 4, "value ?name?"},
-    {"orient",    2, LineOrientOp, 6, 7, "qw qx qy qz ?name?"},
-    {"pos",       2, LinePositionOp, 5, 6, "x y z ?name?"},
-    {"scale",     2, LineScaleOp, 5, 6, "sx sy sz ?name?"},
-    {"visible",   1, LineVisibleOp, 3, 4, "bool ?name?"}
-};
-static int nLineOps = NumCmdSpecs(lineOps);
-
-static int
-LineCmd(ClientData clientData, Tcl_Interp *interp, int objc, 
-       Tcl_Obj *const *objv)
-{
-    Tcl_ObjCmdProc *proc;
-
-    proc = Rappture::GetOpFromObj(interp, nLineOps, lineOps,
-                                  Rappture::CMDSPEC_ARG1, objc, objv, 0);
-    if (proc == NULL) {
-        return TCL_ERROR;
-    }
-    return (*proc) (clientData, interp, objc, objv);
-}
-
-static int
-MoleculeAddOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-              Tcl_Obj *const *objv)
-{
-    if (objc == 3) {
-        const char *name = Tcl_GetString(objv[2]);
-        if (!g_renderer->addGraphicsObject<Molecule>(name)) {
-            Tcl_AppendResult(interp, "Failed to create molecule", (char*)NULL);
-            return TCL_ERROR;
-        }
-    } else {
-        if (!g_renderer->addGraphicsObject<Molecule>("all")) {
-            Tcl_AppendResult(interp, "Failed to create molecule for one or more data sets", (char*)NULL);
-            return TCL_ERROR;
-        }
-    }
-    return TCL_OK;
-}
-
-static int
-MoleculeAtomVisibilityOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                         Tcl_Obj *const *objv)
-{
-    bool state;
-    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 4) {
-        const char *name = Tcl_GetString(objv[3]);
-        g_renderer->setMoleculeAtomVisibility(name, state);
-    } else {
-        g_renderer->setMoleculeAtomVisibility("all", state);
-    }
-    return TCL_OK;
-}
-
-static int
-MoleculeAtomLabelVisibilityOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                              Tcl_Obj *const *objv)
-{
-    bool state;
-    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 4) {
-        const char *name = Tcl_GetString(objv[3]);
-        g_renderer->setMoleculeAtomLabelVisibility(name, state);
-    } else {
-        g_renderer->setMoleculeAtomLabelVisibility("all", state);
-    }
-    return TCL_OK;
-}
-
-static int
-MoleculeAtomScaleFactorOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                          Tcl_Obj *const *objv)
-{
-    double scale;
-    if (Tcl_GetDoubleFromObj(interp, objv[2], &scale) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 4) {
-        const char *name = Tcl_GetString(objv[3]);
-        g_renderer->setMoleculeAtomRadiusScale(name, scale);
-    } else {
-        g_renderer->setMoleculeAtomRadiusScale("all", scale);
-    }
-    return TCL_OK;
-}
-
-static int
-MoleculeAtomScalingOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                      Tcl_Obj *const *objv)
-{
-    Molecule::AtomScaling scaling;
-    const char *scalingOpt = Tcl_GetString(objv[2]);
-    if (scalingOpt[0] == 'v' && strcmp(scalingOpt, "van_der_waals") == 0) {
-        scaling = Molecule::VAN_DER_WAALS_RADIUS;
-    } else if (scalingOpt[0] == 'c' && strcmp(scalingOpt, "covalent") == 0) {
-        scaling = Molecule::COVALENT_RADIUS;
-    } else if (scalingOpt[0] == 'a' && strcmp(scalingOpt, "atomic") == 0) {
-        scaling = Molecule::ATOMIC_RADIUS;
-    } else if (scalingOpt[0] == 'n' && strcmp(scalingOpt, "none") == 0) {
-        scaling = Molecule::NO_ATOM_SCALING;
-    } else {
-        Tcl_AppendResult(interp, "bad atomscale option \"", scalingOpt,
-                         "\": should be van_der_waals, covalent, atomic, or none", (char*)NULL);
-        return TCL_ERROR;
-    }
-    if (objc == 4) {
-        const char *name = Tcl_GetString(objv[3]);
-        g_renderer->setMoleculeAtomScaling(name, scaling);
-    } else {
-        g_renderer->setMoleculeAtomScaling("all", scaling);
-    }
-    return TCL_OK;
-}
-
-static int
-MoleculeBondColorModeOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                        Tcl_Obj *const *objv)
-{
-    Molecule::BondColorMode mode;
-    const char *colorMode = Tcl_GetString(objv[2]);
-    if (colorMode[0] == 'c' && strcmp(colorMode, "constant") == 0) {
-        mode = Molecule::BOND_COLOR_CONSTANT;
-    } else if (colorMode[0] == 'b' && strcmp(colorMode, "by_elements") == 0) {
-        mode = Molecule::BOND_COLOR_BY_ELEMENTS;
-    } else {
-        Tcl_AppendResult(interp, "bad bcmode option \"", colorMode,
-                         "\": should be constant or by_elements", (char*)NULL);
-        return TCL_ERROR;
-    }
-    if (objc == 4) {
-        const char *name = Tcl_GetString(objv[3]);
-        g_renderer->setMoleculeBondColorMode(name, mode);
-    } else {
-        g_renderer->setMoleculeBondColorMode("all", mode);
-    }
-    return TCL_OK;
-}
-
-static int
-MoleculeBondColorOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                    Tcl_Obj *const *objv)
-{
-    float color[3];
-    if (GetFloatFromObj(interp, objv[2], &color[0]) != TCL_OK ||
-        GetFloatFromObj(interp, objv[3], &color[1]) != TCL_OK ||
-        GetFloatFromObj(interp, objv[4], &color[2]) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 6) {
-        const char *name = Tcl_GetString(objv[5]);
-        g_renderer->setMoleculeBondColor(name, color);
-    } else {
-        g_renderer->setMoleculeBondColor("all", color);
-    }
-    return TCL_OK;
-}
-
-static int
-MoleculeBondScaleFactorOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                          Tcl_Obj *const *objv)
-{
-    double scale;
-    if (Tcl_GetDoubleFromObj(interp, objv[2], &scale) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 4) {
-        const char *name = Tcl_GetString(objv[3]);
-        g_renderer->setMoleculeBondRadiusScale(name, scale);
-    } else {
-        g_renderer->setMoleculeBondRadiusScale("all", scale);
-    }
-    return TCL_OK;
-}
-
-static int
-MoleculeBondStyleOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                    Tcl_Obj *const *objv)
-{
-    Molecule::BondStyle style;
-    const char *styleStr = Tcl_GetString(objv[2]);
-    if (styleStr[0] == 'c' && strcmp(styleStr, "cylinder") == 0) {
-        style = Molecule::BOND_STYLE_CYLINDER;
-    } else if (styleStr[0] == 'l' && strcmp(styleStr, "line") == 0) {
-        style = Molecule::BOND_STYLE_LINE;
-    } else {
-        Tcl_AppendResult(interp, "bad bstyle option \"", styleStr,
-                         "\": should be cylinder or line", (char*)NULL);
-        return TCL_ERROR;
-    }
-    if (objc == 4) {
-        const char *name = Tcl_GetString(objv[3]);
-        g_renderer->setMoleculeBondStyle(name, style);
-    } else {
-        g_renderer->setMoleculeBondStyle("all", style);
-    }
-    return TCL_OK;
-}
-
-static int
-MoleculeBondVisibilityOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                         Tcl_Obj *const *objv)
-{
-    bool state;
-    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 4) {
-        const char *name = Tcl_GetString(objv[3]);
-        g_renderer->setMoleculeBondVisibility(name, state);
-    } else {
-        g_renderer->setMoleculeBondVisibility("all", state);
-    }
-    return TCL_OK;
-}
-
-static int
-MoleculeColorOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                Tcl_Obj *const *objv)
-{
-    float color[3];
-    if (GetFloatFromObj(interp, objv[2], &color[0]) != TCL_OK ||
-        GetFloatFromObj(interp, objv[3], &color[1]) != TCL_OK ||
-        GetFloatFromObj(interp, objv[4], &color[2]) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 6) {
-        const char *name = Tcl_GetString(objv[5]);
-        g_renderer->setGraphicsObjectColor<Molecule>(name, color);
-    } else {
-        g_renderer->setGraphicsObjectColor<Molecule>("all", color);
-    }
-    return TCL_OK;
-}
-
-static int
-MoleculeColorMapOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                   Tcl_Obj *const *objv)
-{
-    const char *colorMapName = Tcl_GetString(objv[2]);
-    if (objc == 4) {
-        const char *dataSetName = Tcl_GetString(objv[3]);
-        g_renderer->setGraphicsObjectColorMap<Molecule>(dataSetName, colorMapName);
-    } else {
-        g_renderer->setGraphicsObjectColorMap<Molecule>("all", colorMapName);
-    }
-    return TCL_OK;
-}
-
-static int
-MoleculeColorModeOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                    Tcl_Obj *const *objv)
-{
-    Molecule::ColorMode mode;
-    const char *str = Tcl_GetString(objv[2]);
-    if (str[0] == 'b' && strcmp(str, "by_elements") == 0) {
-        mode = Molecule::COLOR_BY_ELEMENTS;
-    } else if (str[0] == 'c' && strcmp(str, "ccolor") == 0) {
-        mode = Molecule::COLOR_CONSTANT;
-    } else if (str[0] == 's' && strcmp(str, "scalar") == 0) {
-        mode = Molecule::COLOR_BY_SCALAR;
-    } else if (str[0] == 'v' && strcmp(str, "vmag") == 0) {
-        mode = Molecule::COLOR_BY_VECTOR_MAGNITUDE;
-    } else if (str[0] == 'v' && strcmp(str, "vx") == 0) {
-        mode = Molecule::COLOR_BY_VECTOR_X;
-    } else if (str[0] == 'v' && strcmp(str, "vy") == 0) {
-        mode = Molecule::COLOR_BY_VECTOR_Y;
-    } else if (str[0] == 'v' && strcmp(str, "vz") == 0) {
-        mode = Molecule::COLOR_BY_VECTOR_Z;
-    } else {
-        Tcl_AppendResult(interp, "bad color mode option \"", str,
-                         "\": should be one of: 'by_elements', 'scalar', 'vmag', 'vx', 'vy', 'vz', 'ccolor'", (char*)NULL);
-        return TCL_ERROR;
-    }
-    const char *fieldName = Tcl_GetString(objv[3]);
-    if (mode == Molecule::COLOR_CONSTANT) {
-        fieldName = NULL;
-    }
-#if 0
-    else if (mode == Molecule::COLOR_BY_ELEMENTS) {
-        fieldName = "element";
-    }
-#endif
-    if (objc == 5) {
-        const char *name = Tcl_GetString(objv[4]);
-        g_renderer->setMoleculeColorMode(name, mode, fieldName);
-    } else {
-        g_renderer->setMoleculeColorMode("all", mode, fieldName);
-    }
-    return TCL_OK;
-}
-
-static int
-MoleculeDeleteOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                 Tcl_Obj *const *objv)
-{
-    if (objc == 3) {
-        const char *name = Tcl_GetString(objv[2]);
-        g_renderer->deleteGraphicsObject<Molecule>(name);
-    } else {
-        g_renderer->deleteGraphicsObject<Molecule>("all");
-    }
-    return TCL_OK;
-}
-
-static int
-MoleculeEdgeVisibilityOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                         Tcl_Obj *const *objv)
-{
-    bool state;
-    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 4) {
-        const char *name = Tcl_GetString(objv[3]);
-        g_renderer->setGraphicsObjectEdgeVisibility<Molecule>(name, state);
-    } else {
-        g_renderer->setGraphicsObjectEdgeVisibility<Molecule>("all", state);
-    }
-    return TCL_OK;
-}
-
-static int
-MoleculeLightingOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                   Tcl_Obj *const *objv)
-{
-    bool state;
-    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 4) {
-        const char *name = Tcl_GetString(objv[3]);
-        g_renderer->setGraphicsObjectLighting<Molecule>(name, state);
-    } else {
-        g_renderer->setGraphicsObjectLighting<Molecule>("all", state);
-    }
-    return TCL_OK;
-}
-
-static int
-MoleculeLineColorOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                    Tcl_Obj *const *objv)
-{
-    float color[3];
-    if (GetFloatFromObj(interp, objv[2], &color[0]) != TCL_OK ||
-        GetFloatFromObj(interp, objv[3], &color[1]) != TCL_OK ||
-        GetFloatFromObj(interp, objv[4], &color[2]) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 6) {
-        const char *name = Tcl_GetString(objv[5]);
-        g_renderer->setGraphicsObjectEdgeColor<Molecule>(name, color);
-    } else {
-        g_renderer->setGraphicsObjectEdgeColor<Molecule>("all", color);
-    }
-    return TCL_OK;
-}
-
-static int
-MoleculeLineWidthOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                    Tcl_Obj *const *objv)
-{
-    float width;
-    if (GetFloatFromObj(interp, objv[2], &width) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 4) {
-        const char *name = Tcl_GetString(objv[3]);
-        g_renderer->setGraphicsObjectEdgeWidth<Molecule>(name, width);
-    } else {
-        g_renderer->setGraphicsObjectEdgeWidth<Molecule>("all", width);
-    }
-    return TCL_OK;
-}
-
-static int
-MoleculeOpacityOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                  Tcl_Obj *const *objv)
-{
-    double opacity;
-    if (Tcl_GetDoubleFromObj(interp, objv[2], &opacity) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 4) {
-        const char *name = Tcl_GetString(objv[3]);
-        g_renderer->setGraphicsObjectOpacity<Molecule>(name, opacity);
-    } else {
-        g_renderer->setGraphicsObjectOpacity<Molecule>("all", opacity);
-    }
-    return TCL_OK;
-}
-
-static int
-MoleculeOrientOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                 Tcl_Obj *const *objv)
-{
-    double quat[4];
-    if (Tcl_GetDoubleFromObj(interp, objv[2], &quat[0]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[3], &quat[1]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[4], &quat[2]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[5], &quat[3]) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 7) {
-        const char *name = Tcl_GetString(objv[6]);
-        g_renderer->setGraphicsObjectOrientation<Molecule>(name, quat);
-    } else {
-        g_renderer->setGraphicsObjectOrientation<Molecule>("all", quat);
-    }
-    return TCL_OK;
-}
-
-static int
-MoleculePositionOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                   Tcl_Obj *const *objv)
-{
-    double pos[3];
-    if (Tcl_GetDoubleFromObj(interp, objv[2], &pos[0]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[3], &pos[1]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[4], &pos[2]) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 6) {
-        const char *name = Tcl_GetString(objv[5]);
-        g_renderer->setGraphicsObjectPosition<Molecule>(name, pos);
-    } else {
-        g_renderer->setGraphicsObjectPosition<Molecule>("all", pos);
-    }
-    return TCL_OK;
-}
-
-static int
-MoleculeScaleOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                Tcl_Obj *const *objv)
-{
-    double scale[3];
-    if (Tcl_GetDoubleFromObj(interp, objv[2], &scale[0]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[3], &scale[1]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[4], &scale[2]) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 6) {
-        const char *name = Tcl_GetString(objv[5]);
-        g_renderer->setGraphicsObjectScale<Molecule>(name, scale);
-    } else {
-        g_renderer->setGraphicsObjectScale<Molecule>("all", scale);
-    }
-    return TCL_OK;
-}
-
-static int
-MoleculeVisibleOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                  Tcl_Obj *const *objv)
-{
-    bool state;
-    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 4) {
-        const char *name = Tcl_GetString(objv[3]);
-        g_renderer->setGraphicsObjectVisibility<Molecule>(name, state);
-    } else {
-        g_renderer->setGraphicsObjectVisibility<Molecule>("all", state);
-    }
-    return TCL_OK;
-}
-
-static int
-MoleculeWireframeOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                    Tcl_Obj *const *objv)
-{
-    bool state;
-    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 4) {
-        const char *name = Tcl_GetString(objv[3]);
-        g_renderer->setGraphicsObjectWireframe<Molecule>(name, state);
-    } else {
-        g_renderer->setGraphicsObjectWireframe<Molecule>("all", state);
-    }
-    return TCL_OK;
-}
-
-static Rappture::CmdSpec moleculeOps[] = {
-    {"add",          2, MoleculeAddOp, 2, 3, "?dataSetName?"},
-    {"ascale",       2, MoleculeAtomScaleFactorOp, 3, 4, "value ?dataSetName?"},
-    {"atoms",        2, MoleculeAtomVisibilityOp, 3, 4, "bool ?dataSetName?"},
-    {"bcmode",       3, MoleculeBondColorModeOp, 3, 4, "mode ?dataSetName?"},
-    {"bcolor",       3, MoleculeBondColorOp, 5, 6, "r g b ?dataSetName?"},
-    {"bonds",        2, MoleculeBondVisibilityOp, 3, 4, "bool ?dataSetName?"},
-    {"bscale",       3, MoleculeBondScaleFactorOp, 3, 4, "value ?dataSetName?"},
-    {"bstyle",       3, MoleculeBondStyleOp, 3, 4, "value ?dataSetName?"},
-    {"ccolor",       2, MoleculeColorOp, 5, 6, "r g b ?dataSetName?"},
-    {"colormap",     7, MoleculeColorMapOp, 3, 4, "colorMapName ?dataSetName?"},
-    {"colormode",    7, MoleculeColorModeOp, 4, 5, "mode fieldName ?dataSetName?"},
-    {"delete",       1, MoleculeDeleteOp, 2, 3, "?dataSetName?"},
-    {"edges",        1, MoleculeEdgeVisibilityOp, 3, 4, "bool ?dataSetName?"},
-    {"labels",       2, MoleculeAtomLabelVisibilityOp, 3, 4, "bool ?dataSetName?"},
-    {"lighting",     3, MoleculeLightingOp, 3, 4, "bool ?dataSetName?"},
-    {"linecolor",    5, MoleculeLineColorOp, 5, 6, "r g b ?dataSetName?"},
-    {"linewidth",    5, MoleculeLineWidthOp, 3, 4, "width ?dataSetName?"},
-    {"opacity",      2, MoleculeOpacityOp, 3, 4, "value ?dataSetName?"},
-    {"orient",       2, MoleculeOrientOp, 6, 7, "qw qx qy qz ?dataSetName?"},
-    {"pos",          1, MoleculePositionOp, 5, 6, "x y z ?dataSetName?"},
-    {"rscale",       1, MoleculeAtomScalingOp, 3, 4, "scaling ?dataSetName?"},
-    {"scale",        1, MoleculeScaleOp, 5, 6, "sx sy sz ?dataSetName?"},
-    {"visible",      1, MoleculeVisibleOp, 3, 4, "bool ?dataSetName?"},
-    {"wireframe",    1, MoleculeWireframeOp, 3, 4, "bool ?dataSetName?"}
-};
-static int nMoleculeOps = NumCmdSpecs(moleculeOps);
-
-static int
-MoleculeCmd(ClientData clientData, Tcl_Interp *interp, int objc, 
-            Tcl_Obj *const *objv)
-{
-    Tcl_ObjCmdProc *proc;
-
-    proc = Rappture::GetOpFromObj(interp, nMoleculeOps, moleculeOps,
-                                  Rappture::CMDSPEC_ARG1, objc, objv, 0);
-    if (proc == NULL) {
-        return TCL_ERROR;
-    }
-    return (*proc) (clientData, interp, objc, objv);
-}
-
-static int
-OutlineAddOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-             Tcl_Obj *const *objv)
-{
-    if (objc == 3) {
-        const char *name = Tcl_GetString(objv[2]);
-        if (!g_renderer->addGraphicsObject<Outline>(name)) {
-            Tcl_AppendResult(interp, "Failed to create Outline", (char*)NULL);
-            return TCL_ERROR;
-        }
-    } else {
-        if (!g_renderer->addGraphicsObject<Outline>("all")) {
-            Tcl_AppendResult(interp, "Failed to create Outline for one or more data sets", (char*)NULL);
-            return TCL_ERROR;
-        }
-    }
-    return TCL_OK;
-}
-
-static int
-OutlineDeleteOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                Tcl_Obj *const *objv)
-{
-    if (objc == 3) {
-        const char *name = Tcl_GetString(objv[2]);
-        g_renderer->deleteGraphicsObject<Outline>(name);
-    } else {
-        g_renderer->deleteGraphicsObject<Outline>("all");
-    }
-    return TCL_OK;
-}
-
-static int
-OutlineColorOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-               Tcl_Obj *const *objv)
-{
-    float color[3];
-    if (GetFloatFromObj(interp, objv[2], &color[0]) != TCL_OK ||
-        GetFloatFromObj(interp, objv[3], &color[1]) != TCL_OK ||
-        GetFloatFromObj(interp, objv[4], &color[2]) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 6) {
-        const char *name = Tcl_GetString(objv[5]);
-        g_renderer->setGraphicsObjectColor<Outline>(name, color);
-    } else {
-        g_renderer->setGraphicsObjectColor<Outline>("all", color);
-    }
-    return TCL_OK;
-}
-
-static int
-OutlineLineWidthOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                   Tcl_Obj *const *objv)
-{
-    float width;
-    if (GetFloatFromObj(interp, objv[2], &width) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 4) {
-        const char *name = Tcl_GetString(objv[3]);
-        g_renderer->setGraphicsObjectEdgeWidth<Outline>(name, width);
-    } else {
-        g_renderer->setGraphicsObjectEdgeWidth<Outline>("all", width);
-    }
-    return TCL_OK;
-}
-
-static int
-OutlineOpacityOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                 Tcl_Obj *const *objv)
-{
-    double opacity;
-    if (Tcl_GetDoubleFromObj(interp, objv[2], &opacity) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 4) {
-        const char *name = Tcl_GetString(objv[3]);
-        g_renderer->setGraphicsObjectOpacity<Outline>(name, opacity);
-    } else {
-        g_renderer->setGraphicsObjectOpacity<Outline>("all", opacity);
-    }
-    return TCL_OK;
-}
-
-static int
-OutlineOrientOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                Tcl_Obj *const *objv)
-{
-    double quat[4];
-    if (Tcl_GetDoubleFromObj(interp, objv[2], &quat[0]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[3], &quat[1]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[4], &quat[2]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[5], &quat[3]) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 7) {
-        const char *name = Tcl_GetString(objv[6]);
-        g_renderer->setGraphicsObjectOrientation<Outline>(name, quat);
-    } else {
-        g_renderer->setGraphicsObjectOrientation<Outline>("all", quat);
-    }
-    return TCL_OK;
-}
-
-static int
-OutlinePositionOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                  Tcl_Obj *const *objv)
-{
-    double pos[3];
-    if (Tcl_GetDoubleFromObj(interp, objv[2], &pos[0]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[3], &pos[1]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[4], &pos[2]) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 6) {
-        const char *name = Tcl_GetString(objv[5]);
-        g_renderer->setGraphicsObjectPosition<Outline>(name, pos);
-    } else {
-        g_renderer->setGraphicsObjectPosition<Outline>("all", pos);
-    }
-    return TCL_OK;
-}
-
-static int
-OutlineScaleOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-               Tcl_Obj *const *objv)
-{
-    double scale[3];
-    if (Tcl_GetDoubleFromObj(interp, objv[2], &scale[0]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[3], &scale[1]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[4], &scale[2]) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 6) {
-        const char *name = Tcl_GetString(objv[5]);
-        g_renderer->setGraphicsObjectScale<Outline>(name, scale);
-    } else {
-        g_renderer->setGraphicsObjectScale<Outline>("all", scale);
-    }
-    return TCL_OK;
-}
-
-static int
-OutlineVisibleOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                 Tcl_Obj *const *objv)
-{
-    bool state;
-    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 4) {
-        const char *name = Tcl_GetString(objv[3]);
-        g_renderer->setGraphicsObjectVisibility<Outline>(name, state);
-    } else {
-        g_renderer->setGraphicsObjectVisibility<Outline>("all", state);
-    }
-    return TCL_OK;
-}
-
-static Rappture::CmdSpec outlineOps[] = {
-    {"add",       1, OutlineAddOp, 2, 3, "?dataSetName?"},
-    {"color",     1, OutlineColorOp, 5, 6, "r g b ?dataSetName?"},
-    {"delete",    1, OutlineDeleteOp, 2, 3, "?dataSetName?"},
-    {"linecolor", 5, OutlineColorOp, 5, 6, "r g b ?dataSetName?"},
-    {"linewidth", 5, OutlineLineWidthOp, 3, 4, "width ?dataSetName?"},
-    {"opacity",   2, OutlineOpacityOp, 3, 4, "value ?dataSetName?"},
-    {"orient",    2, OutlineOrientOp, 6, 7, "qw qx qy qz ?dataSetName?"},
-    {"pos",       2, OutlinePositionOp, 5, 6, "x y z ?dataSetName?"},
-    {"scale",     2, OutlineScaleOp, 5, 6, "sx sy sz ?dataSetName?"},
-    {"visible",   1, OutlineVisibleOp, 3, 4, "bool ?dataSetName?"}
-};
-static int nOutlineOps = NumCmdSpecs(outlineOps);
-
-static int
-OutlineCmd(ClientData clientData, Tcl_Interp *interp, int objc, 
-           Tcl_Obj *const *objv)
-{
-    Tcl_ObjCmdProc *proc;
-
-    proc = Rappture::GetOpFromObj(interp, nOutlineOps, outlineOps,
-                                  Rappture::CMDSPEC_ARG1, objc, objv, 0);
-    if (proc == NULL) {
-        return TCL_ERROR;
-    }
-    return (*proc) (clientData, interp, objc, objv);
-}
-
-static int
-PolyDataAddOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-              Tcl_Obj *const *objv)
-{
-    if (objc == 3) {
-        const char *name = Tcl_GetString(objv[2]);
-        if (!g_renderer->addGraphicsObject<PolyData>(name)) {
-            Tcl_AppendResult(interp, "Failed to create polydata", (char*)NULL);
-            return TCL_ERROR;
-        }
-    } else {
-        if (!g_renderer->addGraphicsObject<PolyData>("all")) {
-            Tcl_AppendResult(interp, "Failed to create polydata for one or more data sets", (char*)NULL);
-            return TCL_ERROR;
-        }
-    }
-    return TCL_OK;
-}
-
-static int
-PolyDataDeleteOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                 Tcl_Obj *const *objv)
-{
-    if (objc == 3) {
-        const char *name = Tcl_GetString(objv[2]);
-        g_renderer->deleteGraphicsObject<PolyData>(name);
-    } else {
-        g_renderer->deleteGraphicsObject<PolyData>("all");
-    }
-    return TCL_OK;
-}
-
-static int
-PolyDataColorOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                Tcl_Obj *const *objv)
-{
-    float color[3];
-    if (GetFloatFromObj(interp, objv[2], &color[0]) != TCL_OK ||
-        GetFloatFromObj(interp, objv[3], &color[1]) != TCL_OK ||
-        GetFloatFromObj(interp, objv[4], &color[2]) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 6) {
-        const char *name = Tcl_GetString(objv[5]);
-        g_renderer->setGraphicsObjectColor<PolyData>(name, color);
-    } else {
-        g_renderer->setGraphicsObjectColor<PolyData>("all", color);
-    }
-    return TCL_OK;
-}
-
-static int
-PolyDataEdgeVisibilityOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                         Tcl_Obj *const *objv)
-{
-    bool state;
-    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 4) {
-        const char *name = Tcl_GetString(objv[3]);
-        g_renderer->setGraphicsObjectEdgeVisibility<PolyData>(name, state);
-    } else {
-        g_renderer->setGraphicsObjectEdgeVisibility<PolyData>("all", state);
-    }
-    return TCL_OK;
-}
-
-static int
-PolyDataLightingOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                   Tcl_Obj *const *objv)
-{
-    bool state;
-    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 4) {
-        const char *name = Tcl_GetString(objv[3]);
-        g_renderer->setGraphicsObjectLighting<PolyData>(name, state);
-    } else {
-        g_renderer->setGraphicsObjectLighting<PolyData>("all", state);
-    }
-    return TCL_OK;
-}
-
-static int
-PolyDataLineColorOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                    Tcl_Obj *const *objv)
-{
-    float color[3];
-    if (GetFloatFromObj(interp, objv[2], &color[0]) != TCL_OK ||
-        GetFloatFromObj(interp, objv[3], &color[1]) != TCL_OK ||
-        GetFloatFromObj(interp, objv[4], &color[2]) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 6) {
-        const char *name = Tcl_GetString(objv[5]);
-        g_renderer->setGraphicsObjectEdgeColor<PolyData>(name, color);
-    } else {
-        g_renderer->setGraphicsObjectEdgeColor<PolyData>("all", color);
-    }
-    return TCL_OK;
-}
-
-static int
-PolyDataLineWidthOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                    Tcl_Obj *const *objv)
-{
-    float width;
-    if (GetFloatFromObj(interp, objv[2], &width) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 4) {
-        const char *name = Tcl_GetString(objv[3]);
-        g_renderer->setGraphicsObjectEdgeWidth<PolyData>(name, width);
-    } else {
-        g_renderer->setGraphicsObjectEdgeWidth<PolyData>("all", width);
-    }
-    return TCL_OK;
-}
-
-static int
-PolyDataMaterialOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                   Tcl_Obj *const *objv)
-{
-    double ambient, diffuse, specCoeff, specPower;
-    if (Tcl_GetDoubleFromObj(interp, objv[2], &ambient) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[3], &diffuse) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[4], &specCoeff) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[5], &specPower) != TCL_OK) {
-        return TCL_ERROR;
-    }
-
-    if (objc == 7) {
-        const char *name = Tcl_GetString(objv[6]);
-        g_renderer->setGraphicsObjectAmbient<PolyData>(name, ambient);
-        g_renderer->setGraphicsObjectDiffuse<PolyData>(name, diffuse);
-        g_renderer->setGraphicsObjectSpecular<PolyData>(name, specCoeff, specPower);
-    } else {
-        g_renderer->setGraphicsObjectAmbient<PolyData>("all", ambient);
-        g_renderer->setGraphicsObjectDiffuse<PolyData>("all", diffuse);
-        g_renderer->setGraphicsObjectSpecular<PolyData>("all", specCoeff, specPower);
-    }
-    return TCL_OK;
-}
-
-static int
-PolyDataOpacityOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                  Tcl_Obj *const *objv)
-{
-    double opacity;
-    if (Tcl_GetDoubleFromObj(interp, objv[2], &opacity) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 4) {
-        const char *name = Tcl_GetString(objv[3]);
-        g_renderer->setGraphicsObjectOpacity<PolyData>(name, opacity);
-    } else {
-        g_renderer->setGraphicsObjectOpacity<PolyData>("all", opacity);
-    }
-    return TCL_OK;
-}
-
-static int
-PolyDataOrientOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                 Tcl_Obj *const *objv)
-{
-    double quat[4];
-    if (Tcl_GetDoubleFromObj(interp, objv[2], &quat[0]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[3], &quat[1]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[4], &quat[2]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[5], &quat[3]) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 7) {
-        const char *name = Tcl_GetString(objv[6]);
-        g_renderer->setGraphicsObjectOrientation<PolyData>(name, quat);
-    } else {
-        g_renderer->setGraphicsObjectOrientation<PolyData>("all", quat);
-    }
-    return TCL_OK;
-}
-
-static int
-PolyDataPointSizeOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                    Tcl_Obj *const *objv)
-{
-    float size;
-    if (GetFloatFromObj(interp, objv[2], &size) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 4) {
-        const char *name = Tcl_GetString(objv[3]);
-        g_renderer->setGraphicsObjectPointSize<PolyData>(name, size);
-    } else {
-        g_renderer->setGraphicsObjectPointSize<PolyData>("all", size);
-    }
-    return TCL_OK;
-}
-
-static int
-PolyDataPositionOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                   Tcl_Obj *const *objv)
-{
-    double pos[3];
-    if (Tcl_GetDoubleFromObj(interp, objv[2], &pos[0]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[3], &pos[1]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[4], &pos[2]) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 6) {
-        const char *name = Tcl_GetString(objv[5]);
-        g_renderer->setGraphicsObjectPosition<PolyData>(name, pos);
-    } else {
-        g_renderer->setGraphicsObjectPosition<PolyData>("all", pos);
-    }
-    return TCL_OK;
-}
-
-static int
-PolyDataScaleOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                Tcl_Obj *const *objv)
-{
-    double scale[3];
-    if (Tcl_GetDoubleFromObj(interp, objv[2], &scale[0]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[3], &scale[1]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[4], &scale[2]) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 6) {
-        const char *name = Tcl_GetString(objv[5]);
-        g_renderer->setGraphicsObjectScale<PolyData>(name, scale);
-    } else {
-        g_renderer->setGraphicsObjectScale<PolyData>("all", scale);
-    }
-    return TCL_OK;
-}
-
-static int
-PolyDataVisibleOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                  Tcl_Obj *const *objv)
-{
-    bool state;
-    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 4) {
-        const char *name = Tcl_GetString(objv[3]);
-        g_renderer->setGraphicsObjectVisibility<PolyData>(name, state);
-    } else {
-        g_renderer->setGraphicsObjectVisibility<PolyData>("all", state);
-    }
-    return TCL_OK;
-}
-
-static int
-PolyDataWireframeOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                    Tcl_Obj *const *objv)
-{
-    bool state;
-    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 4) {
-        const char *name = Tcl_GetString(objv[3]);
-        g_renderer->setGraphicsObjectWireframe<PolyData>(name, state);
-    } else {
-        g_renderer->setGraphicsObjectWireframe<PolyData>("all", state);
-    }
-    return TCL_OK;
-}
-
-static Rappture::CmdSpec polyDataOps[] = {
-    {"add",       1, PolyDataAddOp, 2, 3, "?dataSetName?"},
-    {"color",     1, PolyDataColorOp, 5, 6, "r g b ?dataSetName?"},
-    {"delete",    1, PolyDataDeleteOp, 2, 3, "?dataSetName?"},
-    {"edges",     1, PolyDataEdgeVisibilityOp, 3, 4, "bool ?dataSetName?"},
-    {"lighting",  3, PolyDataLightingOp, 3, 4, "bool ?dataSetName?"},
-    {"linecolor", 5, PolyDataLineColorOp, 5, 6, "r g b ?dataSetName?"},
-    {"linewidth", 5, PolyDataLineWidthOp, 3, 4, "width ?dataSetName?"},
-    {"material",  1, PolyDataMaterialOp, 6, 7, "ambientCoeff diffuseCoeff specularCoeff specularPower ?dataSetName?"},
-    {"opacity",   2, PolyDataOpacityOp, 3, 4, "value ?dataSetName?"},
-    {"orient",    2, PolyDataOrientOp, 6, 7, "qw qx qy qz ?dataSetName?"},
-    {"pos",       2, PolyDataPositionOp, 5, 6, "x y z ?dataSetName?"},
-    {"ptsize",    2, PolyDataPointSizeOp, 3, 4, "size ?dataSetName?"},
-    {"scale",     1, PolyDataScaleOp, 5, 6, "sx sy sz ?dataSetName?"},
-    {"visible",   1, PolyDataVisibleOp, 3, 4, "bool ?dataSetName?"},
-    {"wireframe", 1, PolyDataWireframeOp, 3, 4, "bool ?dataSetName?"}
-};
-static int nPolyDataOps = NumCmdSpecs(polyDataOps);
-
-static int
-PolyDataCmd(ClientData clientData, Tcl_Interp *interp, int objc, 
-            Tcl_Obj *const *objv)
-{
-    Tcl_ObjCmdProc *proc;
-
-    proc = Rappture::GetOpFromObj(interp, nPolyDataOps, polyDataOps,
-                                  Rappture::CMDSPEC_ARG1, objc, objv, 0);
-    if (proc == NULL) {
-        return TCL_ERROR;
-    }
-    return (*proc) (clientData, interp, objc, objv);
-}
-
-static int
-PolygonAddOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-             Tcl_Obj *const *objv)
-{
-    int numSides;
-    if (Tcl_GetIntFromObj(interp, objv[2], &numSides) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    const char *name = Tcl_GetString(objv[3]);
-    if (!g_renderer->addPolygon(name, numSides)) {
-        Tcl_AppendResult(interp, "Failed to create polygon", (char*)NULL);
-        return TCL_ERROR;
-    }
-    return TCL_OK;
-}
-
-static int
-PolygonDeleteOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                Tcl_Obj *const *objv)
-{
-    if (objc == 3) {
-        const char *name = Tcl_GetString(objv[2]);
-        g_renderer->deleteGraphicsObject<Polygon>(name);
-    } else {
-        g_renderer->deleteGraphicsObject<Polygon>("all");
-    }
-    return TCL_OK;
-}
-
-static int
-PolygonColorOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-               Tcl_Obj *const *objv)
-{
-    float color[3];
-    if (GetFloatFromObj(interp, objv[2], &color[0]) != TCL_OK ||
-        GetFloatFromObj(interp, objv[3], &color[1]) != TCL_OK ||
-        GetFloatFromObj(interp, objv[4], &color[2]) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 6) {
-        const char *name = Tcl_GetString(objv[5]);
-        g_renderer->setGraphicsObjectColor<Polygon>(name, color);
-    } else {
-        g_renderer->setGraphicsObjectColor<Polygon>("all", color);
-    }
-    return TCL_OK;
-}
-
-static int
-PolygonEdgeVisibilityOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                        Tcl_Obj *const *objv)
-{
-    bool state;
-    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 4) {
-        const char *name = Tcl_GetString(objv[3]);
-        g_renderer->setGraphicsObjectEdgeVisibility<Polygon>(name, state);
-    } else {
-        g_renderer->setGraphicsObjectEdgeVisibility<Polygon>("all", state);
-    }
-    return TCL_OK;
-}
-
-static int
-PolygonLightingOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                  Tcl_Obj *const *objv)
-{
-    bool state;
-    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 4) {
-        const char *name = Tcl_GetString(objv[3]);
-        g_renderer->setGraphicsObjectLighting<Polygon>(name, state);
-    } else {
-        g_renderer->setGraphicsObjectLighting<Polygon>("all", state);
-    }
-    return TCL_OK;
-}
-
-static int
-PolygonLineColorOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                   Tcl_Obj *const *objv)
-{
-    float color[3];
-    if (GetFloatFromObj(interp, objv[2], &color[0]) != TCL_OK ||
-        GetFloatFromObj(interp, objv[3], &color[1]) != TCL_OK ||
-        GetFloatFromObj(interp, objv[4], &color[2]) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 6) {
-        const char *name = Tcl_GetString(objv[5]);
-        g_renderer->setGraphicsObjectEdgeColor<Polygon>(name, color);
-    } else {
-        g_renderer->setGraphicsObjectEdgeColor<Polygon>("all", color);
-    }
-    return TCL_OK;
-}
-
-static int
-PolygonLineWidthOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                   Tcl_Obj *const *objv)
-{
-    float width;
-    if (GetFloatFromObj(interp, objv[2], &width) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 4) {
-        const char *name = Tcl_GetString(objv[3]);
-        g_renderer->setGraphicsObjectEdgeWidth<Polygon>(name, width);
-    } else {
-        g_renderer->setGraphicsObjectEdgeWidth<Polygon>("all", width);
-    }
-    return TCL_OK;
-}
-
-static int
-PolygonMaterialOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                  Tcl_Obj *const *objv)
-{
-    double ambient, diffuse, specCoeff, specPower;
-    if (Tcl_GetDoubleFromObj(interp, objv[2], &ambient) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[3], &diffuse) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[4], &specCoeff) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[5], &specPower) != TCL_OK) {
-        return TCL_ERROR;
-    }
-
-    if (objc == 7) {
-        const char *name = Tcl_GetString(objv[6]);
-        g_renderer->setGraphicsObjectAmbient<Polygon>(name, ambient);
-        g_renderer->setGraphicsObjectDiffuse<Polygon>(name, diffuse);
-        g_renderer->setGraphicsObjectSpecular<Polygon>(name, specCoeff, specPower);
-    } else {
-        g_renderer->setGraphicsObjectAmbient<Polygon>("all", ambient);
-        g_renderer->setGraphicsObjectDiffuse<Polygon>("all", diffuse);
-        g_renderer->setGraphicsObjectSpecular<Polygon>("all", specCoeff, specPower);
-    }
-    return TCL_OK;
-}
-
-static int
-PolygonOpacityOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                 Tcl_Obj *const *objv)
-{
-    double opacity;
-    if (Tcl_GetDoubleFromObj(interp, objv[2], &opacity) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 4) {
-        const char *name = Tcl_GetString(objv[3]);
-        g_renderer->setGraphicsObjectOpacity<Polygon>(name, opacity);
-    } else {
-        g_renderer->setGraphicsObjectOpacity<Polygon>("all", opacity);
-    }
-    return TCL_OK;
-}
-
-static int
-PolygonOrientOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                Tcl_Obj *const *objv)
-{
-    double quat[4];
-    if (Tcl_GetDoubleFromObj(interp, objv[2], &quat[0]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[3], &quat[1]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[4], &quat[2]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[5], &quat[3]) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 7) {
-        const char *name = Tcl_GetString(objv[6]);
-        g_renderer->setGraphicsObjectOrientation<Polygon>(name, quat);
-    } else {
-        g_renderer->setGraphicsObjectOrientation<Polygon>("all", quat);
-    }
-    return TCL_OK;
-}
-
-static int
-PolygonPositionOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                  Tcl_Obj *const *objv)
-{
-    double pos[3];
-    if (Tcl_GetDoubleFromObj(interp, objv[2], &pos[0]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[3], &pos[1]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[4], &pos[2]) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 6) {
-        const char *name = Tcl_GetString(objv[5]);
-        g_renderer->setGraphicsObjectPosition<Polygon>(name, pos);
-    } else {
-        g_renderer->setGraphicsObjectPosition<Polygon>("all", pos);
-    }
-    return TCL_OK;
-}
-
-static int
-PolygonScaleOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-               Tcl_Obj *const *objv)
-{
-    double scale[3];
-    if (Tcl_GetDoubleFromObj(interp, objv[2], &scale[0]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[3], &scale[1]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[4], &scale[2]) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 6) {
-        const char *name = Tcl_GetString(objv[5]);
-        g_renderer->setGraphicsObjectScale<Polygon>(name, scale);
-    } else {
-        g_renderer->setGraphicsObjectScale<Polygon>("all", scale);
-    }
-    return TCL_OK;
-}
-
-static int
-PolygonVisibleOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                 Tcl_Obj *const *objv)
-{
-    bool state;
-    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 4) {
-        const char *name = Tcl_GetString(objv[3]);
-        g_renderer->setGraphicsObjectVisibility<Polygon>(name, state);
-    } else {
-        g_renderer->setGraphicsObjectVisibility<Polygon>("all", state);
-    }
-    return TCL_OK;
-}
-
-static int
-PolygonWireframeOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                   Tcl_Obj *const *objv)
-{
-    bool state;
-    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 4) {
-        const char *name = Tcl_GetString(objv[3]);
-        g_renderer->setGraphicsObjectWireframe<Polygon>(name, state);
-    } else {
-        g_renderer->setGraphicsObjectWireframe<Polygon>("all", state);
-    }
-    return TCL_OK;
-}
-
-static Rappture::CmdSpec polygonOps[] = {
-    {"add",       1, PolygonAddOp, 4, 4, "numSides name"},
-    {"color",     1, PolygonColorOp, 5, 6, "r g b ?name?"},
-    {"delete",    1, PolygonDeleteOp, 2, 3, "?name?"},
-    {"edges",     1, PolygonEdgeVisibilityOp, 3, 4, "bool ?name?"},
-    {"lighting",  3, PolygonLightingOp, 3, 4, "bool ?name?"},
-    {"linecolor", 5, PolygonLineColorOp, 5, 6, "r g b ?name?"},
-    {"linewidth", 5, PolygonLineWidthOp, 3, 4, "width ?name?"},
-    {"material",  1, PolygonMaterialOp, 6, 7, "ambientCoeff diffuseCoeff specularCoeff specularPower ?name?"},
-    {"opacity",   2, PolygonOpacityOp, 3, 4, "value ?name?"},
-    {"orient",    2, PolygonOrientOp, 6, 7, "qw qx qy qz ?name?"},
-    {"pos",       2, PolygonPositionOp, 5, 6, "x y z ?name?"},
-    {"scale",     1, PolygonScaleOp, 5, 6, "sx sy sz ?name?"},
-    {"visible",   1, PolygonVisibleOp, 3, 4, "bool ?name?"},
-    {"wireframe", 1, PolygonWireframeOp, 3, 4, "bool ?name?"}
-};
-static int nPolygonOps = NumCmdSpecs(polygonOps);
-
-static int
-PolygonCmd(ClientData clientData, Tcl_Interp *interp, int objc, 
-           Tcl_Obj *const *objv)
-{
-    Tcl_ObjCmdProc *proc;
-
-    proc = Rappture::GetOpFromObj(interp, nPolygonOps, polygonOps,
-                                  Rappture::CMDSPEC_ARG1, objc, objv, 0);
-    if (proc == NULL) {
-        return TCL_ERROR;
-    }
-    return (*proc) (clientData, interp, objc, objv);
-}
-
-static int
-PseudoColorAddOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-               Tcl_Obj *const *objv)
-{
-    if (objc == 3) {
-        const char *name = Tcl_GetString(objv[2]);
-        if (!g_renderer->addGraphicsObject<PseudoColor>(name)) {
-            Tcl_AppendResult(interp, "Failed to create pseudocolor", (char*)NULL);
-            return TCL_ERROR;
-        }
-    } else {
-        if (!g_renderer->addGraphicsObject<PseudoColor>("all")) {
-            Tcl_AppendResult(interp, "Failed to create pseudocolor for one or more data sets", (char*)NULL);
-            return TCL_ERROR;
-        }
-    }
-    return TCL_OK;
-}
-
-static int
-PseudoColorColorOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                   Tcl_Obj *const *objv)
-{
-    float color[3];
-    if (GetFloatFromObj(interp, objv[2], &color[0]) != TCL_OK ||
-        GetFloatFromObj(interp, objv[3], &color[1]) != TCL_OK ||
-        GetFloatFromObj(interp, objv[4], &color[2]) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 6) {
-        const char *name = Tcl_GetString(objv[5]);
-        g_renderer->setGraphicsObjectColor<PseudoColor>(name, color);
-    } else {
-        g_renderer->setGraphicsObjectColor<PseudoColor>("all", color);
-    }
-    return TCL_OK;
-}
-
-static int
-PseudoColorColorMapOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                      Tcl_Obj *const *objv)
-{
-    const char *colorMapName = Tcl_GetString(objv[2]);
-    if (objc == 4) {
-        const char *dataSetName = Tcl_GetString(objv[3]);
-        g_renderer->setGraphicsObjectColorMap<PseudoColor>(dataSetName, colorMapName);
-    } else {
-        g_renderer->setGraphicsObjectColorMap<PseudoColor>("all", colorMapName);
-    }
-    return TCL_OK;
-}
-
-static int
-PseudoColorColorModeOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                       Tcl_Obj *const *objv)
-{
-    PseudoColor::ColorMode mode;
-    const char *str = Tcl_GetString(objv[2]);
-    if (str[0] == 'c' && strcmp(str, "ccolor") == 0) {
-        mode = PseudoColor::COLOR_CONSTANT;
-    } else if (str[0] == 's' && strcmp(str, "scalar") == 0) {
-        mode = PseudoColor::COLOR_BY_SCALAR;
-    } else if (str[0] == 'v' && strcmp(str, "vmag") == 0) {
-        mode = PseudoColor::COLOR_BY_VECTOR_MAGNITUDE;
-    } else if (str[0] == 'v' && strcmp(str, "vx") == 0) {
-        mode = PseudoColor::COLOR_BY_VECTOR_X;
-    } else if (str[0] == 'v' && strcmp(str, "vy") == 0) {
-        mode = PseudoColor::COLOR_BY_VECTOR_Y;
-    } else if (str[0] == 'v' && strcmp(str, "vz") == 0) {
-        mode = PseudoColor::COLOR_BY_VECTOR_Z;
-    } else {
-        Tcl_AppendResult(interp, "bad color mode option \"", str,
-                         "\": should be one of: 'scalar', 'vmag', 'vx', 'vy', 'vz', 'ccolor'", (char*)NULL);
-        return TCL_ERROR;
-    }
-    const char *fieldName = Tcl_GetString(objv[3]);
-    if (mode == PseudoColor::COLOR_CONSTANT) {
-        fieldName = NULL;
-    }
-    if (objc == 5) {
-        const char *name = Tcl_GetString(objv[4]);
-        g_renderer->setPseudoColorColorMode(name, mode, fieldName);
-    } else {
-        g_renderer->setPseudoColorColorMode("all", mode, fieldName);
-    }
-    return TCL_OK;
-}
-
-static int
-PseudoColorDeleteOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                  Tcl_Obj *const *objv)
-{
-    if (objc == 3) {
-        const char *name = Tcl_GetString(objv[2]);
-        g_renderer->deleteGraphicsObject<PseudoColor>(name);
-    } else {
-        g_renderer->deleteGraphicsObject<PseudoColor>("all");
-    }
-    return TCL_OK;
-}
-
-static int
-PseudoColorEdgeVisibilityOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                            Tcl_Obj *const *objv)
-{
-    bool state;
-    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 4) {
-        const char *name = Tcl_GetString(objv[3]);
-        g_renderer->setGraphicsObjectEdgeVisibility<PseudoColor>(name, state);
-    } else {
-        g_renderer->setGraphicsObjectEdgeVisibility<PseudoColor>("all", state);
-    }
-    return TCL_OK;
-}
-
-static int
-PseudoColorLightingOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                      Tcl_Obj *const *objv)
-{
-    bool state;
-    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 4) {
-        const char *name = Tcl_GetString(objv[3]);
-        g_renderer->setGraphicsObjectLighting<PseudoColor>(name, state);
-    } else {
-        g_renderer->setGraphicsObjectLighting<PseudoColor>("all", state);
-    }
-    return TCL_OK;
-}
-
-static int
-PseudoColorLineColorOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                       Tcl_Obj *const *objv)
-{
-    float color[3];
-    if (GetFloatFromObj(interp, objv[2], &color[0]) != TCL_OK ||
-        GetFloatFromObj(interp, objv[3], &color[1]) != TCL_OK ||
-        GetFloatFromObj(interp, objv[4], &color[2]) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 6) {
-        const char *name = Tcl_GetString(objv[5]);
-        g_renderer->setGraphicsObjectEdgeColor<PseudoColor>(name, color);
-    } else {
-        g_renderer->setGraphicsObjectEdgeColor<PseudoColor>("all", color);
-    }
-    return TCL_OK;
-}
-
-static int
-PseudoColorLineWidthOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                       Tcl_Obj *const *objv)
-{
-    float width;
-    if (GetFloatFromObj(interp, objv[2], &width) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 4) {
-        const char *name = Tcl_GetString(objv[3]);
-        g_renderer->setGraphicsObjectEdgeWidth<PseudoColor>(name, width);
-    } else {
-        g_renderer->setGraphicsObjectEdgeWidth<PseudoColor>("all", width);
-    }
-    return TCL_OK;
-}
-
-static int
-PseudoColorOpacityOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                     Tcl_Obj *const *objv)
-{
-    double opacity;
-    if (Tcl_GetDoubleFromObj(interp, objv[2], &opacity) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 4) {
-        const char *name = Tcl_GetString(objv[3]);
-        g_renderer->setGraphicsObjectOpacity<PseudoColor>(name, opacity);
-    } else {
-        g_renderer->setGraphicsObjectOpacity<PseudoColor>("all", opacity);
-    }
-    return TCL_OK;
-}
-
-static int
-PseudoColorOrientOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                    Tcl_Obj *const *objv)
-{
-    double quat[4];
-    if (Tcl_GetDoubleFromObj(interp, objv[2], &quat[0]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[3], &quat[1]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[4], &quat[2]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[5], &quat[3]) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 7) {
-        const char *name = Tcl_GetString(objv[6]);
-        g_renderer->setGraphicsObjectOrientation<PseudoColor>(name, quat);
-    } else {
-        g_renderer->setGraphicsObjectOrientation<PseudoColor>("all", quat);
-    }
-    return TCL_OK;
-}
-
-static int
-PseudoColorPositionOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                      Tcl_Obj *const *objv)
-{
-    double pos[3];
-    if (Tcl_GetDoubleFromObj(interp, objv[2], &pos[0]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[3], &pos[1]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[4], &pos[2]) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 6) {
-        const char *name = Tcl_GetString(objv[5]);
-        g_renderer->setGraphicsObjectPosition<PseudoColor>(name, pos);
-    } else {
-        g_renderer->setGraphicsObjectPosition<PseudoColor>("all", pos);
-    }
-    return TCL_OK;
-}
-
-static int
-PseudoColorPreInterpOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                       Tcl_Obj *const *objv)
-{
-    bool state;
-    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 4) {
-        const char *name = Tcl_GetString(objv[3]);
-        g_renderer->setGraphicsObjectInterpolateBeforeMapping<PseudoColor>(name, state);
-    } else {
-        g_renderer->setGraphicsObjectInterpolateBeforeMapping<PseudoColor>("all", state);
-    }
-    return TCL_OK;
-}
-
-static int
-PseudoColorScaleOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                   Tcl_Obj *const *objv)
-{
-    double scale[3];
-    if (Tcl_GetDoubleFromObj(interp, objv[2], &scale[0]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[3], &scale[1]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[4], &scale[2]) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 6) {
-        const char *name = Tcl_GetString(objv[5]);
-        g_renderer->setGraphicsObjectScale<PseudoColor>(name, scale);
-    } else {
-        g_renderer->setGraphicsObjectScale<PseudoColor>("all", scale);
-    }
-    return TCL_OK;
-}
-
-static int
-PseudoColorVisibleOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                     Tcl_Obj *const *objv)
-{
-    bool state;
-    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 4) {
-        const char *name = Tcl_GetString(objv[3]);
-        g_renderer->setGraphicsObjectVisibility<PseudoColor>(name, state);
-    } else {
-        g_renderer->setGraphicsObjectVisibility<PseudoColor>("all", state);
-    }
-    return TCL_OK;
-}
-
-static int
-PseudoColorWireframeOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                       Tcl_Obj *const *objv)
-{
-    bool state;
-    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 4) {
-        const char *name = Tcl_GetString(objv[3]);
-        g_renderer->setGraphicsObjectWireframe<PseudoColor>(name, state);
-    } else {
-        g_renderer->setGraphicsObjectWireframe<PseudoColor>("all", state);
-    }
-    return TCL_OK;
-}
-
-static Rappture::CmdSpec pseudoColorOps[] = {
-    {"add",          1, PseudoColorAddOp, 2, 3, "?dataSetName?"},
-    {"ccolor",       2, PseudoColorColorOp, 5, 6, "r g b ?dataSetName?"},
-    {"colormap",     7, PseudoColorColorMapOp, 3, 4, "colorMapName ?dataSetName?"},
-    {"colormode",    7, PseudoColorColorModeOp, 4, 5, "mode fieldName ?dataSetName?"},
-    {"delete",       1, PseudoColorDeleteOp, 2, 3, "?dataSetName?"},
-    {"edges",        1, PseudoColorEdgeVisibilityOp, 3, 4, "bool ?dataSetName?"},
-    {"lighting",     3, PseudoColorLightingOp, 3, 4, "bool ?dataSetName?"},
-    {"linecolor",    5, PseudoColorLineColorOp, 5, 6, "r g b ?dataSetName?"},
-    {"linewidth",    5, PseudoColorLineWidthOp, 3, 4, "width ?dataSetName?"},
-    {"opacity",      2, PseudoColorOpacityOp, 3, 4, "value ?dataSetName?"},
-    {"orient",       2, PseudoColorOrientOp, 6, 7, "qw qx qy qz ?dataSetName?"},
-    {"pos",          2, PseudoColorPositionOp, 5, 6, "x y z ?dataSetName?"},
-    {"preinterp",    2, PseudoColorPreInterpOp, 3, 4, "bool ?dataSetName?"},
-    {"scale",        1, PseudoColorScaleOp, 5, 6, "sx sy sz ?dataSetName?"},
-    {"visible",      1, PseudoColorVisibleOp, 3, 4, "bool ?dataSetName?"},
-    {"wireframe",    1, PseudoColorWireframeOp, 3, 4, "bool ?dataSetName?"}
-};
-static int nPseudoColorOps = NumCmdSpecs(pseudoColorOps);
-
-static int
-PseudoColorCmd(ClientData clientData, Tcl_Interp *interp, int objc, 
-               Tcl_Obj *const *objv)
-{
-    Tcl_ObjCmdProc *proc;
-
-    proc = Rappture::GetOpFromObj(interp, nPseudoColorOps, pseudoColorOps,
-                                  Rappture::CMDSPEC_ARG1, objc, objv, 0);
-    if (proc == NULL) {
-        return TCL_ERROR;
-    }
-    return (*proc) (clientData, interp, objc, objv);
-}
-
-static int
-RendererClipPlaneOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                    Tcl_Obj *const *objv)
-{
-    const char *string = Tcl_GetString(objv[2]);
-    char c = string[0];
-    Axis axis;
-    if ((c == 'x') && (strcmp(string, "x") == 0)) {
-        axis = X_AXIS;
-    } else if ((c == 'y') && (strcmp(string, "y") == 0)) {
-        axis = Y_AXIS;
-    } else if ((c == 'z') && (strcmp(string, "z") == 0)) {
-        axis = Z_AXIS;
-    } else {
-        Tcl_AppendResult(interp, "bad clipplane option \"", string,
-                         "\": should be axisName ratio direction", (char*)NULL);
-        return TCL_ERROR;
-    }
-    double ratio;
-    if (Tcl_GetDoubleFromObj(interp, objv[3], &ratio) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    int direction;
-    if (Tcl_GetIntFromObj(interp, objv[4], &direction) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    g_renderer->setClipPlane(axis, ratio, direction);
-    return TCL_OK;
-}
-
-static int
-RendererDepthPeelingOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                       Tcl_Obj *const *objv)
-{
-    bool state;
-    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    g_renderer->setUseDepthPeeling(state);
-    return TCL_OK;
-}
-
-static int
-RendererTwoSidedLightingOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                           Tcl_Obj *const *objv)
-{
-    bool state;
-    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    g_renderer->setUseTwoSidedLighting(state);
-    return TCL_OK;
-}
-
-static int
-RendererRenderOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                 Tcl_Obj *const *objv)
-{
-    g_renderer->eventuallyRender();
-    return TCL_OK;
-}
-
-static Rappture::CmdSpec rendererOps[] = {
-    {"clipplane",  1, RendererClipPlaneOp, 5, 5, "axis ratio direction"},
-    {"depthpeel",  1, RendererDepthPeelingOp, 3, 3, "bool"},
-    {"light2side", 1, RendererTwoSidedLightingOp, 3, 3, "bool"},
-    {"render",     1, RendererRenderOp, 2, 2, ""}
-};
-static int nRendererOps = NumCmdSpecs(rendererOps);
-
-static int
-RendererCmd(ClientData clientData, Tcl_Interp *interp, int objc, 
-            Tcl_Obj *const *objv)
-{
-    Tcl_ObjCmdProc *proc;
-
-    proc = Rappture::GetOpFromObj(interp, nRendererOps, rendererOps,
-                                  Rappture::CMDSPEC_ARG1, objc, objv, 0);
-    if (proc == NULL) {
-        return TCL_ERROR;
-    }
-    return (*proc) (clientData, interp, objc, objv);
-}
-
-static int
-ScreenBgColorOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                Tcl_Obj *const *objv)
-{
-    float color[3];
-
-    if (GetFloatFromObj(interp, objv[2], &color[0]) != TCL_OK ||
-        GetFloatFromObj(interp, objv[3], &color[1]) != TCL_OK ||
-        GetFloatFromObj(interp, objv[4], &color[2]) != TCL_OK) {
-        return TCL_ERROR;
-    }
-
-    g_renderer->setBackgroundColor(color);
-    return TCL_OK;
-}
-
-static int
-ScreenSizeOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-             Tcl_Obj *const *objv)
-{
-    int width, height;
-
-    if (Tcl_GetIntFromObj(interp, objv[2], &width) != TCL_OK ||
-        Tcl_GetIntFromObj(interp, objv[3], &height) != TCL_OK) {
-        return TCL_ERROR;
-    }
-
-    g_renderer->setWindowSize(width, height);
-    return TCL_OK;
-}
-
-static Rappture::CmdSpec screenOps[] = {
-    {"bgcolor", 1, ScreenBgColorOp, 5, 5, "r g b"},
-    {"size", 1, ScreenSizeOp, 4, 4, "width height"}
-};
-static int nScreenOps = NumCmdSpecs(screenOps);
-
-static int
-ScreenCmd(ClientData clientData, Tcl_Interp *interp, int objc, 
-          Tcl_Obj *const *objv)
-{
-    Tcl_ObjCmdProc *proc;
-
-    proc = Rappture::GetOpFromObj(interp, nScreenOps, screenOps,
-                                  Rappture::CMDSPEC_ARG1, objc, objv, 0);
-    if (proc == NULL) {
-        return TCL_ERROR;
-    }
-    return (*proc) (clientData, interp, objc, objv);
-}
-
-static int
-SphereAddOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-            Tcl_Obj *const *objv)
-{
-    const char *name = Tcl_GetString(objv[2]);
-    if (!g_renderer->addGraphicsObject<Sphere>(name)) {
-        Tcl_AppendResult(interp, "Failed to create sphere", (char*)NULL);
-        return TCL_ERROR;
-    }
-    return TCL_OK;
-}
-
-static int
-SphereDeleteOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-               Tcl_Obj *const *objv)
-{
-    if (objc == 3) {
-        const char *name = Tcl_GetString(objv[2]);
-        g_renderer->deleteGraphicsObject<Sphere>(name);
-    } else {
-        g_renderer->deleteGraphicsObject<Sphere>("all");
-    }
-    return TCL_OK;
-}
-
-static int
-SphereColorOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-              Tcl_Obj *const *objv)
-{
-    float color[3];
-    if (GetFloatFromObj(interp, objv[2], &color[0]) != TCL_OK ||
-        GetFloatFromObj(interp, objv[3], &color[1]) != TCL_OK ||
-        GetFloatFromObj(interp, objv[4], &color[2]) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 6) {
-        const char *name = Tcl_GetString(objv[5]);
-        g_renderer->setGraphicsObjectColor<Sphere>(name, color);
-    } else {
-        g_renderer->setGraphicsObjectColor<Sphere>("all", color);
-    }
-    return TCL_OK;
-}
-
-static int
-SphereEdgeVisibilityOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                       Tcl_Obj *const *objv)
-{
-    bool state;
-    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 4) {
-        const char *name = Tcl_GetString(objv[3]);
-        g_renderer->setGraphicsObjectEdgeVisibility<Sphere>(name, state);
-    } else {
-        g_renderer->setGraphicsObjectEdgeVisibility<Sphere>("all", state);
-    }
-    return TCL_OK;
-}
-
-static int
-SphereLightingOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                 Tcl_Obj *const *objv)
-{
-    bool state;
-    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 4) {
-        const char *name = Tcl_GetString(objv[3]);
-        g_renderer->setGraphicsObjectLighting<Sphere>(name, state);
-    } else {
-        g_renderer->setGraphicsObjectLighting<Sphere>("all", state);
-    }
-    return TCL_OK;
-}
-
-static int
-SphereLineColorOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                  Tcl_Obj *const *objv)
-{
-    float color[3];
-    if (GetFloatFromObj(interp, objv[2], &color[0]) != TCL_OK ||
-        GetFloatFromObj(interp, objv[3], &color[1]) != TCL_OK ||
-        GetFloatFromObj(interp, objv[4], &color[2]) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 6) {
-        const char *name = Tcl_GetString(objv[5]);
-        g_renderer->setGraphicsObjectEdgeColor<Sphere>(name, color);
-    } else {
-        g_renderer->setGraphicsObjectEdgeColor<Sphere>("all", color);
-    }
-    return TCL_OK;
-}
-
-static int
-SphereLineWidthOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                  Tcl_Obj *const *objv)
-{
-    float width;
-    if (GetFloatFromObj(interp, objv[2], &width) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 4) {
-        const char *name = Tcl_GetString(objv[3]);
-        g_renderer->setGraphicsObjectEdgeWidth<Sphere>(name, width);
-    } else {
-        g_renderer->setGraphicsObjectEdgeWidth<Sphere>("all", width);
-    }
-    return TCL_OK;
-}
-
-static int
-SphereMaterialOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                 Tcl_Obj *const *objv)
-{
-    double ambient, diffuse, specCoeff, specPower;
-    if (Tcl_GetDoubleFromObj(interp, objv[2], &ambient) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[3], &diffuse) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[4], &specCoeff) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[5], &specPower) != TCL_OK) {
-        return TCL_ERROR;
-    }
-
-    if (objc == 7) {
-        const char *name = Tcl_GetString(objv[6]);
-        g_renderer->setGraphicsObjectAmbient<Sphere>(name, ambient);
-        g_renderer->setGraphicsObjectDiffuse<Sphere>(name, diffuse);
-        g_renderer->setGraphicsObjectSpecular<Sphere>(name, specCoeff, specPower);
-    } else {
-        g_renderer->setGraphicsObjectAmbient<Sphere>("all", ambient);
-        g_renderer->setGraphicsObjectDiffuse<Sphere>("all", diffuse);
-        g_renderer->setGraphicsObjectSpecular<Sphere>("all", specCoeff, specPower);
-    }
-    return TCL_OK;
-}
-
-static int
-SphereOpacityOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                Tcl_Obj *const *objv)
-{
-    double opacity;
-    if (Tcl_GetDoubleFromObj(interp, objv[2], &opacity) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 4) {
-        const char *name = Tcl_GetString(objv[3]);
-        g_renderer->setGraphicsObjectOpacity<Sphere>(name, opacity);
-    } else {
-        g_renderer->setGraphicsObjectOpacity<Sphere>("all", opacity);
-    }
-    return TCL_OK;
-}
-
-static int
-SphereOrientOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-               Tcl_Obj *const *objv)
-{
-    double quat[4];
-    if (Tcl_GetDoubleFromObj(interp, objv[2], &quat[0]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[3], &quat[1]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[4], &quat[2]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[5], &quat[3]) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 7) {
-        const char *name = Tcl_GetString(objv[6]);
-        g_renderer->setGraphicsObjectOrientation<Sphere>(name, quat);
-    } else {
-        g_renderer->setGraphicsObjectOrientation<Sphere>("all", quat);
-    }
-    return TCL_OK;
-}
-
-static int
-SpherePositionOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                 Tcl_Obj *const *objv)
-{
-    double pos[3];
-    if (Tcl_GetDoubleFromObj(interp, objv[2], &pos[0]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[3], &pos[1]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[4], &pos[2]) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 6) {
-        const char *name = Tcl_GetString(objv[5]);
-        g_renderer->setGraphicsObjectPosition<Sphere>(name, pos);
-    } else {
-        g_renderer->setGraphicsObjectPosition<Sphere>("all", pos);
-    }
-    return TCL_OK;
-}
-
-static int
-SphereResolutionOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                   Tcl_Obj *const *objv)
-{
-    int theta, phi;
-    if (Tcl_GetIntFromObj(interp, objv[2], &theta) != TCL_OK ||
-        Tcl_GetIntFromObj(interp, objv[3], &phi) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 5) {
-        const char *name = Tcl_GetString(objv[4]);
-        g_renderer->setSphereResolution(name, theta, phi);
-    } else {
-        g_renderer->setSphereResolution("all", theta, phi);
-    }
-    return TCL_OK;
-}
-
-static int
-SphereScaleOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-              Tcl_Obj *const *objv)
-{
-    double scale[3];
-    if (Tcl_GetDoubleFromObj(interp, objv[2], &scale[0]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[3], &scale[1]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[4], &scale[2]) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 6) {
-        const char *name = Tcl_GetString(objv[5]);
-        g_renderer->setGraphicsObjectScale<Sphere>(name, scale);
-    } else {
-        g_renderer->setGraphicsObjectScale<Sphere>("all", scale);
-    }
-    return TCL_OK;
-}
-
-static int
-SphereSectionOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                Tcl_Obj *const *objv)
-{
-    double thetaStart, thetaEnd, phiStart, phiEnd;
-    if (Tcl_GetDoubleFromObj(interp, objv[2], &thetaStart) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[3], &thetaEnd) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[4], &phiStart) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[5], &phiEnd) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 7) {
-        const char *name = Tcl_GetString(objv[6]);
-        g_renderer->setSphereSection(name, thetaStart, thetaEnd, phiStart, phiEnd);
-    } else {
-        g_renderer->setSphereSection("all", thetaStart, thetaEnd, phiStart, phiEnd);
-    }
-    return TCL_OK;
-}
-
-static int
-SphereVisibleOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                Tcl_Obj *const *objv)
-{
-    bool state;
-    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 4) {
-        const char *name = Tcl_GetString(objv[3]);
-        g_renderer->setGraphicsObjectVisibility<Sphere>(name, state);
-    } else {
-        g_renderer->setGraphicsObjectVisibility<Sphere>("all", state);
-    }
-    return TCL_OK;
-}
-
-static int
-SphereWireframeOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                  Tcl_Obj *const *objv)
-{
-    bool state;
-    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 4) {
-        const char *name = Tcl_GetString(objv[3]);
-        g_renderer->setGraphicsObjectWireframe<Sphere>(name, state);
-    } else {
-        g_renderer->setGraphicsObjectWireframe<Sphere>("all", state);
-    }
-    return TCL_OK;
-}
-
-static Rappture::CmdSpec sphereOps[] = {
-    {"add",       1, SphereAddOp, 3, 3, "name"},
-    {"color",     1, SphereColorOp, 5, 6, "r g b ?name?"},
-    {"delete",    1, SphereDeleteOp, 2, 3, "?name?"},
-    {"edges",     1, SphereEdgeVisibilityOp, 3, 4, "bool ?name?"},
-    {"lighting",  3, SphereLightingOp, 3, 4, "bool ?name?"},
-    {"linecolor", 5, SphereLineColorOp, 5, 6, "r g b ?name?"},
-    {"linewidth", 5, SphereLineWidthOp, 3, 4, "width ?name?"},
-    {"material",  1, SphereMaterialOp, 6, 7, "ambientCoeff diffuseCoeff specularCoeff specularPower ?name?"},
-    {"opacity",   2, SphereOpacityOp, 3, 4, "value ?name?"},
-    {"orient",    2, SphereOrientOp, 6, 7, "qw qx qy qz ?name?"},
-    {"pos",       2, SpherePositionOp, 5, 6, "x y z ?name?"},
-    {"resolution",1, SphereResolutionOp, 4, 5, "thetaRes phiRes ?name?"},
-    {"scale",     2, SphereScaleOp, 5, 6, "sx sy sz ?name?"},
-    {"section",   2, SphereSectionOp, 6, 7, "thetaStart thetaEnd phiStart phiEnd ?name?"},
-    {"visible",   1, SphereVisibleOp, 3, 4, "bool ?name?"},
-    {"wireframe", 1, SphereWireframeOp, 3, 4, "bool ?name?"}
-};
-static int nSphereOps = NumCmdSpecs(sphereOps);
-
-static int
-SphereCmd(ClientData clientData, Tcl_Interp *interp, int objc, 
-       Tcl_Obj *const *objv)
-{
-    Tcl_ObjCmdProc *proc;
-
-    proc = Rappture::GetOpFromObj(interp, nSphereOps, sphereOps,
-                                  Rappture::CMDSPEC_ARG1, objc, objv, 0);
-    if (proc == NULL) {
-        return TCL_ERROR;
-    }
-    return (*proc) (clientData, interp, objc, objv);
-}
-
-static int
-StreamlinesAddOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                 Tcl_Obj *const *objv)
-{
-    if (objc == 3) {
-        const char *name = Tcl_GetString(objv[2]);
-        if (!g_renderer->addGraphicsObject<Streamlines>(name)) {
-            Tcl_AppendResult(interp, "Failed to create streamlines", (char*)NULL);
-            return TCL_ERROR;
-        }
-    } else {
-        if (!g_renderer->addGraphicsObject<Streamlines>("all")) {
-            Tcl_AppendResult(interp, "Failed to create streamlines for one or more data sets", (char*)NULL);
-            return TCL_ERROR;
-        }
-    }
-    return TCL_OK;
-}
-
-static int
-StreamlinesColorOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                   Tcl_Obj *const *objv)
-{
-    float color[3];
-    if (GetFloatFromObj(interp, objv[2], &color[0]) != TCL_OK ||
-        GetFloatFromObj(interp, objv[3], &color[1]) != TCL_OK ||
-        GetFloatFromObj(interp, objv[4], &color[2]) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 6) {
-        const char *name = Tcl_GetString(objv[5]);
-        g_renderer->setGraphicsObjectColor<Streamlines>(name, color);
-    } else {
-        g_renderer->setGraphicsObjectColor<Streamlines>("all", color);
-    }
-    return TCL_OK;
-}
-
-static int
-StreamlinesColorMapOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                      Tcl_Obj *const *objv)
-{
-    const char *colorMapName = Tcl_GetString(objv[2]);
-    if (objc == 4) {
-        const char *dataSetName = Tcl_GetString(objv[3]);
-        g_renderer->setGraphicsObjectColorMap<Streamlines>(dataSetName, colorMapName);
-    } else {
-        g_renderer->setGraphicsObjectColorMap<Streamlines>("all", colorMapName);
-    }
-    return TCL_OK;
-}
-
-static int
-StreamlinesColorModeOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                       Tcl_Obj *const *objv)
-{
-    Streamlines::ColorMode mode;
-    const char *str = Tcl_GetString(objv[2]);
-    if (str[0] == 's' && strcmp(str, "scalar") == 0) {
-        mode = Streamlines::COLOR_BY_SCALAR;
-    } else if (str[0] == 'v' && strcmp(str, "vmag") == 0) {
-        mode = Streamlines::COLOR_BY_VECTOR_MAGNITUDE;
-    } else if (str[0] == 'v' && strcmp(str, "vx") == 0) {
-        mode = Streamlines::COLOR_BY_VECTOR_X;
-    } else if (str[0] == 'v' && strcmp(str, "vy") == 0) {
-        mode = Streamlines::COLOR_BY_VECTOR_Y;
-    } else if (str[0] == 'v' && strcmp(str, "vz") == 0) {
-        mode = Streamlines::COLOR_BY_VECTOR_Z;
-    } else if (str[0] == 'c' && strcmp(str, "ccolor") == 0) {
-        mode = Streamlines::COLOR_CONSTANT;
-    } else {
-        Tcl_AppendResult(interp, "bad color mode option \"", str,
-                         "\": should be one of: 'scalar', 'vmag', 'vx', 'vy', 'vz', 'ccolor'", (char*)NULL);
-        return TCL_ERROR;
-    }
-    const char *fieldName = Tcl_GetString(objv[3]);
-    if (mode == Streamlines::COLOR_CONSTANT) {
-        fieldName = NULL;
-    }
-    if (objc == 5) {
-        const char *dataSetName = Tcl_GetString(objv[4]);
-        g_renderer->setStreamlinesColorMode(dataSetName, mode, fieldName);
-    } else {
-        g_renderer->setStreamlinesColorMode("all", mode, fieldName);
-    }
-    return TCL_OK;
-}
-
-static int
-StreamlinesDeleteOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                    Tcl_Obj *const *objv)
-{
-    if (objc == 3) {
-        const char *name = Tcl_GetString(objv[2]);
-        g_renderer->deleteGraphicsObject<Streamlines>(name);
-    } else {
-        g_renderer->deleteGraphicsObject<Streamlines>("all");
-    }
-    return TCL_OK;
-}
-
-static int
-StreamlinesEdgeVisibilityOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                            Tcl_Obj *const *objv)
-{
-    bool state;
-    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 4) {
-        const char *name = Tcl_GetString(objv[3]);
-        g_renderer->setGraphicsObjectEdgeVisibility<Streamlines>(name, state);
-    } else {
-        g_renderer->setGraphicsObjectEdgeVisibility<Streamlines>("all", state);
-    }
-    return TCL_OK;
-}
-
-static int
-StreamlinesLengthOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                    Tcl_Obj *const *objv)
-{
-    double length;
-    if (Tcl_GetDoubleFromObj(interp, objv[2], &length) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 4) {
-        const char *name = Tcl_GetString(objv[3]);
-        g_renderer->setStreamlinesLength(name, length);
-    } else {
-        g_renderer->setStreamlinesLength("all", length);
-    }
-    return TCL_OK;
-}
-
-static int
-StreamlinesLightingOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                      Tcl_Obj *const *objv)
-{
-    bool state;
-    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 4) {
-        const char *name = Tcl_GetString(objv[3]);
-        g_renderer->setGraphicsObjectLighting<Streamlines>(name, state);
-    } else {
-        g_renderer->setGraphicsObjectLighting<Streamlines>("all", state);
-    }
-    return TCL_OK;
-}
-
-static int
-StreamlinesLineColorOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                       Tcl_Obj *const *objv)
-{
-    float color[3];
-    if (GetFloatFromObj(interp, objv[2], &color[0]) != TCL_OK ||
-        GetFloatFromObj(interp, objv[3], &color[1]) != TCL_OK ||
-        GetFloatFromObj(interp, objv[4], &color[2]) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 6) {
-        const char *name = Tcl_GetString(objv[5]);
-        g_renderer->setGraphicsObjectEdgeColor<Streamlines>(name, color);
-    } else {
-        g_renderer->setGraphicsObjectEdgeColor<Streamlines>("all", color);
-    }
-    return TCL_OK;
-}
-
-static int
-StreamlinesLinesOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                   Tcl_Obj *const *objv)
-{
-    if (objc == 3) {
-        const char *name = Tcl_GetString(objv[2]);
-        g_renderer->setStreamlinesTypeToLines(name);
-    } else {
-        g_renderer->setStreamlinesTypeToLines("all");
-    }
-    return TCL_OK;
-}
-
-static int
-StreamlinesLineWidthOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                       Tcl_Obj *const *objv)
-{
-    float width;
-    if (GetFloatFromObj(interp, objv[2], &width) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 4) {
-        const char *name = Tcl_GetString(objv[3]);
-        g_renderer->setGraphicsObjectEdgeWidth<Streamlines>(name, width);
-    } else {
-        g_renderer->setGraphicsObjectEdgeWidth<Streamlines>("all", width);
-    }
-    return TCL_OK;
-}
-
-static int
-StreamlinesOpacityOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                     Tcl_Obj *const *objv)
-{
-    double opacity;
-    if (Tcl_GetDoubleFromObj(interp, objv[2], &opacity) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 4) {
-        const char *name = Tcl_GetString(objv[3]);
-        g_renderer->setGraphicsObjectOpacity<Streamlines>(name, opacity);
-    } else {
-        g_renderer->setGraphicsObjectOpacity<Streamlines>("all", opacity);
-    }
-    return TCL_OK;
-}
-
-static int
-StreamlinesOrientOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                    Tcl_Obj *const *objv)
-{
-    double quat[4];
-    if (Tcl_GetDoubleFromObj(interp, objv[2], &quat[0]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[3], &quat[1]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[4], &quat[2]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[5], &quat[3]) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 7) {
-        const char *name = Tcl_GetString(objv[6]);
-        g_renderer->setGraphicsObjectOrientation<Streamlines>(name, quat);
-    } else {
-        g_renderer->setGraphicsObjectOrientation<Streamlines>("all", quat);
-    }
-    return TCL_OK;
-}
-
-static int
-StreamlinesPositionOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                      Tcl_Obj *const *objv)
-{
-    double pos[3];
-    if (Tcl_GetDoubleFromObj(interp, objv[2], &pos[0]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[3], &pos[1]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[4], &pos[2]) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 6) {
-        const char *name = Tcl_GetString(objv[5]);
-        g_renderer->setGraphicsObjectPosition<Streamlines>(name, pos);
-    } else {
-        g_renderer->setGraphicsObjectPosition<Streamlines>("all", pos);
-    }
-    return TCL_OK;
-}
-
-static int
-StreamlinesScaleOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                   Tcl_Obj *const *objv)
-{
-    double scale[3];
-    if (Tcl_GetDoubleFromObj(interp, objv[2], &scale[0]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[3], &scale[1]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[4], &scale[2]) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 6) {
-        const char *name = Tcl_GetString(objv[5]);
-        g_renderer->setGraphicsObjectScale<Streamlines>(name, scale);
-    } else {
-        g_renderer->setGraphicsObjectScale<Streamlines>("all", scale);
-    }
-    return TCL_OK;
-}
-
-static int
-StreamlinesRibbonsOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                     Tcl_Obj *const *objv)
-{
-    double width, angle;
-    if (Tcl_GetDoubleFromObj(interp, objv[2], &width) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (Tcl_GetDoubleFromObj(interp, objv[3], &angle) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 5) {
-        const char *name = Tcl_GetString(objv[4]);
-        g_renderer->setStreamlinesTypeToRibbons(name, width, angle);
-    } else {
-        g_renderer->setStreamlinesTypeToRibbons("all", width, angle);
-    }
-    return TCL_OK;
-}
-
-static int
-StreamlinesSeedColorOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                       Tcl_Obj *const *objv)
-{
-    float color[3];
-    if (GetFloatFromObj(interp, objv[3], &color[0]) != TCL_OK ||
-        GetFloatFromObj(interp, objv[4], &color[1]) != TCL_OK ||
-        GetFloatFromObj(interp, objv[5], &color[2]) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 7) {
-        const char *name = Tcl_GetString(objv[6]);
-        g_renderer->setStreamlinesSeedColor(name, color);
-    } else {
-        g_renderer->setStreamlinesSeedColor("all", color);
-    }
-    return TCL_OK;
-}
-
-static int
-StreamlinesSeedDiskOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                      Tcl_Obj *const *objv)
-{
-    double center[3], normal[3], radius, innerRadius;
-    int numPoints;
-    for (int i = 0; i < 3; i++) {
-        if (Tcl_GetDoubleFromObj(interp, objv[3+i], &center[i]) != TCL_OK) {
-            return TCL_ERROR;
-        }
-        if (Tcl_GetDoubleFromObj(interp, objv[6+i], &normal[i]) != TCL_OK) {
-            return TCL_ERROR;
-        }
-    }
-    if (Tcl_GetDoubleFromObj(interp, objv[9], &radius) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (Tcl_GetDoubleFromObj(interp, objv[10], &innerRadius) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (Tcl_GetIntFromObj(interp, objv[11], &numPoints) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 13) {
-        const char *name = Tcl_GetString(objv[12]);
-        g_renderer->setStreamlinesSeedToDisk(name, center, normal, radius, innerRadius, numPoints);
-    } else {
-        g_renderer->setStreamlinesSeedToDisk("all", center, normal, radius, innerRadius, numPoints);
-    }
-    return TCL_OK;
-}
-
-static int
-StreamlinesSeedFilledMeshOp(ClientData clientData, Tcl_Interp *interp,
-                            int objc, Tcl_Obj *const *objv)
-{
-    int numPoints = 0;
-    if (Tcl_GetIntFromObj(interp, objv[3], &numPoints) != TCL_OK ||
-        numPoints < 1) {
-        return TCL_ERROR;
-    }
-    const char *string = Tcl_GetString(objv[4]);
-    char c = string[0];
-    if ((c != 'd') || (strcmp(string, "data") != 0)) {
-        Tcl_AppendResult(interp, "bad streamlines seed fmesh option \"",
-                         string, "\": should be data", (char*)NULL);
-        return TCL_ERROR;
-    }
-    string = Tcl_GetString(objv[5]);
-    c = string[0];
-    if ((c != 'f') || (strcmp(string, "follows") != 0)) {
-        Tcl_AppendResult(interp, "bad streamlines seed fmesh option \"",
-                         string, "\": should be follows", (char*)NULL);
-        return TCL_ERROR;
-    }
-    int nbytes = 0;
-    if (Tcl_GetIntFromObj(interp, objv[6], &nbytes) != TCL_OK ||
-        nbytes < 0) {
-        return TCL_ERROR;
-    }
-    char *data = (char *)malloc(nbytes);
-    if (!SocketRead(data, nbytes)) {
-        free(data);
-        return TCL_ERROR;
-    }
-    if (objc == 8) {
-        const char *name = Tcl_GetString(objv[7]);
-        if (!g_renderer->setStreamlinesSeedToFilledMesh(name, data, nbytes,
-                                                        numPoints)) {
-            free(data);
-            Tcl_AppendResult(interp, "Couldn't read mesh data or streamlines not found", (char*)NULL);
-            return TCL_ERROR;
-        }
-    } else {
-        if (!g_renderer->setStreamlinesSeedToFilledMesh("all", data, nbytes,
-                                                        numPoints)) {
-            free(data);
-            Tcl_AppendResult(interp, "Couldn't read mesh data or streamlines not found", (char*)NULL);
-            return TCL_ERROR;
-        }
-    }
-    free(data);
-    return TCL_OK;
-}
-
-static int
-StreamlinesSeedMeshPointsOp(ClientData clientData, Tcl_Interp *interp,
-                            int objc, Tcl_Obj *const *objv)
-{
-    const char *string = Tcl_GetString(objv[3]);
-    char c = string[0];
-    if ((c != 'd') || (strcmp(string, "data") != 0)) {
-        Tcl_AppendResult(interp, "bad streamlines seed fmesh option \"",
-                         string, "\": should be data", (char*)NULL);
-        return TCL_ERROR;
-    }
-    string = Tcl_GetString(objv[4]);
-    c = string[0];
-    if ((c != 'f') || (strcmp(string, "follows") != 0)) {
-        Tcl_AppendResult(interp, "bad streamlines seed fmesh option \"",
-                         string, "\": should be follows", (char*)NULL);
-        return TCL_ERROR;
-    }
-    int nbytes = 0;
-    if (Tcl_GetIntFromObj(interp, objv[5], &nbytes) != TCL_OK ||
-        nbytes < 0) {
-        return TCL_ERROR;
-    }
-    char *data = (char *)malloc(nbytes);
-    if (!SocketRead(data, nbytes)) {
-        free(data);
-        return TCL_ERROR;
-    }
-    if (objc == 7) {
-        const char *name = Tcl_GetString(objv[6]);
-        if (!g_renderer->setStreamlinesSeedToMeshPoints(name, data, nbytes)) {
-            free(data);
-            Tcl_AppendResult(interp, "Couldn't read mesh data or streamlines not found", (char*)NULL);
-            return TCL_ERROR;
-        }
-    } else {
-        if (!g_renderer->setStreamlinesSeedToMeshPoints("all", data, nbytes)) {
-            free(data);
-            Tcl_AppendResult(interp, "Couldn't read mesh data or streamlines not found", (char*)NULL);
-            return TCL_ERROR;
-        }
-    }
-    free(data);
-    return TCL_OK;
-}
-
-static int
-StreamlinesSeedNumPointsOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                           Tcl_Obj *const *objv)
-{
-    int numPoints;
-    if (Tcl_GetIntFromObj(interp, objv[3], &numPoints) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 5) {
-        const char *name = Tcl_GetString(objv[4]);
-        g_renderer->setStreamlinesNumberOfSeedPoints(name, numPoints);
-    } else {
-        g_renderer->setStreamlinesNumberOfSeedPoints("all", numPoints);
-    }
-    return TCL_OK;
-}
-
-static int
-StreamlinesSeedPointsOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                        Tcl_Obj *const *objv)
-{
-    if (objc == 4) {
-        const char *name = Tcl_GetString(objv[3]);
-        g_renderer->setStreamlinesSeedToMeshPoints(name);
-    } else {
-        g_renderer->setStreamlinesSeedToMeshPoints("all");
-    }
-    return TCL_OK;
-}
-
-static int
-StreamlinesSeedPolygonOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                         Tcl_Obj *const *objv)
-{
-    double center[3], normal[3], angle, radius;
-    int numSides;
-    for (int i = 0; i < 3; i++) {
-        if (Tcl_GetDoubleFromObj(interp, objv[3+i], &center[i]) != TCL_OK) {
-            return TCL_ERROR;
-        }
-        if (Tcl_GetDoubleFromObj(interp, objv[6+i], &normal[i]) != TCL_OK) {
-            return TCL_ERROR;
-        }
-    }
-    if (Tcl_GetDoubleFromObj(interp, objv[9], &angle) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (Tcl_GetDoubleFromObj(interp, objv[10], &radius) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (Tcl_GetIntFromObj(interp, objv[11], &numSides) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (numSides < 3) {
-        Tcl_AppendResult(interp, "numSides must be 3 or greater", (char*)NULL);
-        return TCL_ERROR;
-    }
-    if (objc == 13) {
-        const char *name = Tcl_GetString(objv[12]);
-        g_renderer->setStreamlinesSeedToPolygon(name, center, normal, angle, radius, numSides);
-    } else {
-        g_renderer->setStreamlinesSeedToPolygon("all", center, normal, angle, radius, numSides);
-    }
-    return TCL_OK;
-}
-
-static int
-StreamlinesSeedFilledPolygonOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                               Tcl_Obj *const *objv)
-{
-    double center[3], normal[3], angle, radius;
-    int numSides, numPoints;
-    for (int i = 0; i < 3; i++) {
-        if (Tcl_GetDoubleFromObj(interp, objv[3+i], &center[i]) != TCL_OK) {
-            return TCL_ERROR;
-        }
-        if (Tcl_GetDoubleFromObj(interp, objv[6+i], &normal[i]) != TCL_OK) {
-            return TCL_ERROR;
-        }
-    }
-    if (Tcl_GetDoubleFromObj(interp, objv[9], &angle) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (Tcl_GetDoubleFromObj(interp, objv[10], &radius) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (Tcl_GetIntFromObj(interp, objv[11], &numSides) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (numSides < 3) {
-        Tcl_AppendResult(interp, "numSides must be 3 or greater", (char*)NULL);
-        return TCL_ERROR;
-    }
-    if (Tcl_GetIntFromObj(interp, objv[12], &numPoints) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 14) {
-        const char *name = Tcl_GetString(objv[13]);
-        g_renderer->setStreamlinesSeedToFilledPolygon(name, center, normal, angle,
-                                                      radius, numSides, numPoints);
-    } else {
-        g_renderer->setStreamlinesSeedToFilledPolygon("all", center, normal, angle,
-                                                      radius, numSides, numPoints);
-    }
-    return TCL_OK;
-}
-
-static int
-StreamlinesSeedRakeOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                      Tcl_Obj *const *objv)
-{
-    double start[3], end[3];
-    int numPoints;
-    for (int i = 0; i < 3; i++) {
-        if (Tcl_GetDoubleFromObj(interp, objv[3+i], &start[i]) != TCL_OK) {
-            return TCL_ERROR;
-        }
-        if (Tcl_GetDoubleFromObj(interp, objv[6+i], &end[i]) != TCL_OK) {
-            return TCL_ERROR;
-        }
-    }
-    if (Tcl_GetIntFromObj(interp, objv[9], &numPoints) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 11) {
-        const char *name = Tcl_GetString(objv[10]);
-        g_renderer->setStreamlinesSeedToRake(name, start, end, numPoints);
-    } else {
-        g_renderer->setStreamlinesSeedToRake("all", start, end, numPoints);
-    }
-    return TCL_OK;
-}
-
-static int
-StreamlinesSeedRandomOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                        Tcl_Obj *const *objv)
-{
-    int numPoints;
-    if (Tcl_GetIntFromObj(interp, objv[3], &numPoints) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 5) {
-        const char *name = Tcl_GetString(objv[4]);
-        g_renderer->setStreamlinesSeedToFilledMesh(name, numPoints);
-    } else {
-        g_renderer->setStreamlinesSeedToFilledMesh("all", numPoints);
-    }
-    return TCL_OK;
-}
-
-static int
-StreamlinesSeedVisibleOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                         Tcl_Obj *const *objv)
-{
-    bool state;
-    if (GetBooleanFromObj(interp, objv[3], &state) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 5) {
-        const char *name = Tcl_GetString(objv[4]);
-        g_renderer->setStreamlinesSeedVisibility(name, state);
-    } else {
-        g_renderer->setStreamlinesSeedVisibility("all", state);
-    }
-    return TCL_OK;
-}
-
-static Rappture::CmdSpec streamlinesSeedOps[] = {
-    {"color",   1, StreamlinesSeedColorOp,         6, 7, "r g b ?dataSetName?"},
-    {"disk",    1, StreamlinesSeedDiskOp,          12, 13, "centerX centerY centerZ normalX normalY normalZ radius innerRadius numPoints ?dataSetName?"},
-    {"fmesh",   2, StreamlinesSeedFilledMeshOp,    7, 8, "numPoints data follows nbytes ?dataSetName?"},
-    {"fpoly",   2, StreamlinesSeedFilledPolygonOp, 13, 14, "centerX centerY centerZ normalX normalY normalZ angle radius numSides numPoints ?dataSetName?"},
-    {"mesh",    1, StreamlinesSeedMeshPointsOp,    6, 7, "data follows nbytes ?dataSetName?"},
-    {"numpts",  1, StreamlinesSeedNumPointsOp,     4, 5, "numPoints ?dataSetName?"},
-    {"points",  3, StreamlinesSeedPointsOp,        3, 4, "?dataSetName?"},
-    {"polygon", 3, StreamlinesSeedPolygonOp,       12, 13, "centerX centerY centerZ normalX normalY normalZ angle radius numSides ?dataSetName?"},
-    {"rake",    3, StreamlinesSeedRakeOp,          10, 11, "startX startY startZ endX endY endZ numPoints ?dataSetName?"},
-    {"random",  3, StreamlinesSeedRandomOp,        4, 5, "numPoints ?dataSetName?"},
-    {"visible", 1, StreamlinesSeedVisibleOp,       4, 5, "bool ?dataSetName?"}
-};
-static int nStreamlinesSeedOps = NumCmdSpecs(streamlinesSeedOps);
-
-static int
-StreamlinesSeedOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                  Tcl_Obj *const *objv)
-{
-    Tcl_ObjCmdProc *proc;
-
-    proc = Rappture::GetOpFromObj(interp, nStreamlinesSeedOps, streamlinesSeedOps,
-                                  Rappture::CMDSPEC_ARG2, objc, objv, 0);
-    if (proc == NULL) {
-        return TCL_ERROR;
-    }
-    return (*proc) (clientData, interp, objc, objv);
-}
-
-static int
-StreamlinesTubesOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                   Tcl_Obj *const *objv)
-{
-    int numSides;
-    double radius;
-    if (Tcl_GetIntFromObj(interp, objv[2], &numSides) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (Tcl_GetDoubleFromObj(interp, objv[3], &radius) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 5) {
-        const char *name = Tcl_GetString(objv[4]);
-        g_renderer->setStreamlinesTypeToTubes(name, numSides, radius);
-    } else {
-        g_renderer->setStreamlinesTypeToTubes("all", numSides, radius);
-    }
-    return TCL_OK;
-}
-
-static int
-StreamlinesVisibleOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                     Tcl_Obj *const *objv)
-{
-    bool state;
-    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 4) {
-        const char *name = Tcl_GetString(objv[3]);
-        g_renderer->setGraphicsObjectVisibility<Streamlines>(name, state);
-    } else {
-        g_renderer->setGraphicsObjectVisibility<Streamlines>("all", state);
-    }
-    return TCL_OK;
-}
-
-static Rappture::CmdSpec streamlinesOps[] = {
-    {"add",          1, StreamlinesAddOp,            2, 3, "?dataSetName?"},
-    {"ccolor",       1, StreamlinesColorOp,          5, 6, "r g b ?dataSetName?"},
-    {"colormap",     7, StreamlinesColorMapOp,       3, 4, "colorMapName ?dataSetName?"},
-    {"colormode",    7, StreamlinesColorModeOp,      4, 5, "mode fieldName ?dataSetName?"},
-    {"delete",       1, StreamlinesDeleteOp,         2, 3, "?dataSetName?"},
-    {"edges",        1, StreamlinesEdgeVisibilityOp, 3, 4, "bool ?dataSetName?"},
-    {"length",       2, StreamlinesLengthOp,         3, 4, "length ?dataSetName?"},
-    {"lighting",     3, StreamlinesLightingOp,       3, 4, "bool ?dataSetName?"},
-    {"linecolor",    5, StreamlinesLineColorOp,      5, 6, "r g b ?dataSetName?"},
-    {"lines",        5, StreamlinesLinesOp,          2, 3, "?dataSetName?"},
-    {"linewidth",    5, StreamlinesLineWidthOp,      3, 4, "width ?dataSetName?"},
-    {"opacity",      2, StreamlinesOpacityOp,        3, 4, "val ?dataSetName?"},
-    {"orient",       2, StreamlinesOrientOp,         6, 7, "qw qx qy qz ?dataSetName?"},
-    {"pos",          1, StreamlinesPositionOp,       5, 6, "x y z ?dataSetName?"},
-    {"ribbons",      1, StreamlinesRibbonsOp,        4, 5, "width angle ?dataSetName?"},
-    {"scale",        2, StreamlinesScaleOp,          5, 6, "sx sy sz ?dataSetName?"},
-    {"seed",         2, StreamlinesSeedOp,           3, 14, "op params... ?dataSetName?"},
-    {"tubes",        1, StreamlinesTubesOp,          4, 5, "numSides radius ?dataSetName?"},
-    {"visible",      1, StreamlinesVisibleOp,        3, 4, "bool ?dataSetName?"}
-};
-static int nStreamlinesOps = NumCmdSpecs(streamlinesOps);
-
-static int
-StreamlinesCmd(ClientData clientData, Tcl_Interp *interp, int objc, 
-               Tcl_Obj *const *objv)
-{
-    Tcl_ObjCmdProc *proc;
-
-    proc = Rappture::GetOpFromObj(interp, nStreamlinesOps, streamlinesOps,
-                                  Rappture::CMDSPEC_ARG1, objc, objv, 0);
-    if (proc == NULL) {
-        return TCL_ERROR;
-    }
-    return (*proc) (clientData, interp, objc, objv);
-}
-
-static int
-VolumeAddOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-            Tcl_Obj *const *objv)
-{
-    if (objc == 3) {
-        const char *name = Tcl_GetString(objv[2]);
-        if (!g_renderer->addGraphicsObject<Volume>(name)) {
-            Tcl_AppendResult(interp, "Failed to create volume", (char*)NULL);
-            return TCL_ERROR;
-        }
-    } else {
-        if (!g_renderer->addGraphicsObject<Volume>("all")) {
-            Tcl_AppendResult(interp, "Failed to create volume for one or more data sets", (char*)NULL);
-            return TCL_ERROR;
-        }
-    }
-    return TCL_OK;
-}
-
-static int
-VolumeColorMapOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                 Tcl_Obj *const *objv)
-{
-    const char *colorMapName = Tcl_GetString(objv[2]);
-    if (objc == 4) {
-        const char *dataSetName = Tcl_GetString(objv[3]);
-        g_renderer->setGraphicsObjectColorMap<Volume>(dataSetName, colorMapName);
-    } else {
-        g_renderer->setGraphicsObjectColorMap<Volume>("all", colorMapName);
-    }
-    return TCL_OK;
-}
-
-static int
-VolumeDeleteOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-               Tcl_Obj *const *objv)
-{
-    if (objc == 3) {
-        const char *name = Tcl_GetString(objv[2]);
-        g_renderer->deleteGraphicsObject<Volume>(name);
-    } else {
-        g_renderer->deleteGraphicsObject<Volume>("all");
-    }
-    return TCL_OK;
-}
-
-static int
-VolumeLightingOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                 Tcl_Obj *const *objv)
-{
-    bool state;
-    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 4) {
-        const char *name = Tcl_GetString(objv[3]);
-        g_renderer->setGraphicsObjectLighting<Volume>(name, state);
-    } else {
-        g_renderer->setGraphicsObjectLighting<Volume>("all", state);
-    }
-    return TCL_OK;
-}
-
-static int
-VolumeOpacityOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                Tcl_Obj *const *objv)
-{
-    double opacity;
-    if (Tcl_GetDoubleFromObj(interp, objv[2], &opacity) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 4) {
-        const char *name = Tcl_GetString(objv[3]);
-        g_renderer->setGraphicsObjectOpacity<Volume>(name, opacity);
-    } else {
-        g_renderer->setGraphicsObjectOpacity<Volume>("all", opacity);
-    }
-    return TCL_OK;
-}
-
-static int
-VolumeOrientOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-               Tcl_Obj *const *objv)
-{
-    double quat[4];
-    if (Tcl_GetDoubleFromObj(interp, objv[2], &quat[0]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[3], &quat[1]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[4], &quat[2]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[5], &quat[3]) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 7) {
-        const char *name = Tcl_GetString(objv[6]);
-        g_renderer->setGraphicsObjectOrientation<Volume>(name, quat);
-    } else {
-        g_renderer->setGraphicsObjectOrientation<Volume>("all", quat);
-    }
-    return TCL_OK;
-}
-
-static int
-VolumePositionOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                 Tcl_Obj *const *objv)
-{
-    double pos[3];
-    if (Tcl_GetDoubleFromObj(interp, objv[2], &pos[0]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[3], &pos[1]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[4], &pos[2]) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 6) {
-        const char *name = Tcl_GetString(objv[5]);
-        g_renderer->setGraphicsObjectPosition<Volume>(name, pos);
-    } else {
-        g_renderer->setGraphicsObjectPosition<Volume>("all", pos);
-    }
-    return TCL_OK;
-}
-
-static int
-VolumeSampleRateOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                   Tcl_Obj *const *objv)
-{
-    double quality;
-    if (Tcl_GetDoubleFromObj(interp, objv[2], &quality) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (quality < 0.0 || quality > 1.0) {
-        Tcl_AppendResult(interp, "bad volume quality value \"",
-                         Tcl_GetString(objv[2]),
-                         "\": should be in the range [0,1]", (char*)NULL);
-        return TCL_ERROR;
-    }
-    double distance;
-    double maxFactor = 4.0;
-    if (quality >= 0.5) {
-        distance = 1.0 / ((quality - 0.5) * (maxFactor - 1.0) * 2.0 + 1.0);
-    } else {
-        distance = ((0.5 - quality) * (maxFactor - 1.0) * 2.0 + 1.0);
-    }
-    if (objc == 4) {
-        const char *name = Tcl_GetString(objv[3]);
-        g_renderer->setVolumeSampleDistance(name, distance);
-    } else {
-        g_renderer->setVolumeSampleDistance("all", distance);
-    }
-    return TCL_OK;
-}
-
-static int
-VolumeScaleOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-              Tcl_Obj *const *objv)
-{
-    double scale[3];
-    if (Tcl_GetDoubleFromObj(interp, objv[2], &scale[0]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[3], &scale[1]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[4], &scale[2]) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 6) {
-        const char *name = Tcl_GetString(objv[5]);
-        g_renderer->setGraphicsObjectScale<Volume>(name, scale);
-    } else {
-        g_renderer->setGraphicsObjectScale<Volume>("all", scale);
-    }
-    return TCL_OK;
-}
-
-static int
-VolumeShadingAmbientOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                       Tcl_Obj *const *objv)
-{
-    double coeff;
-    if (Tcl_GetDoubleFromObj(interp, objv[3], &coeff) != TCL_OK) {
-        return TCL_ERROR;
-    }
-
-    if (objc == 5) {
-        const char *name = Tcl_GetString(objv[4]);
-        g_renderer->setGraphicsObjectAmbient<Volume>(name, coeff);
-    } else {
-        g_renderer->setGraphicsObjectAmbient<Volume>("all", coeff);
-    }
-    return TCL_OK;
-}
-
-static int
-VolumeShadingDiffuseOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                       Tcl_Obj *const *objv)
-{
-    double coeff;
-    if (Tcl_GetDoubleFromObj(interp, objv[3], &coeff) != TCL_OK) {
-        return TCL_ERROR;
-    }
-
-    if (objc == 5) {
-        const char *name = Tcl_GetString(objv[4]);
-        g_renderer->setGraphicsObjectDiffuse<Volume>(name, coeff);
-    } else {
-        g_renderer->setGraphicsObjectDiffuse<Volume>("all", coeff);
-    }
-    return TCL_OK;
-}
-
-static int
-VolumeShadingSpecularOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                        Tcl_Obj *const *objv)
-{
-    double coeff, power;
-    if (Tcl_GetDoubleFromObj(interp, objv[3], &coeff) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[4], &power) != TCL_OK) {
-        return TCL_ERROR;
-    }
-
-    if (objc == 6) {
-        const char *name = Tcl_GetString(objv[5]);
-        g_renderer->setGraphicsObjectSpecular<Volume>(name, coeff, power);
-    } else {
-        g_renderer->setGraphicsObjectSpecular<Volume>("all", coeff, power);
-    }
-    return TCL_OK;
-}
-
-static Rappture::CmdSpec volumeShadingOps[] = {
-    {"ambient",  1, VolumeShadingAmbientOp,  4, 5, "coeff ?dataSetName?"},
-    {"diffuse",  1, VolumeShadingDiffuseOp,  4, 5, "coeff ?dataSetName?"},
-    {"specular", 1, VolumeShadingSpecularOp, 5, 6, "coeff power ?dataSetName?"}
-};
-static int nVolumeShadingOps = NumCmdSpecs(volumeShadingOps);
-
-static int
-VolumeShadingOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                Tcl_Obj *const *objv)
-{
-    Tcl_ObjCmdProc *proc;
-
-    proc = Rappture::GetOpFromObj(interp, nVolumeShadingOps, volumeShadingOps,
-                                  Rappture::CMDSPEC_ARG2, objc, objv, 0);
-    if (proc == NULL) {
-        return TCL_ERROR;
-    }
-    return (*proc) (clientData, interp, objc, objv);
-}
-
-static int
-VolumeVisibleOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                Tcl_Obj *const *objv)
-{
-    bool state;
-    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 4) {
-        const char *name = Tcl_GetString(objv[3]);
-        g_renderer->setGraphicsObjectVisibility<Volume>(name, state);
-    } else {
-        g_renderer->setGraphicsObjectVisibility<Volume>("all", state);
-    }
-    return TCL_OK;
-}
-
-static Rappture::CmdSpec volumeOps[] = {
-    {"add",          1, VolumeAddOp,        2, 3, "?dataSetName?"},
-    {"colormap",     1, VolumeColorMapOp,   3, 4, "colorMapName ?dataSetName?"},
-    {"delete",       1, VolumeDeleteOp,     2, 3, "?dataSetName?"},
-    {"lighting",     1, VolumeLightingOp,   3, 4, "bool ?dataSetName?"},
-    {"opacity",      2, VolumeOpacityOp,    3, 4, "val ?dataSetName?"},
-    {"orient",       2, VolumeOrientOp,     6, 7, "qw qx qy qz ?dataSetName?"},
-    {"pos",          1, VolumePositionOp,   5, 6, "x y z ?dataSetName?"},
-    {"quality",      1, VolumeSampleRateOp, 3, 4, "val ?dataSetName?"},
-    {"scale",        2, VolumeScaleOp,      5, 6, "sx sy sz ?dataSetName?"},
-    {"shading",      2, VolumeShadingOp,    4, 6, "oper val ?dataSetName?"},
-    {"visible",      1, VolumeVisibleOp,    3, 4, "bool ?dataSetName?"}
-};
-static int nVolumeOps = NumCmdSpecs(volumeOps);
-
-static int
-VolumeCmd(ClientData clientData, Tcl_Interp *interp, int objc, 
-          Tcl_Obj *const *objv)
-{
-    Tcl_ObjCmdProc *proc;
-
-    proc = Rappture::GetOpFromObj(interp, nVolumeOps, volumeOps,
-                                  Rappture::CMDSPEC_ARG1, objc, objv, 0);
-    if (proc == NULL) {
-        return TCL_ERROR;
-    }
-    return (*proc) (clientData, interp, objc, objv);
-}
-
-static int
-WarpAddOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-          Tcl_Obj *const *objv)
-{
-    if (objc == 3) {
-        const char *name = Tcl_GetString(objv[2]);
-        if (!g_renderer->addGraphicsObject<Warp>(name)) {
-            Tcl_AppendResult(interp, "Failed to create warp", (char*)NULL);
-            return TCL_ERROR;
-        }
-    } else {
-        if (!g_renderer->addGraphicsObject<Warp>("all")) {
-            Tcl_AppendResult(interp, "Failed to create warp for one or more data sets", (char*)NULL);
-            return TCL_ERROR;
-        }
-    }
-    return TCL_OK;
-}
-
-static int
-WarpColorOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-            Tcl_Obj *const *objv)
-{
-    float color[3];
-    if (GetFloatFromObj(interp, objv[2], &color[0]) != TCL_OK ||
-        GetFloatFromObj(interp, objv[3], &color[1]) != TCL_OK ||
-        GetFloatFromObj(interp, objv[4], &color[2]) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 6) {
-        const char *name = Tcl_GetString(objv[5]);
-        g_renderer->setGraphicsObjectColor<Warp>(name, color);
-    } else {
-        g_renderer->setGraphicsObjectColor<Warp>("all", color);
-    }
-    return TCL_OK;
-}
-
-static int
-WarpColorMapOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-               Tcl_Obj *const *objv)
-{
-    const char *colorMapName = Tcl_GetString(objv[2]);
-    if (objc == 4) {
-        const char *dataSetName = Tcl_GetString(objv[3]);
-        g_renderer->setGraphicsObjectColorMap<Warp>(dataSetName, colorMapName);
-    } else {
-        g_renderer->setGraphicsObjectColorMap<Warp>("all", colorMapName);
-    }
-    return TCL_OK;
-}
-
-static int
-WarpColorModeOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                Tcl_Obj *const *objv)
-{
-    Warp::ColorMode mode;
-    const char *str = Tcl_GetString(objv[2]);
-    if (str[0] == 'c' && strcmp(str, "ccolor") == 0) {
-        mode = Warp::COLOR_CONSTANT;
-    } else if (str[0] == 's' && strcmp(str, "scalar") == 0) {
-        mode = Warp::COLOR_BY_SCALAR;
-    } else if (str[0] == 'v' && strcmp(str, "vmag") == 0) {
-        mode = Warp::COLOR_BY_VECTOR_MAGNITUDE;
-    } else if (str[0] == 'v' && strcmp(str, "vx") == 0) {
-        mode = Warp::COLOR_BY_VECTOR_X;
-    } else if (str[0] == 'v' && strcmp(str, "vy") == 0) {
-        mode = Warp::COLOR_BY_VECTOR_Y;
-    } else if (str[0] == 'v' && strcmp(str, "vz") == 0) {
-        mode = Warp::COLOR_BY_VECTOR_Z;
-    } else {
-        Tcl_AppendResult(interp, "bad color mode option \"", str,
-                         "\": should be one of: 'scalar', 'vmag', 'vx', 'vy', 'vz', 'ccolor'", (char*)NULL);
-        return TCL_ERROR;
-    }
-    const char *fieldName = Tcl_GetString(objv[3]);
-    if (mode == Warp::COLOR_CONSTANT) {
-        fieldName = NULL;
-    }
-    if (objc == 5) {
-        const char *name = Tcl_GetString(objv[4]);
-        g_renderer->setWarpColorMode(name, mode, fieldName);
-    } else {
-        g_renderer->setWarpColorMode("all", mode, fieldName);
-    }
-    return TCL_OK;
-}
-
-static int
-WarpDeleteOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-             Tcl_Obj *const *objv)
-{
-    if (objc == 3) {
-        const char *name = Tcl_GetString(objv[2]);
-        g_renderer->deleteGraphicsObject<Warp>(name);
-    } else {
-        g_renderer->deleteGraphicsObject<Warp>("all");
-    }
-    return TCL_OK;
-}
-
-static int
-WarpEdgeVisibilityOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                     Tcl_Obj *const *objv)
-{
-    bool state;
-    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 4) {
-        const char *name = Tcl_GetString(objv[3]);
-        g_renderer->setGraphicsObjectEdgeVisibility<Warp>(name, state);
-    } else {
-        g_renderer->setGraphicsObjectEdgeVisibility<Warp>("all", state);
-    }
-    return TCL_OK;
-}
-
-static int
-WarpLightingOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-               Tcl_Obj *const *objv)
-{
-    bool state;
-    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 4) {
-        const char *name = Tcl_GetString(objv[3]);
-        g_renderer->setGraphicsObjectLighting<Warp>(name, state);
-    } else {
-        g_renderer->setGraphicsObjectLighting<Warp>("all", state);
-    }
-    return TCL_OK;
-}
-
-static int
-WarpLineColorOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                Tcl_Obj *const *objv)
-{
-    float color[3];
-    if (GetFloatFromObj(interp, objv[2], &color[0]) != TCL_OK ||
-        GetFloatFromObj(interp, objv[3], &color[1]) != TCL_OK ||
-        GetFloatFromObj(interp, objv[4], &color[2]) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 6) {
-        const char *name = Tcl_GetString(objv[5]);
-        g_renderer->setGraphicsObjectEdgeColor<Warp>(name, color);
-    } else {
-        g_renderer->setGraphicsObjectEdgeColor<Warp>("all", color);
-    }
-    return TCL_OK;
-}
-
-static int
-WarpLineWidthOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                Tcl_Obj *const *objv)
-{
-    float width;
-    if (GetFloatFromObj(interp, objv[2], &width) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 4) {
-        const char *name = Tcl_GetString(objv[3]);
-        g_renderer->setGraphicsObjectEdgeWidth<Warp>(name, width);
-    } else {
-        g_renderer->setGraphicsObjectEdgeWidth<Warp>("all", width);
-    }
-    return TCL_OK;
-}
-
-static int
-WarpOpacityOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                   Tcl_Obj *const *objv)
-{
-    double opacity;
-    if (Tcl_GetDoubleFromObj(interp, objv[2], &opacity) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 4) {
-        const char *name = Tcl_GetString(objv[3]);
-        g_renderer->setGraphicsObjectOpacity<Warp>(name, opacity);
-    } else {
-        g_renderer->setGraphicsObjectOpacity<Warp>("all", opacity);
-    }
-    return TCL_OK;
-}
-
-static int
-WarpOrientOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-             Tcl_Obj *const *objv)
-{
-    double quat[4];
-    if (Tcl_GetDoubleFromObj(interp, objv[2], &quat[0]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[3], &quat[1]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[4], &quat[2]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[5], &quat[3]) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 7) {
-        const char *name = Tcl_GetString(objv[6]);
-        g_renderer->setGraphicsObjectOrientation<Warp>(name, quat);
-    } else {
-        g_renderer->setGraphicsObjectOrientation<Warp>("all", quat);
-    }
-    return TCL_OK;
-}
-
-static int
-WarpPositionOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-               Tcl_Obj *const *objv)
-{
-    double pos[3];
-    if (Tcl_GetDoubleFromObj(interp, objv[2], &pos[0]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[3], &pos[1]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[4], &pos[2]) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 6) {
-        const char *name = Tcl_GetString(objv[5]);
-        g_renderer->setGraphicsObjectPosition<Warp>(name, pos);
-    } else {
-        g_renderer->setGraphicsObjectPosition<Warp>("all", pos);
-    }
-    return TCL_OK;
-}
-
-static int
-WarpPreInterpOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                Tcl_Obj *const *objv)
-{
-    bool state;
-    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 4) {
-        const char *name = Tcl_GetString(objv[3]);
-        g_renderer->setGraphicsObjectInterpolateBeforeMapping<Warp>(name, state);
-    } else {
-        g_renderer->setGraphicsObjectInterpolateBeforeMapping<Warp>("all", state);
-    }
-    return TCL_OK;
-}
-
-static int
-WarpScaleOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-            Tcl_Obj *const *objv)
-{
-    double scale[3];
-    if (Tcl_GetDoubleFromObj(interp, objv[2], &scale[0]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[3], &scale[1]) != TCL_OK ||
-        Tcl_GetDoubleFromObj(interp, objv[4], &scale[2]) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 6) {
-        const char *name = Tcl_GetString(objv[5]);
-        g_renderer->setGraphicsObjectScale<Warp>(name, scale);
-    } else {
-        g_renderer->setGraphicsObjectScale<Warp>("all", scale);
-    }
-    return TCL_OK;
-}
-
-static int
-WarpVisibleOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-              Tcl_Obj *const *objv)
-{
-    bool state;
-    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 4) {
-        const char *name = Tcl_GetString(objv[3]);
-        g_renderer->setGraphicsObjectVisibility<Warp>(name, state);
-    } else {
-        g_renderer->setGraphicsObjectVisibility<Warp>("all", state);
-    }
-    return TCL_OK;
-}
-
-static int
-WarpWarpScaleOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                Tcl_Obj *const *objv)
-{
-    double scale;
-    if (Tcl_GetDoubleFromObj(interp, objv[2], &scale) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 4) {
-        const char *name = Tcl_GetString(objv[3]);
-        g_renderer->setWarpWarpScale(name, scale);
-    } else {
-        g_renderer->setWarpWarpScale("all", scale);
-    }
-    return TCL_OK;
-}
-
-static int
-WarpWireframeOp(ClientData clientData, Tcl_Interp *interp, int objc, 
-                Tcl_Obj *const *objv)
-{
-    bool state;
-    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
-        return TCL_ERROR;
-    }
-    if (objc == 4) {
-        const char *name = Tcl_GetString(objv[3]);
-        g_renderer->setGraphicsObjectWireframe<Warp>(name, state);
-    } else {
-        g_renderer->setGraphicsObjectWireframe<Warp>("all", state);
-    }
-    return TCL_OK;
-}
-
-static Rappture::CmdSpec warpOps[] = {
-    {"add",          1, WarpAddOp, 2, 3, "?dataSetName?"},
-    {"ccolor",       2, WarpColorOp, 5, 6, "r g b ?dataSetName?"},
-    {"colormap",     7, WarpColorMapOp, 3, 4, "colorMapName ?dataSetName?"},
-    {"colormode",    7, WarpColorModeOp, 4, 5, "mode fieldName ?dataSetName?"},
-    {"delete",       1, WarpDeleteOp, 2, 3, "?dataSetName?"},
-    {"edges",        1, WarpEdgeVisibilityOp, 3, 4, "bool ?dataSetName?"},
-    {"lighting",     3, WarpLightingOp, 3, 4, "bool ?dataSetName?"},
-    {"linecolor",    5, WarpLineColorOp, 5, 6, "r g b ?dataSetName?"},
-    {"linewidth",    5, WarpLineWidthOp, 3, 4, "width ?dataSetName?"},
-    {"opacity",      2, WarpOpacityOp, 3, 4, "value ?dataSetName?"},
-    {"orient",       2, WarpOrientOp, 6, 7, "qw qx qy qz ?dataSetName?"},
-    {"pos",          2, WarpPositionOp, 5, 6, "x y z ?dataSetName?"},
-    {"preinterp",    2, WarpPreInterpOp, 3, 4, "bool ?dataSetName?"},
-    {"scale",        2, WarpScaleOp, 5, 6, "sx sy sz ?dataSetName?"},
-    {"visible",      1, WarpVisibleOp, 3, 4, "bool ?dataSetName?"},
-    {"warpscale",    2, WarpWarpScaleOp, 3, 4, "value ?dataSetName?"},
-    {"wireframe",    2, WarpWireframeOp, 3, 4, "bool ?dataSetName?"}
-};
-static int nWarpOps = NumCmdSpecs(warpOps);
-
-static int
-WarpCmd(ClientData clientData, Tcl_Interp *interp, int objc, 
-             Tcl_Obj *const *objv)
-{
-    Tcl_ObjCmdProc *proc;
-
-    proc = Rappture::GetOpFromObj(interp, nWarpOps, warpOps,
-                                  Rappture::CMDSPEC_ARG1, objc, objv, 0);
-    if (proc == NULL) {
-        return TCL_ERROR;
-    }
-    return (*proc) (clientData, interp, objc, objv);
-}
-
-/**
- * \brief Execute commands from client in Tcl interpreter
- * 
- * In this threaded model, the select call is for event compression.  We
- * want to execute render server commands as long as they keep coming.  
- * This lets us execute a stream of many commands but render once.  This 
- * benefits camera movements, screen resizing, and opacity changes 
- * (using a slider on the client).  The down side is you don't render
- * until there's a lull in the command stream.  If the client needs an
- * image, it can issue an "imgflush" command.  That breaks us out of the
- * read loop.
- */
-int
-VtkVis::processCommands(Tcl_Interp *interp,
-                        ClientData clientData,
-                        ReadBuffer *inBufPtr, 
-                        int fdOut)
-{
-    int ret = 1;
-    int status = TCL_OK;
-
-    Tcl_DString command;
-    Tcl_DStringInit(&command);
-    fd_set readFds;
-    struct timeval tv, *tvPtr;
-
-    FD_ZERO(&readFds);
-    FD_SET(inBufPtr->file(), &readFds);
-    tvPtr = NULL;                       /* Wait for the first read. This is so
-                                         * that we don't spin when no data is
-                                         * available. */
-    while (inBufPtr->isLineAvailable() || 
-           (select(1, &readFds, NULL, NULL, tvPtr) > 0)) {
-        size_t numBytes;
-        unsigned char *buffer;
-
-        /* A short read is treated as an error here because we assume that we
-         * will always get commands line by line. */
-        if (inBufPtr->getLine(&numBytes, &buffer) != ReadBuffer::OK) {
-            /* Terminate the server if we can't communicate with the client
-             * anymore. */
-            if (inBufPtr->status() == ReadBuffer::ENDFILE) {
-                TRACE("Exiting server on EOF from client");
-                return -1;
-            } else {
-                ERROR("Exiting server, failed to read from client: %s",
-                      strerror(errno));
-                return -1;
-            }
-        }
-        Tcl_DStringAppend(&command, (char *)buffer, numBytes);
-        if (Tcl_CommandComplete(Tcl_DStringValue(&command))) {
-            struct timeval start, finish;
-            gettimeofday(&start, NULL);
-            status = ExecuteCommand(interp, &command);
-            gettimeofday(&finish, NULL);
-            g_stats.cmdTime += (MSECS_ELAPSED(start, finish) / 1.0e+3);
-            g_stats.nCommands++;
-            if (status == TCL_BREAK) {
-                return 1;               /* This was caused by a "imgflush"
-                                         * command. Break out of the read loop
-                                         * and allow a new image to be
-                                         * rendered. */
-            } else { //if (status != TCL_OK) {
-                ret = 0;
-                if (handleError(interp, clientData, status, fdOut) < 0) {
-                    return -1;
-                }
-            }
-        }
-
-        tv.tv_sec = tv.tv_usec = 0L;    /* On successive reads, we break out
-                                         * if no data is available. */
-        FD_SET(inBufPtr->file(), &readFds);
-        tvPtr = &tv;
-    }
-
-    return ret;
-}
-
-/**
- * \brief Send error message to client socket
- */
-int
-VtkVis::handleError(Tcl_Interp *interp,
-                    ClientData clientData,
-                    int status, int fdOut)
-{
-    const char *string;
-    int nBytes;
-
-    if (status != TCL_OK) {
-        string = Tcl_GetVar(interp, "errorInfo", TCL_GLOBAL_ONLY);
-        nBytes = strlen(string);
-        if (nBytes > 0) {
-            TRACE("status=%d errorInfo=(%s)", status, string);
-
-            std::ostringstream oss;
-            oss << "nv>viserror -type internal_error -token " << g_stats.nCommands << " -bytes " << nBytes << "\n" << string;
-            nBytes = oss.str().length();
-
-#ifdef USE_THREADS
-            queueResponse(clientData, oss.str().c_str(), nBytes, Response::VOLATILE, Response::ERROR);
-#else
-            if (write(fdOut, oss.str().c_str(), nBytes) < 0) {
-                ERROR("write failed: %s", strerror(errno));
-                return -1;
-            }
-#endif
-        }
-    }
-
-    string = getUserMessages();
-    nBytes = strlen(string);
-    if (nBytes > 0) {
-        TRACE("userError=(%s)", string);
-
-        std::ostringstream oss;
-        oss << "nv>viserror -type error -token " << g_stats.nCommands << " -bytes " << nBytes << "\n" << string;
-        nBytes = oss.str().length();
-
-#ifdef USE_THREADS
-        queueResponse(clientData, oss.str().c_str(), nBytes, Response::VOLATILE, Response::ERROR);
-#else
-        if (write(fdOut, oss.str().c_str(), nBytes) < 0) {
-            ERROR("write failed: %s", strerror(errno));
-            return -1;
-        }
-#endif
-        clearUserMessages();
-    }
-
-    return 0;
-}
-
-/**
- * \brief Create Tcl interpreter and add commands
- *
- * \return The initialized Tcl interpreter
- */
-void
-VtkVis::initTcl(Tcl_Interp *interp, ClientData clientData)
-{
-    Tcl_MakeSafe(interp);
-    Tcl_CreateObjCommand(interp, "arc",         ArcCmd,         clientData, NULL);
-    Tcl_CreateObjCommand(interp, "arrow",       ArrowCmd,       clientData, NULL);
-    Tcl_CreateObjCommand(interp, "axis",        AxisCmd,        clientData, NULL);
-    Tcl_CreateObjCommand(interp, "box",         BoxCmd,         clientData, NULL);
-    Tcl_CreateObjCommand(interp, "camera",      CameraCmd,      clientData, NULL);
-    Tcl_CreateObjCommand(interp, "clientinfo",  ClientInfoCmd,  clientData, NULL);
-    Tcl_CreateObjCommand(interp, "colormap",    ColorMapCmd,    clientData, NULL);
-    Tcl_CreateObjCommand(interp, "cone",        ConeCmd,        clientData, NULL);
-    Tcl_CreateObjCommand(interp, "contour2d",   Contour2DCmd,   clientData, NULL);
-    Tcl_CreateObjCommand(interp, "contour3d",   Contour3DCmd,   clientData, NULL);
-    Tcl_CreateObjCommand(interp, "cutplane",    CutplaneCmd,    clientData, NULL);
-    Tcl_CreateObjCommand(interp, "cylinder",    CylinderCmd,    clientData, NULL);
-    Tcl_CreateObjCommand(interp, "dataset",     DataSetCmd,     clientData, NULL);
-    Tcl_CreateObjCommand(interp, "disk",        DiskCmd,        clientData, NULL);
-    Tcl_CreateObjCommand(interp, "glyphs",      GlyphsCmd,      clientData, NULL);
-    Tcl_CreateObjCommand(interp, "heightmap",   HeightMapCmd,   clientData, NULL);
-    Tcl_CreateObjCommand(interp, "imgflush",    ImageFlushCmd,  clientData, NULL);
-    Tcl_CreateObjCommand(interp, "legend",      LegendCmd,      clientData, NULL);
-    Tcl_CreateObjCommand(interp, "lic",         LICCmd,         clientData, NULL);
-    Tcl_CreateObjCommand(interp, "line",        LineCmd,        clientData, NULL);
-    Tcl_CreateObjCommand(interp, "molecule",    MoleculeCmd,    clientData, NULL);
-    Tcl_CreateObjCommand(interp, "outline",     OutlineCmd,     clientData, NULL);
-    Tcl_CreateObjCommand(interp, "polydata",    PolyDataCmd,    clientData, NULL);
-    Tcl_CreateObjCommand(interp, "polygon",     PolygonCmd,     clientData, NULL);
-    Tcl_CreateObjCommand(interp, "pseudocolor", PseudoColorCmd, clientData, NULL);
-    Tcl_CreateObjCommand(interp, "renderer",    RendererCmd,    clientData, NULL);
-    Tcl_CreateObjCommand(interp, "screen",      ScreenCmd,      clientData, NULL);
-    Tcl_CreateObjCommand(interp, "sphere",      SphereCmd,      clientData, NULL);
-    Tcl_CreateObjCommand(interp, "streamlines", StreamlinesCmd, clientData, NULL);
-    Tcl_CreateObjCommand(interp, "volume",      VolumeCmd,      clientData, NULL);
-    Tcl_CreateObjCommand(interp, "warp",        WarpCmd,        clientData, NULL);
-}
-
-/**
- * \brief Delete Tcl commands and interpreter
- */
-void VtkVis::exitTcl(Tcl_Interp *interp)
-{
-    Tcl_DeleteCommand(interp, "arc");
-    Tcl_DeleteCommand(interp, "arrow");
-    Tcl_DeleteCommand(interp, "axis");
-    Tcl_DeleteCommand(interp, "box");
-    Tcl_DeleteCommand(interp, "camera");
-    Tcl_DeleteCommand(interp, "clientinfo");
-    Tcl_DeleteCommand(interp, "colormap");
-    Tcl_DeleteCommand(interp, "cone");
-    Tcl_DeleteCommand(interp, "contour2d");
-    Tcl_DeleteCommand(interp, "contour3d");
-    Tcl_DeleteCommand(interp, "cutplane");
-    Tcl_DeleteCommand(interp, "cylinder");
-    Tcl_DeleteCommand(interp, "dataset");
-    Tcl_DeleteCommand(interp, "disk");
-    Tcl_DeleteCommand(interp, "glyphs");
-    Tcl_DeleteCommand(interp, "heightmap");
-    Tcl_DeleteCommand(interp, "imgflush");
-    Tcl_DeleteCommand(interp, "legend");
-    Tcl_DeleteCommand(interp, "lic");
-    Tcl_DeleteCommand(interp, "line");
-    Tcl_DeleteCommand(interp, "molecule");
-    Tcl_DeleteCommand(interp, "outline");
-    Tcl_DeleteCommand(interp, "polydata");
-    Tcl_DeleteCommand(interp, "polygon");
-    Tcl_DeleteCommand(interp, "pseudocolor");
-    Tcl_DeleteCommand(interp, "renderer");
-    Tcl_DeleteCommand(interp, "screen");
-    Tcl_DeleteCommand(interp, "sphere");
-    Tcl_DeleteCommand(interp, "streamlines");
-    Tcl_DeleteCommand(interp, "volume");
-    Tcl_DeleteCommand(interp, "warp");
-
-    Tcl_DeleteInterp(interp);
-}
Index: unk/packages/vizservers/vtkvis/RpVtkRendererCmd.h
===================================================================
--- /trunk/packages/vizservers/vtkvis/RpVtkRendererCmd.h	(revision 3615)
+++ 	(revision )
@@ -1,44 +1,0 @@
-/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
-/*
- * Copyright (C) 2004-2012  HUBzero Foundation, LLC
- *
- * Author: Leif Delgass <ldelgass@purdue.edu>
- */
-
-#ifndef VTKVIS_RENDERERCMD_H
-#define VTKVIS_RENDERERCMD_H
-
-#include <cstdio>
-#include <tcl.h>
-
-#include "ReadBuffer.h"
-#ifdef USE_THREADS
-#include "ResponseQueue.h"
-#endif
-
-namespace VtkVis {
-
-#ifdef USE_THREADS
-extern void queueResponse(ClientData clientData, const void *bytes, size_t len, 
-                          Response::AllocationType allocType,
-                          Response::ResponseType type = Response::DATA);
-#endif
-
-extern int processCommands(Tcl_Interp *interp,
-                           ClientData clientData,
-                           ReadBuffer *inBufPtr,
-                           int fdOut);
-
-extern int handleError(Tcl_Interp *interp,
-                       ClientData clientData,
-                       int status,
-                       int fdOut);
-
-extern void initTcl(Tcl_Interp *interp,
-                    ClientData clientData);
-
-extern void exitTcl(Tcl_Interp *interp);
-
-}
-
-#endif
Index: unk/packages/vizservers/vtkvis/RpVtkRendererGraphicsObjs.cpp
===================================================================
--- /trunk/packages/vizservers/vtkvis/RpVtkRendererGraphicsObjs.cpp	(revision 3615)
+++ 	(revision )
@@ -1,3057 +1,0 @@
-/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
-/*
- * Copyright (C) 2004-2012  HUBzero Foundation, LLC
- *
- * Author: Leif Delgass <ldelgass@purdue.edu>
- */
-
-#include <cstring>
-#include <typeinfo>
-
-#include <vtkVersion.h>
-#include <vtkSmartPointer.h>
-#include <vtkDataSet.h>
-#include <vtkCharArray.h>
-#include <vtkDataSetReader.h>
-
-#include "RpVtkRendererGraphicsObjs.h"
-#include "RpVtkRenderer.h"
-#include "RpVtkDataSet.h"
-#include "RpBox.h"
-#include "RpContour2D.h"
-#include "RpContour3D.h"
-#include "RpCutplane.h"
-#include "RpGlyphs.h"
-#include "RpHeightMap.h"
-#include "RpLIC.h"
-#include "RpLine.h"
-#include "RpMolecule.h"
-#include "RpPolyData.h"
-#include "RpPseudoColor.h"
-#include "RpSphere.h"
-#include "RpStreamlines.h"
-#include "RpVolume.h"
-#include "ColorMap.h"
-#include "Trace.h"
-
-// Template specializations
-namespace VtkVis {
-
-template<>
-Renderer::ArcHashmap &
-Renderer::getGraphicsObjectHashmap<Arc>()
-{ return _arcs; }
-
-template<>
-Renderer::ArrowHashmap &
-Renderer::getGraphicsObjectHashmap<Arrow>()
-{ return _arrows; }
-
-template<>
-Renderer::BoxHashmap &
-Renderer::getGraphicsObjectHashmap<Box>()
-{ return _boxes; }
-
-template<>
-Renderer::ConeHashmap &
-Renderer::getGraphicsObjectHashmap<Cone>()
-{ return _cones; }
-
-template<>
-Renderer::Contour2DHashmap &
-Renderer::getGraphicsObjectHashmap<Contour2D>()
-{ return _contour2Ds; }
-
-template<>
-Renderer::Contour3DHashmap &
-Renderer::getGraphicsObjectHashmap<Contour3D>()
-{ return _contour3Ds; }
-
-template<>
-Renderer::CutplaneHashmap &
-Renderer::getGraphicsObjectHashmap<Cutplane>()
-{ return _cutplanes; }
-
-template<>
-Renderer::CylinderHashmap &
-Renderer::getGraphicsObjectHashmap<Cylinder>()
-{ return _cylinders; }
-
-template<>
-Renderer::DiskHashmap &
-Renderer::getGraphicsObjectHashmap<Disk>()
-{ return _disks; }
-
-template<>
-Renderer::GlyphsHashmap &
-Renderer::getGraphicsObjectHashmap<Glyphs>()
-{ return _glyphs; }
-
-template<>
-Renderer::GroupHashmap &
-Renderer::getGraphicsObjectHashmap<Group>()
-{ return _groups; }
-
-template<>
-Renderer::HeightMapHashmap &
-Renderer::getGraphicsObjectHashmap<HeightMap>()
-{ return _heightMaps; }
-
-template<>
-Renderer::LICHashmap &
-Renderer::getGraphicsObjectHashmap<LIC>()
-{ return _lics; }
-
-template<>
-Renderer::LineHashmap &
-Renderer::getGraphicsObjectHashmap<Line>()
-{ return _lines; }
-
-template<>
-Renderer::MoleculeHashmap &
-Renderer::getGraphicsObjectHashmap<Molecule>()
-{ return _molecules; }
-
-template<>
-Renderer::OutlineHashmap &
-Renderer::getGraphicsObjectHashmap<Outline>()
-{ return _outlines; }
-
-template<>
-Renderer::PolyDataHashmap &
-Renderer::getGraphicsObjectHashmap<PolyData>()
-{ return _polyDatas; }
-
-template<>
-Renderer::PolygonHashmap &
-Renderer::getGraphicsObjectHashmap<Polygon>()
-{ return _polygons; }
-
-template<>
-Renderer::PseudoColorHashmap &
-Renderer::getGraphicsObjectHashmap<PseudoColor>()
-{ return _pseudoColors; }
-
-template<>
-Renderer::SphereHashmap &
-Renderer::getGraphicsObjectHashmap<Sphere>()
-{ return _spheres; }
-
-template<>
-Renderer::StreamlinesHashmap &
-Renderer::getGraphicsObjectHashmap<Streamlines>()
-{ return _streamlines; }
-
-template<>
-Renderer::VolumeHashmap &
-Renderer::getGraphicsObjectHashmap<Volume>()
-{ return _volumes; }
-
-template<>
-Renderer::WarpHashmap &
-Renderer::getGraphicsObjectHashmap<Warp>()
-{ return _warps; }
-
-template Arc *Renderer::getGraphicsObject(const DataSetId&);
-template Arrow *Renderer::getGraphicsObject(const DataSetId&);
-template Box *Renderer::getGraphicsObject(const DataSetId&);
-template Cone *Renderer::getGraphicsObject(const DataSetId&);
-template Cylinder *Renderer::getGraphicsObject(const DataSetId&);
-template Disk *Renderer::getGraphicsObject(const DataSetId&);
-template Group *Renderer::getGraphicsObject(const DataSetId&);
-template Line *Renderer::getGraphicsObject(const DataSetId&);
-template Polygon *Renderer::getGraphicsObject(const DataSetId&);
-template Sphere *Renderer::getGraphicsObject(const DataSetId&);
-
-template <>
-bool Renderer::addGraphicsObject<Box>(const DataSetId& id)
-{
-    Box *gobj;
-    if ((gobj = getGraphicsObject<Box>(id)) != NULL) {
-        WARN("Replacing existing %s %s", gobj->getClassName(), id.c_str());
-        deleteGraphicsObject<Box>(id);
-    }
-
-    gobj = new Box();
- 
-    gobj->setDataSet(NULL, this);
-
-    if (gobj->getProp() == NULL &&
-        gobj->getOverlayProp() == NULL) {
-        delete gobj;
-        return false;
-    } else {
-        if (gobj->getProp())
-            _renderer->AddViewProp(gobj->getProp());
-        if (gobj->getOverlayProp())
-            _renderer->AddViewProp(gobj->getOverlayProp());
-    }
-
-    getGraphicsObjectHashmap<Box>()[id] = gobj;
-
-    sceneBoundsChanged();
-    _needsRedraw = true;
-    return true;
-}
-
-template <>
-bool Renderer::addGraphicsObject<Sphere>(const DataSetId& id)
-{
-    Sphere *gobj;
-    if ((gobj = getGraphicsObject<Sphere>(id)) != NULL) {
-        WARN("Replacing existing %s %s", gobj->getClassName(), id.c_str());
-        deleteGraphicsObject<Sphere>(id);
-    }
-
-    gobj = new Sphere();
- 
-    gobj->setDataSet(NULL, this);
-
-    if (gobj->getProp() == NULL &&
-        gobj->getOverlayProp() == NULL) {
-        delete gobj;
-        return false;
-    } else {
-        if (gobj->getProp())
-            _renderer->AddViewProp(gobj->getProp());
-        if (gobj->getOverlayProp())
-            _renderer->AddViewProp(gobj->getOverlayProp());
-    }
-
-    getGraphicsObjectHashmap<Sphere>()[id] = gobj;
-
-    sceneBoundsChanged();
-    _needsRedraw = true;
-    return true;
-}
-
-/**
- * \brief Set the volume slice used for mapping volumetric data
- */
-template <>
-void Renderer::setGraphicsObjectVolumeSlice<HeightMap>(const DataSetId& id, Axis axis, double ratio)
-{
-    HeightMapHashmap::iterator itr;
-
-    bool doAll = false;
-
-    if (id.compare("all") == 0) {
-        itr = _heightMaps.begin();
-        if (itr == _heightMaps.end())
-            return;
-        doAll = true;
-    } else {
-        itr = _heightMaps.find(id);
-    }
-
-    if (itr == _heightMaps.end()) {
-        ERROR("HeightMap not found: %s", id.c_str());
-        return;
-    }
-
-    do {
-        itr->second->selectVolumeSlice(axis, ratio);
-     } while (doAll && ++itr != _heightMaps.end());
-
-    sceneBoundsChanged();
-    _needsRedraw = true;
-}
-
-}
-
-using namespace VtkVis;
-
-/**
- * \brief Create a new Arc and associate it with an ID
- */
-bool Renderer::addArc(const DataSetId& id, double pt1[3], double pt2[3])
-{
-    Arc *gobj;
-    if ((gobj = getGraphicsObject<Arc>(id)) != NULL) {
-        WARN("Replacing existing %s %s", gobj->getClassName(), id.c_str());
-        deleteGraphicsObject<Arc>(id);
-    }
-
-    gobj = new Arc();
- 
-    gobj->setDataSet(NULL, this);
-
-    if (gobj->getProp() == NULL &&
-        gobj->getOverlayProp() == NULL) {
-        delete gobj;
-        return false;
-    } else {
-        if (gobj->getProp())
-            _renderer->AddViewProp(gobj->getProp());
-        if (gobj->getOverlayProp())
-            _renderer->AddViewProp(gobj->getOverlayProp());
-    }
-
-    gobj->setEndPoints(pt1, pt2);
-
-    getGraphicsObjectHashmap<Arc>()[id] = gobj;
-
-    sceneBoundsChanged();
-    _needsRedraw = true;
-    return true;
-}
-
-/**
- * \brief Set Arc resolution
- */
-void Renderer::setArcResolution(const DataSetId& id, int res)
-{
-    ArcHashmap::iterator itr;
-
-    bool doAll = false;
-
-    if (id.compare("all") == 0) {
-        itr = _arcs.begin();
-        if (itr == _arcs.end())
-            return;
-        doAll = true;
-    } else {
-        itr = _arcs.find(id);
-    }
-    if (itr == _arcs.end()) {
-        ERROR("Arc not found: %s", id.c_str());
-        return;
-    }
-
-    do {
-        itr->second->setResolution(res);
-    } while (doAll && ++itr != _arcs.end());
-
-    sceneBoundsChanged();
-    _needsRedraw = true;
-}
-
-/**
- * \brief Create a new Arrow and associate it with an ID
- */
-bool Renderer::addArrow(const DataSetId& id, double tipRadius, double shaftRadius, double tipLength)
-{
-    Arrow *gobj;
-    if ((gobj = getGraphicsObject<Arrow>(id)) != NULL) {
-        WARN("Replacing existing %s %s", gobj->getClassName(), id.c_str());
-        deleteGraphicsObject<Arrow>(id);
-    }
-
-    gobj = new Arrow();
- 
-    gobj->setDataSet(NULL, this);
-
-    if (gobj->getProp() == NULL &&
-        gobj->getOverlayProp() == NULL) {
-        delete gobj;
-        return false;
-    } else {
-        if (gobj->getProp())
-            _renderer->AddViewProp(gobj->getProp());
-        if (gobj->getOverlayProp())
-            _renderer->AddViewProp(gobj->getOverlayProp());
-    }
-
-    gobj->setRadii(tipRadius, shaftRadius);
-    gobj->setTipLength(tipLength);
-
-    getGraphicsObjectHashmap<Arrow>()[id] = gobj;
-
-    sceneBoundsChanged();
-    _needsRedraw = true;
-    return true;
-}
-
-/**
- * \brief Set Arrow resolution
- */
-void Renderer::setArrowResolution(const DataSetId& id, int tipRes, int shaftRes)
-{
-    ArrowHashmap::iterator itr;
-
-    bool doAll = false;
-
-    if (id.compare("all") == 0) {
-        itr = _arrows.begin();
-        if (itr == _arrows.end())
-            return;
-        doAll = true;
-    } else {
-        itr = _arrows.find(id);
-    }
-    if (itr == _arrows.end()) {
-        ERROR("Arrow not found: %s", id.c_str());
-        return;
-    }
-
-    do {
-        itr->second->setResolution(tipRes, shaftRes);
-    } while (doAll && ++itr != _arrows.end());
-
-    sceneBoundsChanged();
-    _needsRedraw = true;
-}
-
-/**
- * \brief Create a new Cone and associate it with an ID
- */
-bool Renderer::addCone(const DataSetId& id, double radius, double height, bool cap)
-{
-    Cone *gobj;
-    if ((gobj = getGraphicsObject<Cone>(id)) != NULL) {
-        WARN("Replacing existing %s %s", gobj->getClassName(), id.c_str());
-        deleteGraphicsObject<Cone>(id);
-    }
-
-    gobj = new Cone();
- 
-    gobj->setDataSet(NULL, this);
-
-    if (gobj->getProp() == NULL &&
-        gobj->getOverlayProp() == NULL) {
-        delete gobj;
-        return false;
-    } else {
-        if (gobj->getProp())
-            _renderer->AddViewProp(gobj->getProp());
-        if (gobj->getOverlayProp())
-            _renderer->AddViewProp(gobj->getOverlayProp());
-    }
-
-    gobj->setRadius(radius);
-    gobj->setHeight(height);
-    gobj->setCapping(cap);
-
-    getGraphicsObjectHashmap<Cone>()[id] = gobj;
-
-    sceneBoundsChanged();
-    _needsRedraw = true;
-    return true;
-}
-
-/**
- * \brief Set Cone resolution
- */
-void Renderer::setConeResolution(const DataSetId& id, int res)
-{
-    ConeHashmap::iterator itr;
-
-    bool doAll = false;
-
-    if (id.compare("all") == 0) {
-        itr = _cones.begin();
-        if (itr == _cones.end())
-            return;
-        doAll = true;
-    } else {
-        itr = _cones.find(id);
-    }
-    if (itr == _cones.end()) {
-        ERROR("Cone not found: %s", id.c_str());
-        return;
-    }
-
-    do {
-        itr->second->setResolution(res);
-    } while (doAll && ++itr != _cones.end());
-
-    sceneBoundsChanged();
-    _needsRedraw = true;
-}
-
-/**
- * \brief Create a new Contour2D and associate it with the named DataSet
- */
-bool Renderer::addContour2D(const DataSetId& id, int numContours)
-{
-    DataSetHashmap::iterator itr;
-
-    bool doAll = false;
-
-    if (id.compare("all") == 0) {
-        itr = _dataSets.begin();
-    } else {
-        itr = _dataSets.find(id);
-    }
-    if (itr == _dataSets.end()) {
-        ERROR("Unknown dataset %s", id.c_str());
-        return false;
-    }
-
-    do {
-        DataSet *ds = itr->second;
-        const DataSetId& dsID = ds->getName();
-
-        if (getGraphicsObject<Contour2D>(dsID)) {
-            WARN("Replacing existing Contour2D %s", dsID.c_str());
-            deleteGraphicsObject<Contour2D>(dsID);
-        }
-
-        Contour2D *contour = new Contour2D(numContours);
- 
-        contour->setDataSet(ds, this);
-
-        if (contour->getProp() == NULL) {
-            delete contour;
-            return false;
-        } else {
-            _renderer->AddViewProp(contour->getProp());
-        }
-
-        _contour2Ds[dsID] = contour;
-    } while (doAll && ++itr != _dataSets.end());
-
-    sceneBoundsChanged();
-    _needsRedraw = true;
-    return true;
-}
-
-/**
- * \brief Create a new Contour2D and associate it with the named DataSet
- */
-bool Renderer::addContour2D(const DataSetId& id, const std::vector<double>& contours)
-{
-    DataSetHashmap::iterator itr;
-
-    bool doAll = false;
-
-    if (id.compare("all") == 0) {
-        itr = _dataSets.begin();
-    } else {
-        itr = _dataSets.find(id);
-    }
-    if (itr == _dataSets.end()) {
-        ERROR("Unknown dataset %s", id.c_str());
-        return false;
-    }
-
-    do {
-        DataSet *ds = itr->second;
-        const DataSetId& dsID = ds->getName();
-
-        if (getGraphicsObject<Contour2D>(dsID)) {
-            WARN("Replacing existing Contour2D %s", dsID.c_str());
-            deleteGraphicsObject<Contour2D>(dsID);
-        }
-
-        Contour2D *contour = new Contour2D(contours);
-
-        contour->setDataSet(ds, this);
-
-        if (contour->getProp() == NULL) {
-            delete contour;
-            return false;
-        } else {
-            _renderer->AddViewProp(contour->getProp());
-        }
-
-        _contour2Ds[dsID] = contour;
-    } while (doAll && ++itr != _dataSets.end());
-
-    sceneBoundsChanged();
-    _needsRedraw = true;
-    return true;
-}
-
-/**
- * \brief Set the number of equally spaced contour isolines for the given DataSet
- */
-void Renderer::setContour2DNumContours(const DataSetId& id, int numContours)
-{
-    Contour2DHashmap::iterator itr;
-
-    bool doAll = false;
-
-    if (id.compare("all") == 0) {
-        itr = _contour2Ds.begin();
-        doAll = true;
-    } else {
-        itr = _contour2Ds.find(id);
-    }
-    if (itr == _contour2Ds.end()) {
-        ERROR("Contour2D not found: %s", id.c_str());
-        return;
-    }
-
-    do {
-        itr->second->setNumContours(numContours);
-    } while (doAll && ++itr != _contour2Ds.end());
-
-    sceneBoundsChanged();
-    _needsRedraw = true;
-}
-
-/**
- * \brief Set the number of equally spaced isosurfaces for the given DataSet
- */
-void Renderer::setContour2DContourField(const DataSetId& id, const char *fieldName)
-{
-    Contour2DHashmap::iterator itr;
-
-    bool doAll = false;
-
-    if (id.compare("all") == 0) {
-        itr = _contour2Ds.begin();
-        doAll = true;
-    } else {
-        itr = _contour2Ds.find(id);
-    }
-    if (itr == _contour2Ds.end()) {
-        ERROR("Contour2D not found: %s", id.c_str());
-        return;
-    }
-
-    do {
-        itr->second->setContourField(fieldName);
-     } while (doAll && ++itr != _contour2Ds.end());
-
-    sceneBoundsChanged();
-    _needsRedraw = true;
-}
-
-/**
- * \brief Set a list of isovalues for the given DataSet
- */
-void Renderer::setContour2DContourList(const DataSetId& id, const std::vector<double>& contours)
-{
-    Contour2DHashmap::iterator itr;
-
-    bool doAll = false;
-
-    if (id.compare("all") == 0) {
-        itr = _contour2Ds.begin();
-        doAll = true;
-    } else {
-        itr = _contour2Ds.find(id);
-    }
-    if (itr == _contour2Ds.end()) {
-        ERROR("Contour2D not found: %s", id.c_str());
-        return;
-    }
-
-    do {
-        itr->second->setContourList(contours);
-    } while (doAll && ++itr != _contour2Ds.end());
-
-    sceneBoundsChanged();
-     _needsRedraw = true;
-}
-
-/**
- * \brief Set the color mode for the specified DataSet
- */
-void Renderer::setContour2DColorMode(const DataSetId& id,
-                                     Contour2D::ColorMode mode,
-                                     DataSet::DataAttributeType type,
-                                     const char *name, double range[2])
-{
-    Contour2DHashmap::iterator itr;
-
-    bool doAll = false;
-
-    if (id.compare("all") == 0) {
-        itr = _contour2Ds.begin();
-        if (itr == _contour2Ds.end())
-            return;
-        doAll = true;
-    } else {
-        itr = _contour2Ds.find(id);
-    }
-    if (itr == _contour2Ds.end()) {
-        ERROR("Contour2D not found: %s", id.c_str());
-        return;
-    }
-
-    do {
-        itr->second->setColorMode(mode, type, name, range);
-    } while (doAll && ++itr != _contour2Ds.end());
-
-    _needsRedraw = true;
-}
-
-/**
- * \brief Set the color mode for the specified DataSet
- */
-void Renderer::setContour2DColorMode(const DataSetId& id,
-                                     Contour2D::ColorMode mode,
-                                     const char *name, double range[2])
-{
-    Contour2DHashmap::iterator itr;
-
-    bool doAll = false;
-
-    if (id.compare("all") == 0) {
-        itr = _contour2Ds.begin();
-        if (itr == _contour2Ds.end())
-            return;
-        doAll = true;
-    } else {
-        itr = _contour2Ds.find(id);
-    }
-    if (itr == _contour2Ds.end()) {
-        ERROR("Contour2D not found: %s", id.c_str());
-        return;
-    }
-
-    do {
-        itr->second->setColorMode(mode, name, range);
-    } while (doAll && ++itr != _contour2Ds.end());
-
-    _needsRedraw = true;
-}
-
-/**
- * \brief Create a new Contour3D and associate it with the named DataSet
- */
-bool Renderer::addContour3D(const DataSetId& id, int numContours)
-{
-    DataSetHashmap::iterator itr;
-
-    bool doAll = false;
-
-    if (id.compare("all") == 0) {
-        itr = _dataSets.begin();
-    } else {
-        itr = _dataSets.find(id);
-    }
-    if (itr == _dataSets.end()) {
-        ERROR("Unknown dataset %s", id.c_str());
-        return false;
-    }
-
-    do {
-        DataSet *ds = itr->second;
-        const DataSetId& dsID = ds->getName();
-
-        if (getGraphicsObject<Contour3D>(dsID)) {
-            WARN("Replacing existing Contour3D %s", dsID.c_str());
-            deleteGraphicsObject<Contour3D>(dsID);
-        }
-
-        Contour3D *contour = new Contour3D(numContours);
-
-        contour->setDataSet(ds, this);
-
-        if (contour->getProp() == NULL) {
-            delete contour;
-            return false;
-        } else {
-            _renderer->AddViewProp(contour->getProp());
-        }
-
-        _contour3Ds[dsID] = contour;
-    } while (doAll && ++itr != _dataSets.end());
-
-    sceneBoundsChanged();
-    _needsRedraw = true;
-    return true;
-}
-
-/**
- * \brief Create a new Contour3D and associate it with the named DataSet
- */
-bool Renderer::addContour3D(const DataSetId& id,const std::vector<double>& contours)
-{
-    DataSetHashmap::iterator itr;
-
-    bool doAll = false;
-
-    if (id.compare("all") == 0) {
-        itr = _dataSets.begin();
-    } else {
-        itr = _dataSets.find(id);
-    }
-    if (itr == _dataSets.end()) {
-        ERROR("Unknown dataset %s", id.c_str());
-        return false;
-    }
-
-    do {
-        DataSet *ds = itr->second;
-        const DataSetId& dsID = ds->getName();
-
-        if (getGraphicsObject<Contour3D>(dsID)) {
-            WARN("Replacing existing Contour3D %s", dsID.c_str());
-            deleteGraphicsObject<Contour3D>(dsID);
-        }
-
-        Contour3D *contour = new Contour3D(contours);
-
-        contour->setDataSet(ds, this);
-
-        if (contour->getProp() == NULL) {
-            delete contour;
-            return false;
-        } else {
-            _renderer->AddViewProp(contour->getProp());
-        }
-
-        _contour3Ds[dsID] = contour;
-    } while (doAll && ++itr != _dataSets.end());
-
-    sceneBoundsChanged();
-    _needsRedraw = true;
-    return true;
-}
-
-/**
- * \brief Set the number of equally spaced isosurfaces for the given DataSet
- */
-void Renderer::setContour3DContourField(const DataSetId& id, const char *fieldName)
-{
-    Contour3DHashmap::iterator itr;
-
-    bool doAll = false;
-
-    if (id.compare("all") == 0) {
-        itr = _contour3Ds.begin();
-        doAll = true;
-    } else {
-        itr = _contour3Ds.find(id);
-    }
-    if (itr == _contour3Ds.end()) {
-        ERROR("Contour3D not found: %s", id.c_str());
-        return;
-    }
-
-    do {
-        itr->second->setContourField(fieldName);
-     } while (doAll && ++itr != _contour3Ds.end());
-
-    sceneBoundsChanged();
-    _needsRedraw = true;
-}
-
-/**
- * \brief Set the number of equally spaced isosurfaces for the given DataSet
- */
-void Renderer::setContour3DNumContours(const DataSetId& id, int numContours)
-{
-    Contour3DHashmap::iterator itr;
-
-    bool doAll = false;
-
-    if (id.compare("all") == 0) {
-        itr = _contour3Ds.begin();
-        doAll = true;
-    } else {
-        itr = _contour3Ds.find(id);
-    }
-    if (itr == _contour3Ds.end()) {
-        ERROR("Contour3D not found: %s", id.c_str());
-        return;
-    }
-
-    do {
-        itr->second->setNumContours(numContours);
-     } while (doAll && ++itr != _contour3Ds.end());
-
-    sceneBoundsChanged();
-    _needsRedraw = true;
-}
-
-/**
- * \brief Set a list of isovalues for the given DataSet
- */
-void Renderer::setContour3DContourList(const DataSetId& id, const std::vector<double>& contours)
-{
-    Contour3DHashmap::iterator itr;
-
-    bool doAll = false;
-
-    if (id.compare("all") == 0) {
-        itr = _contour3Ds.begin();
-        doAll = true;
-    } else {
-        itr = _contour3Ds.find(id);
-    }
-    if (itr == _contour3Ds.end()) {
-        ERROR("Contour3D not found: %s", id.c_str());
-        return;
-    }
-
-    do {
-        itr->second->setContourList(contours);
-    } while (doAll && ++itr != _contour3Ds.end());
-
-    sceneBoundsChanged();
-    _needsRedraw = true;
-}
-
-/**
- * \brief Set the color mode for the specified DataSet
- */
-void Renderer::setContour3DColorMode(const DataSetId& id,
-                                     Contour3D::ColorMode mode,
-                                     DataSet::DataAttributeType type,
-                                     const char *name, double range[2])
-{
-    Contour3DHashmap::iterator itr;
-
-    bool doAll = false;
-
-    if (id.compare("all") == 0) {
-        itr = _contour3Ds.begin();
-        if (itr == _contour3Ds.end())
-            return;
-        doAll = true;
-    } else {
-        itr = _contour3Ds.find(id);
-    }
-    if (itr == _contour3Ds.end()) {
-        ERROR("Contour3D not found: %s", id.c_str());
-        return;
-    }
-
-    do {
-        itr->second->setColorMode(mode, type, name, range);
-    } while (doAll && ++itr != _contour3Ds.end());
-
-    _needsRedraw = true;
-}
-
-/**
- * \brief Set the color mode for the specified DataSet
- */
-void Renderer::setContour3DColorMode(const DataSetId& id,
-                                     Contour3D::ColorMode mode,
-                                     const char *name, double range[2])
-{
-    Contour3DHashmap::iterator itr;
-
-    bool doAll = false;
-
-    if (id.compare("all") == 0) {
-        itr = _contour3Ds.begin();
-        if (itr == _contour3Ds.end())
-            return;
-        doAll = true;
-    } else {
-        itr = _contour3Ds.find(id);
-    }
-    if (itr == _contour3Ds.end()) {
-        ERROR("Contour3D not found: %s", id.c_str());
-        return;
-    }
-
-    do {
-        itr->second->setColorMode(mode, name, range);
-    } while (doAll && ++itr != _contour3Ds.end());
-
-    _needsRedraw = true;
-}
-
-/**
- * \brief Set the visibility of cutplane outlines
- */
-void Renderer::setCutplaneOutlineVisibility(const DataSetId& id, bool state)
-{
-    CutplaneHashmap::iterator itr;
-
-    bool doAll = false;
-
-    if (id.compare("all") == 0) {
-        itr = _cutplanes.begin();
-        if (itr == _cutplanes.end())
-            return;
-        doAll = true;
-    } else {
-        itr = _cutplanes.find(id);
-    }
-
-    if (itr == _cutplanes.end()) {
-        ERROR("Cutplane not found: %s", id.c_str());
-        return;
-    }
-
-    do {
-        itr->second->setOutlineVisibility(state);
-     } while (doAll && ++itr != _cutplanes.end());
-
-    sceneBoundsChanged();
-    _needsRedraw = true;
-}
-
-/**
- * \brief Set the visibility of slices in one of the three axes
- */
-void Renderer::setCutplaneSliceVisibility(const DataSetId& id, Axis axis, bool state)
-{
-    CutplaneHashmap::iterator itr;
-
-    bool doAll = false;
-
-    if (id.compare("all") == 0) {
-        itr = _cutplanes.begin();
-        if (itr == _cutplanes.end())
-            return;
-        doAll = true;
-    } else {
-        itr = _cutplanes.find(id);
-    }
-
-    if (itr == _cutplanes.end()) {
-        ERROR("Cutplane not found: %s", id.c_str());
-        return;
-    }
-
-    do {
-        itr->second->setSliceVisibility(axis, state);
-     } while (doAll && ++itr != _cutplanes.end());
-
-    sceneBoundsChanged();
-    _needsRedraw = true;
-}
-
-/**
- * \brief Set the color mode for the specified DataSet
- */
-void Renderer::setCutplaneColorMode(const DataSetId& id,
-                                    Cutplane::ColorMode mode,
-                                    DataSet::DataAttributeType type,
-                                    const char *name, double range[2])
-{
-    CutplaneHashmap::iterator itr;
-
-    bool doAll = false;
-
-    if (id.compare("all") == 0) {
-        itr = _cutplanes.begin();
-        if (itr == _cutplanes.end())
-            return;
-        doAll = true;
-    } else {
-        itr = _cutplanes.find(id);
-    }
-    if (itr == _cutplanes.end()) {
-        ERROR("Cutplane not found: %s", id.c_str());
-        return;
-    }
-
-    do {
-        itr->second->setColorMode(mode, type, name, range);
-    } while (doAll && ++itr != _cutplanes.end());
-
-    _needsRedraw = true;
-}
-
-/**
- * \brief Set the color mode for the specified DataSet
- */
-void Renderer::setCutplaneColorMode(const DataSetId& id,
-                                    Cutplane::ColorMode mode,
-                                    const char *name, double range[2])
-{
-    CutplaneHashmap::iterator itr;
-
-    bool doAll = false;
-
-    if (id.compare("all") == 0) {
-        itr = _cutplanes.begin();
-        if (itr == _cutplanes.end())
-            return;
-        doAll = true;
-    } else {
-        itr = _cutplanes.find(id);
-    }
-    if (itr == _cutplanes.end()) {
-        ERROR("Cutplane not found: %s", id.c_str());
-        return;
-    }
-
-    do {
-        itr->second->setColorMode(mode, name, range);
-    } while (doAll && ++itr != _cutplanes.end());
-
-    _needsRedraw = true;
-}
-
-/**
- * \brief Create a new Cylinder and associate it with an ID
- */
-bool Renderer::addCylinder(const DataSetId& id, double radius, double height, bool cap)
-{
-    Cylinder *gobj;
-    if ((gobj = getGraphicsObject<Cylinder>(id)) != NULL) {
-        WARN("Replacing existing %s %s", gobj->getClassName(), id.c_str());
-        deleteGraphicsObject<Cylinder>(id);
-    }
-
-    gobj = new Cylinder();
- 
-    gobj->setDataSet(NULL, this);
-
-    if (gobj->getProp() == NULL &&
-        gobj->getOverlayProp() == NULL) {
-        delete gobj;
-        return false;
-    } else {
-        if (gobj->getProp())
-            _renderer->AddViewProp(gobj->getProp());
-        if (gobj->getOverlayProp())
-            _renderer->AddViewProp(gobj->getOverlayProp());
-    }
-
-    gobj->setRadius(radius);
-    gobj->setHeight(height);
-    gobj->setCapping(cap);
-
-    getGraphicsObjectHashmap<Cylinder>()[id] = gobj;
-
-    sceneBoundsChanged();
-    _needsRedraw = true;
-    return true;
-}
-
-/**
- * \brief Set Cylinder resolution
- */
-void Renderer::setCylinderResolution(const DataSetId& id, int res)
-{
-    CylinderHashmap::iterator itr;
-
-    bool doAll = false;
-
-    if (id.compare("all") == 0) {
-        itr = _cylinders.begin();
-        if (itr == _cylinders.end())
-            return;
-        doAll = true;
-    } else {
-        itr = _cylinders.find(id);
-    }
-    if (itr == _cylinders.end()) {
-        ERROR("Cylinder not found: %s", id.c_str());
-        return;
-    }
-
-    do {
-        itr->second->setResolution(res);
-    } while (doAll && ++itr != _cylinders.end());
-
-    sceneBoundsChanged();
-    _needsRedraw = true;
-}
-
-/**
- * \brief Create a new Disk and associate it with an ID
- */
-bool Renderer::addDisk(const DataSetId& id, double innerRadius, double outerRadius)
-{
-    Disk *gobj;
-    if ((gobj = getGraphicsObject<Disk>(id)) != NULL) {
-        WARN("Replacing existing %s %s", gobj->getClassName(), id.c_str());
-        deleteGraphicsObject<Disk>(id);
-    }
-
-    gobj = new Disk();
- 
-    gobj->setDataSet(NULL, this);
-
-    if (gobj->getProp() == NULL &&
-        gobj->getOverlayProp() == NULL) {
-        delete gobj;
-        return false;
-    } else {
-        if (gobj->getProp())
-            _renderer->AddViewProp(gobj->getProp());
-        if (gobj->getOverlayProp())
-            _renderer->AddViewProp(gobj->getOverlayProp());
-    }
-
-    gobj->setRadii(innerRadius, outerRadius);
-
-    getGraphicsObjectHashmap<Disk>()[id] = gobj;
-
-    sceneBoundsChanged();
-    _needsRedraw = true;
-    return true;
-}
-
-/**
- * \brief Set Disk resolution
- */
-void Renderer::setDiskResolution(const DataSetId& id, int resRadial, int resCircum)
-{
-    DiskHashmap::iterator itr;
-
-    bool doAll = false;
-
-    if (id.compare("all") == 0) {
-        itr = _disks.begin();
-        if (itr == _disks.end())
-            return;
-        doAll = true;
-    } else {
-        itr = _disks.find(id);
-    }
-    if (itr == _disks.end()) {
-        ERROR("Disk not found: %s", id.c_str());
-        return;
-    }
-
-    do {
-        itr->second->setResolution(resRadial, resCircum);
-    } while (doAll && ++itr != _disks.end());
-
-    sceneBoundsChanged();
-    _needsRedraw = true;
-}
-
-/**
- * \brief Create a new Glyphs and associate it with the named DataSet
- */
-bool Renderer::addGlyphs(const DataSetId& id, Glyphs::GlyphShape shape)
-{
-    DataSetHashmap::iterator itr;
-
-    bool doAll = false;
-
-    if (id.compare("all") == 0) {
-        itr = _dataSets.begin();
-    } else {
-        itr = _dataSets.find(id);
-    }
-    if (itr == _dataSets.end()) {
-        ERROR("Unknown dataset %s", id.c_str());
-        return false;
-    }
-
-    do {
-        DataSet *ds = itr->second;
-        const DataSetId& dsID = ds->getName();
-
-        if (getGraphicsObject<Glyphs>(dsID)) {
-            WARN("Replacing existing Glyphs %s", dsID.c_str());
-            deleteGraphicsObject<Glyphs>(dsID);
-        }
-
-        Glyphs *glyphs = new Glyphs(shape);
-
-        glyphs->setDataSet(ds, this);
-
-        if (glyphs->getProp() == NULL) {
-            delete glyphs;
-            return false;
-        } else {
-            _renderer->AddViewProp(glyphs->getProp());
-        }
-
-        _glyphs[dsID] = glyphs;
-    } while (doAll && ++itr != _dataSets.end());
-
-    sceneBoundsChanged();
-    _needsRedraw = true;
-    return true;
-}
-
-/**
- * \brief Set the color mode for the specified DataSet
- */
-void Renderer::setGlyphsColorMode(const DataSetId& id,
-                                  Glyphs::ColorMode mode,
-                                  const char *name, double range[2])
-{
-    GlyphsHashmap::iterator itr;
-
-    bool doAll = false;
-
-    if (id.compare("all") == 0) {
-        itr = _glyphs.begin();
-        if (itr == _glyphs.end())
-            return;
-        doAll = true;
-    } else {
-        itr = _glyphs.find(id);
-    }
-    if (itr == _glyphs.end()) {
-        ERROR("Glyphs not found: %s", id.c_str());
-        return;
-    }
-
-    do {
-        itr->second->setColorMode(mode, name, range);
-    } while (doAll && ++itr != _glyphs.end());
-
-    _needsRedraw = true;
-}
-
-/**
- * \brief Controls the array used to scale glyphs for the given DataSet
- */
-void Renderer::setGlyphsScalingMode(const DataSetId& id,
-                                    Glyphs::ScalingMode mode,
-                                    const char *name, double range[2])
-{
-    GlyphsHashmap::iterator itr;
-
-    bool doAll = false;
-
-    if (id.compare("all") == 0) {
-        itr = _glyphs.begin();
-        if (itr == _glyphs.end())
-            return;
-        doAll = true;
-    } else {
-        itr = _glyphs.find(id);
-    }
-    if (itr == _glyphs.end()) {
-        ERROR("Glyphs not found: %s", id.c_str());
-        return;
-    }
-
-    do {
-        itr->second->setScalingMode(mode, name, range);
-    } while (doAll && ++itr != _glyphs.end());
-
-    sceneBoundsChanged();
-    _needsRedraw = true;
-}
-
-/**
- * \brief Controls if field data range is normalized to [0,1] before
- * applying scale factor for the given DataSet
- */
-void Renderer::setGlyphsNormalizeScale(const DataSetId& id, bool normalize)
-{
-    GlyphsHashmap::iterator itr;
-
-    bool doAll = false;
-
-    if (id.compare("all") == 0) {
-        itr = _glyphs.begin();
-        if (itr == _glyphs.end())
-            return;
-        doAll = true;
-    } else {
-        itr = _glyphs.find(id);
-    }
-    if (itr == _glyphs.end()) {
-        ERROR("Glyphs not found: %s", id.c_str());
-        return;
-    }
-
-    do {
-        itr->second->setNormalizeScale(normalize);
-    } while (doAll && ++itr != _glyphs.end());
-
-    sceneBoundsChanged();
-    _needsRedraw = true;
-}
-
-/**
- * \brief Controls if glyphs are oriented from a vector field for the 
- * given DataSet
- */
-void Renderer::setGlyphsOrientMode(const DataSetId& id, bool state,
-                                   const char *name)
-{
-    GlyphsHashmap::iterator itr;
-
-    bool doAll = false;
-
-    if (id.compare("all") == 0) {
-        itr = _glyphs.begin();
-        if (itr == _glyphs.end())
-            return;
-        doAll = true;
-    } else {
-        itr = _glyphs.find(id);
-    }
-    if (itr == _glyphs.end()) {
-        ERROR("Glyphs not found: %s", id.c_str());
-        return;
-    }
-
-    do {
-        itr->second->setOrientMode(state, name);
-    } while (doAll && ++itr != _glyphs.end());
-
-    sceneBoundsChanged();
-    _needsRedraw = true;
-}
-
-/**
- * \brief Set the shape of Glyphs for the given DataSet
- */
-void Renderer::setGlyphsShape(const DataSetId& id, Glyphs::GlyphShape shape)
-{
-    GlyphsHashmap::iterator itr;
-
-    bool doAll = false;
-
-    if (id.compare("all") == 0) {
-        itr = _glyphs.begin();
-        if (itr == _glyphs.end())
-            return;
-        doAll = true;
-    } else {
-        itr = _glyphs.find(id);
-    }
-    if (itr == _glyphs.end()) {
-        ERROR("Glyphs not found: %s", id.c_str());
-        return;
-    }
-
-    do {
-        itr->second->setGlyphShape(shape);
-    } while (doAll && ++itr != _glyphs.end());
-
-    sceneBoundsChanged();
-    _needsRedraw = true;
-}
-
-/**
- * \brief Set the glyph scaling factor for the given DataSet
- */
-void Renderer::setGlyphsScaleFactor(const DataSetId& id, double scale)
-{
-    GlyphsHashmap::iterator itr;
-
-    bool doAll = false;
-
-    if (id.compare("all") == 0) {
-        itr = _glyphs.begin();
-        if (itr == _glyphs.end())
-            return;
-        doAll = true;
-    } else {
-        itr = _glyphs.find(id);
-    }
-    if (itr == _glyphs.end()) {
-        ERROR("Glyphs not found: %s", id.c_str());
-        return;
-    }
-
-    do {
-        itr->second->setScaleFactor(scale);
-    } while (doAll && ++itr != _glyphs.end());
-
-    sceneBoundsChanged();
-    _needsRedraw = true;
-}
-
-/**
- * \brief Create a new HeightMap and associate it with the named DataSet
- */
-bool Renderer::addHeightMap(const DataSetId& id, int numContours, double heightScale)
-{
-    DataSetHashmap::iterator itr;
-
-    bool doAll = false;
-
-    if (id.compare("all") == 0) {
-        itr = _dataSets.begin();
-    } else {
-        itr = _dataSets.find(id);
-    }
-    if (itr == _dataSets.end()) {
-        ERROR("Unknown dataset %s", id.c_str());
-        return false;
-    }
-
-    do {
-        DataSet *ds = itr->second;
-        const DataSetId& dsID = ds->getName();
-
-        if (getGraphicsObject<HeightMap>(dsID)) {
-            WARN("Replacing existing HeightMap %s", dsID.c_str());
-            deleteGraphicsObject<HeightMap>(dsID);
-        }
-
-        HeightMap *hmap = new HeightMap(numContours, heightScale);
-
-        hmap->setDataSet(ds, this);
-
-        if (hmap->getProp() == NULL) {
-            delete hmap;
-            return false;
-        } else {
-            _renderer->AddViewProp(hmap->getProp());
-        }
-
-        _heightMaps[dsID] = hmap;
-    } while (doAll && ++itr != _dataSets.end());
-
-    sceneBoundsChanged();
-    _needsRedraw = true;
-    return true;
-}
-
-/**
- * \brief Create a new HeightMap and associate it with the named DataSet
- */
-bool Renderer::addHeightMap(const DataSetId& id, const std::vector<double>& contours, double heightScale)
-{
-    DataSetHashmap::iterator itr;
-
-    bool doAll = false;
-
-    if (id.compare("all") == 0) {
-        itr = _dataSets.begin();
-    } else {
-        itr = _dataSets.find(id);
-    }
-    if (itr == _dataSets.end()) {
-        ERROR("Unknown dataset %s", id.c_str());
-        return false;
-    }
-
-    do {
-        DataSet *ds = itr->second;
-        const DataSetId& dsID = ds->getName();
-
-        if (getGraphicsObject<HeightMap>(dsID)) {
-            WARN("Replacing existing HeightMap %s", dsID.c_str());
-            deleteGraphicsObject<HeightMap>(dsID);
-        }
-
-        HeightMap *hmap = new HeightMap(contours, heightScale);
-
-        hmap->setDataSet(ds, this);
-
-        if (hmap->getProp() == NULL) {
-            delete hmap;
-            return false;
-        } else {
-            _renderer->AddViewProp(hmap->getProp());
-        }
-
-        _heightMaps[dsID] = hmap;
-    } while (doAll && ++itr != _dataSets.end());
-
-    sceneBoundsChanged();
-    _needsRedraw = true;
-    return true;
-}
-
-/**
- * \brief Set amount to scale scalar values when creating elevations
- * in the height map
- */
-void Renderer::setHeightMapHeightScale(const DataSetId& id, double scale)
-{
-    HeightMapHashmap::iterator itr;
-
-    bool doAll = false;
-
-    if (id.compare("all") == 0) {
-        itr = _heightMaps.begin();
-        if (itr == _heightMaps.end())
-            return;
-        doAll = true;
-    } else {
-        itr = _heightMaps.find(id);
-    }
-
-    if (itr == _heightMaps.end()) {
-        ERROR("HeightMap not found: %s", id.c_str());
-        return;
-    }
-
-    do {
-        itr->second->setHeightScale(scale);
-     } while (doAll && ++itr != _heightMaps.end());
-
-    sceneBoundsChanged();
-    _needsRedraw = true;
-}
-
-/**
- * \brief Set the number of equally spaced contour isolines for the given DataSet
- */
-void Renderer::setHeightMapNumContours(const DataSetId& id, int numContours)
-{
-    HeightMapHashmap::iterator itr;
-
-    bool doAll = false;
-
-    if (id.compare("all") == 0) {
-        itr = _heightMaps.begin();
-        doAll = true;
-    } else {
-        itr = _heightMaps.find(id);
-    }
-    if (itr == _heightMaps.end()) {
-        ERROR("HeightMap not found: %s", id.c_str());
-        return;
-    }
-
-    do {
-        itr->second->setNumContours(numContours);
-    } while (doAll && ++itr != _heightMaps.end());
-
-    sceneBoundsChanged();
-    _needsRedraw = true;
-}
-
-/**
- * \brief Set a list of height map contour isovalues for the given DataSet
- */
-void Renderer::setHeightMapContourList(const DataSetId& id, const std::vector<double>& contours)
-{
-    HeightMapHashmap::iterator itr;
-
-    bool doAll = false;
-
-    if (id.compare("all") == 0) {
-        itr = _heightMaps.begin();
-        doAll = true;
-    } else {
-        itr = _heightMaps.find(id);
-    }
-    if (itr == _heightMaps.end()) {
-        ERROR("HeightMap not found: %s", id.c_str());
-        return;
-    }
-
-    do {
-        itr->second->setContourList(contours);
-    } while (doAll && ++itr != _heightMaps.end());
-
-    sceneBoundsChanged();
-     _needsRedraw = true;
-}
-
-/**
- * \brief Turn on/off rendering height map contour lines for the given DataSet
- */
-void Renderer::setHeightMapContourLineVisibility(const DataSetId& id, bool state)
-{
-    HeightMapHashmap::iterator itr;
-
-    bool doAll = false;
-
-    if (id.compare("all") == 0) {
-        itr = _heightMaps.begin();
-        if (itr == _heightMaps.end())
-            return;
-        doAll = true;
-    } else {
-        itr = _heightMaps.find(id);
-    }
-    if (itr == _heightMaps.end()) {
-        ERROR("HeightMap not found: %s", id.c_str());
-        return;
-    }
-
-    do {
-        itr->second->setContourLineVisibility(state);
-    } while (doAll && ++itr != _heightMaps.end());
-
-    sceneBoundsChanged();
-    _needsRedraw = true;
-}
-
-/**
- * \brief Turn on/off rendering height map colormap surface for the given DataSet
- */
-void Renderer::setHeightMapContourSurfaceVisibility(const DataSetId& id, bool state)
-{
-    HeightMapHashmap::iterator itr;
-
-    bool doAll = false;
-
-    if (id.compare("all") == 0) {
-        itr = _heightMaps.begin();
-        if (itr == _heightMaps.end())
-            return;
-        doAll = true;
-    } else {
-        itr = _heightMaps.find(id);
-    }
-    if (itr == _heightMaps.end()) {
-        ERROR("HeightMap not found: %s", id.c_str());
-        return;
-    }
-
-    do {
-        itr->second->setContourSurfaceVisibility(state);
-    } while (doAll && ++itr != _heightMaps.end());
-
-    sceneBoundsChanged();
-    _needsRedraw = true;
-}
-
-/**
- * \brief Set the RGB height map isoline color for the specified DataSet
- */
-void Renderer::setHeightMapContourEdgeColor(const DataSetId& id, float color[3])
-{
-    HeightMapHashmap::iterator itr;
-
-    bool doAll = false;
-
-    if (id.compare("all") == 0) {
-        itr = _heightMaps.begin();
-        if (itr == _heightMaps.end())
-            return;
-        doAll = true;
-    } else {
-        itr = _heightMaps.find(id);
-    }
-    if (itr == _heightMaps.end()) {
-        ERROR("HeightMap not found: %s", id.c_str());
-        return;
-    }
-
-    do {
-        itr->second->setContourEdgeColor(color);
-    } while (doAll && ++itr != _heightMaps.end());
-
-    _needsRedraw = true;
-}
-
-/**
- * \brief Set the height map isoline width for the specified DataSet (may be a no-op)
- *
- * If the OpenGL implementation/hardware does not support wide lines, 
- * this function may not have an effect.
- */
-void Renderer::setHeightMapContourEdgeWidth(const DataSetId& id, float edgeWidth)
-{
-    HeightMapHashmap::iterator itr;
-
-    bool doAll = false;
-
-    if (id.compare("all") == 0) {
-        itr = _heightMaps.begin();
-        if (itr == _heightMaps.end())
-            return;
-        doAll = true;
-    } else {
-        itr = _heightMaps.find(id);
-    }
-    if (itr == _heightMaps.end()) {
-        ERROR("HeightMap not found: %s", id.c_str());
-        return;
-    }
-
-    do {
-        itr->second->setContourEdgeWidth(edgeWidth);
-    } while (doAll && ++itr != _heightMaps.end());
-
-    sceneBoundsChanged();
-    _needsRedraw = true;
-}
-
-/**
- * \brief Toggle colormapping of contour lines
- */
-void Renderer::setHeightMapContourLineColorMapEnabled(const DataSetId& id, bool mode)
-{
-    HeightMapHashmap::iterator itr;
-
-    bool doAll = false;
-
-    if (id.compare("all") == 0) {
-        itr = _heightMaps.begin();
-        if (itr == _heightMaps.end())
-            return;
-        doAll = true;
-    } else {
-        itr = _heightMaps.find(id);
-    }
-    if (itr == _heightMaps.end()) {
-        ERROR("HeightMap not found: %s", id.c_str());
-        return;
-    }
-
-    do {
-        itr->second->setContourLineColorMapEnabled(mode);
-    } while (doAll && ++itr != _heightMaps.end());
-
-    _needsRedraw = true;    
-}
-
-/**
- * \brief Set the color mode for the specified DataSet
- */
-void Renderer::setHeightMapColorMode(const DataSetId& id,
-                                     HeightMap::ColorMode mode,
-                                     DataSet::DataAttributeType type,
-                                     const char *name, double range[2])
-{
-    HeightMapHashmap::iterator itr;
-
-    bool doAll = false;
-
-    if (id.compare("all") == 0) {
-        itr = _heightMaps.begin();
-        if (itr == _heightMaps.end())
-            return;
-        doAll = true;
-    } else {
-        itr = _heightMaps.find(id);
-    }
-    if (itr == _heightMaps.end()) {
-        ERROR("HeightMap not found: %s", id.c_str());
-        return;
-    }
-
-    do {
-        itr->second->setColorMode(mode, type, name, range);
-    } while (doAll && ++itr != _heightMaps.end());
-
-    _needsRedraw = true;
-}
-
-/**
- * \brief Set the color mode for the specified DataSet
- */
-void Renderer::setHeightMapColorMode(const DataSetId& id,
-                                     HeightMap::ColorMode mode,
-                                     const char *name, double range[2])
-{
-    HeightMapHashmap::iterator itr;
-
-    bool doAll = false;
-
-    if (id.compare("all") == 0) {
-        itr = _heightMaps.begin();
-        if (itr == _heightMaps.end())
-            return;
-        doAll = true;
-    } else {
-        itr = _heightMaps.find(id);
-    }
-    if (itr == _heightMaps.end()) {
-        ERROR("HeightMap not found: %s", id.c_str());
-        return;
-    }
-
-    do {
-        itr->second->setColorMode(mode, name, range);
-    } while (doAll && ++itr != _heightMaps.end());
-
-    _needsRedraw = true;
-}
-
-/**
- * \brief Create a new Line and associate it with an ID
- */
-bool Renderer::addLine(const DataSetId& id, double pt1[3], double pt2[3])
-{
-    Line *gobj;
-    if ((gobj = getGraphicsObject<Line>(id)) != NULL) {
-        WARN("Replacing existing %s %s", gobj->getClassName(), id.c_str());
-        deleteGraphicsObject<Line>(id);
-    }
-
-    gobj = new Line();
- 
-    gobj->setDataSet(NULL, this);
-
-    if (gobj->getProp() == NULL &&
-        gobj->getOverlayProp() == NULL) {
-        delete gobj;
-        return false;
-    } else {
-        if (gobj->getProp())
-            _renderer->AddViewProp(gobj->getProp());
-        if (gobj->getOverlayProp())
-            _renderer->AddViewProp(gobj->getOverlayProp());
-    }
-
-    gobj->setEndPoints(pt1, pt2);
-
-    getGraphicsObjectHashmap<Line>()[id] = gobj;
-
-    sceneBoundsChanged();
-    _needsRedraw = true;
-    return true;
-}
-
-/**
- * \brief Set radius scale factor for atoms
- */
-void Renderer::setMoleculeAtomRadiusScale(const DataSetId& id, double scale)
-{
-    MoleculeHashmap::iterator itr;
-
-    bool doAll = false;
-
-    if (id.compare("all") == 0) {
-        itr = _molecules.begin();
-        if (itr == _molecules.end())
-            return;
-        doAll = true;
-    } else {
-        itr = _molecules.find(id);
-    }
-    if (itr == _molecules.end()) {
-        ERROR("Molecule not found: %s", id.c_str());
-        return;
-    }
-
-    do {
-        itr->second->setAtomRadiusScale(scale);
-    } while (doAll && ++itr != _molecules.end());
-
-    sceneBoundsChanged();
-    _needsRedraw = true;
-}
-
-/**
- * \brief Set radius standard for scaling atoms
- */
-void Renderer::setMoleculeAtomScaling(const DataSetId& id, Molecule::AtomScaling scaling)
-{
-    MoleculeHashmap::iterator itr;
-
-    bool doAll = false;
-
-    if (id.compare("all") == 0) {
-        itr = _molecules.begin();
-        if (itr == _molecules.end())
-            return;
-        doAll = true;
-    } else {
-        itr = _molecules.find(id);
-    }
-    if (itr == _molecules.end()) {
-        ERROR("Molecule not found: %s", id.c_str());
-        return;
-    }
-
-    do {
-        itr->second->setAtomScaling(scaling);
-    } while (doAll && ++itr != _molecules.end());
-
-    sceneBoundsChanged();
-    _needsRedraw = true;
-}
-
-/**
- * \brief Turn on/off rendering of the Molecule atoms for the given DataSet
- */
-void Renderer::setMoleculeAtomVisibility(const DataSetId& id, bool state)
-{
-    MoleculeHashmap::iterator itr;
-
-    bool doAll = false;
-
-    if (id.compare("all") == 0) {
-        itr = _molecules.begin();
-        if (itr == _molecules.end())
-            return;
-        doAll = true;
-    } else {
-        itr = _molecules.find(id);
-    }
-    if (itr == _molecules.end()) {
-        ERROR("Molecule not found: %s", id.c_str());
-        return;
-    }
-
-    do {
-        itr->second->setAtomVisibility(state);
-    } while (doAll && ++itr != _molecules.end());
-
-    sceneBoundsChanged();
-    _needsRedraw = true;
-}
-
-/**
- * \brief Turn on/off rendering of the Molecule atom labels for the given DataSet
- */
-void Renderer::setMoleculeAtomLabelVisibility(const DataSetId& id, bool state)
-{
-    MoleculeHashmap::iterator itr;
-
-    bool doAll = false;
-
-    if (id.compare("all") == 0) {
-        itr = _molecules.begin();
-        if (itr == _molecules.end())
-            return;
-        doAll = true;
-    } else {
-        itr = _molecules.find(id);
-    }
-    if (itr == _molecules.end()) {
-        ERROR("Molecule not found: %s", id.c_str());
-        return;
-    }
-
-    do {
-        itr->second->setAtomLabelVisibility(state);
-    } while (doAll && ++itr != _molecules.end());
-
-    sceneBoundsChanged();
-    _needsRedraw = true;
-}
-
-/**
- * \brief Set radius scale factor for atoms
- */
-void Renderer::setMoleculeBondRadiusScale(const DataSetId& id, double scale)
-{
-    MoleculeHashmap::iterator itr;
-
-    bool doAll = false;
-
-    if (id.compare("all") == 0) {
-        itr = _molecules.begin();
-        if (itr == _molecules.end())
-            return;
-        doAll = true;
-    } else {
-        itr = _molecules.find(id);
-    }
-    if (itr == _molecules.end()) {
-        ERROR("Molecule not found: %s", id.c_str());
-        return;
-    }
-
-    do {
-        itr->second->setBondRadiusScale(scale);
-    } while (doAll && ++itr != _molecules.end());
-
-    sceneBoundsChanged();
-    _needsRedraw = true;
-}
-
-/**
- * \brief Turn on/off rendering of the Molecule bonds for the given DataSet
- */
-void Renderer::setMoleculeBondVisibility(const DataSetId& id, bool state)
-{
-    MoleculeHashmap::iterator itr;
-
-    bool doAll = false;
-
-    if (id.compare("all") == 0) {
-        itr = _molecules.begin();
-        if (itr == _molecules.end())
-            return;
-        doAll = true;
-    } else {
-        itr = _molecules.find(id);
-    }
-    if (itr == _molecules.end()) {
-        ERROR("Molecule not found: %s", id.c_str());
-        return;
-    }
-
-    do {
-        itr->second->setBondVisibility(state);
-    } while (doAll && ++itr != _molecules.end());
-
-    sceneBoundsChanged();
-    _needsRedraw = true;
-}
-
-/**
- * \brief Set render style of the Molecule bonds for the given DataSet
- */
-void Renderer::setMoleculeBondStyle(const DataSetId& id, Molecule::BondStyle style)
-{
-    MoleculeHashmap::iterator itr;
-
-    bool doAll = false;
-
-    if (id.compare("all") == 0) {
-        itr = _molecules.begin();
-        if (itr == _molecules.end())
-            return;
-        doAll = true;
-    } else {
-        itr = _molecules.find(id);
-    }
-    if (itr == _molecules.end()) {
-        ERROR("Molecule not found: %s", id.c_str());
-        return;
-    }
-
-    do {
-        itr->second->setBondStyle(style);
-    } while (doAll && ++itr != _molecules.end());
-
-    sceneBoundsChanged();
-    _needsRedraw = true;
-}
-
-/**
- * \brief Set coloring mode of the Molecule bonds for the given DataSet
- */
-void Renderer::setMoleculeBondColorMode(const DataSetId& id, Molecule::BondColorMode mode)
-{
-    MoleculeHashmap::iterator itr;
-
-    bool doAll = false;
-
-    if (id.compare("all") == 0) {
-        itr = _molecules.begin();
-        if (itr == _molecules.end())
-            return;
-        doAll = true;
-    } else {
-        itr = _molecules.find(id);
-    }
-    if (itr == _molecules.end()) {
-        ERROR("Molecule not found: %s", id.c_str());
-        return;
-    }
-
-    do {
-        itr->second->setBondColorMode(mode);
-    } while (doAll && ++itr != _molecules.end());
-
-    _needsRedraw = true;
-}
-
-/**
- * \brief Set constant color of the Molecule bonds for the given DataSet
- */
-void Renderer::setMoleculeBondColor(const DataSetId& id, float color[3])
-{
-    MoleculeHashmap::iterator itr;
-
-    bool doAll = false;
-
-    if (id.compare("all") == 0) {
-        itr = _molecules.begin();
-        if (itr == _molecules.end())
-            return;
-        doAll = true;
-    } else {
-        itr = _molecules.find(id);
-    }
-    if (itr == _molecules.end()) {
-        ERROR("Molecule not found: %s", id.c_str());
-        return;
-    }
-
-    do {
-        itr->second->setBondColor(color);
-    } while (doAll && ++itr != _molecules.end());
-
-    _needsRedraw = true;
-}
-
-/**
- * \brief Set the color mode for the specified DataSet
- */
-void Renderer::setMoleculeColorMode(const DataSetId& id,
-                                    Molecule::ColorMode mode,
-                                    DataSet::DataAttributeType type,
-                                    const char *name, double range[2])
-{
-    MoleculeHashmap::iterator itr;
-
-    bool doAll = false;
-
-    if (id.compare("all") == 0) {
-        itr = _molecules.begin();
-        if (itr == _molecules.end())
-            return;
-        doAll = true;
-    } else {
-        itr = _molecules.find(id);
-    }
-    if (itr == _molecules.end()) {
-        ERROR("Molecule not found: %s", id.c_str());
-        return;
-    }
-
-    do {
-        itr->second->setColorMode(mode, type, name, range);
-    } while (doAll && ++itr != _molecules.end());
-
-    _needsRedraw = true;
-}
-
-/**
- * \brief Set the color mode for the specified DataSet
- */
-void Renderer::setMoleculeColorMode(const DataSetId& id,
-                                    Molecule::ColorMode mode,
-                                    const char *name, double range[2])
-{
-    MoleculeHashmap::iterator itr;
-
-    bool doAll = false;
-
-    if (id.compare("all") == 0) {
-        itr = _molecules.begin();
-        if (itr == _molecules.end())
-            return;
-        doAll = true;
-    } else {
-        itr = _molecules.find(id);
-    }
-    if (itr == _molecules.end()) {
-        ERROR("Molecule not found: %s", id.c_str());
-        return;
-    }
-
-    do {
-        itr->second->setColorMode(mode, name, range);
-    } while (doAll && ++itr != _molecules.end());
-
-    _needsRedraw = true;
-}
-
-/**
- * \brief Create a new n-sided regular Polygon and associate it with an ID
- */
-bool Renderer::addPolygon(const DataSetId& id, int numSides)
-{
-    Polygon *gobj;
-    if ((gobj = getGraphicsObject<Polygon>(id)) != NULL) {
-        WARN("Replacing existing %s %s", gobj->getClassName(), id.c_str());
-        deleteGraphicsObject<Polygon>(id);
-    }
-
-    gobj = new Polygon();
- 
-    gobj->setDataSet(NULL, this);
-
-    if (gobj->getProp() == NULL &&
-        gobj->getOverlayProp() == NULL) {
-        delete gobj;
-        return false;
-    } else {
-        if (gobj->getProp())
-            _renderer->AddViewProp(gobj->getProp());
-        if (gobj->getOverlayProp())
-            _renderer->AddViewProp(gobj->getOverlayProp());
-    }
-
-    gobj->setNumberOfSides(numSides);
-
-    getGraphicsObjectHashmap<Polygon>()[id] = gobj;
-
-    sceneBoundsChanged();
-    _needsRedraw = true;
-    return true;
-}
-
-/**
- * \brief Set the color mode for the specified DataSet
- */
-void Renderer::setPseudoColorColorMode(const DataSetId& id,
-                                       PseudoColor::ColorMode mode,
-                                       DataSet::DataAttributeType type,
-                                       const char *name, double range[2])
-{
-    PseudoColorHashmap::iterator itr;
-
-    bool doAll = false;
-
-    if (id.compare("all") == 0) {
-        itr = _pseudoColors.begin();
-        if (itr == _pseudoColors.end())
-            return;
-        doAll = true;
-    } else {
-        itr = _pseudoColors.find(id);
-    }
-    if (itr == _pseudoColors.end()) {
-        ERROR("PseudoColor not found: %s", id.c_str());
-        return;
-    }
-
-    do {
-        itr->second->setColorMode(mode, type, name, range);
-    } while (doAll && ++itr != _pseudoColors.end());
-
-    _needsRedraw = true;
-}
-
-/**
- * \brief Set the color mode for the specified DataSet
- */
-void Renderer::setPseudoColorColorMode(const DataSetId& id,
-                                       PseudoColor::ColorMode mode,
-                                       const char *name, double range[2])
-{
-    PseudoColorHashmap::iterator itr;
-
-    bool doAll = false;
-
-    if (id.compare("all") == 0) {
-        itr = _pseudoColors.begin();
-        if (itr == _pseudoColors.end())
-            return;
-        doAll = true;
-    } else {
-        itr = _pseudoColors.find(id);
-    }
-    if (itr == _pseudoColors.end()) {
-        ERROR("PseudoColor not found: %s", id.c_str());
-        return;
-    }
-
-    do {
-        itr->second->setColorMode(mode, name, range);
-    } while (doAll && ++itr != _pseudoColors.end());
-
-    _needsRedraw = true;
-}
-
-/**
- * \brief Set Sphere resolution
- */
-void Renderer::setSphereResolution(const DataSetId& id, int thetaRes, int phiRes)
-{
-    SphereHashmap::iterator itr;
-
-    bool doAll = false;
-
-    if (id.compare("all") == 0) {
-        itr = _spheres.begin();
-        if (itr == _spheres.end())
-            return;
-        doAll = true;
-    } else {
-        itr = _spheres.find(id);
-    }
-    if (itr == _spheres.end()) {
-        ERROR("Sphere not found: %s", id.c_str());
-        return;
-    }
-
-    do {
-        itr->second->setThetaResolution(thetaRes);
-        itr->second->setPhiResolution(phiRes);
-    } while (doAll && ++itr != _spheres.end());
-
-    sceneBoundsChanged();
-    _needsRedraw = true;
-}
-
-/**
- * \brief Set Sphere section
- */
-void Renderer::setSphereSection(const DataSetId& id, double thetaStart, double thetaEnd,
-                                double phiStart, double phiEnd)
-{
-    SphereHashmap::iterator itr;
-
-    bool doAll = false;
-
-    if (id.compare("all") == 0) {
-        itr = _spheres.begin();
-        if (itr == _spheres.end())
-            return;
-        doAll = true;
-    } else {
-        itr = _spheres.find(id);
-    }
-    if (itr == _spheres.end()) {
-        ERROR("Sphere not found: %s", id.c_str());
-        return;
-    }
-
-    do {
-        itr->second->setStartTheta(thetaStart);
-        itr->second->setEndTheta(thetaEnd);
-        itr->second->setStartPhi(phiStart);
-        itr->second->setEndPhi(phiEnd);
-    } while (doAll && ++itr != _spheres.end());
-
-    sceneBoundsChanged();
-    _needsRedraw = true;
-}
-
-/**
- * \brief Set the streamlines seed to points of the streamlines DataSet
- */
-void Renderer::setStreamlinesNumberOfSeedPoints(const DataSetId& id, int numPoints)
-{
-    StreamlinesHashmap::iterator itr;
-
-    bool doAll = false;
-
-    if (id.compare("all") == 0) {
-        itr = _streamlines.begin();
-        if (itr == _streamlines.end())
-            return;
-        doAll = true;
-    } else {
-        itr = _streamlines.find(id);
-    }
-    if (itr == _streamlines.end()) {
-        ERROR("Streamlines not found: %s", id.c_str());
-        return;
-    }
-
-    do {
-        itr->second->setNumberOfSeedPoints(numPoints);
-    } while (doAll && ++itr != _streamlines.end());
-
-    sceneBoundsChanged();
-    _needsRedraw = true;
-}
-
-/**
- * \brief Set the streamlines seed to points of the streamlines DataSet
- */
-void Renderer::setStreamlinesSeedToMeshPoints(const DataSetId& id)
-{
-    StreamlinesHashmap::iterator itr;
-
-    bool doAll = false;
-
-    if (id.compare("all") == 0) {
-        itr = _streamlines.begin();
-        if (itr == _streamlines.end())
-            return;
-        doAll = true;
-    } else {
-        itr = _streamlines.find(id);
-    }
-    if (itr == _streamlines.end()) {
-        ERROR("Streamlines not found: %s", id.c_str());
-        return;
-    }
-
-    do {
-        itr->second->setSeedToMeshPoints();
-    } while (doAll && ++itr != _streamlines.end());
-
-    sceneBoundsChanged();
-    _needsRedraw = true;
-}
-
-/**
- * \brief Set the streamlines seed to points distributed randomly inside
- * cells of the streamlines DataSet
- */
-void Renderer::setStreamlinesSeedToFilledMesh(const DataSetId& id, int numPoints)
-{
-    StreamlinesHashmap::iterator itr;
-
-    bool doAll = false;
-
-    if (id.compare("all") == 0) {
-        itr = _streamlines.begin();
-        if (itr == _streamlines.end())
-            return;
-        doAll = true;
-    } else {
-        itr = _streamlines.find(id);
-    }
-    if (itr == _streamlines.end()) {
-        ERROR("Streamlines not found: %s", id.c_str());
-        return;
-    }
-
-    do {
-        itr->second->setSeedToFilledMesh(numPoints);
-    } while (doAll && ++itr != _streamlines.end());
-
-    sceneBoundsChanged();
-    _needsRedraw = true;
-}
-
-/**
- * \brief Set the streamlines seed to points of a DataSet
- *
- * \param[in] id DataSet identifier
- * \param[in] data Bytes of VTK DataSet file
- * \param[in] nbytes Length of data array
- *
- * \return boolean indicating success or failure
- */
-bool Renderer::setStreamlinesSeedToMeshPoints(const DataSetId& id,
-                                              char *data, size_t nbytes)
-{
-    vtkSmartPointer<vtkDataSetReader> reader = vtkSmartPointer<vtkDataSetReader>::New();
-    vtkSmartPointer<vtkCharArray> dataSetString = vtkSmartPointer<vtkCharArray>::New();
-
-    dataSetString->SetArray(data, nbytes, 1);
-    reader->SetInputArray(dataSetString);
-    reader->ReadFromInputStringOn();
-    reader->Update();
-
-    vtkSmartPointer<vtkDataSet> dataSet = reader->GetOutput();
-    if (dataSet == NULL) {
-        return false;
-    }
-#ifndef USE_VTK6
-    dataSet->SetPipelineInformation(NULL);
-#endif
-    StreamlinesHashmap::iterator itr;
-
-    bool doAll = false;
-
-    if (id.compare("all") == 0) {
-        itr = _streamlines.begin();
-        doAll = true;
-    } else {
-        itr = _streamlines.find(id);
-    }
-    if (itr == _streamlines.end()) {
-        ERROR("Streamlines not found: %s", id.c_str());
-        return false;
-    }
-
-    do {
-        itr->second->setSeedToMeshPoints(dataSet);
-    } while (doAll && ++itr != _streamlines.end());
-
-    sceneBoundsChanged();
-    _needsRedraw = true;
-    return true;
-}
-
-/**
- * \brief Set the streamlines seed to points distributed randomly inside
- * cells of DataSet
- *
- * \param[in] id DataSet identifier
- * \param[in] data Bytes of VTK DataSet file
- * \param[in] nbytes Length of data array
- * \param[in] numPoints Number of random seed points to generate
- *
- * \return boolean indicating success or failure
- */
-bool Renderer::setStreamlinesSeedToFilledMesh(const DataSetId& id,
-                                              char *data, size_t nbytes,
-                                              int numPoints)
-{
-    vtkSmartPointer<vtkDataSetReader> reader = vtkSmartPointer<vtkDataSetReader>::New();
-    vtkSmartPointer<vtkCharArray> dataSetString = vtkSmartPointer<vtkCharArray>::New();
-
-    dataSetString->SetArray(data, nbytes, 1);
-    reader->SetInputArray(dataSetString);
-    reader->ReadFromInputStringOn();
-    reader->Update();
-
-    vtkSmartPointer<vtkDataSet> dataSet = reader->GetOutput();
-    if (dataSet == NULL) {
-        return false;
-    }
-#ifndef USE_VTK6
-    dataSet->SetPipelineInformation(NULL);
-#endif
-    StreamlinesHashmap::iterator itr;
-
-    bool doAll = false;
-
-    if (id.compare("all") == 0) {
-        itr = _streamlines.begin();
-        doAll = true;
-    } else {
-        itr = _streamlines.find(id);
-    }
-    if (itr == _streamlines.end()) {
-        ERROR("Streamlines not found: %s", id.c_str());
-        return false;
-    }
-
-    do {
-        itr->second->setSeedToFilledMesh(dataSet, numPoints);
-    } while (doAll && ++itr != _streamlines.end());
-
-    sceneBoundsChanged();
-    _needsRedraw = true;
-    return true;
-}
-
-/**
- * \brief Set the streamlines seed to points along a line
- */
-void Renderer::setStreamlinesSeedToRake(const DataSetId& id,
-                                        double start[3], double end[3],
-                                        int numPoints)
-{
-    StreamlinesHashmap::iterator itr;
-
-    bool doAll = false;
-
-    if (id.compare("all") == 0) {
-        itr = _streamlines.begin();
-        if (itr == _streamlines.end())
-            return;
-        doAll = true;
-    } else {
-        itr = _streamlines.find(id);
-    }
-    if (itr == _streamlines.end()) {
-        ERROR("Streamlines not found: %s", id.c_str());
-        return;
-    }
-
-    do {
-        itr->second->setSeedToRake(start, end, numPoints);
-    } while (doAll && ++itr != _streamlines.end());
-
-    sceneBoundsChanged();
-    _needsRedraw = true;
-}
-
-/**
- * \brief Set the streamlines seed to points inside a disk, with optional
- * hole
- */
-void Renderer::setStreamlinesSeedToDisk(const DataSetId& id,
-                                        double center[3], double normal[3],
-                                        double radius, double innerRadius,
-                                        int numPoints)
-{
-    StreamlinesHashmap::iterator itr;
-
-    bool doAll = false;
-
-    if (id.compare("all") == 0) {
-        itr = _streamlines.begin();
-        if (itr == _streamlines.end())
-            return;
-        doAll = true;
-    } else {
-        itr = _streamlines.find(id);
-    }
-    if (itr == _streamlines.end()) {
-        ERROR("Streamlines not found: %s", id.c_str());
-        return;
-    }
-
-    do {
-        itr->second->setSeedToDisk(center, normal, radius, innerRadius, numPoints);
-    } while (doAll && ++itr != _streamlines.end());
-
-    sceneBoundsChanged();
-    _needsRedraw = true;
-}
-
-/**
- * \brief Set the streamlines seed to vertices of an n-sided polygon
- */
-void Renderer::setStreamlinesSeedToPolygon(const DataSetId& id,
-                                           double center[3], double normal[3],
-                                           double angle, double radius,
-                                           int numSides)
-{
-    StreamlinesHashmap::iterator itr;
-
-    bool doAll = false;
-
-    if (id.compare("all") == 0) {
-        itr = _streamlines.begin();
-        if (itr == _streamlines.end())
-            return;
-        doAll = true;
-    } else {
-        itr = _streamlines.find(id);
-    }
-    if (itr == _streamlines.end()) {
-        ERROR("Streamlines not found: %s", id.c_str());
-        return;
-    }
-
-    do {
-        itr->second->setSeedToPolygon(center, normal, angle, radius, numSides);
-    } while (doAll && ++itr != _streamlines.end());
-
-    sceneBoundsChanged();
-    _needsRedraw = true;
-}
-
-/**
- * \brief Set the streamlines seed to vertices of an n-sided polygon
- */
-void Renderer::setStreamlinesSeedToFilledPolygon(const DataSetId& id,
-                                                 double center[3],
-                                                 double normal[3],
-                                                 double angle, double radius,
-                                                 int numSides, int numPoints)
-{
-    StreamlinesHashmap::iterator itr;
-
-    bool doAll = false;
-
-    if (id.compare("all") == 0) {
-        itr = _streamlines.begin();
-        if (itr == _streamlines.end())
-            return;
-        doAll = true;
-    } else {
-        itr = _streamlines.find(id);
-    }
-    if (itr == _streamlines.end()) {
-        ERROR("Streamlines not found: %s", id.c_str());
-        return;
-    }
-
-    do {
-        itr->second->setSeedToFilledPolygon(center, normal, angle,
-                                            radius, numSides, numPoints);
-    } while (doAll && ++itr != _streamlines.end());
-
-    sceneBoundsChanged();
-    _needsRedraw = true;
-}
-
-/**
- * \brief Set Streamlines rendering to polylines for the specified DataSet
- */
-void Renderer::setStreamlinesTypeToLines(const DataSetId& id)
-{
-    StreamlinesHashmap::iterator itr;
-
-    bool doAll = false;
-
-    if (id.compare("all") == 0) {
-        itr = _streamlines.begin();
-        if (itr == _streamlines.end())
-            return;
-        doAll = true;
-    } else {
-        itr = _streamlines.find(id);
-    }
-    if (itr == _streamlines.end()) {
-        ERROR("Streamlines not found: %s", id.c_str());
-        return;
-    }
-
-    do {
-        itr->second->setLineTypeToLines();
-    } while (doAll && ++itr != _streamlines.end());
-
-    sceneBoundsChanged();
-    _needsRedraw = true;
-}
-
-/**
- * \brief Set Streamlines rendering to tubes for the specified DataSet
- */
-void Renderer::setStreamlinesTypeToTubes(const DataSetId& id, int numSides, double radius)
-{
-    StreamlinesHashmap::iterator itr;
-
-    bool doAll = false;
-
-    if (id.compare("all") == 0) {
-        itr = _streamlines.begin();
-        if (itr == _streamlines.end())
-            return;
-        doAll = true;
-    } else {
-        itr = _streamlines.find(id);
-    }
-    if (itr == _streamlines.end()) {
-        ERROR("Streamlines not found: %s", id.c_str());
-        return;
-    }
-
-    do {
-        itr->second->setLineTypeToTubes(numSides, radius);
-    } while (doAll && ++itr != _streamlines.end());
-
-    sceneBoundsChanged();
-    _needsRedraw = true;
-}
-
-/**
- * \brief Set Streamlines rendering to ribbons for the specified DataSet
- */
-void Renderer::setStreamlinesTypeToRibbons(const DataSetId& id, double width, double angle)
-{
-    StreamlinesHashmap::iterator itr;
-
-    bool doAll = false;
-
-    if (id.compare("all") == 0) {
-        itr = _streamlines.begin();
-        if (itr == _streamlines.end())
-            return;
-        doAll = true;
-    } else {
-        itr = _streamlines.find(id);
-    }
-    if (itr == _streamlines.end()) {
-        ERROR("Streamlines not found: %s", id.c_str());
-        return;
-    }
-
-    do {
-        itr->second->setLineTypeToRibbons(width, angle);
-    } while (doAll && ++itr != _streamlines.end());
-
-    sceneBoundsChanged();
-    _needsRedraw = true;
-}
-
-/**
- * \brief Set Streamlines maximum length for the specified DataSet
- */
-void Renderer::setStreamlinesLength(const DataSetId& id, double length)
-{
-    StreamlinesHashmap::iterator itr;
-
-    bool doAll = false;
-
-    if (id.compare("all") == 0) {
-        itr = _streamlines.begin();
-        if (itr == _streamlines.end())
-            return;
-        doAll = true;
-    } else {
-        itr = _streamlines.find(id);
-    }
-    if (itr == _streamlines.end()) {
-        ERROR("Streamlines not found: %s", id.c_str());
-        return;
-    }
-
-    do {
-        itr->second->setMaxPropagation(length);
-    } while (doAll && ++itr != _streamlines.end());
-
-    sceneBoundsChanged();
-    _needsRedraw = true;
-}
-
-/**
- * \brief Turn on/off rendering of the Streamlines seed geometry for the given DataSet
- */
-void Renderer::setStreamlinesSeedVisibility(const DataSetId& id, bool state)
-{
-    StreamlinesHashmap::iterator itr;
-
-    bool doAll = false;
-
-    if (id.compare("all") == 0) {
-        itr = _streamlines.begin();
-        if (itr == _streamlines.end())
-            return;
-        doAll = true;
-    } else {
-        itr = _streamlines.find(id);
-    }
-    if (itr == _streamlines.end()) {
-        ERROR("Streamlines not found: %s", id.c_str());
-        return;
-    }
-
-    do {
-        itr->second->setSeedVisibility(state);
-    } while (doAll && ++itr != _streamlines.end());
-
-    sceneBoundsChanged();
-    _needsRedraw = true;
-}
-
-/**
- * \brief Set the color mode for the specified DataSet
- */
-void Renderer::setStreamlinesColorMode(const DataSetId& id,
-                                       Streamlines::ColorMode mode,
-                                       DataSet::DataAttributeType type,
-                                       const char *name, double range[2])
-{
-    StreamlinesHashmap::iterator itr;
-
-    bool doAll = false;
-
-    if (id.compare("all") == 0) {
-        itr = _streamlines.begin();
-        if (itr == _streamlines.end())
-            return;
-        doAll = true;
-    } else {
-        itr = _streamlines.find(id);
-    }
-    if (itr == _streamlines.end()) {
-        ERROR("Streamlines not found: %s", id.c_str());
-        return;
-    }
-
-    do {
-        itr->second->setColorMode(mode, type, name, range);
-    } while (doAll && ++itr != _streamlines.end());
-
-    _needsRedraw = true;
-}
-
-/**
- * \brief Set the color mode for the specified DataSet
- */
-void Renderer::setStreamlinesColorMode(const DataSetId& id,
-                                       Streamlines::ColorMode mode,
-                                       const char *name, double range[2])
-{
-    StreamlinesHashmap::iterator itr;
-
-    bool doAll = false;
-
-    if (id.compare("all") == 0) {
-        itr = _streamlines.begin();
-        if (itr == _streamlines.end())
-            return;
-        doAll = true;
-    } else {
-        itr = _streamlines.find(id);
-    }
-    if (itr == _streamlines.end()) {
-        ERROR("Streamlines not found: %s", id.c_str());
-        return;
-    }
-
-    do {
-        itr->second->setColorMode(mode, name, range);
-    } while (doAll && ++itr != _streamlines.end());
-
-    _needsRedraw = true;
-}
-
-/**
- * \brief Set the RGB line/edge color for the specified DataSet
- */
-void Renderer::setStreamlinesSeedColor(const DataSetId& id, float color[3])
-{
-    StreamlinesHashmap::iterator itr;
-
-    bool doAll = false;
-
-    if (id.compare("all") == 0) {
-        itr = _streamlines.begin();
-        if (itr == _streamlines.end())
-            return;
-        doAll = true;
-    } else {
-        itr = _streamlines.find(id);
-    }
-    if (itr == _streamlines.end()) {
-        ERROR("Streamlines not found: %s", id.c_str());
-        return;
-    }
-
-    do {
-        itr->second->setSeedColor(color);
-    } while (doAll && ++itr != _streamlines.end());
-
-    _needsRedraw = true;
-}
-
-/**
- * \brief Set the sample rate for the volume shader
- *
- * Smaller values will give better rendering at the cost
- * of slower rendering
- */
-void Renderer::setVolumeSampleDistance(const DataSetId& id, double distance)
-{
-    VolumeHashmap::iterator itr;
-
-    bool doAll = false;
-
-    if (id.compare("all") == 0) {
-        itr = _volumes.begin();
-        if (itr == _volumes.end())
-            return;
-        doAll = true;
-    } else {
-        itr = _volumes.find(id);
-    }
-    if (itr == _volumes.end()) {
-        ERROR("Volume not found: %s", id.c_str());
-        return;
-    }
-
-    do {
-        distance *= itr->second->getAverageSpacing();
-        itr->second->setSampleDistance((float)distance);
-    } while (doAll && ++itr != _volumes.end());
-
-    _needsRedraw = true;
-}
-
-/**
- * \brief Set the color mode for the specified DataSet
- */
-void Renderer::setWarpColorMode(const DataSetId& id,
-                                Warp::ColorMode mode,
-                                DataSet::DataAttributeType type,
-                                const char *name, double range[2])
-{
-    WarpHashmap::iterator itr;
-
-    bool doAll = false;
-
-    if (id.compare("all") == 0) {
-        itr = _warps.begin();
-        if (itr == _warps.end())
-            return;
-        doAll = true;
-    } else {
-        itr = _warps.find(id);
-    }
-    if (itr == _warps.end()) {
-        ERROR("Warp not found: %s", id.c_str());
-        return;
-    }
-
-    do {
-        itr->second->setColorMode(mode, type, name, range);
-    } while (doAll && ++itr != _warps.end());
-
-    _needsRedraw = true;
-}
-
-/**
- * \brief Set the color mode for the specified DataSet
- */
-void Renderer::setWarpColorMode(const DataSetId& id,
-                                Warp::ColorMode mode,
-                                const char *name, double range[2])
-{
-    WarpHashmap::iterator itr;
-
-    bool doAll = false;
-
-    if (id.compare("all") == 0) {
-        itr = _warps.begin();
-        if (itr == _warps.end())
-            return;
-        doAll = true;
-    } else {
-        itr = _warps.find(id);
-    }
-    if (itr == _warps.end()) {
-        ERROR("Warp not found: %s", id.c_str());
-        return;
-    }
-
-    do {
-        itr->second->setColorMode(mode, name, range);
-    } while (doAll && ++itr != _warps.end());
-
-    _needsRedraw = true;
-}
-
-/**
- * \brief Set amount to scale vector magnitudes when warping
- * a mesh
- */
-void Renderer::setWarpWarpScale(const DataSetId& id, double scale)
-{
-    WarpHashmap::iterator itr;
-
-    bool doAll = false;
-
-    if (id.compare("all") == 0) {
-        itr = _warps.begin();
-        if (itr == _warps.end())
-            return;
-        doAll = true;
-    } else {
-        itr = _warps.find(id);
-    }
-
-    if (itr == _warps.end()) {
-        ERROR("Warp not found: %s", id.c_str());
-        return;
-    }
-
-    do {
-        itr->second->setWarpScale(scale);
-     } while (doAll && ++itr != _warps.end());
-
-    sceneBoundsChanged();
-    _needsRedraw = true;
-}
Index: unk/packages/vizservers/vtkvis/RpVtkRendererGraphicsObjs.h
===================================================================
--- /trunk/packages/vizservers/vtkvis/RpVtkRendererGraphicsObjs.h	(revision 3615)
+++ 	(revision )
@@ -1,1027 +1,0 @@
-/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
-/*
- * Copyright (C) 2004-2012  HUBzero Foundation, LLC
- *
- * Author: Leif Delgass <ldelgass@purdue.edu>
- */
-
-#ifndef VTKVIS_RENDERER_GRAPHICS_OBJS_H
-#define VTKVIS_RENDERER_GRAPHICS_OBJS_H
-
-#include <tr1/unordered_map>
-#include <typeinfo>
-
-// Use GCC/G++ specific name demangling
-#define DEMANGLE
-
-#ifdef DEMANGLE
-#include <cstdlib>
-#include <cxxabi.h>
-#define GO_TRACE(go, format, ...)                                            \
-do {                                                                         \
-    int status;                                                              \
-    char * typeName = abi::__cxa_demangle(typeid(go).name(), 0, 0, &status); \
-    TRACE("%s " format, typeName, __VA_ARGS__);                              \
-    free(typeName);                                                          \
-} while (0)
-
-#define GO_ERROR(go, format, ...)                                            \
-do {                                                                         \
-    int status;                                                              \
-    char * typeName = abi::__cxa_demangle(typeid(go).name(), 0, 0, &status); \
-    ERROR("%s " format, typeName, __VA_ARGS__);                              \
-    free(typeName);                                                          \
-} while (0)
-#else
-#define GO_TRACE(go, format, ...) TRACE("%s " format, typeid(go).name(), __VA_ARGS__);
-#define GO_ERROR(go, format, ...) ERROR("%s " format, typeid(go).name(), __VA_ARGS__);
-#endif
-
-#include "RpVtkRenderer.h"
-
-namespace VtkVis {
-
-/**
- * \brief Look up graphics object by name
- */
-template<class GraphicsObject>
-GraphicsObject *Renderer::getGraphicsObject(const DataSetId& id)
-{
-    std::tr1::unordered_map<DataSetId, GraphicsObject *>& hashmap =
-        getGraphicsObjectHashmap<GraphicsObject>();
-    typename std::tr1::unordered_map<DataSetId, GraphicsObject *>::iterator
-        itr = hashmap.find(id);
-
-    if (itr == hashmap.end()) {
-#ifdef DEBUG
-        GO_TRACE(GraphicsObject, "not found: %s", id.c_str());
-#endif
-        return NULL;
-    } else
-        return itr->second;
-}
-
-/**
- * \brief Delete graphics object by name
- */
-template<class GraphicsObject>
-void Renderer::deleteGraphicsObject(const DataSetId& id)
-{
-    std::tr1::unordered_map<DataSetId, GraphicsObject *>& hashmap =
-        getGraphicsObjectHashmap<GraphicsObject>();
-    typename std::tr1::unordered_map<DataSetId, GraphicsObject *>::iterator itr;
-
-    bool doAll = false;
-
-    if (id.compare("all") == 0) {
-        itr = hashmap.begin();
-        doAll = true;
-    } else {
-        itr = hashmap.find(id);
-    }
-    if (itr == hashmap.end()) {
-        GO_ERROR(GraphicsObject, "not found: %s", id.c_str());
-        return;
-    }
-
-    TRACE("Deleting %s for %s", itr->second->getClassName(), id.c_str());
-
-    do {
-        GraphicsObject *gobj = itr->second;
-        if (gobj->getProp())
-            _renderer->RemoveViewProp(gobj->getProp());
-        if (gobj->getOverlayProp())
-            _renderer->RemoveViewProp(gobj->getOverlayProp());
-        delete gobj;
-
-        itr = hashmap.erase(itr);
-    } while (doAll && itr != hashmap.end());
-
-    sceneBoundsChanged();
-    _needsRedraw = true;
-}
-
-/**
- * \brief Delete all graphics objects from renderer
- */
-template<class GraphicsObject>
-void Renderer::deleteAllGraphicsObjects()
-{
-    std::tr1::unordered_map<DataSetId, GraphicsObject *>& hashmap =
-        getGraphicsObjectHashmap<GraphicsObject>();
-    typename std::tr1::unordered_map<DataSetId, GraphicsObject *>::iterator itr;
-
-    itr = hashmap.begin();
-    if (itr == hashmap.end())
-        return;
-
-    TRACE("Deleting all %s objects", itr->second->getClassName());
-
-    for (; itr != hashmap.end(); ++itr) {
-        delete itr->second;
-    }
-    hashmap.clear();
-}
-
-/**
- * \brief Add a graphics objects to the renderer's scene
- */
-template<class GraphicsObject>
-bool Renderer::addGraphicsObject(const DataSetId& id)
-{
-    DataSetHashmap::iterator itr;
-
-    bool doAll = false;
-
-    if (id.compare("all") == 0) {
-        itr = _dataSets.begin();
-    } else {
-        itr = _dataSets.find(id);
-    }
-    if (itr == _dataSets.end()) {
-        ERROR("Unknown dataset %s", id.c_str());
-        return false;
-    }
-
-    do {
-        DataSet *ds = itr->second;
-        const DataSetId& dsID = ds->getName();
-
-        GraphicsObject *gobj;
-        if ((gobj = getGraphicsObject<GraphicsObject>(dsID)) != NULL) {
-            WARN("Replacing existing %s %s", gobj->getClassName(), dsID.c_str());
-            deleteGraphicsObject<GraphicsObject>(dsID);
-        }
-
-        gobj = new GraphicsObject();
- 
-        gobj->setDataSet(ds, this);
-
-        if (gobj->getProp() == NULL &&
-            gobj->getOverlayProp() == NULL) {
-            delete gobj;
-            return false;
-        } else {
-            if (gobj->getProp())
-                _renderer->AddViewProp(gobj->getProp());
-            if (gobj->getOverlayProp())
-                _renderer->AddViewProp(gobj->getOverlayProp());
-        }
-
-        getGraphicsObjectHashmap<GraphicsObject>()[dsID] = gobj;
-    } while (doAll && ++itr != _dataSets.end());
-
-    sceneBoundsChanged();
-    _needsRedraw = true;
-    return true;
-}
-
-/**
- * \brief Set the prop orientation with a quaternion
- */
-template<class GraphicsObject>
-void Renderer::setGraphicsObjectTransform(const DataSetId& id, vtkMatrix4x4 *trans)
-{
-    std::tr1::unordered_map<DataSetId, GraphicsObject *>& hashmap = 
-        getGraphicsObjectHashmap<GraphicsObject>();
-    typename std::tr1::unordered_map<DataSetId, GraphicsObject *>::iterator itr;
-
-    bool doAll = false;
-
-    if (id.compare("all") == 0) {
-        itr = hashmap.begin();
-        if (itr == hashmap.end())
-            return;
-        doAll = true;
-    } else {
-        itr = hashmap.find(id);
-    }
-    if (itr == hashmap.end()) {
-        GO_ERROR(GraphicsObject, "not found: %s", id.c_str());
-        return;
-    }
-
-    do {
-        itr->second->setTransform(trans);
-    } while (doAll && ++itr != hashmap.end());
-
-    sceneBoundsChanged();
-    _needsRedraw = true;
-}
-
-/**
- * \brief Set the prop orientation with a quaternion
- */
-template<class GraphicsObject>
-void Renderer::setGraphicsObjectOrientation(const DataSetId& id, double quat[4])
-{
-    std::tr1::unordered_map<DataSetId, GraphicsObject *>& hashmap = 
-        getGraphicsObjectHashmap<GraphicsObject>();
-    typename std::tr1::unordered_map<DataSetId, GraphicsObject *>::iterator itr;
-
-    bool doAll = false;
-
-    if (id.compare("all") == 0) {
-        itr = hashmap.begin();
-        if (itr == hashmap.end())
-            return;
-        doAll = true;
-    } else {
-        itr = hashmap.find(id);
-    }
-    if (itr == hashmap.end()) {
-        GO_ERROR(GraphicsObject, "not found: %s", id.c_str());
-        return;
-    }
-
-    do {
-        itr->second->setOrientation(quat);
-    } while (doAll && ++itr != hashmap.end());
-
-    sceneBoundsChanged();
-    _needsRedraw = true;
-}
-
-/**
- * \brief Set the prop orientation with a rotation about an axis
- */
-template<class GraphicsObject>
-void Renderer::setGraphicsObjectOrientation(const DataSetId& id, double angle, double axis[3])
-{
-    std::tr1::unordered_map<DataSetId, GraphicsObject *>& hashmap = 
-        getGraphicsObjectHashmap<GraphicsObject>();
-    typename std::tr1::unordered_map<DataSetId, GraphicsObject *>::iterator itr;
-
-    bool doAll = false;
-
-    if (id.compare("all") == 0) {
-        itr = hashmap.begin();
-        if (itr == hashmap.end())
-            return;
-        doAll = true;
-    } else {
-        itr = hashmap.find(id);
-    }
-    if (itr == hashmap.end()) {
-        GO_ERROR(GraphicsObject, "not found: %s", id.c_str());
-        return;
-    }
-
-    do {
-        itr->second->setOrientation(angle, axis);
-    } while (doAll && ++itr != hashmap.end());
-
-    sceneBoundsChanged();
-    _needsRedraw = true;
-}
-
-/**
- * \brief Set the prop position in world coords
- */
-template<class GraphicsObject>
-void Renderer::setGraphicsObjectPosition(const DataSetId& id, double pos[3])
-{
-    std::tr1::unordered_map<DataSetId, GraphicsObject *>& hashmap = 
-        getGraphicsObjectHashmap<GraphicsObject>();
-    typename std::tr1::unordered_map<DataSetId, GraphicsObject *>::iterator itr;
-
-    bool doAll = false;
-
-    if (id.compare("all") == 0) {
-        itr = hashmap.begin();
-        if (itr == hashmap.end())
-            return;
-        doAll = true;
-    } else {
-        itr = hashmap.find(id);
-    }
-    if (itr == hashmap.end()) {
-        GO_ERROR(GraphicsObject, "not found: %s", id.c_str());
-        return;
-    }
-
-    do {
-        itr->second->setPosition(pos);
-    } while (doAll && ++itr != hashmap.end());
-
-    sceneBoundsChanged();
-    _needsRedraw = true;
-}
-
-/**
- * \brief Set the prop scaling based on a 2D aspect ratio
- *
- * \param id The name of the DataSet
- * \param aspect The aspect ratio (width/height), zero means native aspect
- */
-template<class GraphicsObject>
-void Renderer::setGraphicsObjectAspect(const DataSetId& id, double aspect)
-{
-    std::tr1::unordered_map<DataSetId, GraphicsObject *>& hashmap = 
-        getGraphicsObjectHashmap<GraphicsObject>();
-    typename std::tr1::unordered_map<DataSetId, GraphicsObject *>::iterator itr;
-
-    bool doAll = false;
-
-    if (id.compare("all") == 0) {
-        itr = hashmap.begin();
-        if (itr == hashmap.end())
-            return;
-        doAll = true;
-    } else {
-        itr = hashmap.find(id);
-    }
-    if (itr == hashmap.end()) {
-        GO_ERROR(GraphicsObject, "not found: %s", id.c_str());
-        return;
-    }
-
-    do {
-        itr->second->setAspect(aspect);
-    } while (doAll && ++itr != hashmap.end());
-
-    sceneBoundsChanged();
-    _needsRedraw = true;
-}
-
-/**
- * \brief Set the prop scaling
- */
-template<class GraphicsObject>
-void Renderer::setGraphicsObjectScale(const DataSetId& id, double scale[3])
-{
-    std::tr1::unordered_map<DataSetId, GraphicsObject *>& hashmap = 
-        getGraphicsObjectHashmap<GraphicsObject>();
-    typename std::tr1::unordered_map<DataSetId, GraphicsObject *>::iterator itr;
-
-    bool doAll = false;
-
-    if (id.compare("all") == 0) {
-        itr = hashmap.begin();
-        if (itr == hashmap.end())
-            return;
-        doAll = true;
-    } else {
-        itr = hashmap.find(id);
-    }
-    if (itr == hashmap.end()) {
-        GO_ERROR(GraphicsObject, "not found: %s", id.c_str());
-        return;
-    }
-
-    do {
-        itr->second->setScale(scale);
-    } while (doAll && ++itr != hashmap.end());
-
-    sceneBoundsChanged();
-    _needsRedraw = true;
-}
-
-/**
- * \brief Set visibility of VtkGraphicsObject for the given DataSet
- */
-template<class GraphicsObject>
-void Renderer::setGraphicsObjectVisibility(const DataSetId& id, bool state)
-{
-    std::tr1::unordered_map<DataSetId, GraphicsObject *>& hashmap =
-        getGraphicsObjectHashmap<GraphicsObject>();
-    typename std::tr1::unordered_map<DataSetId, GraphicsObject *>::iterator itr;
-
-    bool doAll = false;
-
-    if (id.compare("all") == 0) {
-        itr = hashmap.begin();
-        if (itr == hashmap.end())
-            return;
-        doAll = true;
-    } else {
-        itr = hashmap.find(id);
-    }
-    if (itr == hashmap.end()) {
-        GO_ERROR(GraphicsObject, "not found: %s", id.c_str());
-        return;
-    }
-
-    do {
-        itr->second->setVisibility(state);
-    } while (doAll && ++itr != hashmap.end());
-
-    sceneBoundsChanged();
-    _needsRedraw = true;
-}
-
-/**
- * \brief Set the volume slice
- */
-template<class GraphicsObject>
-void Renderer::setGraphicsObjectVolumeSlice(const DataSetId& id, Axis axis, double ratio)
-{
-    std::tr1::unordered_map<DataSetId, GraphicsObject *>& hashmap = 
-        getGraphicsObjectHashmap<GraphicsObject>();
-    typename std::tr1::unordered_map<DataSetId, GraphicsObject *>::iterator itr;
-
-    bool doAll = false;
-
-    if (id.compare("all") == 0) {
-        itr = hashmap.begin();
-        if (itr == hashmap.end())
-            return;
-        doAll = true;
-    } else {
-        itr = hashmap.find(id);
-    }
-
-    if (itr == hashmap.end()) {
-        GO_ERROR(GraphicsObject, "not found: %s", id.c_str());
-        return;
-    }
-
-    do {
-        itr->second->selectVolumeSlice(axis, ratio);
-     } while (doAll && ++itr != hashmap.end());
-
-    sceneBoundsChanged();
-    _needsRedraw = true;
-}
-
-
-/**
- * \brief Set the RGB actor color for the specified DataSet
- */
-template<class GraphicsObject>
-void Renderer::setGraphicsObjectColor(const DataSetId& id, float color[3])
-{
-    std::tr1::unordered_map<DataSetId, GraphicsObject *>& hashmap = 
-        getGraphicsObjectHashmap<GraphicsObject>();
-    typename std::tr1::unordered_map<DataSetId, GraphicsObject *>::iterator itr;
-
-    bool doAll = false;
-
-    if (id.compare("all") == 0) {
-        itr = hashmap.begin();
-        if (itr == hashmap.end())
-            return;
-        doAll = true;
-    } else {
-        itr = hashmap.find(id);
-    }
-    if (itr == hashmap.end()) {
-        GO_ERROR(GraphicsObject, "not found: %s", id.c_str());
-        return;
-    }
-
-    do {
-        itr->second->setColor(color);
-    } while (doAll && ++itr != hashmap.end());
-
-    _needsRedraw = true;
-}
-
-/**
- * \brief Turn on/off edges for the given DataSet
- */
-template<class GraphicsObject>
-void Renderer::setGraphicsObjectEdgeVisibility(const DataSetId& id, bool state)
-{
-    std::tr1::unordered_map<DataSetId, GraphicsObject *>& hashmap = 
-        getGraphicsObjectHashmap<GraphicsObject>();
-    typename std::tr1::unordered_map<DataSetId, GraphicsObject *>::iterator itr;
-
-    bool doAll = false;
-
-    if (id.compare("all") == 0) {
-        itr = hashmap.begin();
-        if (itr == hashmap.end())
-            return;
-        doAll = true;
-    } else {
-        itr = hashmap.find(id);
-    }
-    if (itr == hashmap.end()) {
-        GO_ERROR(GraphicsObject, "not found: %s", id.c_str());
-        return;
-    }
-
-    do {
-        itr->second->setEdgeVisibility(state);
-    } while (doAll && ++itr != hashmap.end());
-
-    sceneBoundsChanged();
-    _needsRedraw = true;
-}
-
-/**
- * \brief Set the RGB isosurface edge color for the specified DataSet
- */
-template<class GraphicsObject>
-void Renderer::setGraphicsObjectEdgeColor(const DataSetId& id, float color[3])
-{
-    std::tr1::unordered_map<DataSetId, GraphicsObject *>& hashmap = 
-        getGraphicsObjectHashmap<GraphicsObject>();
-    typename std::tr1::unordered_map<DataSetId, GraphicsObject *>::iterator itr;
-
-    bool doAll = false;
-
-    if (id.compare("all") == 0) {
-        itr = hashmap.begin();
-        if (itr == hashmap.end())
-            return;
-        doAll = true;
-    } else {
-        itr = hashmap.find(id);
-    }
-    if (itr == hashmap.end()) {
-        GO_ERROR(GraphicsObject, "not found: %s", id.c_str());
-        return;
-    }
-
-    do {
-        itr->second->setEdgeColor(color);
-    } while (doAll && ++itr != hashmap.end());
-
-    _needsRedraw = true;
-}
-
-/**
- * \brief Set the isosurface edge width for the specified DataSet (may be a no-op)
- *
- * If the OpenGL implementation/hardware does not support wide lines, 
- * this function may not have an effect.
- */
-template<class GraphicsObject>
-void Renderer::setGraphicsObjectEdgeWidth(const DataSetId& id, float edgeWidth)
-{
-    std::tr1::unordered_map<DataSetId, GraphicsObject *>& hashmap = 
-        getGraphicsObjectHashmap<GraphicsObject>();
-    typename std::tr1::unordered_map<DataSetId, GraphicsObject *>::iterator itr;
-
-    bool doAll = false;
-
-    if (id.compare("all") == 0) {
-        itr = hashmap.begin();
-        if (itr == hashmap.end())
-            return;
-        doAll = true;
-    } else {
-        itr = hashmap.find(id);
-    }
-    if (itr == hashmap.end()) {
-        GO_ERROR(GraphicsObject, "not found: %s", id.c_str());
-        return;
-    }
-
-    do {
-        itr->second->setEdgeWidth(edgeWidth);
-    } while (doAll && ++itr != hashmap.end());
-
-    sceneBoundsChanged();
-    _needsRedraw = true;
-}
-
-/**
- * \brief Set ambient lighting/shading coefficient for the specified DataSet
- */
-template<class GraphicsObject>
-void Renderer::setGraphicsObjectAmbient(const DataSetId& id, double coeff)
-{
-    std::tr1::unordered_map<DataSetId, GraphicsObject *>& hashmap = 
-        getGraphicsObjectHashmap<GraphicsObject>();
-    typename std::tr1::unordered_map<DataSetId, GraphicsObject *>::iterator itr;
-
-    bool doAll = false;
-
-    if (id.compare("all") == 0) {
-        itr = hashmap.begin();
-        if (itr == hashmap.end())
-            return;
-        doAll = true;
-    } else {
-        itr = hashmap.find(id);
-    }
-    if (itr == hashmap.end()) {
-        GO_ERROR(GraphicsObject, "not found: %s", id.c_str());
-        return;
-    }
-
-    do {
-        itr->second->setAmbient(coeff);
-    } while (doAll && ++itr != hashmap.end());
-
-    _needsRedraw = true;
-}
-
-/**
- * \brief Set diffuse lighting/shading coefficient for the specified DataSet
- */
-template<class GraphicsObject>
-void Renderer::setGraphicsObjectDiffuse(const DataSetId& id, double coeff)
-{
-    std::tr1::unordered_map<DataSetId, GraphicsObject *>& hashmap = 
-        getGraphicsObjectHashmap<GraphicsObject>();
-    typename std::tr1::unordered_map<DataSetId, GraphicsObject *>::iterator itr;
-
-    bool doAll = false;
-
-    if (id.compare("all") == 0) {
-        itr = hashmap.begin();
-        if (itr == hashmap.end())
-            return;
-        doAll = true;
-    } else {
-        itr = hashmap.find(id);
-    }
-    if (itr == hashmap.end()) {
-        GO_ERROR(GraphicsObject, "not found: %s", id.c_str());
-        return;
-    }
-
-    do {
-        itr->second->setDiffuse(coeff);
-    } while (doAll && ++itr != hashmap.end());
-
-    _needsRedraw = true;
-}
-
-/**
- * \brief Set specular lighting/shading coefficient and power for the specified DataSet
- */
-template<class GraphicsObject>
-void Renderer::setGraphicsObjectSpecular(const DataSetId& id, double coeff, double power)
-{
-    std::tr1::unordered_map<DataSetId, GraphicsObject *>& hashmap = 
-        getGraphicsObjectHashmap<GraphicsObject>();
-    typename std::tr1::unordered_map<DataSetId, GraphicsObject *>::iterator itr;
-
-    bool doAll = false;
-
-    if (id.compare("all") == 0) {
-        itr = hashmap.begin();
-        if (itr == hashmap.end())
-            return;
-        doAll = true;
-    } else {
-        itr = hashmap.find(id);
-    }
-    if (itr == hashmap.end()) {
-        GO_ERROR(GraphicsObject, "not found: %s", id.c_str());
-        return;
-    }
-
-    do {
-        itr->second->setSpecular(coeff, power);
-    } while (doAll && ++itr != hashmap.end());
-
-    _needsRedraw = true;
-}
-
-/**
- * \brief Turn actor lighting on/off for the specified DataSet
- */
-template<class GraphicsObject>
-void Renderer::setGraphicsObjectLighting(const DataSetId& id, bool state)
-{
-    std::tr1::unordered_map<DataSetId, GraphicsObject *>& hashmap = 
-        getGraphicsObjectHashmap<GraphicsObject>();
-    typename std::tr1::unordered_map<DataSetId, GraphicsObject *>::iterator itr;
-
-    bool doAll = false;
-
-    if (id.compare("all") == 0) {
-        itr = hashmap.begin();
-        if (itr == hashmap.end())
-            return;
-        doAll = true;
-    } else {
-        itr = hashmap.find(id);
-    }
-    if (itr == hashmap.end()) {
-        GO_ERROR(GraphicsObject, "not found: %s", id.c_str());
-        return;
-    }
-
-    do {
-        itr->second->setLighting(state);
-    } while (doAll && ++itr != hashmap.end());
-
-    _needsRedraw = true;
-}
-
-/**
- * \brief Set opacity of VtkGraphicsObject for the given DataSet
- */
-template<class GraphicsObject>
-void Renderer::setGraphicsObjectOpacity(const DataSetId& id, double opacity)
-{
-    std::tr1::unordered_map<DataSetId, GraphicsObject *>& hashmap = 
-        getGraphicsObjectHashmap<GraphicsObject>();
-    typename std::tr1::unordered_map<DataSetId, GraphicsObject *>::iterator itr;
-
-    bool doAll = false;
-
-    if (id.compare("all") == 0) {
-        itr = hashmap.begin();
-        if (itr == hashmap.end())
-            return;
-        doAll = true;
-    } else {
-        itr = hashmap.find(id);
-    }
-    if (itr == hashmap.end()) {
-        GO_ERROR(GraphicsObject, "not found: %s", id.c_str());
-        return;
-    }
-
-    do {
-        itr->second->setOpacity(opacity);
-    } while (doAll && ++itr != hashmap.end());
-
-    _needsRedraw = true;
-}
-
-/**
- * \brief Set the point size for the specified DataSet (may be a no-op)
- *
- * If the OpenGL implementation/hardware does not support wide points, 
- * this function may not have an effect.
- */
-template<class GraphicsObject>
-void Renderer::setGraphicsObjectPointSize(const DataSetId& id, float size)
-{
-    std::tr1::unordered_map<DataSetId, GraphicsObject *>& hashmap = 
-        getGraphicsObjectHashmap<GraphicsObject>();
-    typename std::tr1::unordered_map<DataSetId, GraphicsObject *>::iterator itr;
-
-    bool doAll = false;
-
-    if (id.compare("all") == 0) {
-        itr = hashmap.begin();
-        if (itr == hashmap.end())
-            return;
-        doAll = true;
-    } else {
-        itr = hashmap.find(id);
-    }
-    if (itr == hashmap.end()) {
-        GO_ERROR(GraphicsObject, "not found: %s", id.c_str());
-        return;
-    }
-
-    do {
-        itr->second->setPointSize(size);
-    } while (doAll && ++itr != hashmap.end());
-
-    sceneBoundsChanged();
-    _needsRedraw = true;
-}
-
-/**
- * \brief Set wireframe actor rendering for the specified DataSet
- */
-template<class GraphicsObject>
-void Renderer::setGraphicsObjectWireframe(const DataSetId& id, bool state)
-{
-    std::tr1::unordered_map<DataSetId, GraphicsObject *>& hashmap = 
-        getGraphicsObjectHashmap<GraphicsObject>();
-    typename std::tr1::unordered_map<DataSetId, GraphicsObject *>::iterator itr;
-
-    bool doAll = false;
-
-    if (id.compare("all") == 0) {
-        itr = hashmap.begin();
-        if (itr == hashmap.end())
-            return;
-        doAll = true;
-    } else {
-        itr = hashmap.find(id);
-    }
-    if (itr == hashmap.end()) {
-        GO_ERROR(GraphicsObject, "not found: %s", id.c_str());
-        return;
-    }
-
-    do {
-        itr->second->setWireframe(state);
-    } while (doAll && ++itr != hashmap.end());
-
-    _needsRedraw = true;
-}
-
-/**
- * \brief Associate an existing named color map with a graphics object for the given DataSet
- */
-template<class GraphicsObject>
-void Renderer::setGraphicsObjectInterpolateBeforeMapping(const DataSetId& id, bool state)
-{
-    std::tr1::unordered_map<DataSetId, GraphicsObject *>& hashmap = 
-        getGraphicsObjectHashmap<GraphicsObject>();
-    typename std::tr1::unordered_map<DataSetId, GraphicsObject *>::iterator itr;
-
-    bool doAll = false;
-
-    if (id.compare("all") == 0) {
-        itr = hashmap.begin();
-        if (itr == hashmap.end())
-            return;
-        doAll = true;
-    } else {
-        itr = hashmap.find(id);
-    }
-
-    if (itr == hashmap.end()) {
-        GO_ERROR(GraphicsObject, "not found: %s", id.c_str());
-        return;
-    }
-
-    do {
-        itr->second->setInterpolateBeforeMapping(state);
-    } while (doAll && ++itr != hashmap.end());
-
-    _needsRedraw = true;
-}
-
-/**
- * \brief Associate an existing named color map with a graphics object for the given DataSet
- */
-template<class GraphicsObject>
-void Renderer::setGraphicsObjectColorMap(const DataSetId& id, const ColorMapId& colorMapId)
-{
-    std::tr1::unordered_map<DataSetId, GraphicsObject *>& hashmap = 
-        getGraphicsObjectHashmap<GraphicsObject>();
-    typename std::tr1::unordered_map<DataSetId, GraphicsObject *>::iterator itr;
-
-    bool doAll = false;
-
-    if (id.compare("all") == 0) {
-        itr = hashmap.begin();
-        if (itr == hashmap.end())
-            return;
-        doAll = true;
-    } else {
-        itr = hashmap.find(id);
-    }
-
-    if (itr == hashmap.end()) {
-        GO_ERROR(GraphicsObject, "not found: %s", id.c_str());
-        return;
-    }
-
-    ColorMap *cmap = getColorMap(colorMapId);
-    if (cmap == NULL) {
-        ERROR("Unknown colormap: %s", colorMapId.c_str());
-        return;
-    }
-
-    do {
-        GO_TRACE(GraphicsObject, "Set color map: %s for dataset %s",
-                 colorMapId.c_str(),
-                 itr->second->getDataSet()->getName().c_str());
-
-        itr->second->setColorMap(cmap);
-    } while (doAll && ++itr != hashmap.end());
-
-    _needsRedraw = true;
-}
-
-/**
- * \brief Notify graphics object that color map has changed
- */
-template<class GraphicsObject>
-void Renderer::updateGraphicsObjectColorMap(ColorMap *cmap)
-{
-    std::tr1::unordered_map<DataSetId, GraphicsObject *>& hashmap = 
-        getGraphicsObjectHashmap<GraphicsObject>();
-    typename std::tr1::unordered_map<DataSetId, GraphicsObject *>::iterator itr;
-
-    for (itr = hashmap.begin(); itr != hashmap.end(); ++itr) {
-        if (itr->second->getColorMap() == cmap) {
-            itr->second->updateColorMap();
-            _needsRedraw = true;
-        }
-    }
-}
-
-/**
- * \brief Check if a color map is in use by a graphics object
- */
-template<class GraphicsObject>
-bool Renderer::graphicsObjectColorMapUsed(ColorMap *cmap)
-{
-    std::tr1::unordered_map<DataSetId, GraphicsObject *>& hashmap = 
-        getGraphicsObjectHashmap<GraphicsObject>();
-    typename std::tr1::unordered_map<DataSetId, GraphicsObject *>::iterator itr;
-
-    for (itr = hashmap.begin(); itr != hashmap.end(); ++itr) {
-        if (itr->second->getColorMap() == cmap)
-            return true;
-    }
-    return false;
-}
-
-/**
- * \brief Compute union of bounds and GO's bounds
- */
-template<class GraphicsObject>
-void Renderer::mergeGraphicsObjectBounds(double *bounds, bool onlyVisible)
-{
-    std::tr1::unordered_map<DataSetId, GraphicsObject *>& hashmap = 
-        getGraphicsObjectHashmap<GraphicsObject>();
-    typename std::tr1::unordered_map<DataSetId, GraphicsObject *>::iterator itr;
-
-    for (itr = hashmap.begin(); itr != hashmap.end(); ++itr) {
-        if ((!onlyVisible || itr->second->getVisibility()) &&
-            itr->second->getProp() != NULL)
-            mergeBounds(bounds, bounds, itr->second->getBounds());
-#ifdef DEBUG
-        double *bPtr = itr->second->getBounds();
-        assert(bPtr != NULL);
-        GO_TRACE(GraphicsObject,
-                 "%s bounds: %g %g %g %g %g %g",
-                 itr->first.c_str(),
-                 bPtr[0], bPtr[1], bPtr[2], bPtr[3], bPtr[4], bPtr[5]);
-#endif
-    }
-}
-
-/**
- * \brief Compute union of bounds and GO's unscaled bounds
- *
- * Unscaled bounds are the bounds of the object before any actor scaling is
- * applied
- */
-template<class GraphicsObject>
-void Renderer::mergeGraphicsObjectUnscaledBounds(double *bounds, bool onlyVisible)
-{
-    std::tr1::unordered_map<DataSetId, GraphicsObject *>& hashmap = 
-        getGraphicsObjectHashmap<GraphicsObject>();
-    typename std::tr1::unordered_map<DataSetId, GraphicsObject *>::iterator itr;
-
-    for (itr = hashmap.begin(); itr != hashmap.end(); ++itr) {
-        if ((!onlyVisible || itr->second->getVisibility()) &&
-            itr->second->getProp() != NULL)
-            mergeBounds(bounds, bounds, itr->second->getUnscaledBounds());
-#ifdef DEBUG
-        double *bPtr = itr->second->getUnscaledBounds();
-        assert(bPtr != NULL);
-        GO_TRACE(GraphicsObject,
-                 "%s bounds: %g %g %g %g %g %g",
-                 itr->first.c_str(),
-                 bPtr[0], bPtr[1], bPtr[2], bPtr[3], bPtr[4], bPtr[5]);
-#endif
-    }
-}
-
-/**
- * \brief Notify object that field value ranges have changed
- */
-template<class GraphicsObject>
-void Renderer::updateGraphicsObjectFieldRanges()
-{
-    std::tr1::unordered_map<DataSetId, GraphicsObject *>& hashmap = 
-        getGraphicsObjectHashmap<GraphicsObject>();
-    typename std::tr1::unordered_map<DataSetId, GraphicsObject *>::iterator itr;
-
-    for (itr = hashmap.begin(); itr != hashmap.end(); ++itr) {
-        itr->second->updateRanges(this);
-    }
-}
-
-/**
- * \brief Pass global clip planes to graphics object
- */
-template<class GraphicsObject>
-void Renderer::setGraphicsObjectClippingPlanes(vtkPlaneCollection *planes)
-{
-    std::tr1::unordered_map<DataSetId, GraphicsObject *>& hashmap = 
-        getGraphicsObjectHashmap<GraphicsObject>();
-    typename std::tr1::unordered_map<DataSetId, GraphicsObject *>::iterator itr;
-
-    for (itr = hashmap.begin(); itr != hashmap.end(); ++itr) {
-        itr->second->setClippingPlanes(planes);
-    }
-}
-
-/**
- * \brief Set the prop scaling based on a 2D aspect ratio
- *
- * This method sets the aspect on all graphics objects of a given type
- *
- * \param aspectRatio The aspect ratio (width/height), zero means native aspect
- */
-template<class GraphicsObject>
-void Renderer::setGraphicsObjectAspect(double aspectRatio)
-{
-    std::tr1::unordered_map<DataSetId, GraphicsObject *>& hashmap = 
-        getGraphicsObjectHashmap<GraphicsObject>();
-    typename std::tr1::unordered_map<DataSetId, GraphicsObject *>::iterator itr;
-
-    for (itr = hashmap.begin(); itr != hashmap.end(); ++itr) {
-        itr->second->setAspect(aspectRatio);
-    }
-
-    sceneBoundsChanged();
-    _needsRedraw = true;
-}
-
-}
-
-#endif
Index: unk/packages/vizservers/vtkvis/RpWarp.cpp
===================================================================
--- /trunk/packages/vizservers/vtkvis/RpWarp.cpp	(revision 3615)
+++ 	(revision )
@@ -1,616 +1,0 @@
-/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
-/*
- * Copyright (C) 2004-2012  HUBzero Foundation, LLC
- *
- * Author: Leif Delgass <ldelgass@purdue.edu>
- */
-
-#include <cassert>
-#include <cfloat>
-#include <cstring>
-
-#include <vtkDataSet.h>
-#include <vtkPointData.h>
-#include <vtkCellData.h>
-#include <vtkCellDataToPointData.h>
-#include <vtkDataSetMapper.h>
-#include <vtkUnstructuredGrid.h>
-#include <vtkProperty.h>
-#include <vtkImageData.h>
-#include <vtkLookupTable.h>
-#include <vtkTransform.h>
-#include <vtkDelaunay2D.h>
-#include <vtkDelaunay3D.h>
-#include <vtkGaussianSplatter.h>
-#include <vtkExtractVOI.h>
-#include <vtkDataSetSurfaceFilter.h>
-
-#include "RpWarp.h"
-#include "RpVtkRenderer.h"
-#include "Trace.h"
-
-#define MESH_POINT_CLOUDS
-
-using namespace VtkVis;
-
-Warp::Warp() :
-    VtkGraphicsObject(),
-    _warpScale(1.0),
-    _colorMap(NULL),
-    _colorMode(COLOR_BY_SCALAR),
-    _colorFieldType(DataSet::POINT_DATA),
-    _renderer(NULL)
-{
-    _colorFieldRange[0] = DBL_MAX;
-    _colorFieldRange[1] = -DBL_MAX;
-}
-
-Warp::~Warp()
-{
-#ifdef WANT_TRACE
-    if (_dataSet != NULL)
-        TRACE("Deleting Warp for %s", _dataSet->getName().c_str());
-    else
-        TRACE("Deleting Warp with NULL DataSet");
-#endif
-}
-
-void Warp::setDataSet(DataSet *dataSet,
-                      Renderer *renderer)
-{
-    if (_dataSet != dataSet) {
-        _dataSet = dataSet;
-
-        _renderer = renderer;
-
-        if (renderer->getUseCumulativeRange()) {
-            renderer->getCumulativeDataRange(_dataRange,
-                                             _dataSet->getActiveScalarsName(),
-                                             1);
-            renderer->getCumulativeDataRange(_vectorMagnitudeRange,
-                                             _dataSet->getActiveVectorsName(),
-                                             3);
-            for (int i = 0; i < 3; i++) {
-                renderer->getCumulativeDataRange(_vectorComponentRange[i],
-                                                 _dataSet->getActiveVectorsName(),
-                                                 3, i);
-            }
-        } else {
-            _dataSet->getScalarRange(_dataRange);
-            _dataSet->getVectorRange(_vectorMagnitudeRange);
-            for (int i = 0; i < 3; i++) {
-                _dataSet->getVectorRange(_vectorComponentRange[i], i);
-            }
-        }
-
-        update();
-    }
-}
-
-/**
- * \brief Internal method to set up pipeline after a state change
- */
-void Warp::update()
-{
-    if (_dataSet == NULL)
-        return;
-
-    vtkDataSet *ds = _dataSet->getVtkDataSet();
-
-    if (_warp == NULL) {
-        _warp = vtkSmartPointer<vtkWarpVector>::New();
-    }
-
-    // Mapper, actor to render color-mapped data set
-    if (_dsMapper == NULL) {
-        _dsMapper = vtkSmartPointer<vtkDataSetMapper>::New();
-        // Map scalars through lookup table regardless of type
-        _dsMapper->SetColorModeToMapScalars();
-    }
-
-    vtkSmartPointer<vtkCellDataToPointData> cellToPtData;
-    if (ds->GetPointData() == NULL ||
-        ds->GetPointData()->GetVectors() == NULL) {
-        TRACE("No vector point data in dataset %s", _dataSet->getName().c_str());
-        if (ds->GetCellData() != NULL &&
-            ds->GetCellData()->GetVectors() != NULL) {
-            cellToPtData = 
-                vtkSmartPointer<vtkCellDataToPointData>::New();
-#ifdef USE_VTK6
-            cellToPtData->SetInputData(ds);
-#else
-            cellToPtData->SetInput(ds);
-#endif
-            //cellToPtData->PassCellDataOn();
-            cellToPtData->Update();
-            ds = cellToPtData->GetOutput();
-        } else {
-            USER_ERROR("No vector field was found in the data set");
-            return;
-        }
-    }
-
-    vtkPolyData *pd = vtkPolyData::SafeDownCast(ds);
-    if (pd) {
-        // DataSet is a vtkPolyData
-        if (pd->GetNumberOfLines() == 0 &&
-            pd->GetNumberOfPolys() == 0 &&
-            pd->GetNumberOfStrips() == 0) {
-            // DataSet is a point cloud
-            PrincipalPlane plane;
-            double offset;
-            if (_dataSet->is2D(&plane, &offset)) {
-#ifdef MESH_POINT_CLOUDS
-                vtkSmartPointer<vtkDelaunay2D> mesher = vtkSmartPointer<vtkDelaunay2D>::New();
-                if (plane == PLANE_ZY) {
-                    vtkSmartPointer<vtkTransform> trans = vtkSmartPointer<vtkTransform>::New();
-                    trans->RotateWXYZ(90, 0, 1, 0);
-                    if (offset != 0.0) {
-                        trans->Translate(-offset, 0, 0);
-                    }
-                    mesher->SetTransform(trans);
-                } else if (plane == PLANE_XZ) {
-                    vtkSmartPointer<vtkTransform> trans = vtkSmartPointer<vtkTransform>::New();
-                    trans->RotateWXYZ(-90, 1, 0, 0);
-                    if (offset != 0.0) {
-                        trans->Translate(0, -offset, 0);
-                    }
-                    mesher->SetTransform(trans);
-                } else if (offset != 0.0) {
-                    // XY with Z offset
-                    vtkSmartPointer<vtkTransform> trans = vtkSmartPointer<vtkTransform>::New();
-                    trans->Translate(0, 0, -offset);
-                    mesher->SetTransform(trans);
-                }
-#ifdef USE_VTK6
-                mesher->SetInputData(pd);
-#else
-                mesher->SetInput(pd);
-#endif
-                vtkAlgorithmOutput *warpOutput = initWarp(mesher->GetOutputPort());
-                _dsMapper->SetInputConnection(warpOutput);
-#else
-                vtkSmartPointer<vtkGaussianSplatter> splatter = vtkSmartPointer<vtkGaussianSplatter>::New();
-                vtkSmartPointer<vtkExtractVOI> slicer = vtkSmartPointer<vtkExtractVOI>::New();
-#ifdef USE_VTK6
-                splatter->SetInputData(pd);
-#else
-                splatter->SetInput(pd);
-#endif
-                int dims[3];
-                splatter->GetSampleDimensions(dims);
-                TRACE("Sample dims: %d %d %d", dims[0], dims[1], dims[2]);
-                if (plane == PLANE_ZY) {
-                    dims[0] = 3;
-                    slicer->SetVOI(1, 1, 0, dims[1]-1, 0, dims[1]-1);
-                } else if (plane == PLANE_XZ) {
-                    dims[1] = 3;
-                    slicer->SetVOI(0, dims[0]-1, 1, 1, 0, dims[2]-1);
-                } else {
-                    dims[2] = 3;
-                    slicer->SetVOI(0, dims[0]-1, 0, dims[1]-1, 1, 1);
-                }
-                splatter->SetSampleDimensions(dims);
-                double bounds[6];
-                splatter->Update();
-                splatter->GetModelBounds(bounds);
-                TRACE("Model bounds: %g %g %g %g %g %g",
-                      bounds[0], bounds[1],
-                      bounds[2], bounds[3],
-                      bounds[4], bounds[5]);
-                slicer->SetInputConnection(splatter->GetOutputPort());
-                slicer->SetSampleRate(1, 1, 1);
-                vtkSmartPointer<vtkDataSetSurfaceFilter> gf = vtkSmartPointer<vtkDataSetSurfaceFilter>::New();
-                gf->UseStripsOn();
-                gf->SetInputConnection(slicer->GetOutputPort());
-                vtkAlgorithmOutput *warpOutput = initWarp(gf->GetOutputPort());
-                _dsMapper->SetInputConnection(warpOutput);
-#endif
-            } else {
-                // Data Set is a 3D point cloud
-                vtkSmartPointer<vtkDelaunay3D> mesher = vtkSmartPointer<vtkDelaunay3D>::New();
-#ifdef USE_VTK6
-                mesher->SetInputData(pd);
-#else
-                mesher->SetInput(pd);
-#endif
-                vtkSmartPointer<vtkDataSetSurfaceFilter> gf = vtkSmartPointer<vtkDataSetSurfaceFilter>::New();
-                gf->SetInputConnection(mesher->GetOutputPort());
-                vtkAlgorithmOutput *warpOutput = initWarp(gf->GetOutputPort());
-                _dsMapper->SetInputConnection(warpOutput);
-             }
-        } else {
-            // DataSet is a vtkPolyData with lines and/or polygons
-            vtkAlgorithmOutput *warpOutput = initWarp(pd);
-            if (warpOutput != NULL) {
-                _dsMapper->SetInputConnection(warpOutput);
-            } else {
-#ifdef USE_VTK6
-                _dsMapper->SetInputData(pd);
-#else
-                _dsMapper->SetInput(pd);
-#endif
-            }
-        }
-    } else {
-        TRACE("Generating surface for data set");
-        // DataSet is NOT a vtkPolyData
-        vtkSmartPointer<vtkDataSetSurfaceFilter> gf = vtkSmartPointer<vtkDataSetSurfaceFilter>::New();
-#ifdef USE_VTK6
-        gf->SetInputData(ds);
-#else
-        gf->SetInput(ds);
-#endif
-        vtkAlgorithmOutput *warpOutput = initWarp(gf->GetOutputPort());
-        _dsMapper->SetInputConnection(warpOutput);
-    }
-
-    setInterpolateBeforeMapping(true);
-
-    if (_lut == NULL) {
-        setColorMap(ColorMap::getDefault());
-    }
-
-    setColorMode(_colorMode);
-
-    initProp();
-    getActor()->SetMapper(_dsMapper);
-    _dsMapper->Update();
-}
-
-void Warp::setInterpolateBeforeMapping(bool state)
-{
-    if (_dsMapper != NULL) {
-        _dsMapper->SetInterpolateScalarsBeforeMapping((state ? 1 : 0));
-    }
-}
-
-vtkAlgorithmOutput *Warp::initWarp(vtkAlgorithmOutput *input)
-{
-    TRACE("Warp scale: %g", _warpScale);
-    if (_warpScale == 0.0) {
-        _warp = NULL;
-        return input;
-    } else if (input == NULL) {
-        ERROR("NULL input");
-        return input;
-    } else {
-        if (_warp == NULL)
-            _warp = vtkSmartPointer<vtkWarpVector>::New();
-        _warp->SetScaleFactor(_warpScale);
-        _warp->SetInputConnection(input);
-        return _warp->GetOutputPort();
-    }
-}
-
-vtkAlgorithmOutput *Warp::initWarp(vtkDataSet *ds)
-{
-    TRACE("Warp scale: %g", _warpScale);
-    if (_warpScale == 0.0) {
-        _warp = NULL;
-        return NULL;
-    } else if (ds == NULL) {
-        ERROR("NULL input");
-        return NULL;
-    } else {
-        if (_warp == NULL)
-            _warp = vtkSmartPointer<vtkWarpVector>::New();
-        _warp->SetScaleFactor(_warpScale);
-#ifdef USE_VTK6
-        _warp->SetInputData(ds);
-#else
-        _warp->SetInput(ds);
-#endif
-        return _warp->GetOutputPort();
-    }
-}
-
-/**
- * \brief Controls relative scaling of deformation
- */
-void Warp::setWarpScale(double scale)
-{
-    if (_warpScale == scale)
-        return;
-
-    _warpScale = scale;
-    if (_warp == NULL) {
-        vtkAlgorithmOutput *warpOutput = initWarp(_dsMapper->GetInputConnection(0, 0));
-        _dsMapper->SetInputConnection(warpOutput);
-    } else if (scale == 0.0) {
-        vtkAlgorithmOutput *warpInput = _warp->GetInputConnection(0, 0);
-        _dsMapper->SetInputConnection(warpInput);
-        _warp = NULL;
-    } else {
-        _warp->SetScaleFactor(_warpScale);
-    }
-
-    if (_dsMapper != NULL)
-        _dsMapper->Update();
-}
-
-void Warp::updateRanges(Renderer *renderer)
-{
-    if (_dataSet == NULL) {
-        ERROR("called before setDataSet");
-        return;
-    }
-
-    if (renderer->getUseCumulativeRange()) {
-        renderer->getCumulativeDataRange(_dataRange,
-                                         _dataSet->getActiveScalarsName(),
-                                         1);
-        renderer->getCumulativeDataRange(_vectorMagnitudeRange,
-                                         _dataSet->getActiveVectorsName(),
-                                         3);
-        for (int i = 0; i < 3; i++) {
-            renderer->getCumulativeDataRange(_vectorComponentRange[i],
-                                             _dataSet->getActiveVectorsName(),
-                                             3, i);
-        }
-    } else {
-        _dataSet->getScalarRange(_dataRange);
-        _dataSet->getVectorRange(_vectorMagnitudeRange);
-        for (int i = 0; i < 3; i++) {
-            _dataSet->getVectorRange(_vectorComponentRange[i], i);
-        }
-    }
-
-    // Need to update color map ranges
-    double *rangePtr = _colorFieldRange;
-    if (_colorFieldRange[0] > _colorFieldRange[1]) {
-        rangePtr = NULL;
-    }
-    setColorMode(_colorMode, _colorFieldType, _colorFieldName.c_str(), rangePtr);
-}
-
-void Warp::setColorMode(ColorMode mode)
-{
-    _colorMode = mode;
-    if (_dataSet == NULL)
-        return;
-
-    switch (mode) {
-    case COLOR_BY_SCALAR:
-        setColorMode(mode,
-                     _dataSet->getActiveScalarsType(),
-                     _dataSet->getActiveScalarsName(),
-                     _dataRange);
-        break;
-    case COLOR_BY_VECTOR_MAGNITUDE:
-        setColorMode(mode,
-                     _dataSet->getActiveVectorsType(),
-                     _dataSet->getActiveVectorsName(),
-                     _vectorMagnitudeRange);
-        break;
-    case COLOR_BY_VECTOR_X:
-        setColorMode(mode,
-                     _dataSet->getActiveVectorsType(),
-                     _dataSet->getActiveVectorsName(),
-                     _vectorComponentRange[0]);
-        break;
-    case COLOR_BY_VECTOR_Y:
-        setColorMode(mode,
-                     _dataSet->getActiveVectorsType(),
-                     _dataSet->getActiveVectorsName(),
-                     _vectorComponentRange[1]);
-        break;
-    case COLOR_BY_VECTOR_Z:
-        setColorMode(mode,
-                     _dataSet->getActiveVectorsType(),
-                     _dataSet->getActiveVectorsName(),
-                     _vectorComponentRange[2]);
-        break;
-    case COLOR_CONSTANT:
-    default:
-        setColorMode(mode, DataSet::POINT_DATA, NULL, NULL);
-        break;
-    }
-}
-
-void Warp::setColorMode(ColorMode mode,
-                        const char *name, double range[2])
-{
-    if (_dataSet == NULL)
-        return;
-    DataSet::DataAttributeType type = DataSet::POINT_DATA;
-    int numComponents = 1;
-    if (name != NULL && strlen(name) > 0 &&
-        !_dataSet->getFieldInfo(name, &type, &numComponents)) {
-        ERROR("Field not found: %s", name);
-        return;
-    }
-    setColorMode(mode, type, name, range);
-}
-
-void Warp::setColorMode(ColorMode mode, DataSet::DataAttributeType type,
-                        const char *name, double range[2])
-{
-    _colorMode = mode;
-    _colorFieldType = type;
-    if (name == NULL)
-        _colorFieldName.clear();
-    else
-        _colorFieldName = name;
-    if (range == NULL) {
-        _colorFieldRange[0] = DBL_MAX;
-        _colorFieldRange[1] = -DBL_MAX;
-    } else {
-        memcpy(_colorFieldRange, range, sizeof(double)*2);
-    }
-
-    if (_dataSet == NULL || _dsMapper == NULL)
-        return;
-
-    switch (type) {
-    case DataSet::POINT_DATA:
-        _dsMapper->SetScalarModeToUsePointFieldData();
-        break;
-    case DataSet::CELL_DATA:
-        _dsMapper->SetScalarModeToUseCellFieldData();
-        break;
-    default:
-        ERROR("Unsupported DataAttributeType: %d", type);
-        return;
-    }
-
-    if (name != NULL && strlen(name) > 0) {
-        _dsMapper->SelectColorArray(name);
-    } else {
-        _dsMapper->SetScalarModeToDefault();
-    }
-
-    if (_lut != NULL) {
-        if (range != NULL) {
-            _lut->SetRange(range);
-        } else if (name != NULL && strlen(name) > 0) {
-            double r[2];
-            int comp = -1;
-            if (mode == COLOR_BY_VECTOR_X)
-                comp = 0;
-            else if (mode == COLOR_BY_VECTOR_Y)
-                comp = 1;
-            else if (mode == COLOR_BY_VECTOR_Z)
-                comp = 2;
-
-            if (_renderer->getUseCumulativeRange()) {
-                int numComponents;
-                if  (!_dataSet->getFieldInfo(name, type, &numComponents)) {
-                    ERROR("Field not found: %s, type: %d", name, type);
-                    return;
-                } else if (numComponents < comp+1) {
-                    ERROR("Request for component %d in field with %d components",
-                          comp, numComponents);
-                    return;
-                }
-                _renderer->getCumulativeDataRange(r, name, type, numComponents, comp);
-            } else {
-                _dataSet->getDataRange(r, name, type, comp);
-            }
-            _lut->SetRange(r);
-        }
-    }
-
-    switch (mode) {
-    case COLOR_BY_SCALAR:
-        _dsMapper->ScalarVisibilityOn();
-        break;
-    case COLOR_BY_VECTOR_MAGNITUDE:
-        _dsMapper->ScalarVisibilityOn();
-        if (_lut != NULL) {
-            _lut->SetVectorModeToMagnitude();
-        }
-        break;
-    case COLOR_BY_VECTOR_X:
-        _dsMapper->ScalarVisibilityOn();
-        if (_lut != NULL) {
-            _lut->SetVectorModeToComponent();
-            _lut->SetVectorComponent(0);
-        }
-        break;
-    case COLOR_BY_VECTOR_Y:
-        _dsMapper->ScalarVisibilityOn();
-        if (_lut != NULL) {
-            _lut->SetVectorModeToComponent();
-            _lut->SetVectorComponent(1);
-        }
-        break;
-    case COLOR_BY_VECTOR_Z:
-        _dsMapper->ScalarVisibilityOn();
-        if (_lut != NULL) {
-            _lut->SetVectorModeToComponent();
-            _lut->SetVectorComponent(2);
-        }
-        break;
-    case COLOR_CONSTANT:
-    default:
-        _dsMapper->ScalarVisibilityOff();
-        break;
-    }
-}
-
-/**
- * \brief Called when the color map has been edited
- */
-void Warp::updateColorMap()
-{
-    setColorMap(_colorMap);
-}
-
-/**
- * \brief Associate a colormap lookup table with the DataSet
- */
-void Warp::setColorMap(ColorMap *cmap)
-{
-    if (cmap == NULL)
-        return;
-
-    _colorMap = cmap;
- 
-    if (_lut == NULL) {
-        _lut = vtkSmartPointer<vtkLookupTable>::New();
-        if (_dsMapper != NULL) {
-            _dsMapper->UseLookupTableScalarRangeOn();
-            _dsMapper->SetLookupTable(_lut);
-        }
-        _lut->DeepCopy(cmap->getLookupTable());
-        switch (_colorMode) {
-        case COLOR_CONSTANT:
-        case COLOR_BY_SCALAR:
-            _lut->SetRange(_dataRange);
-            break;
-        case COLOR_BY_VECTOR_MAGNITUDE:
-            _lut->SetRange(_vectorMagnitudeRange);
-            break;
-        case COLOR_BY_VECTOR_X:
-            _lut->SetRange(_vectorComponentRange[0]);
-            break;
-        case COLOR_BY_VECTOR_Y:
-            _lut->SetRange(_vectorComponentRange[1]);
-            break;
-        case COLOR_BY_VECTOR_Z:
-            _lut->SetRange(_vectorComponentRange[2]);
-            break;
-        default:
-            break;
-        }
-    } else {
-        double range[2];
-        _lut->GetTableRange(range);
-        _lut->DeepCopy(cmap->getLookupTable());
-        _lut->SetRange(range);
-        _lut->Modified();
-    }
-
-    switch (_colorMode) {
-    case COLOR_BY_VECTOR_MAGNITUDE:
-        _lut->SetVectorModeToMagnitude();
-        break;
-    case COLOR_BY_VECTOR_X:
-        _lut->SetVectorModeToComponent();
-        _lut->SetVectorComponent(0);
-        break;
-    case COLOR_BY_VECTOR_Y:
-        _lut->SetVectorModeToComponent();
-        _lut->SetVectorComponent(1);
-        break;
-    case COLOR_BY_VECTOR_Z:
-        _lut->SetVectorModeToComponent();
-        _lut->SetVectorComponent(2);
-        break;
-    default:
-         break;
-    }
-}
-
-/**
- * \brief Set a group of world coordinate planes to clip rendering
- *
- * Passing NULL for planes will remove all cliping planes
- */
-void Warp::setClippingPlanes(vtkPlaneCollection *planes)
-{
-    if (_dsMapper != NULL) {
-        _dsMapper->SetClippingPlanes(planes);
-    }
-}
Index: unk/packages/vizservers/vtkvis/RpWarp.h
===================================================================
--- /trunk/packages/vizservers/vtkvis/RpWarp.h	(revision 3615)
+++ 	(revision )
@@ -1,110 +1,0 @@
-/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
-/*
- * Copyright (C) 2004-2012  HUBzero Foundation, LLC
- *
- * Author: Leif Delgass <ldelgass@purdue.edu>
- */
-
-#ifndef VTKVIS_WARP_H
-#define VTKVIS_WARP_H
-
-#include <vtkSmartPointer.h>
-#include <vtkAlgorithmOutput.h>
-#include <vtkLookupTable.h>
-#include <vtkDataSet.h>
-#include <vtkDataSetMapper.h>
-#include <vtkActor.h>
-#include <vtkPlaneCollection.h>
-#include <vtkWarpVector.h>
-
-#include "ColorMap.h"
-#include "RpVtkGraphicsObject.h"
-
-namespace VtkVis {
-
-/**
- * \brief Warp a mesh based on point data vectors
- *
- * This class can be used to visualize mechanical deformation or 
- * to create flow profiles/surfaces
- */
-class Warp : public VtkGraphicsObject {
-public:
-    enum ColorMode {
-        COLOR_BY_SCALAR,
-        COLOR_BY_VECTOR_MAGNITUDE,
-        COLOR_BY_VECTOR_X,
-        COLOR_BY_VECTOR_Y,
-        COLOR_BY_VECTOR_Z,
-        COLOR_CONSTANT
-    };
-
-    Warp();
-    virtual ~Warp();
-
-    virtual const char *getClassName() const
-    {
-        return "Warp";
-    }
-
-    virtual void setDataSet(DataSet *dataSet,
-                            Renderer *renderer);
-
-    virtual void setClippingPlanes(vtkPlaneCollection *planes);
-
-    void setWarpScale(double scale);
-
-    double getWarpScale()
-    {
-        return _warpScale;
-    }
-
-    void setInterpolateBeforeMapping(bool state);
-
-    void setColorMode(ColorMode mode, DataSet::DataAttributeType type,
-                      const char *name, double range[2] = NULL);
-
-    void setColorMode(ColorMode mode,
-                      const char *name, double range[2] = NULL);
-
-    void setColorMode(ColorMode mode);
-
-    void setColorMap(ColorMap *colorMap);
-
-    /**
-     * \brief Return the ColorMap in use
-     */
-    ColorMap *getColorMap()
-    {
-        return _colorMap;
-    }
-
-    void updateColorMap();
-
-    virtual void updateRanges(Renderer *renderer);
-
-private:
-    virtual void update();
-
-    vtkAlgorithmOutput *initWarp(vtkAlgorithmOutput *input);
-    vtkAlgorithmOutput *initWarp(vtkDataSet *input);
-
-    double _warpScale;
-
-    ColorMap *_colorMap;
-    ColorMode _colorMode;
-    std::string _colorFieldName;
-    DataSet::DataAttributeType _colorFieldType;
-    double _colorFieldRange[2];
-    double _vectorMagnitudeRange[2];
-    double _vectorComponentRange[3][2];
-    Renderer *_renderer;
-
-    vtkSmartPointer<vtkLookupTable> _lut;
-    vtkSmartPointer<vtkWarpVector> _warp;
-    vtkSmartPointer<vtkDataSetMapper> _dsMapper;
-};
-
-}
-
-#endif
Index: /trunk/packages/vizservers/vtkvis/Shape.cpp
===================================================================
--- /trunk/packages/vizservers/vtkvis/Shape.cpp	(revision 3616)
+++ /trunk/packages/vizservers/vtkvis/Shape.cpp	(revision 3616)
@@ -0,0 +1,42 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (C) 2004-2012  HUBzero Foundation, LLC
+ *
+ * Author: Leif Delgass <ldelgass@purdue.edu>
+ */
+
+#include <cassert>
+
+#include <vtkDataSet.h>
+#include <vtkPolyData.h>
+#include <vtkPolyDataMapper.h>
+#include <vtkActor.h>
+#include <vtkProperty.h>
+#include <vtkTransform.h>
+
+#include "Shape.h"
+#include "Trace.h"
+
+using namespace VtkVis;
+
+Shape::Shape() :
+    VtkGraphicsObject()
+{
+}
+
+Shape::~Shape()
+{
+    //TRACE("Deleting Shape");
+}
+
+/**
+ * \brief Set a group of world coordinate planes to clip rendering
+ *
+ * Passing NULL for planes will remove all cliping planes
+ */
+void Shape::setClippingPlanes(vtkPlaneCollection *planes)
+{
+    if (_pdMapper != NULL) {
+        _pdMapper->SetClippingPlanes(planes);
+    }
+}
Index: /trunk/packages/vizservers/vtkvis/Shape.h
===================================================================
--- /trunk/packages/vizservers/vtkvis/Shape.h	(revision 3616)
+++ /trunk/packages/vizservers/vtkvis/Shape.h	(revision 3616)
@@ -0,0 +1,52 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (C) 2004-2012  HUBzero Foundation, LLC
+ *
+ * Author: Leif Delgass <ldelgass@purdue.edu>
+ */
+
+#ifndef VTKVIS_SHAPE_H
+#define VTKVIS_SHAPE_H
+
+#include <cassert>
+
+#include <vtkSmartPointer.h>
+#include <vtkPolyDataMapper.h>
+#include <vtkActor.h>
+
+#include "VtkGraphicsObject.h"
+#include "VtkDataSet.h"
+
+namespace VtkVis {
+
+/**
+ * \brief VTK Mesh (Polygon data)
+ *
+ * This class creates a boundary mesh of a DataSet
+ */
+class Shape : public VtkGraphicsObject {
+public:
+    Shape();
+    virtual ~Shape();
+
+    virtual const char *getClassName() const
+    {
+        return "Shape";
+    }
+
+    virtual void setDataSet(DataSet *dataSet,
+                            Renderer *renderer)
+    {
+        assert(dataSet == NULL);
+        update();
+    }
+
+    virtual void setClippingPlanes(vtkPlaneCollection *planes);
+
+protected:
+    vtkSmartPointer<vtkPolyDataMapper> _pdMapper;
+};
+
+}
+
+#endif
Index: /trunk/packages/vizservers/vtkvis/Sphere.cpp
===================================================================
--- /trunk/packages/vizservers/vtkvis/Sphere.cpp	(revision 3616)
+++ /trunk/packages/vizservers/vtkvis/Sphere.cpp	(revision 3616)
@@ -0,0 +1,51 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (C) 2004-2012  HUBzero Foundation, LLC
+ *
+ * Author: Leif Delgass <ldelgass@purdue.edu>
+ */
+
+#include <cassert>
+
+#include <vtkDataSet.h>
+#include <vtkPolyData.h>
+#include <vtkPolyDataMapper.h>
+#include <vtkActor.h>
+#include <vtkProperty.h>
+#include <vtkTransform.h>
+#include <vtkSphereSource.h>
+
+#include "Sphere.h"
+#include "Trace.h"
+
+using namespace VtkVis;
+
+Sphere::Sphere() :
+    Shape()
+{
+}
+
+Sphere::~Sphere()
+{
+    TRACE("Deleting Sphere");
+}
+
+void Sphere::update()
+{
+    if (_sphere == NULL) {
+	_sphere = vtkSmartPointer<vtkSphereSource>::New();
+    }
+
+    if (_pdMapper == NULL) {
+        _pdMapper = vtkSmartPointer<vtkPolyDataMapper>::New();
+        _pdMapper->SetResolveCoincidentTopologyToPolygonOffset();
+        _pdMapper->ScalarVisibilityOff();
+    }
+
+    _pdMapper->SetInputConnection(_sphere->GetOutputPort());
+
+    initProp();
+
+    getActor()->SetMapper(_pdMapper);
+    _pdMapper->Update();
+}
Index: /trunk/packages/vizservers/vtkvis/Sphere.h
===================================================================
--- /trunk/packages/vizservers/vtkvis/Sphere.h	(revision 3616)
+++ /trunk/packages/vizservers/vtkvis/Sphere.h	(revision 3616)
@@ -0,0 +1,93 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (C) 2004-2012  HUBzero Foundation, LLC
+ *
+ * Author: Leif Delgass <ldelgass@purdue.edu>
+ */
+
+#ifndef VTKVIS_SPHERE_H
+#define VTKVIS_SPHERE_H
+
+#include <vtkSmartPointer.h>
+#include <vtkPolyDataMapper.h>
+#include <vtkActor.h>
+#include <vtkSphereSource.h>
+
+#include "Shape.h"
+#include "VtkDataSet.h"
+
+namespace VtkVis {
+
+/**
+ * \brief VTK PolyData sphere
+ *
+ * This class creates a mesh sphere
+ */
+class Sphere : public Shape
+{
+public:
+    Sphere();
+    virtual ~Sphere();
+
+    virtual const char *getClassName() const
+    {
+        return "Sphere";
+    }
+
+    void setThetaResolution(int res)
+    {
+        if (_sphere != NULL)
+            _sphere->SetThetaResolution(res);
+    }
+
+    void setPhiResolution(int res)
+    {
+        if (_sphere != NULL)
+            _sphere->SetPhiResolution(res);
+    }
+
+    void setStartTheta(double val)
+    {
+        if (_sphere != NULL)
+            _sphere->SetStartTheta(val);
+    }
+
+    void setEndTheta(double val)
+    {
+        if (_sphere != NULL)
+            _sphere->SetEndTheta(val);
+    }
+
+    void setStartPhi(double val)
+    {
+        if (_sphere != NULL)
+            _sphere->SetStartPhi(val);
+    }
+
+    void setEndPhi(double val)
+    {
+        if (_sphere != NULL)
+            _sphere->SetEndPhi(val);
+    }
+
+    void setLatLongTessellation(bool val)
+    {
+        if (_sphere != NULL)
+            _sphere->SetLatLongTessellation((val ? 1 : 0));
+    }
+
+    void setRadius(double radius)
+    {
+        if (_sphere != NULL)
+            _sphere->SetRadius(radius);
+    }
+
+private:
+    virtual void update();
+
+    vtkSmartPointer<vtkSphereSource> _sphere;
+};
+
+}
+
+#endif
Index: /trunk/packages/vizservers/vtkvis/Streamlines.cpp
===================================================================
--- /trunk/packages/vizservers/vtkvis/Streamlines.cpp	(revision 3616)
+++ /trunk/packages/vizservers/vtkvis/Streamlines.cpp	(revision 3616)
@@ -0,0 +1,1727 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (C) 2004-2012  HUBzero Foundation, LLC
+ *
+ * Author: Leif Delgass <ldelgass@purdue.edu>
+ */
+
+#include <cstdlib>
+#include <ctime>
+#include <cfloat>
+#include <cmath>
+#include <cstring>
+
+#include <vtkMath.h>
+#include <vtkActor.h>
+#include <vtkProperty.h>
+#include <vtkPoints.h>
+#include <vtkCellArray.h>
+#include <vtkPolyLine.h>
+#include <vtkRegularPolygonSource.h>
+#include <vtkPointData.h>
+#include <vtkCellData.h>
+#include <vtkCellDataToPointData.h>
+#include <vtkPolygon.h>
+#include <vtkPolyData.h>
+#include <vtkTubeFilter.h>
+#include <vtkRibbonFilter.h>
+#include <vtkTransform.h>
+#include <vtkTransformPolyDataFilter.h>
+#include <vtkVertexGlyphFilter.h>
+
+#include "Streamlines.h"
+#include "VtkRenderer.h"
+#include "Trace.h"
+
+using namespace VtkVis;
+
+Streamlines::Streamlines() :
+    VtkGraphicsObject(),
+    _lineType(LINES),
+    _colorMap(NULL),
+    _colorMode(COLOR_BY_VECTOR_MAGNITUDE),
+    _colorFieldType(DataSet::POINT_DATA),
+    _seedVisible(true),
+    _renderer(NULL),
+    _dataScale(1)
+{
+    _faceCulling = true;
+    _color[0] = 1.0f;
+    _color[1] = 1.0f;
+    _color[2] = 1.0f;
+    _seedColor[0] = 1.0f;
+    _seedColor[1] = 1.0f;
+    _seedColor[2] = 1.0f;
+    _colorFieldRange[0] = DBL_MAX;
+    _colorFieldRange[1] = -DBL_MAX;
+    vtkMath::RandomSeed((int)time(NULL));
+    srand((unsigned int)time(NULL));
+}
+
+Streamlines::~Streamlines()
+{
+#ifdef WANT_TRACE
+    if (_dataSet != NULL)
+        TRACE("Deleting Streamlines for %s", _dataSet->getName().c_str());
+    else
+        TRACE("Deleting Streamlines with NULL DataSet");
+#endif
+}
+
+void Streamlines::setDataSet(DataSet *dataSet,
+                             Renderer *renderer)
+{
+    if (_dataSet != dataSet) {
+        _dataSet = dataSet;
+
+        _renderer = renderer;
+
+        if (renderer->getUseCumulativeRange()) {
+            renderer->getCumulativeDataRange(_dataRange,
+                                             _dataSet->getActiveScalarsName(),
+                                             1);
+            renderer->getCumulativeDataRange(_vectorMagnitudeRange,
+                                             _dataSet->getActiveVectorsName(),
+                                             3);
+            for (int i = 0; i < 3; i++) {
+                renderer->getCumulativeDataRange(_vectorComponentRange[i],
+                                                 _dataSet->getActiveVectorsName(),
+                                                 3, i);
+            }
+        } else {
+            _dataSet->getScalarRange(_dataRange);
+            _dataSet->getVectorRange(_vectorMagnitudeRange);
+            for (int i = 0; i < 3; i++) {
+                _dataSet->getVectorRange(_vectorComponentRange[i], i);
+            }
+        }
+
+        update();
+    }
+}
+
+/**
+ * \brief Create and initialize a VTK Prop to render Streamlines
+ */
+void Streamlines::initProp()
+{
+    if (_linesActor == NULL) {
+        _linesActor = vtkSmartPointer<vtkActor>::New();
+        _linesActor->GetProperty()->SetColor(_color[0], _color[1], _color[2]);
+        _linesActor->GetProperty()->SetEdgeColor(_edgeColor[0], _edgeColor[1], _edgeColor[2]);
+        _linesActor->GetProperty()->SetLineWidth(_edgeWidth);
+        _linesActor->GetProperty()->SetOpacity(_opacity);
+        _linesActor->GetProperty()->SetAmbient(.2);
+        if (!_lighting)
+            _linesActor->GetProperty()->LightingOff();
+        switch (_lineType) {
+        case LINES:
+            setCulling(_linesActor->GetProperty(), false);
+            _linesActor->GetProperty()->SetRepresentationToWireframe();
+            _linesActor->GetProperty()->EdgeVisibilityOff();
+            break;
+        case TUBES:
+            if (_faceCulling && _opacity == 1.0)
+                setCulling(_linesActor->GetProperty(), true);
+            _linesActor->GetProperty()->SetRepresentationToSurface();
+            _linesActor->GetProperty()->EdgeVisibilityOff();
+            break;
+        case RIBBONS:
+            setCulling(_linesActor->GetProperty(), false);
+            _linesActor->GetProperty()->SetRepresentationToSurface();
+            _linesActor->GetProperty()->EdgeVisibilityOff();
+            break;
+        default:
+            ;
+        }
+    }
+    if (_seedActor == NULL) {
+        _seedActor = vtkSmartPointer<vtkActor>::New();
+        _seedActor->GetProperty()->SetColor(_seedColor[0], _seedColor[1], _seedColor[2]);
+        _seedActor->GetProperty()->SetEdgeColor(_seedColor[0], _seedColor[1], _seedColor[2]);
+        _seedActor->GetProperty()->SetLineWidth(1);
+        _seedActor->GetProperty()->SetPointSize(2);
+        _seedActor->GetProperty()->SetOpacity(_opacity);
+        _seedActor->GetProperty()->SetRepresentationToWireframe();
+        _seedActor->GetProperty()->LightingOff();
+        setSeedVisibility(_seedVisible);
+    }
+    if (_prop == NULL) {
+        _prop = vtkSmartPointer<vtkAssembly>::New();
+        getAssembly()->AddPart(_linesActor);
+        getAssembly()->AddPart(_seedActor);
+    }
+}
+
+/**
+ * \brief Get a pseudo-random number in range [min,max]
+ */
+double Streamlines::getRandomNum(double min, double max)
+{
+#if 1
+    return vtkMath::Random(min, max);
+#else
+    int r = rand();
+    return (min + ((double)r / RAND_MAX) * (max - min));
+#endif
+}
+
+/**
+ * \brief Get a random 3D point within an AABB
+ *
+ * \param[out] pt The random point
+ * \param[in] bounds The bounds of the AABB
+ */
+void Streamlines::getRandomPoint(double pt[3], const double bounds[6])
+{
+    pt[0] = getRandomNum(bounds[0], bounds[1]);
+    pt[1] = getRandomNum(bounds[2], bounds[3]);
+    pt[2] = getRandomNum(bounds[4], bounds[5]);
+}
+
+/**
+ * \brief Get a random point within a triangle (including edges)
+ *
+ * \param[out] pt The random point
+ * \param[in] v1 Triangle vertex 1
+ * \param[in] v2 Triangle vertex 2
+ * \param[in] v3 Triangle vertex 3
+ */
+void Streamlines::getRandomPointInTriangle(double pt[3],
+                                           const double v0[3],
+                                           const double v1[3],
+                                           const double v2[3])
+{
+    // Choose random barycentric coordinates
+    double bary[3];
+    bary[0] = getRandomNum(0, 1);
+    bary[1] = getRandomNum(0, 1);
+    if (bary[0] + bary[1] > 1.0) {
+        bary[0] = 1.0 - bary[0];
+        bary[1] = 1.0 - bary[1];
+    }
+    bary[2] = 1.0 - bary[0] - bary[1];
+
+    //TRACE("bary %g %g %g", bary[0], bary[1], bary[2]);
+    // Convert to cartesian coords
+    for (int i = 0; i < 3; i++) {
+        pt[i] = v0[i] * bary[0] + v1[i] * bary[1] + v2[i] * bary[2];
+    }
+}
+
+void Streamlines::getRandomPointInTetrahedron(double pt[3],
+                                              const double v0[3],
+                                              const double v1[3],
+                                              const double v2[3],
+                                              const double v3[3])
+{
+    // Choose random barycentric coordinates
+    double bary[4];
+    bary[0] = getRandomNum(0, 1);
+    bary[1] = getRandomNum(0, 1);
+    bary[2] = getRandomNum(0, 1);
+    if (bary[0] + bary[1] > 1.0) {
+        bary[0] = 1.0 - bary[0];
+        bary[1] = 1.0 - bary[1];
+    }
+    if (bary[1] + bary[2] > 1.0) {
+        double tmp = bary[2];
+        bary[2] = 1.0 - bary[0] - bary[1];
+        bary[1] = 1.0 - tmp;
+    } else if (bary[0] + bary[1] + bary[2] > 1.0) {
+        double tmp = bary[2];
+        bary[2] = bary[0] + bary[1] + bary[2] - 1.0;
+        bary[0] = 1.0 - bary[1] - tmp;
+    }
+    bary[3] = 1.0 - bary[0] - bary[1] - bary[2];
+    //TRACE("bary %g %g %g %g", bary[0], bary[1], bary[2], bary[3]);
+    // Convert to cartesian coords
+    for (int i = 0; i < 3; i++) {
+#if 0
+        pt[i] = (v0[i] - v3[i]) * bary[0] +
+                (v1[i] - v3[i]) * bary[1] + 
+                (v2[i] - v3[i]) * bary[2] + v3[i];
+#else
+        pt[i] = v0[i] * bary[0] + v1[i] * bary[1] +
+                v2[i] * bary[2] + v3[i] * bary[3];
+#endif
+    }
+}
+
+/**
+ * \brief Get a random point on a line segment (including endpoints)
+ */
+void Streamlines::getRandomPointOnLineSegment(double pt[3],
+                                              const double endpt[3],
+                                              const double endpt2[3])
+{
+    double ratio = getRandomNum(0, 1);
+    pt[0] = endpt[0] + ratio * (endpt2[0] - endpt[0]);
+    pt[1] = endpt[1] + ratio * (endpt2[1] - endpt[1]);
+    pt[2] = endpt[2] + ratio * (endpt2[2] - endpt[2]);
+}
+
+/**
+ * \brief Get a random point within a vtkDataSet's mesh
+ *
+ * Note: This currently doesn't always give a uniform distribution 
+ * of points in space and can generate points outside the mesh for
+ * unusual cell types
+ */
+void Streamlines::getRandomCellPt(double pt[3], vtkDataSet *ds)
+{
+    int numCells = (int)ds->GetNumberOfCells();
+    // XXX: Not uniform distribution (shouldn't use mod, and assumes
+    // all cells are equal area/volume)
+    int cell = rand() % numCells;
+    int type = ds->GetCellType(cell);
+    switch (type) {
+    case VTK_VERTEX: {
+        vtkSmartPointer<vtkIdList> ptIds = vtkSmartPointer<vtkIdList>::New();
+        ds->GetCellPoints(cell, ptIds);
+        assert(ptIds->GetNumberOfIds() == 1);
+        ds->GetPoint(ptIds->GetId(0), pt);
+    }
+        break;
+    case VTK_POLY_VERTEX: {
+        vtkSmartPointer<vtkIdList> ptIds = vtkSmartPointer<vtkIdList>::New();
+        ds->GetCellPoints(cell, ptIds);
+        assert(ptIds->GetNumberOfIds() >= 1);
+        int id = rand() % ptIds->GetNumberOfIds();
+        ds->GetPoint(ptIds->GetId(id), pt);
+    }
+        break;
+    case VTK_LINE: {
+        double v[2][3];
+        vtkSmartPointer<vtkIdList> ptIds = vtkSmartPointer<vtkIdList>::New();
+        ds->GetCellPoints(cell, ptIds);
+        assert(ptIds->GetNumberOfIds() == 2);
+        for (int i = 0; i < 2; i++) {
+            ds->GetPoint(ptIds->GetId(i), v[i]);
+        }
+        getRandomPointOnLineSegment(pt, v[0], v[1]);
+    }
+        break;
+    case VTK_POLY_LINE: {
+        double v[2][3];
+        vtkSmartPointer<vtkIdList> ptIds = vtkSmartPointer<vtkIdList>::New();
+        ds->GetCellPoints(cell, ptIds);
+        assert(ptIds->GetNumberOfIds() >= 2);
+        int id = rand() % (ptIds->GetNumberOfIds()-1);
+        for (int i = 0; i < 2; i++) {
+            ds->GetPoint(ptIds->GetId(id+i), v[i]);
+        }
+        getRandomPointOnLineSegment(pt, v[0], v[1]);
+    }
+        break;
+    case VTK_TRIANGLE: {
+        double v[3][3];
+        vtkSmartPointer<vtkIdList> ptIds = vtkSmartPointer<vtkIdList>::New();
+        ds->GetCellPoints(cell, ptIds);
+        assert(ptIds->GetNumberOfIds() == 3);
+        for (int i = 0; i < 3; i++) {
+            ds->GetPoint(ptIds->GetId(i), v[i]);
+        }
+        getRandomPointInTriangle(pt, v[0], v[1], v[2]);
+    }
+        break;
+    case VTK_TRIANGLE_STRIP: {
+        double v[3][3];
+        vtkSmartPointer<vtkIdList> ptIds = vtkSmartPointer<vtkIdList>::New();
+        ds->GetCellPoints(cell, ptIds);
+        assert(ptIds->GetNumberOfIds() >= 3);
+        int id = rand() % (ptIds->GetNumberOfIds()-2);
+        for (int i = 0; i < 3; i++) {
+            ds->GetPoint(ptIds->GetId(id+i), v[i]);
+        }
+        getRandomPointInTriangle(pt, v[0], v[1], v[2]);
+    }
+        break;
+    case VTK_POLYGON: {
+        vtkPolygon *poly = vtkPolygon::SafeDownCast(ds->GetCell(cell));
+        assert (poly != NULL);
+        vtkSmartPointer<vtkIdList> ptIds = vtkSmartPointer<vtkIdList>::New();
+        poly->Triangulate(ptIds);
+        assert(ptIds->GetNumberOfIds() >= 3 && ptIds->GetNumberOfIds() % 3 == 0);
+        int tri = rand() % (ptIds->GetNumberOfIds()/3);
+        double v[3][3];
+        for (int i = 0; i < 3; i++) {
+            ds->GetPoint(ptIds->GetId(i + tri * 3), v[i]);
+        }
+        getRandomPointInTriangle(pt, v[0], v[1], v[2]);
+    }
+        break;
+    case VTK_QUAD: {
+        double v[4][3];
+        vtkSmartPointer<vtkIdList> ptIds = vtkSmartPointer<vtkIdList>::New();
+        ds->GetCellPoints(cell, ptIds);
+        assert(ptIds->GetNumberOfIds() == 4);
+        for (int i = 0; i < 4; i++) {
+            ds->GetPoint(ptIds->GetId(i), v[i]);
+        }
+        int tri = rand() & 0x1;
+        if (tri) {
+            getRandomPointInTriangle(pt, v[0], v[1], v[2]);
+        } else {
+            getRandomPointInTriangle(pt, v[0], v[2], v[3]);
+        }
+    }
+        break;
+    case VTK_TETRA: {
+        double v[4][3];
+        vtkSmartPointer<vtkIdList> ptIds = vtkSmartPointer<vtkIdList>::New();
+        ds->GetCellPoints(cell, ptIds);
+        assert(ptIds->GetNumberOfIds() == 4);
+        for (int i = 0; i < 4; i++) {
+            ds->GetPoint(ptIds->GetId(i), v[i]);
+        }
+        getRandomPointInTetrahedron(pt, v[0], v[1], v[2], v[3]);
+    }
+        break;
+    case VTK_WEDGE: {
+        double v[6][3];
+        vtkSmartPointer<vtkIdList> ptIds = vtkSmartPointer<vtkIdList>::New();
+        ds->GetCellPoints(cell, ptIds);
+        assert(ptIds->GetNumberOfIds() == 6);
+        for (int i = 0; i < 6; i++) {
+            ds->GetPoint(ptIds->GetId(i), v[i]);
+        }
+        double vv[3][3];
+        getRandomPointOnLineSegment(vv[0], v[0], v[3]);
+        getRandomPointOnLineSegment(vv[1], v[1], v[4]);
+        getRandomPointOnLineSegment(vv[2], v[2], v[5]);
+        getRandomPointInTriangle(pt, vv[0], vv[1], vv[2]);
+    }
+        break;
+    case VTK_PYRAMID: {
+        double v[5][3];
+        vtkSmartPointer<vtkIdList> ptIds = vtkSmartPointer<vtkIdList>::New();
+        ds->GetCellPoints(cell, ptIds);
+        assert(ptIds->GetNumberOfIds() == 5);
+        for (int i = 0; i < 5; i++) {
+            ds->GetPoint(ptIds->GetId(i), v[i]);
+        }
+        int tetra = rand() & 0x1;
+        if (tetra) {
+            getRandomPointInTetrahedron(pt, v[0], v[1], v[2], v[4]);
+        } else {
+            getRandomPointInTetrahedron(pt, v[0], v[2], v[3], v[4]);
+        }
+    }
+        break;
+    case VTK_PIXEL:
+    case VTK_VOXEL: {
+        double bounds[6];
+        ds->GetCellBounds(cell, bounds);
+        getRandomPoint(pt, bounds);
+    }
+        break;
+    default: {
+        vtkSmartPointer<vtkIdList> ptIds = vtkSmartPointer<vtkIdList>::New();
+        vtkSmartPointer<vtkPoints> pts = vtkSmartPointer<vtkPoints>::New();
+        ds->GetCell(cell)->Triangulate(0, ptIds, pts);
+        if (ptIds->GetNumberOfIds() % 4 == 0) {
+            int tetra = rand() % (ptIds->GetNumberOfIds()/4);
+            double v[4][3];
+            for (int i = 0; i < 4; i++) {
+                ds->GetPoint(ptIds->GetId(i + tetra * 4), v[i]);
+            }
+            getRandomPointInTetrahedron(pt, v[0], v[1], v[2], v[4]);
+        } else {
+            assert(ptIds->GetNumberOfIds() % 3 == 0);
+            int tri = rand() % (ptIds->GetNumberOfIds()/3);
+            double v[3][3];
+            for (int i = 0; i < 3; i++) {
+                ds->GetPoint(ptIds->GetId(i + tri * 3), v[i]);
+            }
+            getRandomPointInTriangle(pt, v[0], v[1], v[2]);
+        }
+    }
+    }
+}
+
+/**
+ * \brief Internal method to set up pipeline after a state change
+ */
+void Streamlines::update()
+{
+    if (_dataSet == NULL) {
+        return;
+    }
+
+    vtkDataSet *ds = _dataSet->getVtkDataSet();
+
+    double bounds[6];
+    _dataSet->getBounds(bounds);
+    double xLen = bounds[1] - bounds[0];
+    double yLen = bounds[3] - bounds[2];
+    double zLen = bounds[5] - bounds[4];
+    double maxBound = 0.0;
+    if (xLen > maxBound) {
+        maxBound = xLen;
+    }
+    if (yLen > maxBound) {
+        maxBound = yLen;
+    }
+    if (zLen > maxBound) {
+        maxBound = zLen;
+    }
+
+    double cellSizeRange[2];
+    double avgSize;
+    _dataSet->getCellSizeRange(cellSizeRange, &avgSize);
+    _dataScale = avgSize / 8.;
+
+    vtkSmartPointer<vtkCellDataToPointData> cellToPtData;
+
+    if (ds->GetPointData() == NULL ||
+        ds->GetPointData()->GetVectors() == NULL) {
+        TRACE("No vector point data found in DataSet %s", _dataSet->getName().c_str());
+        if (ds->GetCellData() != NULL &&
+            ds->GetCellData()->GetVectors() != NULL) {
+            cellToPtData = 
+                vtkSmartPointer<vtkCellDataToPointData>::New();
+#ifdef USE_VTK6
+            cellToPtData->SetInputData(ds);
+#else
+            cellToPtData->SetInput(ds);
+#endif
+            //cellToPtData->PassCellDataOn();
+            cellToPtData->Update();
+            ds = cellToPtData->GetOutput();
+        } else {
+            USER_ERROR("No vector field was found in the data set.");
+            return;
+        }
+    }
+
+    if (_streamTracer == NULL) {
+        _streamTracer = vtkSmartPointer<vtkStreamTracer>::New();
+    }
+
+#ifdef USE_VTK6
+    _streamTracer->SetInputData(ds);
+#else
+    _streamTracer->SetInput(ds);
+#endif
+    _streamTracer->SetMaximumPropagation(xLen + yLen + zLen);
+    _streamTracer->SetIntegratorTypeToRungeKutta45();
+
+    TRACE("Setting streamlines max length to %g", 
+          _streamTracer->GetMaximumPropagation());
+
+    if (_pdMapper == NULL) {
+        _pdMapper = vtkSmartPointer<vtkPolyDataMapper>::New();
+        _pdMapper->SetResolveCoincidentTopologyToPolygonOffset();
+        _pdMapper->ScalarVisibilityOn();
+    }
+    if (_seedMapper == NULL) {
+        _seedMapper = vtkSmartPointer<vtkPolyDataMapper>::New();
+        _seedMapper->SetResolveCoincidentTopologyToPolygonOffset();
+        _seedMapper->ScalarVisibilityOff();
+    }
+
+    // Set up seed source object
+    setSeedToFilledMesh(200);
+
+    switch (_lineType) {
+    case LINES: {
+        _streamTracer->SetComputeVorticity(false);
+        _pdMapper->SetInputConnection(_streamTracer->GetOutputPort());
+    }
+        break;
+    case TUBES: {
+        _streamTracer->SetComputeVorticity(true);
+        _lineFilter = vtkSmartPointer<vtkTubeFilter>::New();
+        vtkTubeFilter *tubeFilter = vtkTubeFilter::SafeDownCast(_lineFilter);
+        tubeFilter->SetNumberOfSides(5);
+        _lineFilter->SetInputConnection(_streamTracer->GetOutputPort());
+        _pdMapper->SetInputConnection(_lineFilter->GetOutputPort());
+    }
+        break;
+    case RIBBONS: {
+        _streamTracer->SetComputeVorticity(true);
+        _lineFilter = vtkSmartPointer<vtkRibbonFilter>::New();
+        _lineFilter->SetInputConnection(_streamTracer->GetOutputPort());
+        _pdMapper->SetInputConnection(_lineFilter->GetOutputPort());
+    }
+        break;
+    default:
+        ERROR("Unknown LineType: %d", _lineType);
+    }
+
+#if 0 && defined(WANT_TRACE)
+    _streamTracer->Update();
+    vtkPolyData *pd = _streamTracer->GetOutput();
+    TRACE("Verts: %d Lines: %d Polys: %d Strips: %d",
+          pd->GetNumberOfVerts(),
+          pd->GetNumberOfLines(),
+          pd->GetNumberOfPolys(),
+          pd->GetNumberOfStrips());
+    vtkCellArray *arr = pd->GetLines();
+    arr->InitTraversal();
+    vtkIdType npts, *pts;
+    arr->GetNextCell(npts, pts);
+    for (int i = 0; i < npts; i++) {
+        TRACE("Pt: %d", pts[i]);
+    }
+#endif
+
+    initProp();
+
+    _seedActor->SetMapper(_seedMapper);
+
+    if (_lut == NULL) {
+        setColorMap(ColorMap::getDefault());
+    }
+
+    setColorMode(_colorMode);
+
+    _linesActor->SetMapper(_pdMapper);
+    _pdMapper->Update();
+    _seedMapper->Update();
+#ifdef WANT_TRACE
+    double *b = getBounds();
+    TRACE("bounds: %g %g %g %g %g %g", b[0], b[1], b[2], b[3], b[4], b[5]);
+#endif
+}
+
+void Streamlines::setNumberOfSeedPoints(int numPoints)
+{
+    switch(_seedType) {
+    case DATASET_FILLED_MESH:
+        setSeedToFilledMesh(numPoints);
+        break;
+    case FILLED_MESH:
+        if (_seedMesh != NULL) {
+            setSeedToFilledMesh(_seedMesh, numPoints);
+        } else {
+            ERROR("NULL _seedMesh");
+        }
+        break;
+    default:
+        ERROR("Can't set number of points for seed type %d", _seedType);
+        break;
+    }
+    _pdMapper->Update();
+    _seedMapper->Update();
+}
+
+/**
+ * \brief Use points of the DataSet associated with this 
+ * Streamlines as seeds
+ */
+void Streamlines::setSeedToMeshPoints()
+{
+    _seedType = DATASET_MESH_POINTS;
+    setSeedToMeshPoints(_dataSet->getVtkDataSet());
+}
+
+/**
+ * \brief Use seed points randomly distributed within the cells 
+ * of the DataSet associated with this Streamlines
+ *
+ * Note: The current implementation doesn't give a uniform 
+ * distribution of points, and points outside the mesh bounds
+ * may be generated
+ *
+ * \param[in] numPoints Number of random seed points to generate
+ */
+void Streamlines::setSeedToFilledMesh(int numPoints)
+{
+    _seedType = DATASET_FILLED_MESH;
+    setSeedToFilledMesh(_dataSet->getVtkDataSet(), numPoints);
+}
+
+/**
+ * \brief Use points of a supplied vtkDataSet as seeds
+ *
+ * \param[in] seed vtkDataSet with points to use as seeds
+ */
+void Streamlines::setSeedToMeshPoints(vtkDataSet *seed)
+{
+    if (seed != _dataSet->getVtkDataSet()) {
+        _seedType = MESH_POINTS;
+    }
+    _seedMesh = NULL;
+    if (_streamTracer != NULL) {
+        TRACE("Seed points: %d", seed->GetNumberOfPoints());
+        vtkSmartPointer<vtkDataSet> oldSeed;
+        if (_streamTracer->GetSource() != NULL) {
+            oldSeed = _streamTracer->GetSource();
+        }
+
+#ifdef USE_VTK6
+        _streamTracer->SetSourceData(seed);
+#else
+        _streamTracer->SetSource(seed);
+
+        if (oldSeed != NULL) {
+            oldSeed->SetPipelineInformation(NULL);
+        }
+#endif
+        if (vtkPolyData::SafeDownCast(seed) != NULL) {
+#ifdef USE_VTK6
+            _seedMapper->SetInputData(vtkPolyData::SafeDownCast(seed));
+#else
+            _seedMapper->SetInput(vtkPolyData::SafeDownCast(seed));
+#endif
+        } else {
+            vtkSmartPointer<vtkVertexGlyphFilter> vertFilter = vtkSmartPointer<vtkVertexGlyphFilter>::New();
+#ifdef USE_VTK6
+            vertFilter->SetInputData(seed);
+#else
+            vertFilter->SetInput(seed);
+#endif
+            _seedMapper->SetInputConnection(vertFilter->GetOutputPort());
+        }
+    }
+}
+
+/**
+ * \brief Use seed points randomly distributed within the cells 
+ * of a supplied vtkDataSet
+ *
+ * Note: The current implementation doesn't give a uniform 
+ * distribution of points, and points outside the mesh bounds
+ * may be generated
+ *
+ * \param[in] ds vtkDataSet containing cells
+ * \param[in] numPoints Number of random seed points to generate
+ */
+void Streamlines::setSeedToFilledMesh(vtkDataSet *ds, int numPoints)
+{
+    if (ds != _dataSet->getVtkDataSet()) {
+        _seedMesh = ds;
+        _seedType = FILLED_MESH;
+#ifdef DEBUG
+        DataSet::print(ds);
+#endif
+    } else {
+        _seedMesh = NULL;
+    }
+    if (_streamTracer != NULL) {
+        // Set up seed source object
+        vtkSmartPointer<vtkPolyData> seed = vtkSmartPointer<vtkPolyData>::New();
+        vtkSmartPointer<vtkPoints> pts = vtkSmartPointer<vtkPoints>::New();
+        vtkSmartPointer<vtkCellArray> cells = vtkSmartPointer<vtkCellArray>::New();
+
+        if (ds->GetNumberOfCells() < 1) {
+            ERROR("No cells in mesh");
+        }
+
+        for (int i = 0; i < numPoints; i++) {
+            double pt[3];
+            getRandomCellPt(pt, ds);
+            //TRACE("Seed pt: %g %g %g", pt[0], pt[1], pt[2]);
+            pts->InsertNextPoint(pt);
+            cells->InsertNextCell(1);
+            cells->InsertCellPoint(i);
+        }
+
+        seed->SetPoints(pts);
+        seed->SetVerts(cells);
+
+        TRACE("Seed points: %d", seed->GetNumberOfPoints());
+        vtkSmartPointer<vtkDataSet> oldSeed;
+        if (_streamTracer->GetSource() != NULL) {
+            oldSeed = _streamTracer->GetSource();
+        }
+
+#ifdef USE_VTK6
+        _streamTracer->SetSourceData(seed);
+        _seedMapper->SetInputData(seed);
+#else
+        _streamTracer->SetSource(seed);
+
+        if (oldSeed != NULL) {
+            oldSeed->SetPipelineInformation(NULL);
+        }
+        _seedMapper->SetInput(seed);
+#endif
+    }
+}
+
+/**
+ * \brief Use seed points along a line
+ *
+ * \param[in] start Starting point of rake line
+ * \param[in] end End point of rake line
+ * \param[in] numPoints Number of points along line to generate
+ */
+void Streamlines::setSeedToRake(double start[3], double end[3], int numPoints)
+{
+    if (numPoints < 2)
+        return;
+    _seedType = RAKE;
+    _seedMesh = NULL;
+    if (_streamTracer != NULL) {
+        // Set up seed source object
+        vtkSmartPointer<vtkPolyData> seed = vtkSmartPointer<vtkPolyData>::New();
+        vtkSmartPointer<vtkPoints> pts = vtkSmartPointer<vtkPoints>::New();
+        vtkSmartPointer<vtkCellArray> cells = vtkSmartPointer<vtkCellArray>::New();
+        vtkSmartPointer<vtkPolyLine> polyline = vtkSmartPointer<vtkPolyLine>::New();
+
+        double dir[3];
+        for (int i = 0; i < 3; i++) {
+            dir[i] = end[i] - start[i];
+        }
+
+        polyline->GetPointIds()->SetNumberOfIds(numPoints);
+        for (int i = 0; i < numPoints; i++) {
+            double pt[3];
+            for (int ii = 0; ii < 3; ii++) {
+                pt[ii] = start[ii] + dir[ii] * ((double)i / (numPoints-1));
+            }
+            //TRACE("Seed pt: %g %g %g", pt[0], pt[1], pt[2]);
+            pts->InsertNextPoint(pt);
+            polyline->GetPointIds()->SetId(i, i);
+        }
+
+        cells->InsertNextCell(polyline);
+        seed->SetPoints(pts);
+        seed->SetLines(cells);
+
+        TRACE("Seed points: %d", seed->GetNumberOfPoints());
+        vtkSmartPointer<vtkDataSet> oldSeed;
+        if (_streamTracer->GetSource() != NULL) {
+            oldSeed = _streamTracer->GetSource();
+        }
+#ifdef USE_VTK6
+        _streamTracer->SetSourceData(seed);
+        _seedMapper->SetInputData(seed);
+#else
+        _streamTracer->SetSource(seed);
+        if (oldSeed != NULL) {
+            oldSeed->SetPipelineInformation(NULL);
+        }
+
+        _seedMapper->SetInput(seed);
+#endif
+    }
+}
+
+/**
+ * \brief Create seed points inside a disk with an optional hole
+ *
+ * \param[in] center Center point of disk
+ * \param[in] normal Normal vector to orient disk
+ * \param[in] radius Radius of disk
+ * \param[in] innerRadius Radius of hole at center of disk
+ * \param[in] numPoints Number of random points to generate
+ */
+void Streamlines::setSeedToDisk(double center[3],
+                                double normal[3],
+                                double radius,
+                                double innerRadius,
+                                int numPoints)
+{
+    _seedType = DISK;
+    _seedMesh = NULL;
+    if (_streamTracer != NULL) {
+        // Set up seed source object
+        vtkSmartPointer<vtkPolyData> seed = vtkSmartPointer<vtkPolyData>::New();
+        vtkSmartPointer<vtkPoints> pts = vtkSmartPointer<vtkPoints>::New();
+        vtkSmartPointer<vtkCellArray> cells = vtkSmartPointer<vtkCellArray>::New();
+
+        // The following code is based on vtkRegularPolygonSource::RequestData
+
+        double px[3];
+        double py[3];
+        double axis[3] = {1., 0., 0.};
+
+        if (vtkMath::Normalize(normal) == 0.0) {
+            normal[0] = 0.0;
+            normal[1] = 0.0;
+            normal[2] = 1.0;
+        }
+
+        // Find axis in plane (orthogonal to normal)
+        bool done = false;
+        vtkMath::Cross(normal, axis, px);
+        if (vtkMath::Normalize(px) > 1.0e-3) {
+            done = true;
+        }
+        if (!done) {
+            axis[0] = 0.0;
+            axis[1] = 1.0;
+            axis[2] = 0.0;
+            vtkMath::Cross(normal, axis, px);
+            if (vtkMath::Normalize(px) > 1.0e-3) {
+                done = true;
+            }
+        }
+        if (!done) {
+            axis[0] = 0.0;
+            axis[1] = 0.0;
+            axis[2] = 1.0;
+            vtkMath::Cross(normal, axis, px);
+            vtkMath::Normalize(px);
+        }
+        // Create third orthogonal basis vector
+        vtkMath::Cross(px, normal, py);
+
+        double minSquared = (innerRadius*innerRadius)/(radius*radius);
+        for (int j = 0; j < numPoints; j++) {
+            // Get random sweep angle and radius
+#ifdef USE_VTK6
+            double angle = getRandomNum(0, 2.0 * vtkMath::Pi());
+#else
+            double angle = getRandomNum(0, 2.0 * vtkMath::DoublePi());
+#endif
+            // Need sqrt to get uniform distribution
+            double r = sqrt(getRandomNum(minSquared, 1)) * radius;
+            double pt[3];
+            for (int i = 0; i < 3; i++) {
+                pt[i] = center[i] + r * (px[i] * cos(angle) + py[i] * sin(angle));
+            }
+            //TRACE("Seed pt: %g %g %g", pt[0], pt[1], pt[2]);
+            pts->InsertNextPoint(pt);
+            cells->InsertNextCell(1);
+            cells->InsertCellPoint(j);
+        }
+
+        seed->SetPoints(pts);
+        seed->SetVerts(cells);
+
+        TRACE("Seed points: %d", seed->GetNumberOfPoints());
+        vtkSmartPointer<vtkDataSet> oldSeed;
+        if (_streamTracer->GetSource() != NULL) {
+            oldSeed = _streamTracer->GetSource();
+        }
+#ifdef USE_VTK6
+        _streamTracer->SetSourceData(seed);
+        _seedMapper->SetInputData(seed);
+#else
+        _streamTracer->SetSource(seed);
+        if (oldSeed != NULL) {
+            oldSeed->SetPipelineInformation(NULL);
+        }
+
+        _seedMapper->SetInput(seed);
+#endif
+    }
+}
+
+/**
+ * \brief Use seed points from an n-sided polygon
+ *
+ * \param[in] center Center point of polygon
+ * \param[in] normal Normal vector to orient polygon
+ * \param[in] angle Angle in degrees to rotate about normal
+ * \param[in] radius Radius of circumscribing circle
+ * \param[in] numSides Number of polygon sides (and points) to generate
+ */
+void Streamlines::setSeedToPolygon(double center[3],
+                                   double normal[3],
+                                   double angle,
+                                   double radius,
+                                   int numSides)
+{
+    _seedType = POLYGON;
+    _seedMesh = NULL;
+    if (_streamTracer != NULL) {
+        // Set up seed source object
+        vtkSmartPointer<vtkRegularPolygonSource> seed = vtkSmartPointer<vtkRegularPolygonSource>::New();
+
+        seed->SetCenter(center);
+        seed->SetNormal(normal);
+        seed->SetRadius(radius);
+        seed->SetNumberOfSides(numSides);
+        seed->GeneratePolygonOn();
+
+        if (angle != 0.0) {
+            vtkSmartPointer<vtkTransform> trans = vtkSmartPointer<vtkTransform>::New();
+            trans->RotateWXYZ(angle, normal);
+            vtkSmartPointer<vtkTransformPolyDataFilter> transFilt =
+                vtkSmartPointer<vtkTransformPolyDataFilter>::New();
+            transFilt->SetInputConnection(seed->GetOutputPort());
+            transFilt->SetTransform(trans);
+        }
+
+        TRACE("Seed points: %d", numSides);
+        vtkSmartPointer<vtkDataSet> oldSeed;
+        if (_streamTracer->GetSource() != NULL) {
+            oldSeed = _streamTracer->GetSource();
+        }
+
+        if (angle != 0.0) {
+            vtkSmartPointer<vtkTransform> trans = vtkSmartPointer<vtkTransform>::New();
+            trans->Translate(+center[0], +center[1], +center[2]);
+            trans->RotateWXYZ(angle, normal);
+            trans->Translate(-center[0], -center[1], -center[2]);
+            vtkSmartPointer<vtkTransformPolyDataFilter> transFilt =
+                vtkSmartPointer<vtkTransformPolyDataFilter>::New();
+            transFilt->SetInputConnection(seed->GetOutputPort());
+            transFilt->SetTransform(trans);
+            _streamTracer->SetSourceConnection(transFilt->GetOutputPort());
+            _seedMapper->SetInputConnection(transFilt->GetOutputPort());
+        } else {
+            _streamTracer->SetSourceConnection(seed->GetOutputPort());
+            _seedMapper->SetInputConnection(seed->GetOutputPort());
+        }
+
+#ifndef USE_VTK6
+        if (oldSeed != NULL) {
+            oldSeed->SetPipelineInformation(NULL);
+        }
+#endif
+    }
+}
+
+/**
+ * \brief Use seed points from an n-sided polygon
+ *
+ * \param[in] center Center point of polygon
+ * \param[in] normal Normal vector to orient polygon
+ * \param[in] angle Angle in degrees to rotate about normal
+ * \param[in] radius Radius of circumscribing circle
+ * \param[in] numSides Number of polygon sides (and points) to generate
+ * \param[in] numPoints Number of random points to generate
+ */
+void Streamlines::setSeedToFilledPolygon(double center[3],
+                                         double normal[3],
+                                         double angle,
+                                         double radius,
+                                         int numSides,
+                                         int numPoints)
+{
+    _seedType = FILLED_POLYGON;
+    _seedMesh = NULL;
+    if (_streamTracer != NULL) {
+         // Set up seed source object
+        vtkSmartPointer<vtkPolyData> seed = vtkSmartPointer<vtkPolyData>::New();
+        vtkSmartPointer<vtkPoints> pts = vtkSmartPointer<vtkPoints>::New();
+        vtkSmartPointer<vtkCellArray> cells = vtkSmartPointer<vtkCellArray>::New();
+
+        // The following code is based on vtkRegularPolygonSource::RequestData
+
+        double px[3];
+        double py[3];
+        double axis[3] = {1., 0., 0.};
+
+        if (vtkMath::Normalize(normal) == 0.0) {
+            normal[0] = 0.0;
+            normal[1] = 0.0;
+            normal[2] = 1.0;
+        }
+
+        // Find axis in plane (orthogonal to normal)
+        bool done = false;
+        vtkMath::Cross(normal, axis, px);
+        if (vtkMath::Normalize(px) > 1.0e-3) {
+            done = true;
+        }
+        if (!done) {
+            axis[0] = 0.0;
+            axis[1] = 1.0;
+            axis[2] = 0.0;
+            vtkMath::Cross(normal, axis, px);
+            if (vtkMath::Normalize(px) > 1.0e-3) {
+                done = true;
+            }
+        }
+        if (!done) {
+            axis[0] = 0.0;
+            axis[1] = 0.0;
+            axis[2] = 1.0;
+            vtkMath::Cross(normal, axis, px);
+            vtkMath::Normalize(px);
+        }
+        // Create third orthogonal basis vector
+        vtkMath::Cross(px, normal, py);
+
+        double verts[numSides][3];
+#ifdef USE_VTK6
+        double sliceTheta = 2.0 * vtkMath::Pi() / (double)numSides;
+#else
+        double sliceTheta = 2.0 * vtkMath::DoublePi() / (double)numSides;
+#endif
+        angle = vtkMath::RadiansFromDegrees(angle);
+        for (int j = 0; j < numSides; j++) {
+            for (int i = 0; i < 3; i++) {
+                double theta = sliceTheta * (double)j - angle;
+                verts[j][i] = center[i] + radius * (px[i] * cos(theta) + 
+                                                    py[i] * sin(theta));
+            }
+            //TRACE("Vert %d: %g %g %g", j, verts[j][0], verts[j][1], verts[j][2]);
+        }
+
+        // Note: this gives a uniform distribution because the polygon is regular and
+        // the triangular sections have equal area
+        if (numSides == 3) {
+            for (int j = 0; j < numPoints; j++) {
+                double pt[3];
+                getRandomPointInTriangle(pt, verts[0], verts[1], verts[2]);
+                //TRACE("Seed pt: %g %g %g", pt[0], pt[1], pt[2]);
+                pts->InsertNextPoint(pt);
+                cells->InsertNextCell(1);
+                cells->InsertCellPoint(j);
+            }
+        } else {
+            for (int j = 0; j < numPoints; j++) {
+                // Get random triangle section
+                int tri = rand() % numSides;
+                double pt[3];
+                getRandomPointInTriangle(pt, center, verts[tri], verts[(tri+1) % numSides]);
+                //TRACE("Seed pt: %g %g %g", pt[0], pt[1], pt[2]);
+                pts->InsertNextPoint(pt);
+                cells->InsertNextCell(1);
+                cells->InsertCellPoint(j);
+            }
+        }
+
+        seed->SetPoints(pts);
+        seed->SetVerts(cells);
+
+        TRACE("Seed points: %d", seed->GetNumberOfPoints());
+        vtkSmartPointer<vtkDataSet> oldSeed;
+        if (_streamTracer->GetSource() != NULL) {
+            oldSeed = _streamTracer->GetSource();
+        }
+
+#ifdef USE_VTK6
+        _streamTracer->SetSourceData(seed);
+        _seedMapper->SetInputData(seed);
+#else
+        _streamTracer->SetSource(seed);
+        if (oldSeed != NULL) {
+            oldSeed->SetPipelineInformation(NULL);
+        }
+
+        _seedMapper->SetInput(seed);
+#endif
+    }
+}
+
+/**
+ * \brief Set the integration method used
+ */
+void Streamlines::setIntegrator(IntegratorType integrator)
+{
+    if (_streamTracer != NULL) {
+        switch (integrator) {
+        case RUNGE_KUTTA2:
+            _streamTracer->SetIntegratorTypeToRungeKutta2();
+            break;
+        case RUNGE_KUTTA4:
+            _streamTracer->SetIntegratorTypeToRungeKutta4();
+            break;
+        case RUNGE_KUTTA45:
+            _streamTracer->SetIntegratorTypeToRungeKutta45();
+            break;
+        default:
+            ;
+        }
+    }
+}
+
+/**
+ * \brief Set the direction of integration
+ */
+void Streamlines::setIntegrationDirection(IntegrationDirection dir)
+{
+    if (_streamTracer != NULL) {
+        switch (dir) {
+        case FORWARD:
+            _streamTracer->SetIntegrationDirectionToForward();
+            break;
+        case BACKWARD:
+            _streamTracer->SetIntegrationDirectionToBackward();
+            break;
+        case BOTH:
+            _streamTracer->SetIntegrationDirectionToBoth();
+            break;
+        default:
+            ;
+        }
+    }
+}
+
+/**
+ * \brief Set the step size units.  Length units are world 
+ * coordinates, and cell units means steps are from cell to 
+ * cell.  Default is cell units.
+ *
+ * Note: calling this function will not convert existing
+ * initial, minimum or maximum step value settings to the
+ * new units, so this function should be called before 
+ * setting step values.
+ */
+void Streamlines::setIntegrationStepUnit(StepUnit unit)
+{
+    if (_streamTracer != NULL) {
+        switch (unit) {
+        case LENGTH_UNIT:
+            _streamTracer->SetIntegrationStepUnit(vtkStreamTracer::LENGTH_UNIT);
+            break;
+        case CELL_LENGTH_UNIT:
+            _streamTracer->SetIntegrationStepUnit(vtkStreamTracer::CELL_LENGTH_UNIT);
+            break;
+        default:
+            ;
+        }
+    }
+}
+
+/**
+ * \brief Set initial step size for adaptive step integrator in 
+ * step units (see setIntegrationStepUnit).  For non-adaptive
+ * integrators, this is the fixed step size.
+ */
+void Streamlines::setInitialIntegrationStep(double step)
+{
+    if (_streamTracer != NULL) {
+        _streamTracer->SetInitialIntegrationStep(step);
+    }
+}
+
+/**
+ * \brief Set minimum step for adaptive step integrator in 
+ * step units (see setIntegrationStepUnit)
+ */
+void Streamlines::setMinimumIntegrationStep(double step)
+{
+    if (_streamTracer != NULL) {
+        _streamTracer->SetMinimumIntegrationStep(step);
+    }
+}
+
+/**
+ * \brief Set maximum step for adaptive step integrator in 
+ * step units (see setIntegrationStepUnit)
+ */
+void Streamlines::setMaximumIntegrationStep(double step)
+{
+    if (_streamTracer != NULL) {
+        _streamTracer->SetMaximumIntegrationStep(step);
+    }
+}
+
+/**
+ * \brief Set maximum error tolerance
+ */
+void Streamlines::setMaximumError(double error)
+{
+    if (_streamTracer != NULL) {
+        _streamTracer->SetMaximumError(error);
+    }
+}
+
+/**
+ * \brief Set maximum length of stream lines in world
+ * coordinates
+ */
+void Streamlines::setMaxPropagation(double length)
+{
+    if (_streamTracer != NULL) {
+        _streamTracer->SetMaximumPropagation(length);
+    }
+}
+
+/**
+ * \brief Set maximum number of integration steps
+ */
+void Streamlines::setMaxNumberOfSteps(int steps)
+{
+    if (_streamTracer != NULL) {
+        _streamTracer->SetMaximumNumberOfSteps(steps);
+    }
+}
+
+/**
+ * \brief Set the minimum speed before integration stops
+ */
+void Streamlines::setTerminalSpeed(double speed)
+{
+    if (_streamTracer != NULL) {
+        _streamTracer->SetTerminalSpeed(speed);
+    }
+}
+
+/**
+ * \brief Set streamline type to polylines
+ */
+void Streamlines::setLineTypeToLines()
+{
+    _lineType = LINES;
+    if (_streamTracer != NULL &&
+        _pdMapper != NULL) {
+        _streamTracer->SetComputeVorticity(false);
+        _pdMapper->SetInputConnection(_streamTracer->GetOutputPort());
+        _lineFilter = NULL;
+        setCulling(_linesActor->GetProperty(), false);
+        _linesActor->GetProperty()->SetRepresentationToWireframe();
+        _linesActor->GetProperty()->LightingOff();
+    }
+}
+
+/**
+ * \brief Set streamline type to 3D tubes
+ *
+ * \param[in] numSides Number of sides (>=3) for tubes
+ * \param[in] radius World coordinate minimum tube radius
+ */
+void Streamlines::setLineTypeToTubes(int numSides, double radius)
+{
+    _lineType = TUBES;
+    if (_streamTracer != NULL) {
+        _streamTracer->SetComputeVorticity(true);
+        if (vtkTubeFilter::SafeDownCast(_lineFilter) == NULL) {
+            _lineFilter = vtkSmartPointer<vtkTubeFilter>::New();
+            _lineFilter->SetInputConnection(_streamTracer->GetOutputPort());
+        }
+        vtkTubeFilter *tubeFilter = vtkTubeFilter::SafeDownCast(_lineFilter);
+        if (numSides < 3)
+            numSides = 3;
+        tubeFilter->SetNumberOfSides(numSides);
+        tubeFilter->SetRadius(_dataScale * radius);
+        _pdMapper->SetInputConnection(_lineFilter->GetOutputPort());
+        if (_faceCulling && _opacity == 1.0)
+            setCulling(_linesActor->GetProperty(), true);
+        _linesActor->GetProperty()->SetRepresentationToSurface();
+        _linesActor->GetProperty()->LightingOn();
+     }
+}
+
+/**
+ * \brief Set streamline type to 3D ribbons
+ *
+ * \param[in] width Minimum half-width of ribbons
+ * \param[in] angle Default ribbon angle in degrees from normal
+ */
+void Streamlines::setLineTypeToRibbons(double width, double angle)
+{
+    _lineType = RIBBONS;
+    if (_streamTracer != NULL) {
+        _streamTracer->SetComputeVorticity(true);
+        if (vtkRibbonFilter::SafeDownCast(_lineFilter) == NULL) {
+            _lineFilter = vtkSmartPointer<vtkRibbonFilter>::New();
+            _lineFilter->SetInputConnection(_streamTracer->GetOutputPort());
+        }
+        vtkRibbonFilter *ribbonFilter = vtkRibbonFilter::SafeDownCast(_lineFilter);
+        ribbonFilter->SetWidth(_dataScale * width);
+        ribbonFilter->SetAngle(angle);
+        ribbonFilter->UseDefaultNormalOn();
+        _pdMapper->SetInputConnection(_lineFilter->GetOutputPort());
+        setCulling(_linesActor->GetProperty(), false);
+        _linesActor->GetProperty()->SetRepresentationToSurface();
+        _linesActor->GetProperty()->LightingOn();
+    }
+}
+
+void Streamlines::updateRanges(Renderer *renderer)
+{
+    if (_dataSet == NULL) {
+        ERROR("called before setDataSet");
+        return;
+    }
+
+    if (renderer->getUseCumulativeRange()) {
+        renderer->getCumulativeDataRange(_dataRange,
+                                         _dataSet->getActiveScalarsName(),
+                                         1);
+        renderer->getCumulativeDataRange(_vectorMagnitudeRange,
+                                         _dataSet->getActiveVectorsName(),
+                                         3);
+        for (int i = 0; i < 3; i++) {
+            renderer->getCumulativeDataRange(_vectorComponentRange[i],
+                                             _dataSet->getActiveVectorsName(),
+                                             3, i);
+        }
+    } else {
+        _dataSet->getScalarRange(_dataRange);
+        _dataSet->getVectorRange(_vectorMagnitudeRange);
+        for (int i = 0; i < 3; i++) {
+            _dataSet->getVectorRange(_vectorComponentRange[i], i);
+        }
+    }
+
+    // Need to update color map ranges and/or active vector field
+    double *rangePtr = _colorFieldRange;
+    if (_colorFieldRange[0] > _colorFieldRange[1]) {
+        rangePtr = NULL;
+    }
+    setColorMode(_colorMode, _colorFieldType, _colorFieldName.c_str(), rangePtr);
+}
+
+void Streamlines::setColorMode(ColorMode mode)
+{
+    _colorMode = mode;
+    if (_dataSet == NULL)
+        return;
+
+    switch (mode) {
+    case COLOR_BY_SCALAR:
+        setColorMode(mode,
+                     _dataSet->getActiveScalarsType(),
+                     _dataSet->getActiveScalarsName(),
+                     _dataRange);
+        break;
+    case COLOR_BY_VECTOR_MAGNITUDE:
+        setColorMode(mode,
+                     _dataSet->getActiveVectorsType(),
+                     _dataSet->getActiveVectorsName(),
+                     _vectorMagnitudeRange);
+        break;
+    case COLOR_BY_VECTOR_X:
+        setColorMode(mode,
+                     _dataSet->getActiveVectorsType(),
+                     _dataSet->getActiveVectorsName(),
+                     _vectorComponentRange[0]);
+        break;
+    case COLOR_BY_VECTOR_Y:
+        setColorMode(mode,
+                     _dataSet->getActiveVectorsType(),
+                     _dataSet->getActiveVectorsName(),
+                     _vectorComponentRange[1]);
+        break;
+    case COLOR_BY_VECTOR_Z:
+        setColorMode(mode,
+                     _dataSet->getActiveVectorsType(),
+                     _dataSet->getActiveVectorsName(),
+                     _vectorComponentRange[2]);
+        break;
+    case COLOR_CONSTANT:
+    default:
+        setColorMode(mode, DataSet::POINT_DATA, NULL, NULL);
+        break;
+    }
+}
+
+void Streamlines::setColorMode(ColorMode mode,
+                               const char *name, double range[2])
+{
+    if (_dataSet == NULL)
+        return;
+    DataSet::DataAttributeType type = DataSet::POINT_DATA;
+    int numComponents = 1;
+    if (name != NULL && strlen(name) > 0 &&
+        !_dataSet->getFieldInfo(name, &type, &numComponents)) {
+        ERROR("Field not found: %s", name);
+        return;
+    }
+    setColorMode(mode, type, name, range);
+}
+
+void Streamlines::setColorMode(ColorMode mode, DataSet::DataAttributeType type,
+                               const char *name, double range[2])
+{
+    _colorMode = mode;
+    _colorFieldType = type;
+    if (name == NULL)
+        _colorFieldName.clear();
+    else
+        _colorFieldName = name;
+    if (range == NULL) {
+        _colorFieldRange[0] = DBL_MAX;
+        _colorFieldRange[1] = -DBL_MAX;
+    } else {
+        memcpy(_colorFieldRange, range, sizeof(double)*2);
+    }
+
+    if (_dataSet == NULL || _pdMapper == NULL)
+        return;
+
+    switch (type) {
+    case DataSet::POINT_DATA:
+        _pdMapper->SetScalarModeToUsePointFieldData();
+        break;
+    case DataSet::CELL_DATA:
+        _pdMapper->SetScalarModeToUseCellFieldData();
+        break;
+    default:
+        ERROR("Unsupported DataAttributeType: %d", type);
+        return;
+    }
+
+    if (name != NULL && strlen(name) > 0) {
+        _pdMapper->SelectColorArray(name);
+    } else {
+        _pdMapper->SetScalarModeToDefault();
+    }
+
+    if (_lut != NULL) {
+        if (range != NULL) {
+            _lut->SetRange(range);
+        } else if (name != NULL && strlen(name) > 0) {
+            double r[2];
+            int comp = -1;
+            if (mode == COLOR_BY_VECTOR_X)
+                comp = 0;
+            else if (mode == COLOR_BY_VECTOR_Y)
+                comp = 1;
+            else if (mode == COLOR_BY_VECTOR_Z)
+                comp = 2;
+
+            if (_renderer->getUseCumulativeRange()) {
+                int numComponents;
+                if  (!_dataSet->getFieldInfo(name, type, &numComponents)) {
+                    ERROR("Field not found: %s, type: %d", name, type);
+                    return;
+                } else if (numComponents < comp+1) {
+                    ERROR("Request for component %d in field with %d components",
+                          comp, numComponents);
+                    return;
+                }
+                _renderer->getCumulativeDataRange(r, name, type, numComponents, comp);
+            } else {
+                _dataSet->getDataRange(r, name, type, comp);
+            }
+            _lut->SetRange(r);
+        }
+    }
+
+    switch (mode) {
+    case COLOR_BY_SCALAR:
+        _pdMapper->ScalarVisibilityOn();
+        break;
+    case COLOR_BY_VECTOR_MAGNITUDE:
+        _pdMapper->ScalarVisibilityOn();
+        if (_lut != NULL) {
+            _lut->SetVectorModeToMagnitude();
+        }
+        break;
+    case COLOR_BY_VECTOR_X:
+        _pdMapper->ScalarVisibilityOn();
+        if (_lut != NULL) {
+            _lut->SetVectorModeToComponent();
+            _lut->SetVectorComponent(0);
+        }
+        break;
+    case COLOR_BY_VECTOR_Y:
+        _pdMapper->ScalarVisibilityOn();
+        if (_lut != NULL) {
+            _lut->SetVectorModeToComponent();
+            _lut->SetVectorComponent(1);
+        }
+        break;
+    case COLOR_BY_VECTOR_Z:
+        _pdMapper->ScalarVisibilityOn();
+        if (_lut != NULL) {
+            _lut->SetVectorModeToComponent();
+            _lut->SetVectorComponent(2);
+        }
+        break;
+    case COLOR_CONSTANT:
+    default:
+        _pdMapper->ScalarVisibilityOff();
+        break;
+    }
+}
+
+/**
+ * \brief Called when the color map has been edited
+ */
+void Streamlines::updateColorMap()
+{
+    setColorMap(_colorMap);
+}
+
+/**
+ * \brief Associate a colormap lookup table with the DataSet
+ */
+void Streamlines::setColorMap(ColorMap *cmap)
+{
+    if (cmap == NULL)
+        return;
+
+    _colorMap = cmap;
+ 
+    if (_lut == NULL) {
+        _lut = vtkSmartPointer<vtkLookupTable>::New();
+        if (_pdMapper != NULL) {
+            _pdMapper->UseLookupTableScalarRangeOn();
+            _pdMapper->SetLookupTable(_lut);
+        }
+        _lut->DeepCopy(cmap->getLookupTable());
+        switch (_colorMode) {
+        case COLOR_CONSTANT:
+        case COLOR_BY_SCALAR:
+            _lut->SetRange(_dataRange);
+            break;
+        case COLOR_BY_VECTOR_MAGNITUDE:
+            _lut->SetRange(_vectorMagnitudeRange);
+            break;
+        case COLOR_BY_VECTOR_X:
+            _lut->SetRange(_vectorComponentRange[0]);
+            break;
+        case COLOR_BY_VECTOR_Y:
+            _lut->SetRange(_vectorComponentRange[1]);
+            break;
+        case COLOR_BY_VECTOR_Z:
+            _lut->SetRange(_vectorComponentRange[2]);
+            break;
+        default:
+            break;
+        }
+    } else {
+        double range[2];
+        _lut->GetTableRange(range);
+        _lut->DeepCopy(cmap->getLookupTable());
+        _lut->SetRange(range);
+        _lut->Modified();
+    }
+
+    switch (_colorMode) {
+    case COLOR_BY_VECTOR_MAGNITUDE:
+        _lut->SetVectorModeToMagnitude();
+        break;
+    case COLOR_BY_VECTOR_X:
+        _lut->SetVectorModeToComponent();
+        _lut->SetVectorComponent(0);
+        break;
+    case COLOR_BY_VECTOR_Y:
+        _lut->SetVectorModeToComponent();
+        _lut->SetVectorComponent(1);
+        break;
+    case COLOR_BY_VECTOR_Z:
+        _lut->SetVectorModeToComponent();
+        _lut->SetVectorComponent(2);
+        break;
+    default:
+         break;
+    }
+}
+
+/**
+ * \brief Turn on/off lighting of this object
+ */
+void Streamlines::setLighting(bool state)
+{
+    _lighting = state;
+    if (_linesActor != NULL)
+        _linesActor->GetProperty()->SetLighting((state ? 1 : 0));
+}
+
+/**
+ * \brief Set opacity of this object
+ */
+void Streamlines::setOpacity(double opacity)
+{
+    _opacity = opacity;
+    if (_linesActor != NULL) {
+        _linesActor->GetProperty()->SetOpacity(_opacity);
+        if (_opacity < 1.0)
+            setCulling(_linesActor->GetProperty(), false);
+        else if (_faceCulling && _lineType == TUBES)
+            setCulling(_linesActor->GetProperty(), true);
+    }
+    if (_seedActor != NULL) {
+        _seedActor->GetProperty()->SetOpacity(_opacity);
+    }
+}
+
+/**
+ * \brief Turn on/off rendering of this Streamlines
+ */
+void Streamlines::setVisibility(bool state)
+{
+    if (_linesActor != NULL) {
+        _linesActor->SetVisibility((state ? 1 : 0));
+    }
+    if (_seedActor != NULL) {
+        if (!state ||
+            (state && _seedVisible)) {
+            _seedActor->SetVisibility((state ? 1 : 0));
+        }
+    }
+}
+
+/**
+ * \brief Turn on/off rendering of the seed geometry
+ */
+void Streamlines::setSeedVisibility(bool state)
+{
+    _seedVisible = state;
+    if (_seedActor != NULL) {
+        _seedActor->SetVisibility((state ? 1 : 0));
+    }
+}
+
+/**
+ * \brief Get visibility state of the Streamlines
+ * 
+ * \return Are the Streamlines visible?
+ */
+bool Streamlines::getVisibility()
+{
+    if (_linesActor == NULL) {
+        return false;
+    } else {
+        return (_linesActor->GetVisibility() != 0);
+    }
+}
+
+/**
+ * \brief Turn on/off rendering of edges
+ */
+void Streamlines::setEdgeVisibility(bool state)
+{
+    if (_linesActor != NULL) {
+        _linesActor->GetProperty()->SetEdgeVisibility((state ? 1 : 0));
+    }
+}
+
+/**
+ * \brief Set RGB color of stream lines
+ */
+void Streamlines::setColor(float color[3])
+{
+    _color[0] = color[0];
+    _color[1] = color[1];
+    _color[2] = color[2];
+    if (_linesActor != NULL)
+        _linesActor->GetProperty()->SetColor(_color[0], _color[1], _color[2]);
+}
+
+/**
+ * \brief Set RGB color of stream line edges
+ */
+void Streamlines::setEdgeColor(float color[3])
+{
+    _edgeColor[0] = color[0];
+    _edgeColor[1] = color[1];
+    _edgeColor[2] = color[2];
+    if (_linesActor != NULL)
+        _linesActor->GetProperty()->SetEdgeColor(_edgeColor[0], _edgeColor[1], _edgeColor[2]);
+}
+
+/**
+ * \brief Set RGB color of seed geometry
+ */
+void Streamlines::setSeedColor(float color[3])
+{
+    _seedColor[0] = color[0];
+    _seedColor[1] = color[1];
+    _seedColor[2] = color[2];
+    if (_seedActor != NULL) {
+        _seedActor->GetProperty()->SetColor(_seedColor[0], _seedColor[1], _seedColor[2]);
+        _seedActor->GetProperty()->SetEdgeColor(_seedColor[0], _seedColor[1], _seedColor[2]);
+    }
+}
+
+/**
+ * \brief Set pixel width of stream lines (may be a no-op)
+ */
+void Streamlines::setEdgeWidth(float edgeWidth)
+{
+    _edgeWidth = edgeWidth;
+    if (_linesActor != NULL)
+        _linesActor->GetProperty()->SetLineWidth(_edgeWidth);
+}
+
+/**
+ * \brief Set a group of world coordinate planes to clip rendering
+ *
+ * Passing NULL for planes will remove all cliping planes
+ */
+void Streamlines::setClippingPlanes(vtkPlaneCollection *planes)
+{
+    if (_pdMapper != NULL) {
+        _pdMapper->SetClippingPlanes(planes);
+    }
+    if (_seedMapper != NULL) {
+        _seedMapper->SetClippingPlanes(planes);
+    }
+}
Index: /trunk/packages/vizservers/vtkvis/Streamlines.h
===================================================================
--- /trunk/packages/vizservers/vtkvis/Streamlines.h	(revision 3616)
+++ /trunk/packages/vizservers/vtkvis/Streamlines.h	(revision 3616)
@@ -0,0 +1,221 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (C) 2004-2012  HUBzero Foundation, LLC
+ *
+ * Author: Leif Delgass <ldelgass@purdue.edu>
+ */
+
+#ifndef VTKVIS_STREAMLINES_H
+#define VTKVIS_STREAMLINES_H
+
+#include <vtkSmartPointer.h>
+#include <vtkProp.h>
+#include <vtkPlaneCollection.h>
+#include <vtkStreamTracer.h>
+#include <vtkPolyDataAlgorithm.h>
+#include <vtkPolyDataMapper.h>
+#include <vtkLookupTable.h>
+#include <vtkAssembly.h>
+
+#include "ColorMap.h"
+#include "VtkGraphicsObject.h"
+#include "VtkDataSet.h"
+
+namespace VtkVis {
+
+/**
+ * \brief Streamline visualization of vector fields
+ *
+ * The DataSet must contain vectors
+ */
+class Streamlines : public VtkGraphicsObject {
+public:
+    enum LineType {
+        LINES,
+        TUBES,
+        RIBBONS
+    };
+    enum ColorMode {
+        COLOR_BY_SCALAR,
+        COLOR_BY_VECTOR_MAGNITUDE,
+        COLOR_BY_VECTOR_X,
+        COLOR_BY_VECTOR_Y,
+        COLOR_BY_VECTOR_Z,
+        COLOR_CONSTANT
+    };
+    enum StepUnit {
+        LENGTH_UNIT,
+        CELL_LENGTH_UNIT
+    };
+    enum IntegratorType {
+        RUNGE_KUTTA2,
+        RUNGE_KUTTA4,
+        RUNGE_KUTTA45
+    };
+    enum IntegrationDirection {
+        FORWARD,
+        BACKWARD,
+        BOTH
+    };
+    enum SeedType {
+        DATASET_MESH_POINTS,
+        DATASET_FILLED_MESH,
+        MESH_POINTS,
+        FILLED_MESH,
+        RAKE,
+        DISK,
+        POLYGON,
+        FILLED_POLYGON
+    };
+
+    Streamlines();
+    virtual ~Streamlines();
+
+    virtual const char *getClassName() const 
+    {
+        return "Streamlines";
+    }
+
+    virtual void setDataSet(DataSet *dataSet,
+                            Renderer *renderer);
+
+    virtual void setLighting(bool state);
+
+    virtual void setOpacity(double opacity);
+
+    virtual void setVisibility(bool state);
+
+    virtual bool getVisibility();
+
+    virtual void setColor(float color[3]);
+
+    virtual void setEdgeVisibility(bool state);
+
+    virtual void setEdgeColor(float color[3]);
+
+    virtual void setEdgeWidth(float edgeWidth);
+
+    virtual void setClippingPlanes(vtkPlaneCollection *planes);
+
+    void setNumberOfSeedPoints(int numPoints);
+
+    void setSeedToMeshPoints();
+
+    void setSeedToFilledMesh(int numPoints);
+
+    void setSeedToMeshPoints(vtkDataSet *ds);
+
+    void setSeedToFilledMesh(vtkDataSet *ds, int numPoints);
+
+    void setSeedToRake(double start[3], double end[3], int numPoints);
+
+    void setSeedToDisk(double center[3], double normal[3],
+                       double radius, double innerRadius, int numPoints);
+
+    void setSeedToPolygon(double center[3], double normal[3],
+                          double angle, double radius,
+                          int numSides);
+
+    void setSeedToFilledPolygon(double center[3], double normal[3],
+                                double angle, double radius,
+                                int numSides, int numPoints);
+
+    void setIntegrator(IntegratorType integrator);
+
+    void setIntegrationDirection(IntegrationDirection dir);
+
+    void setIntegrationStepUnit(StepUnit unit);
+
+    void setInitialIntegrationStep(double step);
+
+    void setMinimumIntegrationStep(double step);
+
+    void setMaximumIntegrationStep(double step);
+
+    void setMaximumError(double error);
+
+    void setMaxPropagation(double length);
+
+    void setMaxNumberOfSteps(int steps);
+
+    void setTerminalSpeed(double speed);
+
+    void setLineTypeToLines();
+
+    void setLineTypeToTubes(int numSides, double radius);
+
+    void setLineTypeToRibbons(double width, double angle);
+
+    void setColorMode(ColorMode mode, DataSet::DataAttributeType type,
+                      const char *name, double range[2] = NULL);
+
+    void setColorMode(ColorMode mode,
+                      const char *name, double range[2] = NULL);
+
+    void setColorMode(ColorMode mode);
+
+    void setColorMap(ColorMap *colorMap);
+
+    /**
+     * \brief Return the ColorMap in use
+     */
+    ColorMap *getColorMap()
+    {
+        return _colorMap;
+    }
+
+    void updateColorMap();
+
+    virtual void updateRanges(Renderer *renderer);
+
+    void setSeedVisibility(bool state);
+
+    void setSeedColor(float color[3]);
+
+private:
+    virtual void initProp();
+    virtual void update();
+
+    static double getRandomNum(double min, double max);
+    static void getRandomPoint(double pt[3], const double bounds[6]);
+    static void getRandomPointInTriangle(double pt[3],
+                                         const double v0[3],
+                                         const double v1[3],
+                                         const double v2[3]);
+    static void getRandomPointOnLineSegment(double pt[3],
+                                            const double endpt[3],
+                                            const double endpt2[3]);
+    static void getRandomPointInTetrahedron(double pt[3],
+                                            const double v0[3],
+                                            const double v1[3],
+                                            const double v2[3],
+                                            const double v3[3]);
+    static void getRandomCellPt(double pt[3], vtkDataSet *ds);
+
+    LineType _lineType;
+    ColorMap *_colorMap;
+    ColorMode _colorMode;
+    std::string _colorFieldName;
+    DataSet::DataAttributeType _colorFieldType;
+    double _colorFieldRange[2];
+    SeedType _seedType;
+    float _seedColor[3];
+    bool _seedVisible;
+    double _vectorMagnitudeRange[2];
+    double _vectorComponentRange[3][2];
+    Renderer *_renderer;
+    double _dataScale;
+
+    vtkSmartPointer<vtkLookupTable> _lut;
+    vtkSmartPointer<vtkActor> _linesActor;
+    vtkSmartPointer<vtkActor> _seedActor;
+    vtkSmartPointer<vtkDataSet> _seedMesh;
+    vtkSmartPointer<vtkStreamTracer> _streamTracer;
+    vtkSmartPointer<vtkPolyDataAlgorithm> _lineFilter;
+    vtkSmartPointer<vtkPolyDataMapper> _pdMapper;
+    vtkSmartPointer<vtkPolyDataMapper> _seedMapper;
+};
+
+}
+
+#endif
Index: /trunk/packages/vizservers/vtkvis/Types.h
===================================================================
--- /trunk/packages/vizservers/vtkvis/Types.h	(revision 3616)
+++ /trunk/packages/vizservers/vtkvis/Types.h	(revision 3616)
@@ -0,0 +1,27 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (C) 2004-2012  HUBzero Foundation, LLC
+ *
+ * Author: Leif Delgass <ldelgass@purdue.edu>
+ */
+
+#ifndef VTKVIS_TYPES_H
+#define VTKVIS_TYPES_H
+
+namespace VtkVis {
+
+    enum Axis {
+        X_AXIS = 0,
+        Y_AXIS,
+        Z_AXIS
+    };
+
+    enum PrincipalPlane {
+        PLANE_XY = 0,
+        PLANE_ZY,
+        PLANE_XZ
+    };
+
+}
+
+#endif
Index: /trunk/packages/vizservers/vtkvis/Volume.cpp
===================================================================
--- /trunk/packages/vizservers/vtkvis/Volume.cpp	(revision 3616)
+++ /trunk/packages/vizservers/vtkvis/Volume.cpp	(revision 3616)
@@ -0,0 +1,282 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (C) 2004-2012  HUBzero Foundation, LLC
+ *
+ * Author: Leif Delgass <ldelgass@purdue.edu>
+ */
+
+#include <cassert>
+
+#include <vtkDataSet.h>
+#include <vtkPointData.h>
+#include <vtkImageData.h>
+#include <vtkVolumeProperty.h>
+#include <vtkGPUVolumeRayCastMapper.h>
+#include <vtkVolumeTextureMapper3D.h>
+#include <vtkUnstructuredGrid.h>
+#include <vtkPolyData.h>
+#include <vtkCellType.h>
+#include <vtkUnstructuredGridVolumeMapper.h>
+#include <vtkUnstructuredGridVolumeRayCastMapper.h>
+#include <vtkProjectedTetrahedraMapper.h>
+#include <vtkDataSetTriangleFilter.h>
+#include <vtkGaussianSplatter.h>
+
+#include "Volume.h"
+#include "Trace.h"
+
+using namespace VtkVis;
+
+Volume::Volume() :
+    VtkGraphicsObject(),
+    _colorMap(NULL)
+{
+}
+
+Volume::~Volume()
+{
+#ifdef WANT_TRACE
+    if (_dataSet != NULL)
+        TRACE("Deleting Volume for %s", _dataSet->getName().c_str());
+    else
+        TRACE("Deleting Volume with NULL DataSet");
+#endif
+}
+
+/**
+ * \brief Create and initialize a VTK Prop to render the Volume
+ */
+void Volume::initProp()
+{
+    if (_prop == NULL) {
+        _prop = vtkSmartPointer<vtkVolume>::New();
+        getVolume()->GetProperty()->SetInterpolationTypeToLinear();
+    }
+}
+
+/**
+ * \brief Get the voxel dimensions (if the volume is not a
+ * uniform grid, unit spacing is returned)
+ */
+void Volume::getSpacing(double spacing[3])
+{
+    spacing[0] = spacing[1] = spacing[2] = 1.0;
+    if (_dataSet == NULL)
+        return;
+    vtkDataSet *ds = _dataSet->getVtkDataSet();
+    if (ds != NULL && vtkImageData::SafeDownCast(ds) != NULL) {
+        vtkImageData::SafeDownCast(ds)->GetSpacing(spacing);
+    } else if (ds != NULL && vtkVolumeMapper::SafeDownCast(_volumeMapper) != NULL) {
+        vtkImageData *imgData = vtkVolumeMapper::SafeDownCast(_volumeMapper)->GetInput();
+        if (imgData != NULL) {
+            imgData->GetSpacing(spacing);
+        }
+    }
+}
+
+/**
+ * \brief Get the average voxel dimension (if the volume is not a
+ * uniform grid, unit spacing is returned)
+ */
+double Volume::getAverageSpacing()
+{
+    double spacing[3];
+    getSpacing(spacing);
+    return (spacing[0] + spacing[1] + spacing[2]) * 0.333;
+}
+
+/**
+ * \brief Internal method to set up pipeline after a state change
+ */
+void Volume::update()
+{
+    if (_dataSet == NULL)
+        return;
+
+    vtkDataSet *ds = _dataSet->getVtkDataSet();
+
+    if (_dataSet->is2D()) {
+        USER_ERROR("Volume rendering requires a 3D data set");
+        _dataSet = NULL;
+        return;
+    }
+
+    if (vtkImageData::SafeDownCast(ds) != NULL) {
+        // Image data required for these mappers
+#ifdef USE_GPU_RAYCAST_MAPPER
+        _volumeMapper = vtkSmartPointer<vtkGPUVolumeRayCastMapper>::New();
+        vtkGPUVolumeRayCastMapper::SafeDownCast(_volumeMapper)->AutoAdjustSampleDistancesOff();
+#else
+        _volumeMapper = vtkSmartPointer<vtkVolumeTextureMapper3D>::New();
+#endif
+#ifdef USE_VTK6
+#ifdef USE_GPU_RAYCAST_MAPPER
+        vtkGPUVolumeRayCastMapper::SafeDownCast(_volumeMapper)->SetInputData(ds);
+#else
+        vtkVolumeTextureMapper3D::SafeDownCast(_volumeMapper)->SetInputData(ds);
+#endif
+#else
+        _volumeMapper->SetInput(ds);
+#endif
+        vtkVolumeMapper::SafeDownCast(_volumeMapper)->SetBlendModeToComposite();
+    } else if (vtkUnstructuredGrid::SafeDownCast(ds) != NULL) {
+        vtkUnstructuredGrid *ugrid = vtkUnstructuredGrid::SafeDownCast(ds);
+        // DataSet is unstructured grid
+        // Only works if cells are all tetrahedra
+        _volumeMapper = vtkSmartPointer<vtkProjectedTetrahedraMapper>::New();
+        // Software raycast rendering - requires all tetrahedra
+        //_volumeMapper = vtkSmartPointer<vtkUnstructuredGridVolumeRayCastMapper>::New();
+        if (ugrid->GetCellType(0) == VTK_TETRA &&
+            ugrid->IsHomogeneous()) {
+#ifdef USE_VTK6
+            vtkProjectedTetrahedraMapper::SafeDownCast(_volumeMapper)->SetInputData(ds);
+#else
+            _volumeMapper->SetInput(ds);
+#endif
+        } else {
+            // Decompose to tetrahedra
+            vtkSmartPointer<vtkDataSetTriangleFilter> filter = 
+                vtkSmartPointer<vtkDataSetTriangleFilter>::New();
+#ifdef USE_VTK6
+            filter->SetInputData(ugrid);
+#else
+            filter->SetInput(ugrid);
+#endif
+            filter->TetrahedraOnlyOn();
+            _volumeMapper->SetInputConnection(filter->GetOutputPort());
+        }
+
+        vtkUnstructuredGridVolumeMapper::SafeDownCast(_volumeMapper)->
+            SetBlendModeToComposite();
+    } else if (vtkPolyData::SafeDownCast(ds) != NULL &&
+               vtkPolyData::SafeDownCast(ds)->GetNumberOfLines() == 0 &&
+               vtkPolyData::SafeDownCast(ds)->GetNumberOfPolys() == 0 &&
+               vtkPolyData::SafeDownCast(ds)->GetNumberOfStrips() == 0 ) {
+        // DataSet is a 3D point cloud
+        vtkSmartPointer<vtkGaussianSplatter> splatter = vtkSmartPointer<vtkGaussianSplatter>::New();
+#ifdef USE_VTK6
+        splatter->SetInputData(ds);
+#else
+        splatter->SetInput(ds);
+#endif
+        int dims[3];
+        dims[0] = dims[1] = dims[2] = 64;
+        TRACE("Generating volume with dims (%d,%d,%d) from point cloud",
+              dims[0], dims[1], dims[2]);
+        splatter->SetSampleDimensions(dims);
+#ifdef USE_GPU_RAYCAST_MAPPER
+        _volumeMapper = vtkSmartPointer<vtkGPUVolumeRayCastMapper>::New();
+        vtkGPUVolumeRayCastMapper::SafeDownCast(_volumeMapper)->AutoAdjustSampleDistancesOff();
+#else
+        _volumeMapper = vtkSmartPointer<vtkVolumeTextureMapper3D>::New();
+#endif
+        _volumeMapper->SetInputConnection(splatter->GetOutputPort());
+        vtkVolumeMapper::SafeDownCast(_volumeMapper)->SetBlendModeToComposite();
+    } else {
+        ERROR("Unsupported DataSet type: %s", _dataSet->getVtkType());
+        _dataSet = NULL;
+        return;
+    }
+
+    TRACE("Using mapper type: %s", _volumeMapper->GetClassName());
+
+    initProp();
+
+    if (ds->GetPointData() == NULL ||
+        ds->GetPointData()->GetScalars() == NULL) {
+        WARN("No scalar point data in dataset %s", _dataSet->getName().c_str());
+    }
+
+    if (_colorMap == NULL) {
+        setColorMap(ColorMap::getVolumeDefault());
+    }
+
+    setSampleDistance(getAverageSpacing());
+
+    getVolume()->SetMapper(_volumeMapper);
+    _volumeMapper->Update();
+}
+
+void Volume::updateRanges(Renderer *renderer)
+{
+    VtkGraphicsObject::updateRanges(renderer);
+
+    if (getVolume() != NULL) {
+        getVolume()->GetProperty()->SetColor(_colorMap->getColorTransferFunction(_dataRange));
+        getVolume()->GetProperty()->SetScalarOpacity(_colorMap->getOpacityTransferFunction(_dataRange));
+    }
+}
+
+void Volume::updateColorMap()
+{
+    setColorMap(_colorMap);
+}
+
+/**
+ * \brief Assign a color map (transfer function) to use in rendering the Volume
+ */
+void Volume::setColorMap(ColorMap *cmap)
+{
+    if (cmap == NULL)
+        return;
+
+    _colorMap = cmap;
+
+    if (getVolume() != NULL) {
+        getVolume()->GetProperty()->SetColor(_colorMap->getColorTransferFunction(_dataRange));
+        getVolume()->GetProperty()->SetScalarOpacity(_colorMap->getOpacityTransferFunction(_dataRange));
+    }
+}
+
+/**
+ * \brief Return the ColorMap assigned to this Volume
+ */
+ColorMap *Volume::getColorMap()
+{
+    return _colorMap;
+}
+
+/**
+ * \brief Set opacity scaling used to render the Volume
+ */
+void Volume::setOpacity(double opacity)
+{
+    _opacity = opacity;
+    // FIXME: There isn't really a good opacity scaling option that works
+    // across the different mappers/algorithms.  This only works with the
+    // 3D texture mapper, not the GPU raycast mapper
+    if (getVolume() != NULL) {
+        if (opacity < 1.0e-6)
+            opacity = 1.0e-6;
+        getVolume()->GetProperty()->SetScalarOpacityUnitDistance(1.0/opacity);
+    }
+}
+
+/**
+ * \brief Set a group of world coordinate planes to clip rendering
+ *
+ * Passing NULL for planes will remove all cliping planes
+ */
+void Volume::setClippingPlanes(vtkPlaneCollection *planes)
+{
+    if (_volumeMapper != NULL) {
+        _volumeMapper->SetClippingPlanes(planes);
+    }
+}
+
+/**
+ * \brief Set distance between samples along rays
+ */
+void Volume::setSampleDistance(float d)
+{
+    TRACE("Sample distance: %g", d);
+    if (_volumeMapper != NULL &&
+#ifdef USE_GPU_RAYCAST_MAPPER
+        vtkGPUVolumeRayCastMapper::SafeDownCast(_volumeMapper) != NULL) {
+        vtkGPUVolumeRayCastMapper::SafeDownCast(_volumeMapper)->SetSampleDistance(d);
+#else
+        vtkVolumeTextureMapper3D::SafeDownCast(_volumeMapper) != NULL) {
+        vtkVolumeTextureMapper3D::SafeDownCast(_volumeMapper)->SetSampleDistance(d);
+#endif
+    }
+}
Index: /trunk/packages/vizservers/vtkvis/Volume.h
===================================================================
--- /trunk/packages/vizservers/vtkvis/Volume.h	(revision 3616)
+++ /trunk/packages/vizservers/vtkvis/Volume.h	(revision 3616)
@@ -0,0 +1,72 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (C) 2004-2012  HUBzero Foundation, LLC
+ *
+ * Author: Leif Delgass <ldelgass@purdue.edu>
+ */
+
+#ifndef VTKVIS_VOLUME_H
+#define VTKVIS_VOLUME_H
+
+#include <vtkSmartPointer.h>
+#include <vtkProp.h>
+#include <vtkVolume.h>
+#include <vtkAbstractVolumeMapper.h>
+#include <vtkPlaneCollection.h>
+
+#include "VtkGraphicsObject.h"
+#include "ColorMap.h"
+
+namespace VtkVis {
+
+/**
+ * \brief Volume Rendering
+ *
+ * Currently the DataSet must be image data (3D uniform grid),
+ * or an UnstructuredGrid
+ */
+class Volume : public VtkGraphicsObject {
+public:
+    enum BlendMode {
+        COMPOSITE = 0,
+        MAX_INTENSITY,
+        MIN_INTENSITY
+    };
+
+    Volume();
+    virtual ~Volume();
+
+    virtual const char *getClassName() const
+    {
+        return "Volume";
+    }
+
+    void getSpacing(double spacing[3]);
+
+    double getAverageSpacing();
+
+    virtual void setOpacity(double opacity);
+
+    virtual void setClippingPlanes(vtkPlaneCollection *planes);
+
+    void setColorMap(ColorMap *cmap);
+
+    ColorMap *getColorMap();
+
+    void updateColorMap();
+
+    virtual void updateRanges(Renderer *renderer);
+
+    void setSampleDistance(float d);
+
+private:
+    virtual void initProp();
+    virtual void update();
+
+    ColorMap *_colorMap;
+    vtkSmartPointer<vtkAbstractVolumeMapper> _volumeMapper;
+};
+
+}
+
+#endif
Index: /trunk/packages/vizservers/vtkvis/VtkDataSet.cpp
===================================================================
--- /trunk/packages/vizservers/vtkvis/VtkDataSet.cpp	(revision 3616)
+++ /trunk/packages/vizservers/vtkvis/VtkDataSet.cpp	(revision 3616)
@@ -0,0 +1,930 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (C) 2004-2012  HUBzero Foundation, LLC
+ *
+ * Author: Leif Delgass <ldelgass@purdue.edu>
+ */
+
+#include <cassert>
+#include <cstring>
+#include <cfloat>
+#include <cmath>
+
+#include <vtkCharArray.h>
+#include <vtkDataSetReader.h>
+#include <vtkDataSetWriter.h>
+#include <vtkPolyData.h>
+#include <vtkStructuredPoints.h>
+#include <vtkStructuredGrid.h>
+#include <vtkRectilinearGrid.h>
+#include <vtkUnstructuredGrid.h>
+#include <vtkProperty.h>
+#include <vtkPointData.h>
+#include <vtkCellData.h>
+#include <vtkCell.h>
+#include <vtkLookupTable.h>
+
+#include "VtkDataSet.h"
+#include "Trace.h"
+
+using namespace VtkVis;
+
+DataSet::DataSet(const std::string& name) :
+    _name(name),
+    _visible(true),
+    _opacity(1),
+    _cellSizeAverage(0)
+{
+    _cellSizeRange[0] = -1;
+    _cellSizeRange[1] = -1;
+}
+
+DataSet::~DataSet()
+{
+}
+
+/**
+ * \brief Set opacity of DataSet outline
+ *
+ * This method is used for record-keeping and opacity of the
+ * DataSet bounds outline.  The renderer controls opacity 
+ * of other related graphics objects.
+ */
+void DataSet::setOpacity(double opacity)
+{
+    _opacity = opacity;
+}
+
+/**
+ * \brief Set visibility flag in DataSet
+ *
+ * This method is used for record-keeping and visibility of the
+ * DataSet bounds outline.  The renderer controls visibility 
+ * of other related graphics objects.
+ */
+void DataSet::setVisibility(bool state)
+{
+    _visible = state;
+}
+
+/**
+ * \brief Get visibility flag in DataSet
+ *
+ * This method is used for record-keeping.  The renderer controls
+ * the visibility of related graphics objects.
+ */
+bool DataSet::getVisibility() const
+{
+    return _visible;
+}
+
+void DataSet::writeDataFile(const char *filename)
+{
+    if (_dataSet == NULL)
+        return;
+    
+    vtkSmartPointer<vtkDataSetWriter> writer = vtkSmartPointer<vtkDataSetWriter>::New();
+
+    writer->SetFileName(filename);
+#ifdef USE_VTK6
+    writer->SetInputData(_dataSet);
+#else
+    writer->SetInput(_dataSet);
+#endif
+    writer->Write();
+}
+
+/**
+ * \brief Read a VTK data file
+ */
+bool DataSet::setDataFile(const char *filename)
+{
+    vtkSmartPointer<vtkDataSetReader> reader = vtkSmartPointer<vtkDataSetReader>::New();
+
+#if defined(WANT_TRACE) && defined(DEBUG)
+    reader->DebugOn();
+#endif
+
+    reader->SetFileName(filename);
+    reader->ReadAllNormalsOn();
+    //reader->ReadAllTCoordsOn();
+    reader->ReadAllScalarsOn();
+    //reader->ReadAllColorScalarsOn();
+    reader->ReadAllVectorsOn();
+    //reader->ReadAllTensorsOn();
+    reader->ReadAllFieldsOn();
+
+    return setData(reader);
+}
+
+/**
+ * \brief Read a VTK data file from a memory buffer
+ */
+bool DataSet::setData(char *data, int nbytes)
+{
+    vtkSmartPointer<vtkDataSetReader> reader = vtkSmartPointer<vtkDataSetReader>::New();
+    vtkSmartPointer<vtkCharArray> dataSetString = vtkSmartPointer<vtkCharArray>::New();
+
+#if defined(WANT_TRACE) && defined(DEBUG)
+    reader->DebugOn();
+    dataSetString->DebugOn();
+#endif
+
+    dataSetString->SetArray(data, nbytes, 1);
+    reader->SetInputArray(dataSetString);
+    reader->ReadFromInputStringOn();
+    reader->ReadAllNormalsOn();
+    //reader->ReadAllTCoordsOn();
+    reader->ReadAllScalarsOn();
+    //reader->ReadAllColorScalarsOn();
+    reader->ReadAllVectorsOn();
+    //reader->ReadAllTensorsOn();
+    reader->ReadAllFieldsOn();
+
+    return setData(reader);
+}
+
+void DataSet::print() const
+{
+    print(_dataSet);
+}
+
+void DataSet::print(vtkDataSet *ds)
+{
+    if (ds == NULL)
+        return;
+
+    TRACE("DataSet class: %s", ds->GetClassName());
+
+    TRACE("DataSet memory: %g MiB", ds->GetActualMemorySize()/1024.);
+
+    double bounds[6];
+    ds->GetBounds(bounds);
+
+    // Topology
+    TRACE("DataSet bounds: %g %g %g %g %g %g",
+          bounds[0], bounds[1],
+          bounds[2], bounds[3],
+          bounds[4], bounds[5]);
+    TRACE("Points: %d Cells: %d", ds->GetNumberOfPoints(), ds->GetNumberOfCells());
+
+    double dataRange[2];
+    if (ds->GetPointData() != NULL) {
+        TRACE("PointData arrays: %d", ds->GetPointData()->GetNumberOfArrays());
+        for (int i = 0; i < ds->GetPointData()->GetNumberOfArrays(); i++) {
+            if (ds->GetPointData()->GetArray(i) != NULL) {
+                ds->GetPointData()->GetArray(i)->GetRange(dataRange, -1);
+                TRACE("PointData[%d]: '%s' comp:%d, (%g,%g)", i,
+                      ds->GetPointData()->GetArrayName(i),
+                      ds->GetPointData()->GetAbstractArray(i)->GetNumberOfComponents(),
+                      dataRange[0], dataRange[1]);
+            } else {
+                TRACE("PointData[%d]: '%s' comp:%d", i,
+                      ds->GetPointData()->GetArrayName(i),
+                      ds->GetPointData()->GetAbstractArray(i)->GetNumberOfComponents());
+            }
+        }
+    }
+    if (ds->GetCellData() != NULL) {
+        TRACE("CellData arrays: %d", ds->GetCellData()->GetNumberOfArrays());
+        for (int i = 0; i < ds->GetCellData()->GetNumberOfArrays(); i++) {
+            if (ds->GetCellData()->GetArray(i) != NULL) {
+                ds->GetCellData()->GetArray(i)->GetRange(dataRange, -1);
+                TRACE("CellData[%d]: '%s' comp:%d, (%g,%g)", i,
+                      ds->GetCellData()->GetArrayName(i),
+                      ds->GetCellData()->GetAbstractArray(i)->GetNumberOfComponents(),
+                      dataRange[0], dataRange[1]);
+            } else {
+                TRACE("CellData[%d]: '%s' comp:%d", i,
+                      ds->GetCellData()->GetArrayName(i),
+                      ds->GetCellData()->GetAbstractArray(i)->GetNumberOfComponents());
+            }
+        }
+    }
+    if (ds->GetFieldData() != NULL) {
+        TRACE("FieldData arrays: %d", ds->GetFieldData()->GetNumberOfArrays());
+        for (int i = 0; i < ds->GetFieldData()->GetNumberOfArrays(); i++) {
+            if (ds->GetFieldData()->GetArray(i) != NULL) {
+                ds->GetFieldData()->GetArray(i)->GetRange(dataRange, -1);
+                TRACE("FieldData[%d]: '%s' comp:%d, tuples:%d (%g,%g)", i,
+                      ds->GetFieldData()->GetArrayName(i),
+                      ds->GetFieldData()->GetAbstractArray(i)->GetNumberOfComponents(),
+                      ds->GetFieldData()->GetAbstractArray(i)->GetNumberOfTuples(),
+                      dataRange[0], dataRange[1]);
+            } else {
+                TRACE("FieldData[%d]: '%s' comp:%d, tuples:%d", i,
+                      ds->GetFieldData()->GetArrayName(i),
+                      ds->GetFieldData()->GetAbstractArray(i)->GetNumberOfComponents(),
+                      ds->GetFieldData()->GetAbstractArray(i)->GetNumberOfTuples());
+            }
+        }
+    }
+}
+
+void DataSet::setDefaultArrays()
+{
+    if (_dataSet->GetPointData() != NULL &&
+        _dataSet->GetPointData()->GetScalars() == NULL &&
+        _dataSet->GetPointData()->GetNumberOfArrays() > 0) {
+        for (int i = 0; i < _dataSet->GetPointData()->GetNumberOfArrays(); i++) {
+            if (_dataSet->GetPointData()->GetArray(i) != NULL &&
+                _dataSet->GetPointData()->GetArray(i)->GetNumberOfComponents() == 1) {
+                TRACE("Setting point scalars to '%s'", _dataSet->GetPointData()->GetArrayName(i));
+                _dataSet->GetPointData()->SetActiveScalars(_dataSet->GetPointData()->GetArrayName(i));
+                break;
+            }
+        }
+    }
+    if (_dataSet->GetPointData() != NULL &&
+        _dataSet->GetPointData()->GetVectors() == NULL &&
+        _dataSet->GetPointData()->GetNumberOfArrays() > 0) {
+        for (int i = 0; i < _dataSet->GetPointData()->GetNumberOfArrays(); i++) {
+            if (_dataSet->GetPointData()->GetArray(i) != NULL &&
+                _dataSet->GetPointData()->GetArray(i)->GetNumberOfComponents() == 3) {
+                TRACE("Setting point vectors to '%s'", _dataSet->GetPointData()->GetArrayName(i));
+                _dataSet->GetPointData()->SetActiveVectors(_dataSet->GetPointData()->GetArrayName(i));
+                break;
+            }
+        }
+    }
+    if (_dataSet->GetCellData() != NULL &&
+        _dataSet->GetCellData()->GetScalars() == NULL &&
+        _dataSet->GetCellData()->GetNumberOfArrays() > 0) {
+        for (int i = 0; i < _dataSet->GetCellData()->GetNumberOfArrays(); i++) {
+            if (_dataSet->GetCellData()->GetArray(i) != NULL &&
+                _dataSet->GetCellData()->GetArray(i)->GetNumberOfComponents() == 1) {
+                TRACE("Setting cell scalars to '%s'", _dataSet->GetCellData()->GetArrayName(i));
+                _dataSet->GetCellData()->SetActiveScalars(_dataSet->GetCellData()->GetArrayName(i));
+                break;
+            }
+        }
+    }
+    if (_dataSet->GetCellData() != NULL &&
+        _dataSet->GetCellData()->GetVectors() == NULL &&
+        _dataSet->GetCellData()->GetNumberOfArrays() > 0) {
+        for (int i = 0; i < _dataSet->GetCellData()->GetNumberOfArrays(); i++) {
+            if (_dataSet->GetCellData()->GetArray(i) != NULL &&
+                _dataSet->GetCellData()->GetArray(i)->GetNumberOfComponents() == 3) {
+                TRACE("Setting cell vectors to '%s'", _dataSet->GetCellData()->GetArrayName(i));
+                _dataSet->GetCellData()->SetActiveVectors(_dataSet->GetCellData()->GetArrayName(i));
+                break;
+            }
+        }
+    }
+}
+
+/**
+ * \brief Read dataset using supplied reader
+ *
+ * Pipeline information is removed from the resulting 
+ * vtkDataSet, so that the reader and its data can be 
+ * released
+ */
+bool DataSet::setData(vtkDataSetReader *reader)
+{
+    TRACE("Enter");
+    // Force reading data set
+    reader->SetLookupTableName("");
+    reader->Update();
+
+    _dataSet = reader->GetOutput();
+    if (_dataSet == NULL)
+        return false;
+#ifndef USE_VTK6
+    _dataSet->SetPipelineInformation(NULL);
+#endif
+    if (_dataSet->GetPointData() != NULL &&
+        _dataSet->GetPointData()->GetScalars() != NULL &&
+        _dataSet->GetPointData()->GetScalars()->GetLookupTable() != NULL) {
+        USER_ERROR("No lookup table should be specified in VTK data sets");
+    }
+
+    setDefaultArrays();
+
+#ifdef WANT_TRACE
+    print();
+#endif
+    TRACE("Leave");
+    return true;
+}
+
+/**
+ * \brief Set DataSet from existing vtkDataSet object
+ *
+ * Pipeline information is removed from the supplied vtkDataSet
+ */
+bool DataSet::setData(vtkDataSet *ds)
+{
+    _dataSet = ds;
+#ifndef USE_VTK6
+    _dataSet->SetPipelineInformation(NULL);
+#endif
+
+    if (_dataSet->GetPointData() != NULL &&
+        _dataSet->GetPointData()->GetScalars() != NULL &&
+        _dataSet->GetPointData()->GetScalars()->GetLookupTable() != NULL) {
+        USER_ERROR("No lookup table should be specified in VTK data sets");
+    }
+
+    setDefaultArrays();
+
+#ifdef WANT_TRACE
+    print();
+#endif
+    return true;
+}
+
+/**
+ * \brief Copy an existing vtkDataSet object
+ *
+ * Pipeline information is not copied from the supplied vtkDataSet
+ * into this DataSet, but pipeline information in the supplied 
+ * vtkDataSet is not removed
+ */
+vtkDataSet *DataSet::copyData(vtkDataSet *ds)
+{
+    if (vtkPolyData::SafeDownCast(ds) != NULL) {
+        _dataSet = vtkSmartPointer<vtkPolyData>::New();
+        _dataSet->DeepCopy(vtkPolyData::SafeDownCast(ds));
+    } else if (vtkStructuredPoints::SafeDownCast(ds) != NULL) {
+        _dataSet = vtkSmartPointer<vtkStructuredPoints>::New();
+        _dataSet->DeepCopy(vtkStructuredPoints::SafeDownCast(ds));
+    } else if (vtkStructuredGrid::SafeDownCast(ds) != NULL) {
+        _dataSet = vtkSmartPointer<vtkStructuredGrid>::New();
+        _dataSet->DeepCopy(vtkStructuredGrid::SafeDownCast(ds));
+    } else if (vtkRectilinearGrid::SafeDownCast(ds) != NULL) {
+        _dataSet = vtkSmartPointer<vtkRectilinearGrid>::New();
+        _dataSet->DeepCopy(vtkRectilinearGrid::SafeDownCast(ds));
+    } else if (vtkUnstructuredGrid::SafeDownCast(ds) != NULL) {
+        _dataSet = vtkSmartPointer<vtkUnstructuredGrid>::New();
+        _dataSet->DeepCopy(vtkUnstructuredGrid::SafeDownCast(ds));
+    } else {
+        ERROR("Unknown data type");
+        return NULL;
+    }
+
+#ifdef WANT_TRACE
+    print();
+#endif    
+    return _dataSet;
+}
+
+/**
+ * \brief Does DataSet lie in the XY plane (z = 0)
+ */
+bool DataSet::isXY() const
+{
+    double bounds[6];
+    getBounds(bounds);
+    return (bounds[4] == 0. && bounds[4] == bounds[5]);
+}
+
+/**
+ * \brief Returns the dimensionality of the AABB
+ */
+int DataSet::numDimensions() const
+{
+    double bounds[6];
+    getBounds(bounds);
+    int numDims = 0;
+    if (bounds[0] != bounds[1])
+        numDims++;
+    if (bounds[2] != bounds[3])
+        numDims++;
+    if (bounds[4] != bounds[5])
+        numDims++;
+
+    return numDims;
+}
+
+/**
+ * \brief Determines if DataSet lies in a principal axis plane
+ * and if so, returns the plane normal and offset from origin
+ */
+bool DataSet::is2D(PrincipalPlane *plane, double *offset) const
+{
+    double bounds[6];
+    getBounds(bounds);
+    if (bounds[4] == bounds[5]) {
+        // Z = 0, XY plane
+        if (plane != NULL) {
+            *plane = PLANE_XY;
+        }
+        if (offset != NULL)
+            *offset = bounds[4];
+        return true;
+    } else if (bounds[0] == bounds[1]) {
+        // X = 0, ZY plane
+        if (plane != NULL) {
+            *plane = PLANE_ZY;
+        }
+        if (offset != NULL)
+            *offset = bounds[0];
+        return true;
+    } else if (bounds[2] == bounds[3]) {
+        // Y = 0, XZ plane
+        if (plane != NULL) {
+            *plane = PLANE_XZ;
+         }
+        if (offset != NULL)
+            *offset = bounds[2];
+        return true;
+    }
+    return false;
+}
+
+/**
+ * \brief Determines a principal plane with the
+ * largest two dimensions of the AABB
+ */
+PrincipalPlane DataSet::principalPlane() const
+{
+    double bounds[6];
+    getBounds(bounds);
+    double xlen = bounds[1] - bounds[0];
+    double ylen = bounds[3] - bounds[2];
+    double zlen = bounds[5] - bounds[4];
+    if (zlen <= xlen && zlen <= ylen) {
+        return PLANE_XY;
+    } else if (xlen <= ylen && xlen <= zlen) {
+        return PLANE_ZY;
+    } else {
+        return PLANE_XZ;
+    }
+}
+
+/**
+ * \brief Get the name/id of this dataset
+ */
+const std::string& DataSet::getName() const
+{
+    return _name;
+}
+
+/**
+ * \brief Get the underlying VTK DataSet object
+ */
+vtkDataSet *DataSet::getVtkDataSet()
+{
+    return _dataSet;
+}
+
+/**
+ * \brief Get the underlying VTK DataSet subclass class name
+ */
+const char *DataSet::getVtkType() const
+{
+    return _dataSet->GetClassName();
+}
+
+/**
+ * \brief Set the ative scalar array to the named field
+ */
+bool DataSet::setActiveScalars(const char *name)
+{
+    bool found = false;
+    if (_dataSet != NULL) {
+        if (_dataSet->GetPointData() != NULL) {
+            if (_dataSet->GetPointData()->SetActiveScalars(name) >= 0) {
+                TRACE("Set active point data scalars to %s", name);
+                found = true;
+            }
+        }
+        if (_dataSet->GetCellData() != NULL) {
+            if (_dataSet->GetCellData()->SetActiveScalars(name) >= 0) {
+                TRACE("Set active cell data scalars to %s", name);
+                found = true;
+            }
+        }
+    }
+#ifdef WANT_TRACE
+    if (_dataSet->GetPointData() != NULL) {
+        if (_dataSet->GetPointData()->GetScalars() != NULL) {
+            TRACE("Point data scalars: %s", _dataSet->GetPointData()->GetScalars()->GetName());
+        } else {
+            TRACE("NULL point data scalars");
+        }
+    }
+    if (_dataSet->GetCellData() != NULL) {
+        if (_dataSet->GetCellData()->GetScalars() != NULL) {
+            TRACE("Cell data scalars: %s", _dataSet->GetCellData()->GetScalars()->GetName());
+        } else {
+            TRACE("NULL cell data scalars");
+        }
+    }
+#endif
+    return found;
+}
+
+/**
+ * \brief Get the active scalar array field name
+ */
+const char *DataSet::getActiveScalarsName() const
+{
+    if (_dataSet != NULL) {
+         if (_dataSet->GetPointData() != NULL &&
+             _dataSet->GetPointData()->GetScalars() != NULL) {
+            return _dataSet->GetPointData()->GetScalars()->GetName();
+        }
+        TRACE("No point scalars");
+        if (_dataSet->GetCellData() != NULL &&
+            _dataSet->GetCellData()->GetScalars() != NULL) {
+            return _dataSet->GetCellData()->GetScalars()->GetName();
+        }
+        TRACE("No cell scalars");
+    }
+    return NULL;
+}
+
+/**
+ * \brief Get the active scalar array default attribute type
+ */
+DataSet::DataAttributeType DataSet::getActiveScalarsType() const
+{
+    if (_dataSet != NULL) {
+         if (_dataSet->GetPointData() != NULL &&
+             _dataSet->GetPointData()->GetScalars() != NULL) {
+            return POINT_DATA;
+        }
+        TRACE("No point scalars");
+        if (_dataSet->GetCellData() != NULL &&
+            _dataSet->GetCellData()->GetScalars() != NULL) {
+            return CELL_DATA;
+        }
+        TRACE("No cell scalars");
+    }
+    return POINT_DATA;
+}
+
+/**
+ * \brief Set the ative vector array to the named field
+ */
+bool DataSet::setActiveVectors(const char *name)
+{
+    bool found = false;
+    if (_dataSet != NULL) {
+        if (_dataSet->GetPointData() != NULL) {
+            if (_dataSet->GetPointData()->SetActiveVectors(name) >= 0) {
+                TRACE("Set active point data vectors to %s", name);
+                found = true;
+            }
+        }
+        if (_dataSet->GetCellData() != NULL) {
+            if (_dataSet->GetCellData()->SetActiveVectors(name) >= 0) {
+                TRACE("Set active cell data vectors to %s", name);
+                found = true;
+            }
+        }
+    }
+
+    return found;
+}
+
+/**
+ * \brief Get the active vector array default attribute type
+ */
+DataSet::DataAttributeType DataSet::getActiveVectorsType() const
+{
+    if (_dataSet != NULL) {
+         if (_dataSet->GetPointData() != NULL &&
+             _dataSet->GetPointData()->GetVectors() != NULL) {
+            return POINT_DATA;
+        }
+        TRACE("No point vectors");
+        if (_dataSet->GetCellData() != NULL &&
+            _dataSet->GetCellData()->GetVectors() != NULL) {
+            return CELL_DATA;
+        }
+        TRACE("No cell vectors");
+    }
+    return POINT_DATA;
+}
+
+/**
+ * \brief Get the active vector array field name
+ */
+const char *DataSet::getActiveVectorsName() const
+{
+    if (_dataSet != NULL) {
+        if (_dataSet->GetPointData() != NULL &&
+            _dataSet->GetPointData()->GetVectors() != NULL) {
+            return _dataSet->GetPointData()->GetVectors()->GetName();
+        }
+        TRACE("No point vectors");
+        if (_dataSet->GetCellData() != NULL &&
+            _dataSet->GetCellData()->GetVectors() != NULL) {
+            return _dataSet->GetCellData()->GetVectors()->GetName();
+        }
+        TRACE("No cell vectors");
+    }
+    return NULL;
+}
+
+bool DataSet::getFieldInfo(const char *fieldName,
+                           DataAttributeType *type,
+                           int *numComponents) const
+{
+    if (_dataSet->GetPointData() != NULL &&
+        _dataSet->GetPointData()->GetAbstractArray(fieldName) != NULL) {
+        if (type != NULL)
+            *type = POINT_DATA;
+        if (numComponents != NULL)
+            *numComponents = _dataSet->GetPointData()->GetAbstractArray(fieldName)->GetNumberOfComponents();
+        return true;
+    } else if (_dataSet->GetCellData() != NULL &&
+               _dataSet->GetCellData()->GetAbstractArray(fieldName) != NULL) {
+        if (type != NULL)
+            *type = CELL_DATA;
+        if (numComponents != NULL)
+            *numComponents = _dataSet->GetCellData()->GetAbstractArray(fieldName)->GetNumberOfComponents();
+        return true;
+    } else if (_dataSet->GetFieldData() != NULL &&
+               _dataSet->GetFieldData()->GetAbstractArray(fieldName) != NULL) {
+        if (type != NULL)
+            *type = FIELD_DATA;
+        if (numComponents != NULL)
+            *numComponents = _dataSet->GetFieldData()->GetAbstractArray(fieldName)->GetNumberOfComponents();
+        return true;
+    }
+    return false;
+}
+
+bool DataSet::getFieldInfo(const char *fieldName,
+                           DataAttributeType type,
+                           int *numComponents) const
+{
+    switch (type) {
+    case POINT_DATA:
+        if (_dataSet->GetPointData() != NULL &&
+            _dataSet->GetPointData()->GetAbstractArray(fieldName) != NULL) {
+            if (numComponents != NULL)
+                *numComponents = _dataSet->GetPointData()->GetAbstractArray(fieldName)->GetNumberOfComponents();
+            return true;
+        } else
+            return false;
+        break;
+    case CELL_DATA:
+        if (_dataSet->GetCellData() != NULL &&
+            _dataSet->GetCellData()->GetAbstractArray(fieldName) != NULL) {
+            if (numComponents != NULL)
+                *numComponents = _dataSet->GetCellData()->GetAbstractArray(fieldName)->GetNumberOfComponents();
+            return true;
+        } else
+            return false;
+        break;
+    case FIELD_DATA:
+        if (_dataSet->GetFieldData() != NULL &&
+            _dataSet->GetFieldData()->GetAbstractArray(fieldName) != NULL) {
+            if (numComponents != NULL)
+                *numComponents = _dataSet->GetFieldData()->GetAbstractArray(fieldName)->GetNumberOfComponents();
+            return true;
+        } else
+            return false;
+        break;
+    default:
+        ;
+    }
+    return false;
+}
+
+/**
+ * \brief Get the list of field names in the DataSet
+ * 
+ * \param[in,out] names The field names will be appended to this list
+ * \param[in] type The DataAttributeType: e.g. POINT_DATA, CELL_DATA
+ * \param[in] numComponents Filter list by number of components, -1 means to
+ * return all fields regardless of dimension
+ */
+void DataSet::getFieldNames(std::vector<std::string>& names,
+                            DataAttributeType type, int numComponents) const
+{
+    if (_dataSet == NULL)
+        return;
+    switch (type) {
+    case POINT_DATA:
+        if (_dataSet->GetPointData() != NULL) {
+            for (int i = 0; i < _dataSet->GetPointData()->GetNumberOfArrays(); i++) {
+                if (numComponents == -1 ||
+                    (_dataSet->GetPointData()->GetAbstractArray(i) != NULL &&
+                     _dataSet->GetPointData()->GetAbstractArray(i)->GetNumberOfComponents() == numComponents)) {
+                    names.push_back(_dataSet->GetPointData()->GetArrayName(i));
+                }
+            }
+        }
+        break;
+    case CELL_DATA:
+        if (_dataSet->GetCellData() != NULL) {
+            for (int i = 0; i < _dataSet->GetCellData()->GetNumberOfArrays(); i++) {
+                if (numComponents == -1 ||
+                    (_dataSet->GetCellData()->GetAbstractArray(i) != NULL &&
+                     _dataSet->GetCellData()->GetAbstractArray(i)->GetNumberOfComponents() == numComponents)) {
+                    names.push_back(_dataSet->GetCellData()->GetArrayName(i));
+                }
+            }
+        }
+        break;
+    case FIELD_DATA:
+        if (_dataSet->GetFieldData() != NULL) {
+            for (int i = 0; i < _dataSet->GetFieldData()->GetNumberOfArrays(); i++) {
+                if (numComponents == -1 ||
+                    (_dataSet->GetFieldData()->GetAbstractArray(i) != NULL &&
+                     _dataSet->GetFieldData()->GetAbstractArray(i)->GetNumberOfComponents() == numComponents)) {
+                    names.push_back(_dataSet->GetFieldData()->GetArrayName(i));
+                }
+            }
+        }
+        break;
+    default:
+        ERROR("Unknown DataAttributeType %d", type);
+    }
+}
+
+/**
+ * \brief Get the range of scalar values in the DataSet
+ */
+void DataSet::getScalarRange(double minmax[2]) const
+{
+    if (_dataSet == NULL)
+        return;
+    if (_dataSet->GetPointData() != NULL &&
+        _dataSet->GetPointData()->GetScalars() != NULL) {
+        _dataSet->GetPointData()->GetScalars()->GetRange(minmax, -1);
+    } else if (_dataSet->GetCellData() != NULL &&
+               _dataSet->GetCellData()->GetScalars() != NULL) {
+        _dataSet->GetCellData()->GetScalars()->GetRange(minmax, -1);
+    }
+}
+
+/**
+ * \brief Get the range of a vector component in the DataSet
+ *
+ * \param[out] minmax The data range
+ * \param[in] component The field component, -1 means magnitude
+ */
+void DataSet::getVectorRange(double minmax[2], int component) const
+{
+    if (_dataSet == NULL)
+        return;
+    if (_dataSet->GetPointData() != NULL &&
+        _dataSet->GetPointData()->GetVectors() != NULL) {
+        _dataSet->GetPointData()->GetVectors()->GetRange(minmax, component);
+    } else if (_dataSet->GetCellData() != NULL &&
+               _dataSet->GetCellData()->GetVectors() != NULL) {
+        _dataSet->GetCellData()->GetVectors()->GetRange(minmax, component);
+    }
+}
+
+/**
+ * \brief Get the range of values for the named field in the DataSet
+ *
+ * \param[out] minmax The data range
+ * \param[in] fieldName The array name
+ * \param[in] type The DataAttributeType
+ * \param[in] component The field component, -1 means magnitude
+ * \return boolean indicating if field was found
+ */
+bool DataSet::getDataRange(double minmax[2], const char *fieldName,
+                           DataAttributeType type, int component) const
+{
+    if (_dataSet == NULL)
+        return false;
+    switch (type) {
+    case POINT_DATA:
+        if (_dataSet->GetPointData() != NULL &&
+            _dataSet->GetPointData()->GetArray(fieldName) != NULL) {
+            _dataSet->GetPointData()->GetArray(fieldName)->GetRange(minmax, component);
+            return true;
+        } else {
+            return false;
+        }
+        break;
+    case CELL_DATA:
+        if (_dataSet->GetCellData() != NULL &&
+            _dataSet->GetCellData()->GetArray(fieldName) != NULL) {
+            _dataSet->GetCellData()->GetArray(fieldName)->GetRange(minmax, component);
+            return true;
+        } else {
+            return false;
+        }
+        break;
+    case FIELD_DATA:
+        if (_dataSet->GetFieldData() != NULL &&
+            _dataSet->GetFieldData()->GetArray(fieldName) != NULL) {
+            _dataSet->GetFieldData()->GetArray(fieldName)->GetRange(minmax, component);
+            return true;
+        } else {
+            return false;
+        }
+        break;
+    default:
+        ERROR("Unknown DataAttributeType %d", type);
+        break;
+    }
+    return false;
+}
+
+/**
+ * \brief Get the bounds the DataSet
+ */
+void DataSet::getBounds(double bounds[6]) const
+{
+    _dataSet->GetBounds(bounds);
+}
+
+/**
+ * \brief Get the range of cell AABB diagonal lengths in the DataSet
+ */
+void DataSet::getCellSizeRange(double minmax[2], double *average)
+{
+    if (_dataSet == NULL ||
+        _dataSet->GetNumberOfCells() < 1) {
+        minmax[0] = 1;
+        minmax[1] = 1;
+        *average = 1;
+        return;
+    }
+
+    if (_cellSizeRange[0] >= 0.0) {
+        minmax[0] = _cellSizeRange[0];
+        minmax[1] = _cellSizeRange[1];
+        *average = _cellSizeAverage;
+        return;
+    }
+
+    minmax[0] = DBL_MAX;
+    minmax[1] = -DBL_MAX;
+
+    *average = 0;
+    for (int i = 0; i < _dataSet->GetNumberOfCells(); i++) {
+        double length2 = _dataSet->GetCell(i)->GetLength2();
+        if (length2 < minmax[0])
+            minmax[0] = length2;
+        if (length2 > minmax[1])
+            minmax[1] = length2;
+        *average += length2;
+    }
+    if (minmax[0] == DBL_MAX)
+        minmax[0] = 1;
+    if (minmax[1] == -DBL_MAX)
+        minmax[1] = 1;
+
+    minmax[0] = sqrt(minmax[0]);
+    minmax[1] = sqrt(minmax[1]);
+    *average = sqrt(*average/((double)_dataSet->GetNumberOfCells()));
+    _cellSizeRange[0] = minmax[0];
+    _cellSizeRange[1] = minmax[1];
+    _cellSizeAverage = *average;
+}
+
+/**
+ * \brief Get nearest data value given world coordinates x,y,z
+ *
+ * Note: no interpolation is performed on data
+ *
+ * \param[in] x World x coordinate to probe
+ * \param[in] y World y coordinate to probe
+ * \param[in] z World z coordinate to probe
+ * \param[out] value On success, contains the data value
+ * \return boolean indicating success or failure
+ */
+bool DataSet::getScalarValue(double x, double y, double z, double *value) const
+{
+    if (_dataSet == NULL)
+        return false;
+    if (_dataSet->GetPointData() == NULL ||
+        _dataSet->GetPointData()->GetScalars() == NULL) {
+        return false;
+    }
+    vtkIdType pt = _dataSet->FindPoint(x, y, z);
+    if (pt < 0)
+        return false;
+    *value = _dataSet->GetPointData()->GetScalars()->GetComponent(pt, 0);
+    return true;
+}
+
+/**
+ * \brief Get nearest vector data value given world coordinates x,y,z
+ *
+ * Note: no interpolation is performed on data
+ *
+ * \param[in] x World x coordinate to probe
+ * \param[in] y World y coordinate to probe
+ * \param[in] z World z coordinate to probe
+ * \param[out] vector On success, contains the data values
+ * \return boolean indicating success or failure
+ */
+bool DataSet::getVectorValue(double x, double y, double z, double vector[3]) const
+{
+    if (_dataSet == NULL)
+        return false;
+    if (_dataSet->GetPointData() == NULL ||
+        _dataSet->GetPointData()->GetVectors() == NULL) {
+        return false;
+    }
+    vtkIdType pt = _dataSet->FindPoint(x, y, z);
+    if (pt < 0)
+        return false;
+    assert(_dataSet->GetPointData()->GetVectors()->GetNumberOfComponents() == 3);
+    _dataSet->GetPointData()->GetVectors()->GetTuple(pt, vector);
+    return true;
+}
Index: /trunk/packages/vizservers/vtkvis/VtkDataSet.h
===================================================================
--- /trunk/packages/vizservers/vtkvis/VtkDataSet.h	(revision 3616)
+++ /trunk/packages/vizservers/vtkvis/VtkDataSet.h	(revision 3616)
@@ -0,0 +1,141 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (C) 2004-2012  HUBzero Foundation, LLC
+ *
+ * Author: Leif Delgass <ldelgass@purdue.edu>
+ */
+
+#ifndef VTKVIS_DATASET_H
+#define VTKVIS_DATASET_H
+
+#include <vtkSmartPointer.h>
+#include <vtkDataSet.h>
+#include <vtkDataSetReader.h>
+
+#include <string>
+#include <vector>
+
+#include "Types.h"
+#include "Trace.h"
+
+namespace VtkVis {
+
+/**
+ * \brief VTK DataSet wrapper
+ */
+class DataSet {
+public:
+    enum DataAttributeType {
+        POINT_DATA,
+        CELL_DATA,
+        FIELD_DATA
+    };
+    DataSet(const std::string& name);
+    virtual ~DataSet();
+
+    void writeDataFile(const char *filename);
+
+    bool setDataFile(const char *filename);
+
+    bool setData(char *data, int nbytes);
+
+    bool setData(vtkDataSetReader *reader);
+
+    bool setData(vtkDataSet *ds);
+
+    vtkDataSet *copyData(vtkDataSet *ds);
+
+    bool isXY() const;
+
+    int numDimensions() const;
+
+    bool is2D(PrincipalPlane *plane = NULL, double *offset = NULL) const;
+
+    PrincipalPlane principalPlane() const;
+
+    const std::string& getName() const;
+
+    vtkDataSet *getVtkDataSet();
+
+    const char *getVtkType() const;
+
+    bool setActiveScalars(const char *name);
+
+    const char *getActiveScalarsName() const;
+
+    DataAttributeType getActiveScalarsType() const;
+
+    bool setActiveVectors(const char *name);
+
+    const char *getActiveVectorsName() const;
+
+    DataAttributeType getActiveVectorsType() const;
+
+    bool hasField(const char *fieldName) const
+    {
+        return getFieldInfo(fieldName, NULL, NULL);
+    }
+
+    bool hasField(const char *fieldName, DataAttributeType type) const
+    {
+        return getFieldInfo(fieldName, type, NULL);
+    }
+
+    bool getFieldInfo(const char *fieldName, DataAttributeType *type, int *numComponents) const;
+
+    bool getFieldInfo(const char *fieldName, DataAttributeType type, int *numComponents) const;
+
+    void getFieldNames(std::vector<std::string>& names,
+                       DataAttributeType type, int numComponents = -1) const;
+
+    bool getDataRange(double minmax[2], const char *fieldName,
+                      DataAttributeType type, int component = -1) const;
+
+    void getScalarRange(double minmax[2]) const;
+
+    void getVectorRange(double minmax[2], int component = -1) const;
+
+    void getBounds(double bounds[6]) const;
+
+    void getCellSizeRange(double minmax[2], double *average);
+
+    bool getScalarValue(double x, double y, double z, double *value) const;
+
+    bool getVectorValue(double x, double y, double z, double vector[3]) const;
+
+    void setOpacity(double opacity);
+
+    /**
+     * \brief Get the opacity setting for the DataSet
+     *
+     * This method is used for record-keeping.  The renderer controls
+     * the visibility of related graphics objects.
+     */
+    inline double getOpacity()
+    {
+        return _opacity;
+    }
+
+    void setVisibility(bool state);
+
+    bool getVisibility() const;
+
+    static void print(vtkDataSet *ds);
+
+private:
+    DataSet();
+
+    void setDefaultArrays();
+    void print() const;
+
+    std::string _name;
+    vtkSmartPointer<vtkDataSet> _dataSet;
+    bool _visible;
+    double _opacity;
+    double _cellSizeRange[2];
+    double _cellSizeAverage;
+};
+
+}
+
+#endif
Index: /trunk/packages/vizservers/vtkvis/VtkGraphicsObject.cpp
===================================================================
--- /trunk/packages/vizservers/vtkvis/VtkGraphicsObject.cpp	(revision 3616)
+++ /trunk/packages/vizservers/vtkvis/VtkGraphicsObject.cpp	(revision 3616)
@@ -0,0 +1,52 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (C) 2004-2012  HUBzero Foundation, LLC
+ *
+ * Author: Leif Delgass <ldelgass@purdue.edu>
+ */
+
+#include "VtkGraphicsObject.h"
+#include "VtkRenderer.h"
+#include "Trace.h"
+
+using namespace VtkVis;
+
+void VtkGraphicsObject::setDataSet(DataSet *dataSet,
+                                   Renderer *renderer)
+{
+    if (_dataSet != dataSet) {
+        _dataSet = dataSet;
+
+        if (renderer != NULL &&
+            dataSet != NULL &&
+            renderer->getUseCumulativeRange()) {
+            renderer->getCumulativeDataRange(_dataRange,
+                                             _dataSet->getActiveScalarsName(),
+                                             1);
+        } else if (_dataSet != NULL) {
+            _dataSet->getScalarRange(_dataRange);
+        }
+
+        update();
+    }
+}
+
+void VtkGraphicsObject::updateRanges(Renderer *renderer)
+{
+    if (_dataSet == NULL) {
+        ERROR("called before setDataSet");
+        return;
+    }
+    if (renderer == NULL) {
+        ERROR("NULL renderer");
+        return;
+    }
+
+    if (renderer->getUseCumulativeRange()) {
+        renderer->getCumulativeDataRange(_dataRange,
+                                         _dataSet->getActiveScalarsName(),
+                                         1);
+    } else {
+        _dataSet->getScalarRange(_dataRange);
+    }
+}
Index: /trunk/packages/vizservers/vtkvis/VtkGraphicsObject.h
===================================================================
--- /trunk/packages/vizservers/vtkvis/VtkGraphicsObject.h	(revision 3616)
+++ /trunk/packages/vizservers/vtkvis/VtkGraphicsObject.h	(revision 3616)
@@ -0,0 +1,933 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (C) 2004-2012  HUBzero Foundation, LLC
+ *
+ * Author: Leif Delgass <ldelgass@purdue.edu>
+ */
+
+#ifndef VTKVIS_VTKGRAPHICSOBJECT_H
+#define VTKVIS_VTKGRAPHICSOBJECT_H
+
+#include <cmath>
+#include <string>
+
+#include <vtkSmartPointer.h>
+#include <vtkProp.h>
+#include <vtkProp3D.h>
+#include <vtkProp3DCollection.h>
+#include <vtkAssembly.h>
+#include <vtkActor.h>
+#include <vtkVolume.h>
+#include <vtkProperty.h>
+#include <vtkVolumeProperty.h>
+#include <vtkMath.h>
+#include <vtkMatrix4x4.h>
+#include <vtkPlaneCollection.h>
+
+#include "VtkDataSet.h"
+#include "Trace.h"
+
+namespace VtkVis {
+
+class Renderer;
+
+/**
+ * \brief Base class for graphics objects
+ */
+class VtkGraphicsObject {
+public:
+    enum CullFace {
+        CULL_FRONT,
+        CULL_BACK,
+        CULL_FRONT_AND_BACK
+    };
+
+    VtkGraphicsObject() :
+        _dataSet(NULL),
+        _opacity(1.0),
+        _edgeWidth(1.0f),
+        _pointSize(1.0f),
+        _lighting(true),
+        _cullFace(CULL_BACK),
+        _faceCulling(false)
+    {
+        _dataRange[0] = 0;
+        _dataRange[1] = 1;
+        _color[0] = 1.0f;
+        _color[1] = 1.0f;
+        _color[2] = 1.0f;
+        _edgeColor[0] = 0.0f;
+        _edgeColor[1] = 0.0f;
+        _edgeColor[2] = 0.0f;
+    }
+
+    virtual ~VtkGraphicsObject()
+    {}
+
+    /**
+     * \brief Return the name of the sublass of VtkGraphicsObject
+     */
+    virtual const char *getClassName() const = 0;
+
+    /**
+     * \brief Specify input DataSet and information on cumulative data ranges
+     *
+     * Default implementation calls update() and stores scalarRange to
+     * _dataRange based on cumulative range settings
+     *
+     * \param[in] dataSet DataSet to use in rendering
+     * \param[in] renderer Pointer to Renderer -- may be used to get 
+     * cumulative data ranges
+     */
+    virtual void setDataSet(DataSet *dataSet,
+                            Renderer *renderer);
+
+    /**
+     * \brief Called when scalar or vector field changes (e.g. active field) or 
+     * cumulative ranges or settings change
+     *
+     * \param[in] renderer Pointer to Renderer -- may be used to get 
+     * cumulative data ranges
+     */
+    virtual void updateRanges(Renderer *renderer);
+
+    /**
+     * \brief Return the DataSet this object renders
+     */
+    inline DataSet *getDataSet()
+    {
+        return _dataSet;
+    }
+
+    /**
+     * \brief Return the VTK prop object to render
+     */
+    inline vtkProp *getProp()
+    {
+        return _prop;
+    }
+
+    /**
+     * \brief Cast the vktProp to a vtkProp3D
+     *
+     * \return NULL or a vtkProp3D pointer
+     */
+    inline vtkProp3D *getProp3D()
+    {
+        return vtkProp3D::SafeDownCast(_prop);
+    }
+
+    /**
+     * \brief Cast the vktProp to a vtkActor
+     *
+     * \return NULL or a vtkActor pointer
+     */
+    inline vtkActor *getActor()
+    {
+        return vtkActor::SafeDownCast(_prop);
+    }
+
+    /**
+     * \brief Cast the vktProp to a vtkVolume
+     *
+     * \return NULL or a vtkVolume pointer
+     */
+    inline vtkVolume *getVolume()
+    {
+        return vtkVolume::SafeDownCast(_prop);
+    }
+
+    /**
+     * \brief Cast the vktProp to a vtkAssembly
+     *
+     * \return NULL or a vtkAssembly pointer
+     */
+    inline vtkAssembly *getAssembly()
+    {
+        return vtkAssembly::SafeDownCast(_prop);
+    }
+
+    /**
+     * \brief If the object has a 2D overlay prop, return it
+     *
+     * \return NULL or a vtkProp pointer
+     */
+    virtual vtkProp *getOverlayProp()
+    {
+        return NULL;
+    }
+
+    /**
+     * \brief Set an additional transform on the prop
+     * 
+     * prop must be a vtkProp3D.  The transform is 
+     * concatenated with the internal transform created
+     * by setting the prop position, orientation and scale
+     */
+    virtual void setTransform(vtkMatrix4x4 *matrix)
+    {
+        if (getProp3D() != NULL) {
+            getProp3D()->SetUserMatrix(matrix);
+        }
+    }
+
+    /**
+     * \brief Set the prop center of rotation
+     *
+     * \param[in] origin The point about which the object rotates
+     */
+    virtual void setOrigin(double origin[3])
+    {
+        if (getProp3D() != NULL) {
+            getProp3D()->SetOrigin(origin);
+        }
+    }
+
+    /**
+     * \brief Set the prop orientation with a quaternion
+     *
+     * \param[in] quat Quaternion with scalar part first
+     */
+    virtual void setOrientation(double quat[4])
+    {
+        if (getProp3D() != NULL) {
+            double angle = vtkMath::DegreesFromRadians(2.0 * acos(quat[0]));
+            double axis[3];
+            if (angle < 1.0e-6) {
+                axis[0] = 1;
+                axis[1] = 0;
+                axis[2] = 0;
+            } else {
+                double denom = sqrt(1. - quat[0] * quat[0]);
+                axis[0] = quat[1] / denom;
+                axis[1] = quat[2] / denom;
+                axis[2] = quat[3] / denom;
+            }
+            setOrientation(angle, axis);
+        }
+    }
+
+    /**
+     * \brief Set the prop orientation with a rotation about an axis
+     *
+     * \param[in] angle Angle in degrees
+     * \param[in] axis Axis of rotation
+     */
+    virtual void setOrientation(double angle, double axis[3])
+    {
+        if (getProp3D() != NULL) {
+            getProp3D()->SetOrientation(0, 0, 0);
+            getProp3D()->RotateWXYZ(angle, axis[0], axis[1], axis[2]);
+        }
+    }
+
+    /**
+     * \brief Set the prop position
+     *
+     * \param[in] pos Position in world coordinates
+     */
+    virtual void setPosition(double pos[3])
+    {
+        if (getProp3D() != NULL) {
+            getProp3D()->SetPosition(pos);
+        }
+    }
+
+    /**
+     * \brief Set 2D aspect ratio scaling
+     *
+     * \param aspect 0=no scaling, otherwise aspect
+     * is horiz/vertical ratio
+     */
+    virtual void setAspect(double aspect)
+    {
+        double scale[3];
+        scale[0] = scale[1] = scale[2] = 1.;
+
+        if (aspect == 0.0) {
+            setScale(scale);
+            return;
+        }
+        if (_dataSet == NULL ||
+            _dataSet->getVtkDataSet() == NULL) {
+            TRACE("Not setting aspect for object with no data set");
+            return;
+        }
+
+        PrincipalPlane plane;
+        if (!_dataSet->is2D(&plane)) {
+            TRACE("Not setting aspect for 3D object");
+            return;
+        }
+
+        double bounds[6];
+        vtkDataSet *ds = _dataSet->getVtkDataSet();
+        ds->GetBounds(bounds);
+        double size[3];
+        size[0] = bounds[1] - bounds[0];
+        size[1] = bounds[3] - bounds[2];
+        size[2] = bounds[5] - bounds[4];
+
+        if (aspect == 1.0) {
+            // Square
+            switch (plane) {
+            case PLANE_XY: {
+                if (size[0] > size[1] && size[1] > 1.0e-6) {
+                    scale[1] = size[0] / size[1];
+                } else if (size[1] > size[0] && size[0] > 1.0e-6) {
+                    scale[0] = size[1] / size[0];
+                }
+            }
+                break;
+            case PLANE_ZY: {
+                if (size[1] > size[2] && size[2] > 1.0e-6) {
+                    scale[2] = size[1] / size[2];
+                } else if (size[2] > size[1] && size[1] > 1.0e-6) {
+                    scale[1] = size[2] / size[1];
+                }
+            }
+                break;
+            case PLANE_XZ: {
+                if (size[0] > size[2] && size[2] > 1.0e-6) {
+                    scale[2] = size[0] / size[2];
+                } else if (size[2] > size[0] && size[0] > 1.0e-6) {
+                    scale[0] = size[2] / size[0];
+                }
+            }
+                break;
+            default:
+                break;
+            }
+        } else {
+            switch (plane) {
+            case PLANE_XY: {
+                if (aspect > 1.0) {
+                    if (size[0] > size[1]) {
+                        scale[1] = (size[0] / aspect) / size[1];
+                    } else {
+                        scale[0] = (size[1] * aspect) / size[0];
+                    }
+                } else {
+                    if (size[1] > size[0]) {
+                        scale[0] = (size[1] * aspect) / size[0];
+                    } else {
+                        scale[1] = (size[0] / aspect) / size[1];
+                    }
+                }
+            }
+                break;
+            case PLANE_ZY: {
+                if (aspect > 1.0) {
+                    if (size[2] > size[1]) {
+                        scale[1] = (size[2] / aspect) / size[1];
+                    } else {
+                        scale[2] = (size[1] * aspect) / size[2];
+                    }
+                } else {
+                    if (size[1] > size[2]) {
+                        scale[2] = (size[1] * aspect) / size[2];
+                    } else {
+                        scale[1] = (size[2] / aspect) / size[1];
+                    }
+                }
+            }
+                break;
+            case PLANE_XZ: {
+                if (aspect > 1.0) {
+                    if (size[0] > size[2]) {
+                        scale[2] = (size[0] / aspect) / size[2];
+                    } else {
+                        scale[0] = (size[2] * aspect) / size[0];
+                    }
+                } else {
+                    if (size[2] > size[0]) {
+                        scale[0] = (size[2] * aspect) / size[0];
+                    } else {
+                        scale[2] = (size[0] / aspect) / size[2];
+                    }
+                }
+            }
+            default:
+                break;
+            }
+        }
+
+        TRACE("obj %g,%g,%g", size[0], size[1], size[2]);
+        TRACE("Setting scale to %g,%g,%g", scale[0], scale[1], scale[2]);
+        setScale(scale);
+    }
+
+    /**
+     * \brief Get the prop scaling
+     *
+     * \param[out] scale Scaling in x,y,z
+     */
+    virtual void getScale(double scale[3])
+    {
+        if (getProp3D() != NULL) {
+            getProp3D()->GetScale(scale);
+        } else {
+            scale[0] = scale[1] = scale[2] = 1.0;
+        }
+    }
+
+    /**
+     * \brief Set the prop scaling
+     *
+     * \param[in] scale Scaling in x,y,z
+     */
+    virtual void setScale(double scale[3])
+    {
+        if (getProp3D() != NULL) {
+            getProp3D()->SetScale(scale);
+        }
+    }
+
+    /**
+     * \brief Get the physical bounds of the prop
+     *
+     * If the prop is scaled, these bounds will be
+     * scaled as well
+     */
+    virtual double *getBounds()
+    {
+        if (getProp() != NULL)
+            return getProp()->GetBounds();
+        else
+            return NULL;
+    }
+
+    /**
+     * \brief Get the data bounds of the prop
+     *
+     * If the prop is scaled, these bounds will NOT
+     * be scaled, they will reflect the unscaled data
+     * bounds.
+     */
+    virtual double *getUnscaledBounds()
+    {
+        if (getProp3D() != NULL) {
+            double scale[3];
+            getProp3D()->GetScale(scale);
+            if (scale[0] == scale[1] && scale[1] == scale[2] &&
+                scale[0] == 1.0) {
+                return getBounds();
+            } else if (getBounds() != NULL) {
+                _unscaledBounds[0] = getBounds()[0] / scale[0];
+                _unscaledBounds[1] = getBounds()[1] / scale[0];
+                _unscaledBounds[2] = getBounds()[2] / scale[1];
+                _unscaledBounds[3] = getBounds()[3] / scale[1];
+                _unscaledBounds[4] = getBounds()[4] / scale[2];
+                _unscaledBounds[5] = getBounds()[5] / scale[2];
+                return _unscaledBounds;
+            }
+        }
+        return getBounds();
+    }
+
+    /**
+     * \brief Toggle visibility of the prop
+     */
+    virtual void setVisibility(bool state)
+    {
+        if (_prop != NULL)
+            _prop->SetVisibility((state ? 1 : 0));
+    }
+
+    /**
+     * \brief Get visibility state of the prop
+     */
+    virtual bool getVisibility()
+    {
+        if (_prop != NULL &&
+            _prop->GetVisibility() != 0) {
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    /**
+     * \brief Set the opacity of the object
+     *
+     * The prop must be a vtkActor or vtkAssembly
+     */
+    virtual void setOpacity(double opacity)
+    {
+        _opacity = opacity;
+        if (getActor() != NULL) {
+            getActor()->GetProperty()->SetOpacity(opacity);
+            if (_faceCulling && _opacity < 1.0) {
+                setCulling(getActor()->GetProperty(), false);
+                TRACE("Culling off");
+            } else if (_faceCulling && _opacity == 1.0) {
+                setCulling(getActor()->GetProperty(), true);
+                TRACE("Culling on");
+            }
+        } else if (getAssembly() != NULL) {
+            vtkProp3DCollection *props = getAssembly()->GetParts();
+            vtkProp3D *prop;
+            props->InitTraversal();
+            while ((prop = props->GetNextProp3D()) != NULL) {
+                if (vtkActor::SafeDownCast(prop) != NULL) {
+                    vtkActor::SafeDownCast(prop)->GetProperty()->SetOpacity(opacity);
+                    if (_faceCulling && _opacity < 1.0) {
+                        setCulling(vtkActor::SafeDownCast(prop)->GetProperty(), false);
+                        TRACE("Culling off");
+                    } else if (_faceCulling && _opacity == 1.0) {
+                        setCulling(vtkActor::SafeDownCast(prop)->GetProperty(), true);
+                        TRACE("Culling on");
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * \brief Get the opacity of the object
+     */
+    inline double getOpacity()
+    {
+        return _opacity;
+    }
+
+    /**
+     * \brief Set the ambient material coefficient
+     */
+    virtual void setAmbient(double ambient)
+    {
+        if (getActor() != NULL) {
+            getActor()->GetProperty()->SetAmbient(ambient);
+        } else if (getVolume() != NULL) {
+            getVolume()->GetProperty()->SetAmbient(ambient);
+        } else if (getAssembly() != NULL) {
+            vtkProp3DCollection *props = getAssembly()->GetParts();
+            vtkProp3D *prop;
+            props->InitTraversal();
+            while ((prop = props->GetNextProp3D()) != NULL) {
+                if (vtkActor::SafeDownCast(prop) != NULL) {
+                    vtkActor::SafeDownCast(prop)->GetProperty()->SetAmbient(ambient);
+                } else if (vtkVolume::SafeDownCast(prop) != NULL) {
+                    vtkVolume::SafeDownCast(prop)->GetProperty()->SetAmbient(ambient);
+                }
+            }
+        }
+    }
+
+    /**
+     * \brief Set the diffuse material coefficient
+     */
+    virtual void setDiffuse(double diffuse)
+    {
+        if (getActor() != NULL) {
+            getActor()->GetProperty()->SetDiffuse(diffuse);
+        } else if (getVolume() != NULL) {
+            getVolume()->GetProperty()->SetDiffuse(diffuse);
+        } else if (getAssembly() != NULL) {
+            vtkProp3DCollection *props = getAssembly()->GetParts();
+            vtkProp3D *prop;
+            props->InitTraversal();
+            while ((prop = props->GetNextProp3D()) != NULL) {
+                if (vtkActor::SafeDownCast(prop) != NULL) {
+                    vtkActor::SafeDownCast(prop)->GetProperty()->SetDiffuse(diffuse);
+                } else if (vtkVolume::SafeDownCast(prop) != NULL) {
+                    vtkVolume::SafeDownCast(prop)->GetProperty()->SetDiffuse(diffuse);
+                }
+            }
+        }
+    }
+
+    /**
+     * \brief Set the specular material coefficient and power
+     */
+    virtual void setSpecular(double coeff, double power)
+    {
+        if (getActor() != NULL) {
+            getActor()->GetProperty()->SetSpecular(coeff);
+            getActor()->GetProperty()->SetSpecularPower(power);
+        } else if (getVolume() != NULL) {
+            getVolume()->GetProperty()->SetSpecular(coeff);
+            getVolume()->GetProperty()->SetSpecularPower(power);
+        } else if (getAssembly() != NULL) {
+            vtkProp3DCollection *props = getAssembly()->GetParts();
+            vtkProp3D *prop;
+            props->InitTraversal();
+            while ((prop = props->GetNextProp3D()) != NULL) {
+                if (vtkActor::SafeDownCast(prop) != NULL) {
+                    vtkActor::SafeDownCast(prop)->GetProperty()->SetSpecular(coeff);
+                    vtkActor::SafeDownCast(prop)->GetProperty()->SetSpecularPower(power);
+                } else if (vtkVolume::SafeDownCast(prop) != NULL) {
+                    vtkVolume::SafeDownCast(prop)->GetProperty()->SetSpecular(coeff);
+                    vtkVolume::SafeDownCast(prop)->GetProperty()->SetSpecularPower(power);
+                }
+            }
+        }
+    }
+
+    /**
+     * \brief Set material properties (coefficients and specular power) of object
+     */
+    virtual void setMaterial(double ambient, double diffuse, double specular, double specPower)
+    {
+        if (getActor() != NULL) {
+            vtkProperty *property = getActor()->GetProperty();
+            property->SetAmbient(ambient);
+            property->SetDiffuse(diffuse);
+            property->SetSpecular(specular);
+            property->SetSpecularPower(specPower);
+        } else if (getVolume() != NULL) {
+            vtkVolumeProperty *property = getVolume()->GetProperty();
+            property->SetAmbient(ambient);
+            property->SetDiffuse(diffuse);
+            property->SetSpecular(specular);
+            property->SetSpecularPower(specPower);
+        } else if (getAssembly() != NULL) {
+            vtkProp3DCollection *props = getAssembly()->GetParts();
+            vtkProp3D *prop;
+            props->InitTraversal();
+            while ((prop = props->GetNextProp3D()) != NULL) {
+                if (vtkActor::SafeDownCast(prop) != NULL) {
+                    vtkProperty *property = vtkActor::SafeDownCast(prop)->GetProperty();
+                    property->SetAmbient(ambient);
+                    property->SetDiffuse(diffuse);
+                    property->SetSpecular(specular);
+                    property->SetSpecularPower(specPower);
+                } else if (vtkVolume::SafeDownCast(prop) != NULL) {
+                    vtkVolumeProperty *property = vtkVolume::SafeDownCast(prop)->GetProperty();
+                    property->SetAmbient(ambient);
+                    property->SetDiffuse(diffuse);
+                    property->SetSpecular(specular);
+                    property->SetSpecularPower(specPower);
+                }
+            }
+        }
+    }
+
+    /**
+     * \brief Set the material color (sets ambient, diffuse, and specular)
+     */
+    virtual void setColor(float color[3])
+    {
+        for (int i = 0; i < 3; i++)
+            _color[i] = color[i];
+        if (getActor() != NULL) {
+            getActor()->GetProperty()->SetColor(color[0], color[1], color[2]);
+        } else if (getAssembly() != NULL) {
+            vtkProp3DCollection *props = getAssembly()->GetParts();
+            vtkProp3D *prop;
+            props->InitTraversal();
+            while ((prop = props->GetNextProp3D()) != NULL) {
+                if (vtkActor::SafeDownCast(prop) != NULL) {
+                    vtkActor::SafeDownCast(prop)->GetProperty()->SetColor(color[0], color[1], color[2]);
+                }
+            }
+        }
+    }
+
+    /**
+     * \brief Set the material ambient color
+     */
+    virtual void setAmbientColor(float color[3])
+    {
+        if (getActor() != NULL) {
+            getActor()->GetProperty()->SetAmbientColor(color[0], color[1], color[2]);
+        } else if (getAssembly() != NULL) {
+            vtkProp3DCollection *props = getAssembly()->GetParts();
+            vtkProp3D *prop;
+            props->InitTraversal();
+            while ((prop = props->GetNextProp3D()) != NULL) {
+                if (vtkActor::SafeDownCast(prop) != NULL) {
+                    vtkActor::SafeDownCast(prop)->GetProperty()->SetAmbientColor(color[0], color[1], color[2]);
+                }
+            }
+        }
+    }
+
+    /**
+     * \brief Set the material diffuse color
+     */
+    virtual void setDiffuseColor(float color[3])
+    {
+        if (getActor() != NULL) {
+            getActor()->GetProperty()->SetDiffuseColor(color[0], color[1], color[2]);
+        } else if (getAssembly() != NULL) {
+            vtkProp3DCollection *props = getAssembly()->GetParts();
+            vtkProp3D *prop;
+            props->InitTraversal();
+            while ((prop = props->GetNextProp3D()) != NULL) {
+                if (vtkActor::SafeDownCast(prop) != NULL) {
+                    vtkActor::SafeDownCast(prop)->GetProperty()->SetDiffuseColor(color[0], color[1], color[2]);
+                }
+            }
+        }
+    }
+
+    /**
+     * \brief Set the material specular color
+     */
+    virtual void setSpecularColor(float color[3])
+    {
+        if (getActor() != NULL) {
+            getActor()->GetProperty()->SetSpecularColor(color[0], color[1], color[2]);
+        } else if (getAssembly() != NULL) {
+            vtkProp3DCollection *props = getAssembly()->GetParts();
+            vtkProp3D *prop;
+            props->InitTraversal();
+            while ((prop = props->GetNextProp3D()) != NULL) {
+                if (vtkActor::SafeDownCast(prop) != NULL) {
+                    vtkActor::SafeDownCast(prop)->GetProperty()->SetSpecularColor(color[0], color[1], color[2]);
+                }
+            }
+        }
+    }
+
+    /**
+     * \brief Toggle lighting of the prop
+     */
+    virtual void setLighting(bool state)
+    {
+        _lighting = state;
+        if (getActor() != NULL) {
+            getActor()->GetProperty()->SetLighting((state ? 1 : 0));
+        } else if (getVolume() != NULL) {
+            getVolume()->GetProperty()->SetShade((state ? 1 : 0));
+         } else if (getAssembly() != NULL) {
+            vtkProp3DCollection *props = getAssembly()->GetParts();
+            vtkProp3D *prop;
+            props->InitTraversal();
+            while ((prop = props->GetNextProp3D()) != NULL) {
+                if (vtkActor::SafeDownCast(prop) != NULL) {
+                    vtkActor::SafeDownCast(prop)->GetProperty()->SetLighting((state ? 1 : 0));
+                } else if (vtkVolume::SafeDownCast(prop) != NULL) {
+                    vtkVolume::SafeDownCast(prop)->GetProperty()->SetShade((state ? 1 : 0));
+                }
+            }
+        }
+    }
+
+    /**
+     * \brief Toggle drawing of edges
+     */
+    virtual void setEdgeVisibility(bool state)
+    {
+        if (getActor() != NULL) {
+            getActor()->GetProperty()->SetEdgeVisibility((state ? 1 : 0));
+        } else if (getAssembly() != NULL) {
+            vtkProp3DCollection *props = getAssembly()->GetParts();
+            vtkProp3D *prop;
+            props->InitTraversal();
+            while ((prop = props->GetNextProp3D()) != NULL) {
+                if (vtkActor::SafeDownCast(prop) != NULL) {
+                    vtkActor::SafeDownCast(prop)->GetProperty()->SetEdgeVisibility((state ? 1 : 0));
+                }
+            }
+        }
+    }
+
+    /**
+     * \brief Set color of edges
+     */
+    virtual void setEdgeColor(float color[3])
+    {
+        for (int i = 0; i < 3; i++)
+            _edgeColor[i] = color[i];
+        if (getActor() != NULL) {
+            getActor()->GetProperty()->SetEdgeColor(color[0], color[1], color[2]);
+        } else if (getAssembly() != NULL) {
+            vtkProp3DCollection *props = getAssembly()->GetParts();
+            vtkProp3D *prop;
+            props->InitTraversal();
+            while ((prop = props->GetNextProp3D()) != NULL) {
+                if (vtkActor::SafeDownCast(prop) != NULL) {
+                    vtkActor::SafeDownCast(prop)->GetProperty()->SetEdgeColor(color[0], color[1], color[2]);
+                }
+            }
+        }
+    }
+
+    /**
+     * \brief Set pixel width of edges
+     *
+     * NOTE: May be a no-op if OpenGL implementation doesn't support wide lines
+     */
+    virtual void setEdgeWidth(float width)
+    {
+        _edgeWidth = width;
+        if (getActor() != NULL) {
+            getActor()->GetProperty()->SetLineWidth(width);
+        } else if (getAssembly() != NULL) {
+            vtkProp3DCollection *props = getAssembly()->GetParts();
+            vtkProp3D *prop;
+            props->InitTraversal();
+            while ((prop = props->GetNextProp3D()) != NULL) {
+                if (vtkActor::SafeDownCast(prop) != NULL) {
+                    vtkActor::SafeDownCast(prop)->GetProperty()->SetLineWidth(width);
+                }
+            }
+        }
+    }
+
+    /**
+     * \brief Set point size
+     *
+     * NOTE: May be a no-op if OpenGL implementation doesn't support wide points
+     */
+    virtual void setPointSize(float size)
+    {
+        _pointSize = size;
+        if (getActor() != NULL) {
+            getActor()->GetProperty()->SetPointSize(size);
+        } else if (getAssembly() != NULL) {
+            vtkProp3DCollection *props = getAssembly()->GetParts();
+            vtkProp3D *prop;
+            props->InitTraversal();
+            while ((prop = props->GetNextProp3D()) != NULL) {
+                if (vtkActor::SafeDownCast(prop) != NULL) {
+                    vtkActor::SafeDownCast(prop)->GetProperty()->SetPointSize(size);
+                }
+            }
+        }
+    }
+
+    /**
+     * \brief Toggle wireframe rendering of prop
+     */
+    virtual void setWireframe(bool state)
+    {
+        if (getActor() != NULL) {
+            if (state) {
+                getActor()->GetProperty()->SetRepresentationToWireframe();
+                getActor()->GetProperty()->LightingOff();
+            } else {
+                getActor()->GetProperty()->SetRepresentationToSurface();
+                setLighting(_lighting);
+            }
+        } else if (getAssembly() != NULL) {
+            vtkProp3DCollection *props = getAssembly()->GetParts();
+            vtkProp3D *prop;
+            props->InitTraversal();
+            while ((prop = props->GetNextProp3D()) != NULL) {
+                if (vtkActor::SafeDownCast(prop) != NULL) {
+                    if (state) {
+                        vtkActor::SafeDownCast(prop)->GetProperty()->SetRepresentationToWireframe();
+                        vtkActor::SafeDownCast(prop)->GetProperty()->LightingOff();
+                    } else {
+                        vtkActor::SafeDownCast(prop)->GetProperty()->SetRepresentationToSurface();
+                        vtkActor::SafeDownCast(prop)->GetProperty()->SetLighting((_lighting ? 1 : 0));
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * \brief Toggle culling of selected CullFace
+     */
+    virtual void setCulling(bool state)
+    {
+        _faceCulling = state;
+        if (state && _opacity < 1.0)
+            return;
+        if (getActor() != NULL) {
+            setCulling(getActor()->GetProperty(), state);
+        } else if (getAssembly() != NULL) {
+            vtkProp3DCollection *props = getAssembly()->GetParts();
+            vtkProp3D *prop;
+            props->InitTraversal();
+            while ((prop = props->GetNextProp3D()) != NULL) {
+                if (vtkActor::SafeDownCast(prop) != NULL) {
+                    setCulling(vtkActor::SafeDownCast(prop)->GetProperty(), state);
+                }
+            }
+        }
+    }
+
+    /**
+     * \brief Specify which face(s) to cull when culling is enabled
+     */
+    virtual void setCullFace(CullFace cull)
+    {
+        _cullFace = cull;
+        setCulling(_faceCulling);
+    }
+
+    /**
+     * \brief Subclasses need to implement setting clipping planes in their mappers
+     */
+    virtual void setClippingPlanes(vtkPlaneCollection *planes) = 0;
+
+protected:
+    /**
+     * \brief Create and initialize a VTK Prop to render the object
+     */
+    virtual void initProp()
+    {
+        if (_prop == NULL) {
+            _prop = vtkSmartPointer<vtkActor>::New();
+            vtkProperty *property = getActor()->GetProperty();
+            property->SetColor(_color[0], _color[1], _color[2]);
+            property->SetEdgeColor(_edgeColor[0], _edgeColor[1], _edgeColor[2]);
+            property->SetLineWidth(_edgeWidth);
+            property->SetPointSize(_pointSize);
+            property->EdgeVisibilityOff();
+            if (_dataSet != NULL)
+                _opacity = _dataSet->getOpacity();
+            property->SetOpacity(_opacity);
+            property->SetAmbient(.2);
+            if (!_lighting)
+                property->LightingOff();
+            if (_faceCulling && _opacity == 1.0) {
+                setCulling(property, true);
+            }
+            if (_dataSet != NULL)
+                setVisibility(_dataSet->getVisibility());
+        }
+    }
+
+    /**
+     * \brief Subclasses implement this to create the VTK pipeline
+     * on a state change (e.g. new DataSet)
+     */
+    virtual void update() = 0;
+
+    /**
+     * \brief Convenience method to set culling state on a vtkProperty
+     *
+     * Note: Does not change the culling state flag of this VtkGraphicsObject
+     */
+    virtual void setCulling(vtkProperty *property, bool state)
+    {
+        switch (_cullFace) {
+        case CULL_FRONT:
+            property->SetFrontfaceCulling((state ? 1 : 0));
+            property->BackfaceCullingOff();
+            break;
+        case CULL_BACK:
+            property->SetBackfaceCulling((state ? 1 : 0));
+            property->FrontfaceCullingOff();
+            break;
+        case CULL_FRONT_AND_BACK:
+            property->SetBackfaceCulling((state ? 1 : 0));
+            property->SetFrontfaceCulling((state ? 1 : 0));
+            break;
+        }
+    }
+
+    DataSet *_dataSet;
+    double _dataRange[2];
+    double _unscaledBounds[6];
+    double _opacity;
+    float _color[3];
+    float _edgeColor[3];
+    float _edgeWidth;
+    float _pointSize;
+    bool _lighting;
+    CullFace _cullFace;
+    bool _faceCulling;
+
+    vtkSmartPointer<vtkProp> _prop;
+};
+
+}
+
+#endif
Index: /trunk/packages/vizservers/vtkvis/VtkRenderServer.cpp
===================================================================
--- /trunk/packages/vizservers/vtkvis/VtkRenderServer.cpp	(revision 3616)
+++ /trunk/packages/vizservers/vtkvis/VtkRenderServer.cpp	(revision 3616)
@@ -0,0 +1,579 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (C) 2004-2012  HUBzero Foundation, LLC
+ *
+ * Author: Leif Delgass <ldelgass@purdue.edu>
+ */
+
+#include <cstdio>
+#include <cstring>
+#include <cstdlib>
+#include <cerrno>
+#include <unistd.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/time.h>
+#include <sys/times.h>
+
+#include <string>
+#include <sstream>
+
+#include <tcl.h>
+
+#include "Trace.h"
+#include "ReadBuffer.h"
+#include "VtkRenderServer.h"
+#include "VtkRendererCmd.h"
+#include "VtkRenderer.h"
+#include "PPMWriter.h"
+#include "TGAWriter.h"
+#ifdef USE_THREADS
+#include <pthread.h>
+#include "ResponseQueue.h"
+#endif 
+#include <md5.h>
+
+using namespace VtkVis;
+
+Stats VtkVis::g_stats;
+
+int VtkVis::g_statsFile = -1; ///< Stats output file descriptor.
+int VtkVis::g_fdIn = STDIN_FILENO; ///< Input file descriptor
+int VtkVis::g_fdOut = STDOUT_FILENO; ///< Output file descriptor
+FILE *VtkVis::g_fOut = stdout; ///< Output file handle
+FILE *VtkVis::g_fLog = NULL; ///< Trace logging file handle
+Renderer *VtkVis::g_renderer = NULL; ///< Main render worker
+ReadBuffer *VtkVis::g_inBufPtr = NULL; ///< Socket read buffer
+
+#ifdef USE_THREADS
+static void
+queueFrame(ResponseQueue *queue, vtkUnsignedCharArray *imgData)
+{
+#ifdef DEBUG
+    if (g_renderer->getCameraMode() == Renderer::IMAGE) {
+        double xywh[4];
+        g_renderer->getScreenWorldCoords(xywh);
+        TRACE("Image bbox: %g %g %g %g", 
+              xywh[0], 
+              (xywh[1] + xywh[3]), 
+              (xywh[0] + xywh[2]), 
+              xywh[1]);
+    }
+
+#ifdef RENDER_TARGA
+    writeTGAFile("/tmp/frame.tga",
+                 imgData->GetPointer(0),
+                 g_renderer->getWindowWidth(),
+                 g_renderer->getWindowHeight(),
+                 TARGA_BYTES_PER_PIXEL);
+#else
+    writeTGAFile("/tmp/frame.tga",
+                 imgData->GetPointer(0),
+                 g_renderer->getWindowWidth(),
+                 g_renderer->getWindowHeight(),
+                 TARGA_BYTES_PER_PIXEL,
+                 true);
+#endif  /*RENDER_TARGA*/
+
+#else
+    if (g_renderer->getCameraMode() == Renderer::IMAGE) {
+        double xywh[4];
+        g_renderer->getCameraZoomRegion(xywh);
+        std::ostringstream oss;
+        oss.precision(12);
+        // Send upper left and lower right corners as bbox
+        oss << "nv>image -type image -bbox {"
+            << std::scientific
+            << xywh[0] << " "
+            << xywh[1] << " "
+            << xywh[2] << " "
+            << xywh[3] << "} -bytes";
+
+#ifdef RENDER_TARGA
+        queueTGA(queue, oss.str().c_str(),
+                 imgData->GetPointer(0),
+                 g_renderer->getWindowWidth(),
+                 g_renderer->getWindowHeight(),
+                 TARGA_BYTES_PER_PIXEL);
+#else
+        queuePPM(queue, oss.str().c_str(),
+                 imgData->GetPointer(0),
+                 g_renderer->getWindowWidth(),
+                 g_renderer->getWindowHeight());
+#endif  /*RENDER_TARGA*/
+    } else {
+#ifdef RENDER_TARGA
+        queueTGA(queue, "nv>image -type image -bytes",
+                 imgData->GetPointer(0),
+                 g_renderer->getWindowWidth(),
+                 g_renderer->getWindowHeight(),
+                 TARGA_BYTES_PER_PIXEL);
+#else
+        queuePPM(queue, "nv>image -type image -bytes",
+                 imgData->GetPointer(0),
+                 g_renderer->getWindowWidth(),
+                 g_renderer->getWindowHeight());
+#endif  /*RENDER_TARGA*/
+    }
+#endif  /*DEBUG*/
+}
+
+#else
+
+static void
+writeFrame(int fd, vtkUnsignedCharArray *imgData)
+{
+#ifdef DEBUG
+    if (g_renderer->getCameraMode() == Renderer::IMAGE) {
+        double xywh[4];
+        g_renderer->getScreenWorldCoords(xywh);
+        TRACE("Image bbox: %g %g %g %g", 
+              xywh[0], 
+              (xywh[1] + xywh[3]), 
+              (xywh[0] + xywh[2]), 
+              xywh[1]);
+    }
+
+#ifdef RENDER_TARGA
+    writeTGAFile("/tmp/frame.tga",
+                 imgData->GetPointer(0),
+                 g_renderer->getWindowWidth(),
+                 g_renderer->getWindowHeight(),
+                 TARGA_BYTES_PER_PIXEL);
+#else
+    writeTGAFile("/tmp/frame.tga",
+                 imgData->GetPointer(0),
+                 g_renderer->getWindowWidth(),
+                 g_renderer->getWindowHeight(),
+                 TARGA_BYTES_PER_PIXEL,
+                 true);
+#endif  /*RENDER_TARGA*/
+
+#else
+    if (g_renderer->getCameraMode() == Renderer::IMAGE) {
+        double xywh[4];
+        g_renderer->getCameraZoomRegion(xywh);
+        std::ostringstream oss;
+        oss.precision(12);
+        // Send upper left and lower right corners as bbox
+        oss << "nv>image -type image -bbox {"
+            << std::scientific
+            << xywh[0] << " "
+            << xywh[1] << " "
+            << xywh[2] << " "
+            << xywh[3] << "} -bytes";
+
+#ifdef RENDER_TARGA
+        writeTGA(fd, oss.str().c_str(),
+                 imgData->GetPointer(0),
+                 g_renderer->getWindowWidth(),
+                 g_renderer->getWindowHeight(),
+                 TARGA_BYTES_PER_PIXEL);
+#else
+        writePPM(fd, oss.str().c_str(),
+                 imgData->GetPointer(0),
+                 g_renderer->getWindowWidth(),
+                 g_renderer->getWindowHeight());
+#endif  /*RENDER_TARGA*/
+    } else {
+#ifdef RENDER_TARGA
+        writeTGA(fd, "nv>image -type image -bytes",
+                 imgData->GetPointer(0),
+                 g_renderer->getWindowWidth(),
+                 g_renderer->getWindowHeight(),
+                 TARGA_BYTES_PER_PIXEL);
+#else
+        writePPM(fd, "nv>image -type image -bytes",
+                 imgData->GetPointer(0),
+                 g_renderer->getWindowWidth(),
+                 g_renderer->getWindowHeight());
+#endif  /*RENDER_TARGA*/
+    }
+#endif  /*DEBUG*/
+}
+#endif /*USE_THREADS*/
+
+static int
+sendAck(ClientData clientData, int fdOut)
+{
+    std::ostringstream oss;
+    oss << "nv>ok -token " << g_stats.nCommands <<  "\n";
+    int nBytes = oss.str().length();
+
+    TRACE("Sending OK for commands through %lu", g_stats.nCommands);
+#ifdef USE_THREADS
+    queueResponse(clientData, oss.str().c_str(), nBytes, Response::VOLATILE, Response::OK);
+#else
+    if (write(fdOut, oss.str().c_str(), nBytes) < 0) {
+        ERROR("write failed: %s", strerror(errno));
+        return -1;
+    }
+#endif
+    return 0;
+}
+
+int
+VtkVis::getStatsFile(Tcl_Interp *interp, Tcl_Obj *objPtr)
+{
+    Tcl_DString ds;
+    Tcl_Obj **objv;
+    int objc;
+    int i;
+    char fileName[33];
+    const char *path;
+    md5_state_t state;
+    md5_byte_t digest[16];
+    char *string;
+    int length;
+
+    if ((objPtr == NULL) || (g_statsFile >= 0)) {
+        return g_statsFile;
+    }
+    if (Tcl_ListObjGetElements(interp, objPtr, &objc, &objv) != TCL_OK) {
+	return -1;
+    }
+    Tcl_ListObjAppendElement(interp, objPtr, Tcl_NewStringObj("pid", 3));
+    Tcl_ListObjAppendElement(interp, objPtr, Tcl_NewIntObj(getpid()));
+    string = Tcl_GetStringFromObj(objPtr, &length);
+
+    md5_init(&state);
+    md5_append(&state, (const md5_byte_t *)string, length);
+    md5_finish(&state, digest);
+    for (i = 0; i < 16; i++) {
+        sprintf(fileName + i * 2, "%02x", digest[i]);
+    }
+    Tcl_DStringInit(&ds);
+    Tcl_DStringAppend(&ds, STATSDIR, -1);
+    Tcl_DStringAppend(&ds, "/", 1);
+    Tcl_DStringAppend(&ds, fileName, 32);
+    path = Tcl_DStringValue(&ds);
+
+    g_statsFile = open(path, O_EXCL | O_CREAT | O_WRONLY, 0600);
+    Tcl_DStringFree(&ds);
+    if (g_statsFile < 0) {
+	ERROR("can't open \"%s\": %s", fileName, strerror(errno));
+	return -1;
+    }
+    return g_statsFile;
+}
+
+int
+VtkVis::writeToStatsFile(int f, const char *s, size_t length)
+{
+    if (f >= 0) {
+        ssize_t numWritten;
+
+        numWritten = write(f, s, length);
+        if (numWritten == (ssize_t)length) {
+            close(dup(f));
+        }
+    }
+    return 0;
+}
+
+static int
+serverStats(int code) 
+{
+    double start, finish;
+    char buf[BUFSIZ];
+    Tcl_DString ds;
+    int result;
+    int f;
+
+    {
+	struct timeval tv;
+
+	/* Get ending time.  */
+	gettimeofday(&tv, NULL);
+	finish = CVT2SECS(tv);
+	tv = g_stats.start;
+	start = CVT2SECS(tv);
+    }
+    /* 
+     * Session information:
+     *   - Name of render server
+     *   - Process ID
+     *   - Hostname where server is running
+     *   - Start date of session
+     *   - Start date of session in seconds
+     *   - Number of data sets loaded from client
+     *   - Number of data bytes total loaded from client
+     *   - Number of frames returned
+     *   - Number of bytes total returned (in frames)
+     *   - Number of commands received
+     *   - Total elapsed time of all commands
+     *   - Total elapsed time of session
+     *   - Exit code of vizserver
+     *   - User time 
+     *   - System time
+     *   - User time of children 
+     *   - System time of children 
+     */
+
+    Tcl_DStringInit(&ds);
+    
+    Tcl_DStringAppendElement(&ds, "render_stop");
+    /* renderer */
+    Tcl_DStringAppendElement(&ds, "renderer");
+    Tcl_DStringAppendElement(&ds, "vtkvis");
+    /* pid */
+    Tcl_DStringAppendElement(&ds, "pid");
+    sprintf(buf, "%d", getpid());
+    Tcl_DStringAppendElement(&ds, buf);
+    /* host */
+    Tcl_DStringAppendElement(&ds, "host");
+    gethostname(buf, BUFSIZ-1);
+    buf[BUFSIZ-1] = '\0';
+    Tcl_DStringAppendElement(&ds, buf);
+    /* date */
+    Tcl_DStringAppendElement(&ds, "date");
+    strcpy(buf, ctime(&g_stats.start.tv_sec));
+    buf[strlen(buf) - 1] = '\0';
+    Tcl_DStringAppendElement(&ds, buf);
+    /* date_secs */
+    Tcl_DStringAppendElement(&ds, "date_secs");
+    sprintf(buf, "%ld", g_stats.start.tv_sec);
+    Tcl_DStringAppendElement(&ds, buf);
+    /* num_data_sets */
+    Tcl_DStringAppendElement(&ds, "num_data_sets");
+    sprintf(buf, "%lu", (unsigned long int)g_stats.nDataSets);
+    Tcl_DStringAppendElement(&ds, buf);
+    /* data_set_bytes */
+    Tcl_DStringAppendElement(&ds, "data_set_bytes");
+    sprintf(buf, "%lu", (unsigned long int)g_stats.nDataBytes);
+    Tcl_DStringAppendElement(&ds, buf);
+    /* num_frames */
+    Tcl_DStringAppendElement(&ds, "num_frames");
+    sprintf(buf, "%lu", (unsigned long int)g_stats.nFrames);
+    Tcl_DStringAppendElement(&ds, buf);
+    /* frame_bytes */
+    Tcl_DStringAppendElement(&ds, "frame_bytes");
+    sprintf(buf, "%lu", (unsigned long int)g_stats.nFrameBytes);
+    Tcl_DStringAppendElement(&ds, buf);
+    /* num_commands */
+    Tcl_DStringAppendElement(&ds, "num_commands");
+    sprintf(buf, "%lu", (unsigned long int)g_stats.nCommands);
+    Tcl_DStringAppendElement(&ds, buf);
+    /* cmd_time */
+    Tcl_DStringAppendElement(&ds, "cmd_time");
+    sprintf(buf, "%g", g_stats.cmdTime);
+    Tcl_DStringAppendElement(&ds, buf);
+    /* session_time */
+    Tcl_DStringAppendElement(&ds, "session_time");
+    sprintf(buf, "%g", finish - start);
+    Tcl_DStringAppendElement(&ds, buf);
+    /* status */
+    Tcl_DStringAppendElement(&ds, "status");
+    sprintf(buf, "%d", code);
+    Tcl_DStringAppendElement(&ds, buf);
+    {
+	long clocksPerSec = sysconf(_SC_CLK_TCK);
+	double clockRes = 1.0 / clocksPerSec;
+	struct tms tms;
+
+	memset(&tms, 0, sizeof(tms));
+	times(&tms);
+	/* utime */
+	Tcl_DStringAppendElement(&ds, "utime");
+	sprintf(buf, "%g", tms.tms_utime * clockRes);
+	Tcl_DStringAppendElement(&ds, buf);
+	/* stime */
+	Tcl_DStringAppendElement(&ds, "stime");
+	sprintf(buf, "%g", tms.tms_stime * clockRes);
+	Tcl_DStringAppendElement(&ds, buf);
+	/* cutime */
+	Tcl_DStringAppendElement(&ds, "cutime");
+	sprintf(buf, "%g", tms.tms_cutime * clockRes);
+	Tcl_DStringAppendElement(&ds, buf);
+	/* cstime */
+	Tcl_DStringAppendElement(&ds, "cstime");
+	sprintf(buf, "%g", tms.tms_cstime * clockRes);
+	Tcl_DStringAppendElement(&ds, buf);
+    }
+    Tcl_DStringAppend(&ds, "\n", -1);
+    f = getStatsFile(NULL, NULL);
+    result = writeToStatsFile(f, Tcl_DStringValue(&ds), 
+                              Tcl_DStringLength(&ds));
+    close(f);
+    Tcl_DStringFree(&ds);
+    return result;
+}
+
+static void
+initService()
+{
+    TRACE("Enter");
+
+    const char *user = getenv("USER");
+    char *logName = NULL;
+    int logNameLen = 0;
+
+    if (user == NULL) {
+        logNameLen = 19+1;
+        logName = (char *)calloc(logNameLen, sizeof(char));
+        strncpy(logName, "/tmp/vtkvis_log.txt", logNameLen);
+    }
+    else {
+        logNameLen = 16+strlen(user)+4+1;
+        logName = (char *)calloc(logNameLen, sizeof(char));
+        strncpy(logName, "/tmp/vtkvis_log_", logNameLen);
+        strncat(logName, user, strlen(user));
+        strncat(logName, ".txt", 4);
+    }
+
+    // open log and map stderr to log file
+    g_fLog = fopen(logName, "w");
+    close(STDERR_FILENO);
+    dup2(fileno(g_fLog), STDERR_FILENO);
+    // flush junk
+    fflush(stderr);
+
+    // clean up malloc'd memory
+    if (logName != NULL) {
+        free(logName);
+    }
+
+    TRACE("Leave");
+}
+
+static void
+exitService()
+{
+    TRACE("Enter");
+
+    serverStats(0);
+
+    // close log file
+    if (g_fLog != NULL) {
+        fclose(g_fLog);
+	g_fLog = NULL;
+    }
+}
+
+#ifdef USE_THREADS
+
+static void *
+writerThread(void *clientData)
+{
+    ResponseQueue *queue = (ResponseQueue *)clientData;
+
+    TRACE("Starting writer thread");
+    for (;;) {
+        Response *response = queue->dequeue();
+        if (response == NULL)
+            continue;
+        if (fwrite(response->message(), sizeof(char), response->length(),
+                   g_fOut) != response->length()) {
+            ERROR("short write while trying to write %ld bytes", 
+                  response->length());
+        }
+        fflush(g_fOut);
+        TRACE("Wrote response of type %d", response->type());
+        delete response;
+        if (feof(g_fOut))
+            break;
+    }    
+    return NULL;
+}
+
+#endif  /*USE_THREADS*/
+
+int
+main(int argc, char *argv[])
+{
+    // Ignore SIGPIPE.  **Is this needed? **
+    signal(SIGPIPE, SIG_IGN);
+    initService();
+    initLog();
+
+    memset(&g_stats, 0, sizeof(g_stats));
+    gettimeofday(&g_stats.start, NULL);
+
+    TRACE("Starting VTKVis Server");
+
+    /* This synchronizes the client with the server, so that the client 
+     * doesn't start writing commands before the server is ready. It could
+     * also be used to supply information about the server (version, memory
+     * size, etc). */
+    fprintf(g_fOut, "VtkVis %s (build %s)\n", VTKVIS_VERSION_STRING, SVN_VERSION);
+    fflush(g_fOut);
+
+    g_renderer = new Renderer();
+    g_inBufPtr = new ReadBuffer(g_fdIn, 1<<12);
+
+    Tcl_Interp *interp = Tcl_CreateInterp();
+    ClientData clientData = NULL;
+#ifdef USE_THREADS
+    ResponseQueue *queue = new ResponseQueue();
+    clientData = (ClientData)queue;
+    initTcl(interp, clientData);
+
+    pthread_t writerThreadId;
+    if (pthread_create(&writerThreadId, NULL, &writerThread, queue) < 0) {
+        ERROR("Can't create writer thread: %s", strerror(errno));
+    }
+#else 
+    initTcl(interp, clientData);
+#endif
+
+    vtkSmartPointer<vtkUnsignedCharArray> imgData = 
+        vtkSmartPointer<vtkUnsignedCharArray>::New();
+
+    // Start main server loop
+    for (;;) {
+        if (processCommands(interp, clientData, g_inBufPtr, g_fdOut) < 0)
+            break;
+
+        if (g_renderer->render()) {
+            TRACE("Rendering new frame");
+            g_renderer->getRenderedFrame(imgData);
+#ifdef USE_THREADS
+            queueFrame(queue, imgData);
+#else
+            writeFrame(g_fdOut, imgData);
+#endif
+            g_stats.nFrames++;
+            g_stats.nFrameBytes += imgData->GetDataSize() * imgData->GetDataTypeSize();
+        } else {
+            TRACE("No render required");
+            sendAck(clientData, g_fdOut);
+        }
+
+        if (g_inBufPtr->status() == ReadBuffer::ENDFILE)
+            break;
+    }
+#ifdef USE_THREADS
+    // Writer thread is probably blocked on sem_wait, so cancel instead
+    // of joining
+    if (pthread_cancel(writerThreadId) < 0) {
+        ERROR("Can't cancel writer thread: %s", strerror(errno));
+    } else {
+        TRACE("Cancelled writer thread");
+    }
+
+    TRACE("Deleting ResponseQueue");
+    delete queue;
+    queue = NULL;
+#endif
+
+    TRACE("Stopping Tcl interpreter");
+    exitTcl(interp);
+    interp = NULL;
+
+    TRACE("Deleting ReadBuffer");
+    delete g_inBufPtr;
+    g_inBufPtr = NULL;
+
+    TRACE("Deleting renderer");
+    delete g_renderer;
+    g_renderer = NULL;
+
+    TRACE("Exiting VTKVis Server");
+
+    closeLog();
+    exitService();
+
+    return 0;
+}
Index: /trunk/packages/vizservers/vtkvis/VtkRenderServer.h
===================================================================
--- /trunk/packages/vizservers/vtkvis/VtkRenderServer.h	(revision 3616)
+++ /trunk/packages/vizservers/vtkvis/VtkRenderServer.h	(revision 3616)
@@ -0,0 +1,55 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (C) 2004-2012  HUBzero Foundation, LLC
+ *
+ * Author: Leif Delgass <ldelgass@purdue.edu>
+ */
+
+#ifndef VTKVIS_RENDERSERVER_H
+#define VTKVIS_RENDERSERVER_H
+
+#include <sys/types.h>
+#include <sys/time.h>
+
+namespace VtkVis {
+
+class Renderer;
+
+#define VTKVIS_VERSION_STRING "1.3"
+
+#define MSECS_ELAPSED(t1, t2) \
+    ((t1).tv_sec == (t2).tv_sec ? (((t2).tv_usec - (t1).tv_usec)/1.0e+3) : \
+     (((t2).tv_sec - (t1).tv_sec))*1.0e+3 + (double)((t2).tv_usec - (t1).tv_usec)/1.0e+3)
+
+#define CVT2SECS(x)  ((double)(x).tv_sec) + ((double)(x).tv_usec * 1.0e-6)
+
+#ifndef STATSDIR
+#define STATSDIR	"/var/tmp/visservers"
+#endif
+
+typedef struct {
+    pid_t pid;
+    size_t nDataSets;       /**< # of data sets received */
+    size_t nDataBytes;      /**< # of bytes received as data sets */
+    size_t nFrames;         /**< # of frames sent to client. */
+    size_t nFrameBytes;     /**< # of bytes for all frames. */
+    size_t nCommands;       /**< # of commands executed */
+    double cmdTime;         /**< Elasped time spend executing commands. */
+    struct timeval start;   /**< Start of elapsed time. */
+} Stats;
+
+extern Stats g_stats;
+
+extern int g_fdIn;
+extern int g_fdOut;
+extern FILE *g_fOut;
+extern FILE *g_fLog;
+extern Renderer *g_renderer;
+extern ReadBuffer *g_inBufPtr;
+extern int g_statsFile;
+extern int writeToStatsFile(int f, const char *s, size_t length);
+extern int getStatsFile(Tcl_Interp * interp, Tcl_Obj *objPtr);
+
+}
+
+#endif
Index: /trunk/packages/vizservers/vtkvis/VtkRenderer.cpp
===================================================================
--- /trunk/packages/vizservers/vtkvis/VtkRenderer.cpp	(revision 3616)
+++ /trunk/packages/vizservers/vtkvis/VtkRenderer.cpp	(revision 3616)
@@ -0,0 +1,4353 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (C) 2004-2012  HUBzero Foundation, LLC
+ *
+ * Author: Leif Delgass <ldelgass@purdue.edu>
+ */
+
+#include <cfloat>
+#include <cstring>
+#include <cassert>
+#include <cmath>
+
+#include <GL/gl.h>
+
+#ifdef WANT_TRACE
+#include <sys/time.h>
+#endif
+
+#include <vtkMath.h>
+#include <vtkCamera.h>
+#include <vtkLight.h>
+#include <vtkCoordinate.h>
+#include <vtkTransform.h>
+#include <vtkCharArray.h>
+#ifdef USE_CUSTOM_AXES
+#include "vtkRpCubeAxesActor.h"
+#else
+#include <vtkCubeAxesActor.h>
+#endif
+#include <vtkDataSetReader.h>
+#include <vtkDataSetMapper.h>
+#include <vtkContourFilter.h>
+#include <vtkPolyDataMapper.h>
+#include <vtkProperty.h>
+#include <vtkProperty2D.h>
+#include <vtkPointData.h>
+#include <vtkLookupTable.h>
+#include <vtkTextProperty.h>
+#include <vtkOpenGLRenderWindow.h>
+#include <vtkVersion.h>
+
+#include "VtkRenderer.h"
+#include "VtkRendererGraphicsObjs.h"
+#include "Math.h"
+#include "ColorMap.h"
+#include "Trace.h"
+
+#define MSECS_ELAPSED(t1, t2) \
+    ((t1).tv_sec == (t2).tv_sec ? (((t2).tv_usec - (t1).tv_usec)/1.0e+3) : \
+     (((t2).tv_sec - (t1).tv_sec))*1.0e+3 + (double)((t2).tv_usec - (t1).tv_usec)/1.0e+3)
+
+#define printCameraInfo(camera)                                         \
+do {                                                                    \
+    TRACE("pscale: %g, angle: %g, d: %g pos: %g %g %g, fpt: %g %g %g, vup: %g %g %g, clip: %g %g", \
+          (camera)->GetParallelScale(),                                 \
+          (camera)->GetViewAngle(),                                     \
+          (camera)->GetDistance(),                                      \
+          (camera)->GetPosition()[0],                                   \
+          (camera)->GetPosition()[1],                                   \
+          (camera)->GetPosition()[2],                                   \
+          (camera)->GetFocalPoint()[0],                                 \
+          (camera)->GetFocalPoint()[1],                                 \
+          (camera)->GetFocalPoint()[2],                                 \
+          (camera)->GetViewUp()[0],                                     \
+          (camera)->GetViewUp()[1],                                     \
+          (camera)->GetViewUp()[2],                                     \
+          (camera)->GetClippingRange()[0],                              \
+          (camera)->GetClippingRange()[1]);                             \
+} while(0)
+
+using namespace VtkVis;
+
+Renderer::Renderer() :
+    _needsRedraw(true),
+    _needsAxesReset(false),
+    _needsCameraClippingRangeReset(false),
+    _needsCameraReset(false),
+    _windowWidth(500),
+    _windowHeight(500),
+    _cameraMode(PERSPECTIVE),
+    _cameraAspect(ASPECT_NATIVE),
+    _imgCameraPlane(PLANE_XY),
+    _imgCameraOffset(0),
+    _cameraZoomRatio(1),
+    _useCumulativeRange(true),
+    _cumulativeRangeOnlyVisible(false)
+{
+    _bgColor[0] = 0;
+    _bgColor[1] = 0;
+    _bgColor[2] = 0;
+    _cameraPan[0] = 0;
+    _cameraPan[1] = 0;
+    _cameraOrientation[0] = 1.0;
+    _cameraOrientation[1] = 0.0;
+    _cameraOrientation[2] = 0.0;
+    _cameraOrientation[3] = 0.0;
+    // clipping planes to prevent overdrawing axes
+    _activeClipPlanes = vtkSmartPointer<vtkPlaneCollection>::New();
+    // bottom
+    _cameraClipPlanes[0] = vtkSmartPointer<vtkPlane>::New();
+    _cameraClipPlanes[0]->SetNormal(0, 1, 0);
+    _cameraClipPlanes[0]->SetOrigin(0, 0, 0);
+    if (_cameraMode == IMAGE)
+        _activeClipPlanes->AddItem(_cameraClipPlanes[0]);
+    // left
+    _cameraClipPlanes[1] = vtkSmartPointer<vtkPlane>::New();
+    _cameraClipPlanes[1]->SetNormal(1, 0, 0);
+    _cameraClipPlanes[1]->SetOrigin(0, 0, 0);
+    if (_cameraMode == IMAGE)
+        _activeClipPlanes->AddItem(_cameraClipPlanes[1]);
+    // top
+    _cameraClipPlanes[2] = vtkSmartPointer<vtkPlane>::New();
+    _cameraClipPlanes[2]->SetNormal(0, -1, 0);
+    _cameraClipPlanes[2]->SetOrigin(0, 1, 0);
+    if (_cameraMode == IMAGE)
+        _activeClipPlanes->AddItem(_cameraClipPlanes[2]);
+    // right
+    _cameraClipPlanes[3] = vtkSmartPointer<vtkPlane>::New();
+    _cameraClipPlanes[3]->SetNormal(-1, 0, 0);
+    _cameraClipPlanes[3]->SetOrigin(1, 0, 0);
+    if (_cameraMode == IMAGE)
+        _activeClipPlanes->AddItem(_cameraClipPlanes[3]);
+    _renderer = vtkSmartPointer<vtkRenderer>::New();
+
+    // Global ambient (defaults to 1,1,1)
+    //_renderer->SetAmbient(.2, .2, .2);
+
+    vtkSmartPointer<vtkLight> headlight = vtkSmartPointer<vtkLight>::New();
+    headlight->SetLightTypeToHeadlight();
+    headlight->PositionalOff();
+    // Light ambient color defaults to 0,0,0
+    //headlight->SetAmbientColor(1, 1, 1);
+    _renderer->AddLight(headlight);
+    vtkSmartPointer<vtkLight> skylight = vtkSmartPointer<vtkLight>::New();
+    skylight->SetLightTypeToCameraLight();
+    skylight->SetPosition(0, 1, 0);
+    skylight->SetFocalPoint(0, 0, 0);
+    skylight->PositionalOff();
+    // Light ambient color defaults to 0,0,0
+    //skylight->SetAmbientColor(1, 1, 1);
+    _renderer->AddLight(skylight);
+    _renderer->LightFollowCameraOn();
+    _renderWindow = vtkSmartPointer<vtkRenderWindow>::New();
+#ifdef USE_OFFSCREEN_RENDERING
+    _renderWindow->DoubleBufferOff();
+    _renderWindow->OffScreenRenderingOn();
+#else
+    _renderWindow->SwapBuffersOff();
+#endif
+    _renderWindow->SetSize(_windowWidth, _windowHeight);
+    // Next 2 options needed to support depth peeling
+    _renderWindow->SetAlphaBitPlanes(1);
+    _renderWindow->SetMultiSamples(0);
+    _renderer->SetMaximumNumberOfPeels(100);
+    _renderer->SetUseDepthPeeling(1);
+    _renderer->SetTwoSidedLighting(1);
+    _renderWindow->AddRenderer(_renderer);
+    setViewAngle(_windowHeight);
+    initAxes();
+    initCamera();
+    addColorMap("default", ColorMap::getDefault());
+    addColorMap("grayDefault", ColorMap::getGrayDefault());
+    addColorMap("volumeDefault", ColorMap::getVolumeDefault());
+    addColorMap("elementDefault", ColorMap::getElementDefault());
+}
+
+Renderer::~Renderer()
+{
+    TRACE("Enter");
+
+    deleteAllGraphicsObjects<Arc>();
+    deleteAllGraphicsObjects<Arrow>();
+    deleteAllGraphicsObjects<Box>();
+    deleteAllGraphicsObjects<Cone>();
+    deleteAllGraphicsObjects<Contour2D>();
+    deleteAllGraphicsObjects<Contour3D>();
+    deleteAllGraphicsObjects<Cutplane>();
+    deleteAllGraphicsObjects<Cylinder>();
+    deleteAllGraphicsObjects<Disk>();
+    deleteAllGraphicsObjects<Glyphs>();
+    deleteAllGraphicsObjects<Group>();
+    deleteAllGraphicsObjects<HeightMap>();
+    deleteAllGraphicsObjects<LIC>();
+    deleteAllGraphicsObjects<Line>();
+    deleteAllGraphicsObjects<Molecule>();
+    deleteAllGraphicsObjects<Outline>();
+    deleteAllGraphicsObjects<PolyData>();
+    deleteAllGraphicsObjects<Polygon>();
+    deleteAllGraphicsObjects<PseudoColor>();
+    deleteAllGraphicsObjects<Sphere>();
+    deleteAllGraphicsObjects<Streamlines>();
+    deleteAllGraphicsObjects<Volume>();
+    deleteAllGraphicsObjects<Warp>();
+
+    TRACE("Deleting ColorMaps");
+    // Delete color maps and data sets last in case references still
+    // exist
+    for (ColorMapHashmap::iterator itr = _colorMaps.begin();
+         itr != _colorMaps.end(); ++itr) {
+        delete itr->second;
+    }
+    _colorMaps.clear();
+    TRACE("Deleting DataSets");
+    for (DataSetHashmap::iterator itr = _dataSets.begin();
+         itr != _dataSets.end(); ++itr) {
+        delete itr->second;
+    }
+    _dataSets.clear();
+
+    clearFieldRanges();
+    clearUserFieldRanges();
+
+    TRACE("Leave");
+}
+
+/**
+ * \brief Add a DataSet to this Renderer
+ *
+ * This just adds the DataSet to the Renderer's list of data sets.
+ * In order to render the data, a graphics object using the data
+ * set must be added to the Renderer.
+ */
+void Renderer::addDataSet(const DataSetId& id)
+{
+    if (getDataSet(id) != NULL) {
+        WARN("Replacing existing DataSet %s", id.c_str());
+        deleteDataSet(id);
+    }
+    _dataSets[id] = new DataSet(id);
+}
+
+/**
+ * \brief Remove the specified DataSet and associated rendering objects
+ *
+ * The underlying DataSet and any associated graphics 
+ * objects are deleted, freeing the memory used.
+ */
+void Renderer::deleteDataSet(const DataSetId& id)
+{
+    DataSetHashmap::iterator itr;
+
+    bool doAll = false;
+
+    if (id.compare("all") == 0) {
+        itr = _dataSets.begin();
+        doAll = true;
+    } else {
+        itr = _dataSets.find(id);
+    }
+    if (itr == _dataSets.end()) {
+        ERROR("Unknown dataset %s", id.c_str());
+        return;
+    }
+
+    do {
+        TRACE("Deleting dataset %s", itr->second->getName().c_str());
+
+        deleteGraphicsObject<Contour2D>(itr->second->getName());
+        deleteGraphicsObject<Contour3D>(itr->second->getName());
+        deleteGraphicsObject<Cutplane>(itr->second->getName());
+        deleteGraphicsObject<Glyphs>(itr->second->getName());
+        deleteGraphicsObject<HeightMap>(itr->second->getName());
+        deleteGraphicsObject<LIC>(itr->second->getName());
+        deleteGraphicsObject<Molecule>(itr->second->getName());
+        deleteGraphicsObject<Outline>(itr->second->getName());
+        deleteGraphicsObject<PolyData>(itr->second->getName());
+        deleteGraphicsObject<PseudoColor>(itr->second->getName());
+        deleteGraphicsObject<Streamlines>(itr->second->getName());
+        deleteGraphicsObject<Volume>(itr->second->getName());
+        deleteGraphicsObject<Warp>(itr->second->getName());
+
+        TRACE("After deleting graphics objects");
+
+        delete itr->second;
+        itr = _dataSets.erase(itr);
+    } while (doAll && itr != _dataSets.end());
+
+    // Update cumulative data range
+    initFieldRanges();
+    updateFieldRanges();
+
+    sceneBoundsChanged();
+    _needsRedraw = true;
+}
+
+/**
+ * \brief Get a list of DataSets this Renderer knows about
+ */
+void Renderer::getDataSetNames(std::vector<std::string>& names)
+{
+    names.clear();
+    for (DataSetHashmap::iterator itr = _dataSets.begin();
+         itr != _dataSets.end(); ++itr) {
+        names.push_back(itr->second->getName());
+    }
+}
+
+/**
+ * \brief Find the DataSet for the given DataSetId key
+ *
+ * \return A pointer to the DataSet, or NULL if not found
+ */
+DataSet *Renderer::getDataSet(const DataSetId& id)
+{
+    DataSetHashmap::iterator itr = _dataSets.find(id);
+    if (itr == _dataSets.end()) {
+#ifdef DEBUG
+        TRACE("DataSet not found: %s", id.c_str());
+#endif
+        return NULL;
+    } else
+        return itr->second;
+}
+
+/**
+ * \brief (Re-)load the data for the specified DataSet key from a file
+ */
+bool Renderer::setDataFile(const DataSetId& id, const char *filename)
+{
+    DataSet *ds = getDataSet(id);
+    if (ds) {
+        bool ret = ds->setDataFile(filename);
+        initFieldRanges();
+        updateFieldRanges();
+        _needsRedraw = true;
+        return ret;
+    } else
+        return false;
+}
+
+/**
+ * \brief (Re-)load the data for the specified DataSet key from a memory buffer
+ */
+bool Renderer::setData(const DataSetId& id, char *data, int nbytes)
+{
+    DataSet *ds = getDataSet(id);
+    if (ds) {
+        bool ret = ds->setData(data, nbytes);
+        initFieldRanges();
+        updateFieldRanges();
+        _needsRedraw = true;
+        return ret;
+    } else
+        return false;
+}
+
+/**
+ * \brief Set the active scalar field array by name for a DataSet
+ */
+bool Renderer::setDataSetActiveScalars(const DataSetId& id, const char *scalarName)
+{
+    DataSetHashmap::iterator itr;
+
+    bool doAll = false;
+
+    if (id.compare("all") == 0) {
+        itr = _dataSets.begin();
+        doAll = true;
+    } else {
+        itr = _dataSets.find(id);
+    }
+    if (itr == _dataSets.end()) {
+        ERROR("DataSet not found: %s", id.c_str());
+        return false;
+    }
+
+    bool ret = true;
+    bool needRangeUpdate = false;
+    do {
+        if (strcmp(itr->second->getActiveScalarsName(), scalarName) != 0) {
+            if (!itr->second->setActiveScalars(scalarName)) {
+                ret = false;
+            } else {
+                needRangeUpdate = true;
+            }
+        }
+    } while (doAll && ++itr != _dataSets.end());
+
+    if (needRangeUpdate) {
+         updateFieldRanges();
+        _needsRedraw = true;
+    } 
+
+    return ret;
+}
+
+/**
+ * \brief Set the active vector field array by name for a DataSet
+ */
+bool Renderer::setDataSetActiveVectors(const DataSetId& id, const char *vectorName)
+{
+    DataSetHashmap::iterator itr;
+
+    bool doAll = false;
+
+    if (id.compare("all") == 0) {
+        itr = _dataSets.begin();
+        doAll = true;
+    } else {
+        itr = _dataSets.find(id);
+    }
+    if (itr == _dataSets.end()) {
+        ERROR("DataSet not found: %s", id.c_str());
+        return false;
+    }
+
+    bool ret = true;
+    bool needRangeUpdate = false;
+    do {
+        if (strcmp(itr->second->getActiveVectorsName(), vectorName) != 0) {
+            if (!itr->second->setActiveVectors(vectorName)) {
+                ret = false;
+            } else {
+                needRangeUpdate = true;
+            }
+        }
+    } while (doAll && ++itr != _dataSets.end());
+
+    if (needRangeUpdate) {
+        updateFieldRanges();
+        _needsRedraw = true;
+    } 
+
+    return ret;
+}
+
+/**
+ * \brief Control whether the cumulative data range of datasets is used for 
+ * colormapping and contours
+ *
+ * NOTE: If using explicit range(s), setting cumulative ranges on will
+ * remove explicit ranges on all fields
+ */
+void Renderer::setUseCumulativeDataRange(bool state, bool onlyVisible)
+{
+    TRACE("use cumulative: %d, only visible: %d", (state ? 1 : 0), (onlyVisible ? 1 : 0));
+    _useCumulativeRange = state;
+    _cumulativeRangeOnlyVisible = onlyVisible;
+    clearUserFieldRanges();
+    updateFieldRanges();
+    resetAxes();
+    _needsRedraw = true;
+}
+
+void Renderer::resetAxes(double bounds[6])
+{
+    TRACE("Resetting axes");
+
+    if (_cubeAxesActor == NULL) {
+        initAxes();
+    }
+
+    if (_cameraMode == IMAGE) {
+        _cubeAxesActor->SetUse2DMode(1);
+    } else {
+        _cubeAxesActor->SetUse2DMode(0);
+    }
+
+    if (_cameraMode == IMAGE) {
+        return;
+    }
+
+    setAxesBounds(bounds);
+    setAxesRanges();
+}
+
+/**
+ * \brief Explicitly set world coordinate bounds of axes
+ *
+ * This determines the region in world coordinates around which
+ * the axes are drawn
+ */
+void Renderer::setAxesBounds(double min, double max)
+{
+    setAxisBounds(X_AXIS, min, max);
+    setAxisBounds(Y_AXIS, min, max);
+    setAxisBounds(Z_AXIS, min, max);
+}
+
+/**
+ * \brief Set axes bounds based on auto/explicit settings
+ */
+void Renderer::setAxesBounds(double boundsIn[6])
+{
+    double newBounds[6];
+    if (boundsIn != NULL) { 
+        memcpy(&newBounds[0], &boundsIn[0], sizeof(double)*6);
+    } else {
+        if (_axesAutoBounds[X_AXIS] ||
+            _axesAutoBounds[Y_AXIS] ||
+            _axesAutoBounds[Z_AXIS]) {
+            collectBounds(newBounds, false);
+        }
+    }
+
+    double bounds[6];
+    if (_axesAutoBounds[X_AXIS]) {
+        memcpy(&bounds[0], &newBounds[0], sizeof(double)*2);
+    } else {
+        memcpy(&bounds[0], &_axesUserBounds[0], sizeof(double)*2);
+    }
+    if (_axesAutoBounds[Y_AXIS]) {
+        memcpy(&bounds[2], &newBounds[2], sizeof(double)*2);
+    } else {
+        memcpy(&bounds[2], &_axesUserBounds[2], sizeof(double)*2);
+    }
+    if (_axesAutoBounds[Z_AXIS]) {
+        memcpy(&bounds[4], &newBounds[4], sizeof(double)*2);
+    } else {
+        memcpy(&bounds[4], &_axesUserBounds[4], sizeof(double)*2);
+    }
+
+    _cubeAxesActor->SetBounds(bounds);
+
+    TRACE("Axis bounds: %g %g %g %g %g %g",
+              bounds[0],
+              bounds[1],
+              bounds[2],
+              bounds[3],
+              bounds[4],
+              bounds[5]);
+
+    _needsRedraw = true;
+}
+
+/**
+ * \brief Toggle automatic vs. explicit range setting on all axes
+ */
+void Renderer::setAxesAutoBounds(bool state)
+{
+    _axesAutoBounds[X_AXIS] = state;
+    _axesAutoBounds[Y_AXIS] = state;
+    _axesAutoBounds[Z_AXIS] = state;
+
+    TRACE("Set axes bounds to %s", (state ? "auto" : "explicit"));
+
+    setAxesBounds();
+
+    _needsRedraw = true;
+}
+
+/**
+ * \brief Toggle automatic vs. explicit range setting on all axes
+ */
+void Renderer::setAxisAutoBounds(Axis axis, bool state)
+{
+    _axesAutoBounds[axis] = state;
+
+    TRACE("Set axis %d bounds to %s", axis, (state ? "auto" : "explicit"));
+
+    setAxesBounds();
+
+    _needsRedraw = true;
+}
+
+/**
+ * \brief Toggle automatic vs. explicit range setting on all axes
+ */
+void Renderer::setAxesAutoRange(bool state)
+{
+    _axesRangeMode[X_AXIS] = state ? RANGE_AUTO : RANGE_EXPLICIT;
+    _axesRangeMode[Y_AXIS] = state ? RANGE_AUTO : RANGE_EXPLICIT;
+    _axesRangeMode[Z_AXIS] = state ? RANGE_AUTO : RANGE_EXPLICIT;
+
+    TRACE("Set axes range to %s", (state ? "auto" : "explicit"));
+
+    setAxesRanges();
+
+    _needsRedraw = true;
+}
+
+/**
+ * \brief Explicitly set world coordinate bounds of axis
+ *
+ * This determines the region in world coordinates around which
+ * the axes are drawn
+ */
+void Renderer::setAxisBounds(Axis axis, double min, double max)
+{
+    double bounds[6];
+    _cubeAxesActor->GetBounds(bounds);
+
+    bounds[axis*2  ] = _axesUserBounds[axis*2  ] = min;
+    bounds[axis*2+1] = _axesUserBounds[axis*2+1] = max;
+
+    _cubeAxesActor->SetBounds(bounds);
+
+    _axesAutoBounds[axis] = false;
+
+    TRACE("Axis bounds: %g %g %g %g %g %g",
+              bounds[0],
+              bounds[1],
+              bounds[2],
+              bounds[3],
+              bounds[4],
+              bounds[5]);
+
+    _needsRedraw = true;
+}
+
+/**
+ * \brief Toggle automatic vs. explicit range setting on specific axis
+ */
+void Renderer::setAxisAutoRange(Axis axis, bool state)
+{
+    _axesRangeMode[axis] = state ? RANGE_AUTO : RANGE_EXPLICIT;
+
+    TRACE("Set axis %d range to %s", axis, (state ? "auto" : "explicit"));
+
+    setAxesRanges();
+
+    _needsRedraw = true;
+}
+
+/**
+ * \brief Set explicit range on axes and disable auto range
+ */
+void Renderer::setAxesRange(double min, double max)
+{
+    setAxisRange(X_AXIS, min, max);
+    setAxisRange(Y_AXIS, min, max);
+    setAxisRange(Z_AXIS, min, max);
+}
+
+/**
+ * \brief Explicitly set power multiplier for axes labels
+ *
+ * The exponent will appear in the axis title and be omitted from labels
+ */
+void Renderer::setAxesLabelPowerScaling(int xPow, int yPow, int zPow, bool useCustom)
+{
+    _cubeAxesActor->SetLabelScaling(!useCustom, xPow, yPow, zPow);
+
+    TRACE("Set axis label scaling: custom: %d, powers: %d,%d,%d", (int)useCustom, xPow, yPow, zPow);
+
+    _needsRedraw = true;
+}
+
+/**
+ * \brief Set explicit range on axis and disable auto range
+ */
+void Renderer::setAxisRange(Axis axis, double min, double max)
+{
+    switch (axis) {
+    case X_AXIS:
+        _axesRangeMode[X_AXIS] = RANGE_EXPLICIT;
+        _cubeAxesActor->SetXAxisRange(min, max);
+        break;
+    case Y_AXIS:
+        _axesRangeMode[Y_AXIS] = RANGE_EXPLICIT;
+        _cubeAxesActor->SetYAxisRange(min, max);
+        break;
+    case Z_AXIS:
+        _axesRangeMode[Z_AXIS] = RANGE_EXPLICIT;
+        _cubeAxesActor->SetZAxisRange(min, max);
+        break;
+    default:
+        break;
+    }
+
+    TRACE("Set axis %d range to: %g, %g", axis, min, max);
+
+     _needsRedraw = true;
+}
+
+/**
+ * \brief Set axes ranges based on bounds and range modes
+ */
+void Renderer::setAxesRanges()
+{
+    computeAxesScale();
+
+    double bounds[6];
+    _cubeAxesActor->GetBounds(bounds);
+
+    double ranges[6];
+    if (_axesRangeMode[X_AXIS] != RANGE_EXPLICIT) {
+        ranges[0] = bounds[0] * _axesScale[X_AXIS];
+        ranges[1] = bounds[1] * _axesScale[X_AXIS];
+        _cubeAxesActor->SetXAxisRange(&ranges[0]);
+    } else {
+        _cubeAxesActor->GetXAxisRange(&ranges[0]);
+    }
+
+    if (_axesRangeMode[Y_AXIS] != RANGE_EXPLICIT) {
+        ranges[2] = bounds[2] * _axesScale[Y_AXIS];
+        ranges[3] = bounds[3] * _axesScale[Y_AXIS];
+        _cubeAxesActor->SetYAxisRange(&ranges[2]);
+    } else {
+        _cubeAxesActor->GetYAxisRange(&ranges[2]);
+    }
+
+    if (_axesRangeMode[Z_AXIS] != RANGE_EXPLICIT) {
+        ranges[4] = bounds[4] * _axesScale[Z_AXIS];
+        ranges[5] = bounds[5] * _axesScale[Z_AXIS];
+        _cubeAxesActor->SetZAxisRange(&ranges[4]);
+    } else {
+        _cubeAxesActor->GetZAxisRange(&ranges[4]);
+    }
+
+    TRACE("Axis ranges: %g %g %g %g %g %g",
+          ranges[0],
+          ranges[1],
+          ranges[2],
+          ranges[3],
+          ranges[4],
+          ranges[5]);
+
+    _needsRedraw = true;
+}
+
+/**
+ * \brief Compute scaling from axes bounds to ranges
+ *
+ * Uses actor scaling to determine if world coordinates
+ * need to be scaled to undo actor scaling in range labels
+ */
+void Renderer::computeAxesScale()
+{
+    if (_axesRangeMode[X_AXIS] != RANGE_AUTO &&
+        _axesRangeMode[Y_AXIS] != RANGE_AUTO &&
+        _axesRangeMode[Z_AXIS] != RANGE_AUTO)
+        return;
+
+    double bounds[6];
+    if (_cameraMode == IMAGE) {
+        collectBounds(bounds, false);
+    } else
+        _cubeAxesActor->GetBounds(bounds);
+
+    double unscaledBounds[6];
+    collectUnscaledBounds(unscaledBounds, false);
+
+    if (_axesRangeMode[X_AXIS] == RANGE_AUTO) {
+        double sx = (bounds[1] == bounds[0]) ? 1.0 : (unscaledBounds[1] - unscaledBounds[0]) / (bounds[1] - bounds[0]);
+        _axesScale[X_AXIS] = sx;
+        TRACE("Setting X axis scale to: %g", sx);
+    }
+    if (_axesRangeMode[Y_AXIS] == RANGE_AUTO) {
+        double sy = (bounds[3] == bounds[2]) ? 1.0 : (unscaledBounds[3] - unscaledBounds[2]) / (bounds[3] - bounds[2]);
+        _axesScale[Y_AXIS] = sy;
+        TRACE("Setting Y axis scale to: %g", sy);
+    }
+    if (_axesRangeMode[Y_AXIS] == RANGE_AUTO) {
+        double sz = (bounds[5] == bounds[4]) ? 1.0 : (unscaledBounds[5] - unscaledBounds[4]) / (bounds[5] - bounds[4]);
+        _axesScale[Z_AXIS] = sz;
+        TRACE("Setting Z axis scale to: %g", sz);
+    }
+}
+
+/**
+ * \brief Set scaling factor to convert world coordinates to axis 
+ * label values in X, Y, Z
+ */
+void Renderer::setAxesScale(double scale)
+{
+    _axesRangeMode[X_AXIS] = RANGE_SCALE_BOUNDS;
+    _axesRangeMode[Y_AXIS] = RANGE_SCALE_BOUNDS;
+    _axesRangeMode[Z_AXIS] = RANGE_SCALE_BOUNDS;
+
+    _axesScale[X_AXIS] = scale;
+    _axesScale[Y_AXIS] = scale;
+    _axesScale[Z_AXIS] = scale;
+
+    TRACE("Setting axes scale to: %g", scale);
+
+    setAxesRanges();
+}
+
+/**
+ * \brief Set scaling factor to convert world coordinates to axis label values
+ */
+void Renderer::setAxisScale(Axis axis, double scale)
+{
+    _axesRangeMode[axis] = RANGE_SCALE_BOUNDS;
+    _axesScale[axis] = scale;
+
+    TRACE("Setting axis %d scale to: %g", axis, scale);
+
+    setAxesRanges();
+}
+
+/**
+ * \brief Set an origin point within the axes bounds where the axes will intersect
+ *
+ * \param x X coordinate of origin
+ * \param y Y coordinate of origin
+ * \param z Z coordinate of origin
+ * \param useCustom Flag indicating if custom origin is to be used/enabled
+ */
+void Renderer::setAxesOrigin(double x, double y, double z, bool useCustom)
+{
+    _cubeAxesActor->SetAxisOrigin(x, y, z);
+    _cubeAxesActor->SetUseAxisOrigin((useCustom ? 1 : 0));
+
+    _needsRedraw = true;
+}
+
+/**
+ * \brief Set inital properties on the 2D Axes
+ */
+void Renderer::initAxes()
+{
+    TRACE("Initializing axes");
+#ifdef USE_CUSTOM_AXES
+    if (_cubeAxesActor == NULL)
+        _cubeAxesActor = vtkSmartPointer<vtkRpCubeAxesActor>::New();
+#else
+    if (_cubeAxesActor == NULL)
+        _cubeAxesActor = vtkSmartPointer<vtkCubeAxesActor>::New();
+#endif
+    _cubeAxesActor->SetCamera(_renderer->GetActiveCamera());
+    _cubeAxesActor->GetProperty()->LightingOff();
+    // Don't offset labels at origin
+    _cubeAxesActor->SetCornerOffset(0);
+    _cubeAxesActor->SetFlyModeToStaticTriad();
+
+    _cubeAxesActor->SetGridLineLocation(VTK_GRID_LINES_ALL);
+    _cubeAxesActor->SetDrawXInnerGridlines(0);
+    _cubeAxesActor->SetDrawYInnerGridlines(0);
+    _cubeAxesActor->SetDrawZInnerGridlines(0);
+    _cubeAxesActor->SetDrawXGridpolys(0);
+    _cubeAxesActor->SetDrawYGridpolys(0);
+    _cubeAxesActor->SetDrawZGridpolys(0);
+    _cubeAxesActor->SetDistanceLODThreshold(1);
+    _cubeAxesActor->SetEnableDistanceLOD(0);
+    _cubeAxesActor->SetViewAngleLODThreshold(0);
+    _cubeAxesActor->SetEnableViewAngleLOD(0);
+    // Attempt to set font sizes for 2D (this currently doesn't work)
+    for (int i = 0; i < 3; i++) {
+        _cubeAxesActor->GetTitleTextProperty(i)->SetFontSize(14);
+        _cubeAxesActor->GetLabelTextProperty(i)->SetFontSize(12);
+    }
+    // Set font pixel size for 3D
+    _cubeAxesActor->SetScreenSize(8.0);
+
+    _cubeAxesActor->SetBounds(0, 1, 0, 1, 0, 1);
+    _cubeAxesActor->SetXAxisRange(0, 1);
+    _cubeAxesActor->SetYAxisRange(0, 1);
+    _cubeAxesActor->SetZAxisRange(0, 1);
+    for (int axis = 0; axis < 3; axis++) {
+        _axesAutoBounds[axis] = true;
+        _axesRangeMode[axis] = RANGE_AUTO;
+        _axesScale[axis] = 1.0;
+    }
+
+    double axesColor[] = {1,1,1};
+    setAxesColor(axesColor);
+
+    if (!_renderer->HasViewProp(_cubeAxesActor))
+        _renderer->AddViewProp(_cubeAxesActor);
+
+    if (_cameraMode == IMAGE) {
+        _cubeAxesActor->SetUse2DMode(1);
+    } else {
+        _cubeAxesActor->SetUse2DMode(0);
+    }
+}
+
+/**
+ * \brief Set Fly mode of axes
+ */
+void Renderer::setAxesFlyMode(AxesFlyMode mode)
+{
+    if (_cubeAxesActor == NULL)
+        return;
+
+    switch (mode) {
+    case FLY_STATIC_EDGES:
+        _cubeAxesActor->SetFlyModeToStaticEdges();
+        _cubeAxesActor->SetGridLineLocation(VTK_GRID_LINES_ALL);
+        break;
+    case FLY_STATIC_TRIAD:
+        _cubeAxesActor->SetFlyModeToStaticTriad();
+        _cubeAxesActor->SetGridLineLocation(VTK_GRID_LINES_ALL);
+        break;
+    case FLY_OUTER_EDGES:
+        _cubeAxesActor->SetFlyModeToOuterEdges();
+        _cubeAxesActor->SetGridLineLocation(VTK_GRID_LINES_ALL);
+        break;
+    case FLY_FURTHEST_TRIAD:
+        _cubeAxesActor->SetFlyModeToFurthestTriad();
+        _cubeAxesActor->SetGridLineLocation(VTK_GRID_LINES_FURTHEST);
+        break;
+    case FLY_CLOSEST_TRIAD:
+    default:
+        _cubeAxesActor->SetFlyModeToClosestTriad();
+        _cubeAxesActor->SetGridLineLocation(VTK_GRID_LINES_CLOSEST);
+        break;
+    }
+    _needsRedraw = true;
+}
+
+/**
+ * \brief Set color of axes, ticks, labels, titles
+ */
+void Renderer::setAxesColor(double color[3], double opacity)
+{
+    setAxesTitleColor(color, opacity);
+    setAxesLabelColor(color, opacity);
+    setAxesLinesColor(color, opacity);
+    setAxesGridlinesColor(color, opacity);
+    setAxesInnerGridlinesColor(color, opacity);
+    setAxesGridpolysColor(color, opacity);
+}
+
+/**
+ * \brief Set color of axes title text
+ */
+void Renderer::setAxesTitleColor(double color[3], double opacity)
+{
+    setAxisTitleColor(X_AXIS, color, opacity);
+    setAxisTitleColor(Y_AXIS, color, opacity);
+    setAxisTitleColor(Z_AXIS, color, opacity);
+}
+
+/**
+ * \brief Set color of axes label text
+ */
+void Renderer::setAxesLabelColor(double color[3], double opacity)
+{
+    setAxisLabelColor(X_AXIS, color, opacity);
+    setAxisLabelColor(Y_AXIS, color, opacity);
+    setAxisLabelColor(Z_AXIS, color, opacity);
+}
+
+/**
+ * \brief Set color of main axes lines
+ */
+void Renderer::setAxesLinesColor(double color[3], double opacity)
+{
+    setAxisLinesColor(X_AXIS, color, opacity);
+    setAxisLinesColor(Y_AXIS, color, opacity);
+    setAxisLinesColor(Z_AXIS, color, opacity);
+}
+
+/**
+ * \brief Set color of axis gridlines
+ */
+void Renderer::setAxesGridlinesColor(double color[3], double opacity)
+{
+    setAxisGridlinesColor(X_AXIS, color, opacity);
+    setAxisGridlinesColor(Y_AXIS, color, opacity);
+    setAxisGridlinesColor(Z_AXIS, color, opacity);
+}
+
+/**
+ * \brief Set color of axes inner gridlines
+ */
+void Renderer::setAxesInnerGridlinesColor(double color[3], double opacity)
+{
+    setAxisInnerGridlinesColor(X_AXIS, color, opacity);
+    setAxisInnerGridlinesColor(Y_AXIS, color, opacity);
+    setAxisInnerGridlinesColor(Z_AXIS, color, opacity);
+}
+
+/**
+ * \brief Set color of axes inner grid polygons
+ */
+void Renderer::setAxesGridpolysColor(double color[3], double opacity)
+{
+    setAxisGridpolysColor(X_AXIS, color, opacity);
+    setAxisGridpolysColor(Y_AXIS, color, opacity);
+    setAxisGridpolysColor(Z_AXIS, color, opacity);
+}
+
+/**
+ * \brief Turn on/off rendering of all enabled axes
+ */
+void Renderer::setAxesVisibility(bool state)
+{
+    if (_cubeAxesActor != NULL) {
+        _cubeAxesActor->SetVisibility((state ? 1 : 0));
+        _needsRedraw = true;
+    }
+}
+
+/**
+ * \brief Turn on/off rendering of all axes gridlines
+ */
+void Renderer::setAxesGridVisibility(bool state)
+{
+    setAxisGridVisibility(X_AXIS, state);
+    setAxisGridVisibility(Y_AXIS, state);
+    setAxisGridVisibility(Z_AXIS, state);
+}
+
+/**
+ * \brief Turn on/off rendering of all axes inner gridlines
+ */
+void Renderer::setAxesInnerGridVisibility(bool state)
+{
+    setAxisInnerGridVisibility(X_AXIS, state);
+    setAxisInnerGridVisibility(Y_AXIS, state);
+    setAxisInnerGridVisibility(Z_AXIS, state);
+}
+
+/**
+ * \brief Turn on/off rendering of all axes inner grid polygons
+ */
+void Renderer::setAxesGridpolysVisibility(bool state)
+{
+    setAxisGridpolysVisibility(X_AXIS, state);
+    setAxisGridpolysVisibility(Y_AXIS, state);
+    setAxisGridpolysVisibility(Z_AXIS, state);
+}
+
+/**
+ * \brief Turn on/off rendering of all axis labels
+ */
+void Renderer::setAxesLabelVisibility(bool state)
+{
+    setAxisLabelVisibility(X_AXIS, state);
+    setAxisLabelVisibility(Y_AXIS, state);
+    setAxisLabelVisibility(Z_AXIS, state);
+}
+
+/**
+ * \brief Turn on/off rendering of all axis ticks
+ */
+void Renderer::setAxesTickVisibility(bool state)
+{
+    setAxisTickVisibility(X_AXIS, state);
+    setAxisTickVisibility(Y_AXIS, state);
+    setAxisTickVisibility(Z_AXIS, state);
+}
+
+/**
+ * \brief Turn on/off rendering of all axis ticks
+ */
+void Renderer::setAxesMinorTickVisibility(bool state)
+{
+    setAxisMinorTickVisibility(X_AXIS, state);
+    setAxisMinorTickVisibility(Y_AXIS, state);
+    setAxisMinorTickVisibility(Z_AXIS, state);
+}
+
+/**
+ * \brief Control position of ticks on 3D axes
+ */
+void Renderer::setAxesTickPosition(AxesTickPosition pos)
+{
+    if (_cubeAxesActor == NULL)
+        return;
+
+    switch (pos) {
+    case TICKS_BOTH:
+        _cubeAxesActor->SetTickLocationToBoth();
+        break;
+    case TICKS_OUTSIDE:
+        _cubeAxesActor->SetTickLocationToOutside();
+        break;
+    case TICKS_INSIDE:
+    default:
+        _cubeAxesActor->SetTickLocationToInside();
+        break;
+    }
+    _needsRedraw = true;
+}
+
+/**
+ * \brief Controls label scaling by power of 10
+ */
+void Renderer::setAxesLabelScaling(bool autoScale, int xpow, int ypow, int zpow)
+{
+    if (_cubeAxesActor != NULL) {
+        _cubeAxesActor->SetLabelScaling(autoScale, xpow, ypow, zpow);
+        _needsRedraw = true;
+    }
+}
+
+/**
+ * \brief Set axes title/label font size in pixels
+ */
+void Renderer::setAxesPixelFontSize(double screenSize)
+{
+    if (_cubeAxesActor != NULL) {
+        TRACE("Setting axes font size to: %g px", screenSize);
+        _cubeAxesActor->SetScreenSize(screenSize);
+        _needsRedraw = true;
+    }
+}
+
+/**
+ * \brief Set axis title font family
+ */
+void Renderer::setAxesTitleFont(const char *fontName)
+{
+    setAxisTitleFont(X_AXIS, fontName);
+    setAxisTitleFont(Y_AXIS, fontName);
+    setAxisTitleFont(Z_AXIS, fontName);
+}
+
+/**
+ * \brief Set axis title font size
+ */
+void Renderer::setAxesTitleFontSize(int sz)
+{
+    setAxisTitleFontSize(X_AXIS, sz);
+    setAxisTitleFontSize(Y_AXIS, sz);
+    setAxisTitleFontSize(Z_AXIS, sz);
+}
+
+/**
+ * \brief Set orientation (as rotation in degrees) of axis title
+ */
+void Renderer::setAxesTitleOrientation(double orientation)
+{
+    setAxisTitleOrientation(X_AXIS, orientation);
+    setAxisTitleOrientation(Y_AXIS, orientation);
+    setAxisTitleOrientation(Z_AXIS, orientation);
+}
+
+/**
+ * \brief Set axis label font family
+ */
+void Renderer::setAxesLabelFont(const char *fontName)
+{
+    setAxisLabelFont(X_AXIS, fontName);
+    setAxisLabelFont(Y_AXIS, fontName);
+    setAxisLabelFont(Z_AXIS, fontName);
+}
+
+/**
+ * \brief Set axis label font size
+ */
+void Renderer::setAxesLabelFontSize(int sz)
+{
+    setAxisLabelFontSize(X_AXIS, sz);
+    setAxisLabelFontSize(Y_AXIS, sz);
+    setAxisLabelFontSize(Z_AXIS, sz);
+}
+
+/**
+ * \brief Set orientation (as rotation in degrees) of axis labels
+ */
+void Renderer::setAxesLabelOrientation(double orientation)
+{
+    setAxisLabelOrientation(X_AXIS, orientation);
+    setAxisLabelOrientation(Y_AXIS, orientation);
+    setAxisLabelOrientation(Z_AXIS, orientation);
+}
+
+/**
+ * \brief Set printf style label format string
+ */
+void Renderer::setAxesLabelFormat(const char *format)
+{
+    setAxisLabelFormat(X_AXIS, format);
+    setAxisLabelFormat(Y_AXIS, format);
+    setAxisLabelFormat(Z_AXIS, format);
+}
+
+/**
+ * \brief Turn on/off rendering of the specified axis
+ */
+void Renderer::setAxisVisibility(Axis axis, bool state)
+{
+    if (_cubeAxesActor != NULL) {
+        if (axis == X_AXIS) {
+            _cubeAxesActor->SetXAxisVisibility((state ? 1 : 0));
+        } else if (axis == Y_AXIS) {
+            _cubeAxesActor->SetYAxisVisibility((state ? 1 : 0));
+        } else if (axis == Z_AXIS) {
+            _cubeAxesActor->SetZAxisVisibility((state ? 1 : 0));
+        }
+        _needsRedraw = true;
+    }
+}
+
+/**
+ * \brief Turn on/off rendering of single axis gridlines
+ */
+void Renderer::setAxisGridVisibility(Axis axis, bool state)
+{
+    if (_cubeAxesActor != NULL) {
+        if (axis == X_AXIS) {
+            _cubeAxesActor->SetDrawXGridlines((state ? 1 : 0));
+        } else if (axis == Y_AXIS) {
+            _cubeAxesActor->SetDrawYGridlines((state ? 1 : 0));
+        } else if (axis == Z_AXIS) {
+            _cubeAxesActor->SetDrawZGridlines((state ? 1 : 0));
+        }
+        _needsRedraw = true;
+    }
+}
+
+/**
+ * \brief Turn on/off rendering of single axis gridlines
+ */
+void Renderer::setAxisInnerGridVisibility(Axis axis, bool state)
+{
+    if (_cubeAxesActor != NULL) {
+        if (axis == X_AXIS) {
+            _cubeAxesActor->SetDrawXInnerGridlines((state ? 1 : 0));
+        } else if (axis == Y_AXIS) {
+            _cubeAxesActor->SetDrawYInnerGridlines((state ? 1 : 0));
+        } else if (axis == Z_AXIS) {
+            _cubeAxesActor->SetDrawZInnerGridlines((state ? 1 : 0));
+        }
+        _needsRedraw = true;
+    }
+}
+
+/**
+ * \brief Turn on/off rendering of single axis gridlines
+ */
+void Renderer::setAxisGridpolysVisibility(Axis axis, bool state)
+{
+    if (_cubeAxesActor != NULL) {
+        if (axis == X_AXIS) {
+            _cubeAxesActor->SetDrawXGridpolys((state ? 1 : 0));
+        } else if (axis == Y_AXIS) {
+            _cubeAxesActor->SetDrawYGridpolys((state ? 1 : 0));
+        } else if (axis == Z_AXIS) {
+            _cubeAxesActor->SetDrawZGridpolys((state ? 1 : 0));
+        }
+        _needsRedraw = true;
+    }
+}
+
+/**
+ * \brief Toggle label visibility for the specified axis
+ */
+void Renderer::setAxisLabelVisibility(Axis axis, bool state)
+{
+    if (_cubeAxesActor != NULL) {
+        if (axis == X_AXIS) {
+            _cubeAxesActor->SetXAxisLabelVisibility((state ? 1 : 0));
+        } else if (axis == Y_AXIS) {
+            _cubeAxesActor->SetYAxisLabelVisibility((state ? 1 : 0));
+        } else if (axis == Z_AXIS) {
+            _cubeAxesActor->SetZAxisLabelVisibility((state ? 1 : 0));
+        }
+        _needsRedraw = true;
+    }
+}
+
+/**
+ * \brief Toggle tick visibility for the specified axis
+ */
+void Renderer::setAxisTickVisibility(Axis axis, bool state)
+{
+    if (_cubeAxesActor != NULL) {
+        if (axis == X_AXIS) {
+            _cubeAxesActor->SetXAxisTickVisibility((state ? 1 : 0));
+        } else if (axis == Y_AXIS) {
+            _cubeAxesActor->SetYAxisTickVisibility((state ? 1 : 0));
+        } else if (axis == Z_AXIS) {
+            _cubeAxesActor->SetZAxisTickVisibility((state ? 1 : 0));
+        }
+        _needsRedraw = true;
+    }
+}
+
+/**
+ * \brief Toggle tick visibility for the specified axis
+ */
+void Renderer::setAxisMinorTickVisibility(Axis axis, bool state)
+{
+    if (_cubeAxesActor != NULL) {
+        if (axis == X_AXIS) {
+            _cubeAxesActor->SetXAxisMinorTickVisibility((state ? 1 : 0));
+        } else if (axis == Y_AXIS) {
+            _cubeAxesActor->SetYAxisMinorTickVisibility((state ? 1 : 0));
+        } else if (axis == Z_AXIS) {
+            _cubeAxesActor->SetZAxisMinorTickVisibility((state ? 1 : 0));
+        }
+        _needsRedraw = true;
+    }
+}
+
+/**
+ * \brief Set color of axis lines, ticks, labels, titles
+ */
+void Renderer::setAxisColor(Axis axis, double color[3], double opacity)
+{
+    setAxisTitleColor(axis, color, opacity);
+    setAxisLabelColor(axis, color, opacity);
+    setAxisLinesColor(axis, color, opacity);
+    setAxisGridlinesColor(axis, color, opacity);
+    setAxisInnerGridlinesColor(axis, color, opacity);
+    setAxisGridpolysColor(axis, color, opacity);
+}
+
+/**
+ * \brief Set color of axis title text
+ */
+void Renderer::setAxisTitleColor(Axis axis, double color[3], double opacity)
+{
+    if (_cubeAxesActor != NULL) {
+        _cubeAxesActor->GetTitleTextProperty(axis)->SetColor(color);
+        _cubeAxesActor->GetTitleTextProperty(axis)->SetOpacity(opacity);
+        _needsRedraw = true;
+    }
+}
+
+/**
+ * \brief Set color of axis label text
+ */
+void Renderer::setAxisLabelColor(Axis axis, double color[3], double opacity)
+{
+    if (_cubeAxesActor != NULL) {
+        _cubeAxesActor->GetLabelTextProperty(axis)->SetColor(color);
+        _cubeAxesActor->GetLabelTextProperty(axis)->SetOpacity(opacity);
+        _needsRedraw = true;
+    }
+}
+
+/**
+ * \brief Set color of main axis line
+ */
+void Renderer::setAxisLinesColor(Axis axis, double color[3], double opacity)
+{
+    if (_cubeAxesActor != NULL) {
+        switch (axis) {
+        case X_AXIS:
+            _cubeAxesActor->GetXAxesLinesProperty()->SetColor(color);
+            _cubeAxesActor->GetXAxesLinesProperty()->SetOpacity(opacity);
+            break;
+        case Y_AXIS:
+            _cubeAxesActor->GetYAxesLinesProperty()->SetColor(color);
+            _cubeAxesActor->GetYAxesLinesProperty()->SetOpacity(opacity);
+            break;
+        case Z_AXIS:
+            _cubeAxesActor->GetZAxesLinesProperty()->SetColor(color);
+            _cubeAxesActor->GetZAxesLinesProperty()->SetOpacity(opacity);
+            break;
+        default:
+            ;
+        }
+        _needsRedraw = true;
+    }
+}
+
+/**
+ * \brief Set color of axis gridlines
+ */
+void Renderer::setAxisGridlinesColor(Axis axis, double color[3], double opacity)
+{
+    if (_cubeAxesActor != NULL) {
+        switch (axis) {
+        case X_AXIS:
+            _cubeAxesActor->GetXAxesGridlinesProperty()->SetColor(color);
+            _cubeAxesActor->GetXAxesGridlinesProperty()->SetOpacity(opacity);
+            break;
+        case Y_AXIS:
+            _cubeAxesActor->GetYAxesGridlinesProperty()->SetColor(color);
+            _cubeAxesActor->GetYAxesGridlinesProperty()->SetOpacity(opacity);
+            break;
+        case Z_AXIS:
+            _cubeAxesActor->GetZAxesGridlinesProperty()->SetColor(color);
+            _cubeAxesActor->GetZAxesGridlinesProperty()->SetOpacity(opacity);
+            break;
+        default:
+            ;
+        }
+        _needsRedraw = true;
+    }
+}
+
+/**
+ * \brief Set color of axis inner gridlines
+ */
+void Renderer::setAxisInnerGridlinesColor(Axis axis, double color[3], double opacity)
+{
+    if (_cubeAxesActor != NULL) {
+        switch (axis) {
+        case X_AXIS:
+            _cubeAxesActor->GetXAxesInnerGridlinesProperty()->SetColor(color);
+            _cubeAxesActor->GetXAxesInnerGridlinesProperty()->SetOpacity(opacity);
+            break;
+        case Y_AXIS:
+            _cubeAxesActor->GetYAxesInnerGridlinesProperty()->SetColor(color);
+            _cubeAxesActor->GetYAxesInnerGridlinesProperty()->SetOpacity(opacity);
+            break;
+        case Z_AXIS:
+            _cubeAxesActor->GetZAxesInnerGridlinesProperty()->SetColor(color);
+            _cubeAxesActor->GetZAxesInnerGridlinesProperty()->SetOpacity(opacity);
+            break;
+        default:
+            ;
+        }
+        _needsRedraw = true;
+    }
+}
+
+/**
+ * \brief Set color of axis inner grid polygons
+ *
+ * Default opacity is 0.6
+ */
+void Renderer::setAxisGridpolysColor(Axis axis, double color[3], double opacity)
+{
+    if (_cubeAxesActor != NULL) {
+        switch (axis) {
+        case X_AXIS:
+            _cubeAxesActor->GetXAxesGridpolysProperty()->SetColor(color);
+            _cubeAxesActor->GetXAxesGridpolysProperty()->SetOpacity(opacity);
+            break;
+        case Y_AXIS:
+            _cubeAxesActor->GetYAxesGridpolysProperty()->SetColor(color);
+            _cubeAxesActor->GetYAxesGridpolysProperty()->SetOpacity(opacity);
+            break;
+        case Z_AXIS:
+            _cubeAxesActor->GetZAxesGridpolysProperty()->SetColor(color);
+            _cubeAxesActor->GetZAxesGridpolysProperty()->SetOpacity(opacity);
+            break;
+        default:
+            ;
+        }
+        _needsRedraw = true;
+    }
+}
+
+/**
+ * \brief Set title of the specified axis
+ */
+void Renderer::setAxisTitle(Axis axis, const char *title)
+{
+    if (_cubeAxesActor != NULL) {
+        if (axis == X_AXIS) {
+            _cubeAxesActor->SetXTitle(title);
+        } else if (axis == Y_AXIS) {
+            _cubeAxesActor->SetYTitle(title);
+        } else if (axis == Z_AXIS) {
+            _cubeAxesActor->SetZTitle(title);
+        }
+        _needsRedraw = true;
+    }
+}
+
+/**
+ * \brief Set units of the specified axis
+ */
+void Renderer::setAxisUnits(Axis axis, const char *units)
+{
+    if (_cubeAxesActor != NULL) {
+        if (axis == X_AXIS) {
+            _cubeAxesActor->SetXUnits(units);
+        } else if (axis == Y_AXIS) {
+            _cubeAxesActor->SetYUnits(units);
+        } else if (axis == Z_AXIS) {
+            _cubeAxesActor->SetZUnits(units);
+        }
+        _needsRedraw = true;
+    }
+}
+
+/**
+ * \brief Set axis title font family
+ */
+void Renderer::setAxisTitleFont(Axis axis, const char *fontName)
+{
+    if (_cubeAxesActor != NULL) {
+        TRACE("Setting axis %d title font to: '%s'", axis, fontName);
+        _cubeAxesActor->GetTitleTextProperty(axis)->SetFontFamilyAsString(fontName);
+        _needsRedraw = true;
+    }
+}
+
+/**
+ * \brief Set axis title font size (and optionally pixel size)
+ */
+void Renderer::setAxisTitleFontSize(Axis axis, int sz)
+{
+    if (_cubeAxesActor != NULL) {
+        TRACE("Setting axis %d title font size to: %d", axis, sz);
+        _cubeAxesActor->GetTitleTextProperty(axis)->SetFontSize(sz);
+        _needsRedraw = true;
+    }
+}
+
+/**
+ * \brief Set orientation (as rotation in degrees) of axis titles
+ */
+void Renderer::setAxisTitleOrientation(Axis axis, double orientation)
+{
+    if (_cubeAxesActor != NULL) {
+        TRACE("Setting axis %d title orientation to: %g", axis, orientation);
+        _cubeAxesActor->GetTitleTextProperty(axis)->SetOrientation(orientation);
+        _needsRedraw = true;
+    }
+}
+
+/**
+ * \brief Set axis label font family
+ */
+void Renderer::setAxisLabelFont(Axis axis, const char *fontName)
+{
+    if (_cubeAxesActor != NULL) {
+        TRACE("Setting axis %d label font to: '%s'", axis, fontName);
+        _cubeAxesActor->GetLabelTextProperty(axis)->SetFontFamilyAsString(fontName);
+        _needsRedraw = true;
+    }
+}
+
+/**
+ * \brief Set axis label font size (and optionally pixel size)
+ */
+void Renderer::setAxisLabelFontSize(Axis axis, int sz)
+{
+    if (_cubeAxesActor != NULL) {
+        TRACE("Setting axis %d label font size to: %d", axis, sz);
+        _cubeAxesActor->GetLabelTextProperty(axis)->SetFontSize(sz);
+        _needsRedraw = true;
+    }
+}
+
+/**
+ * \brief Set orientation (as rotation in degrees) of axis labels
+ */
+void Renderer::setAxisLabelOrientation(Axis axis, double orientation)
+{
+    if (_cubeAxesActor != NULL) {
+        TRACE("Setting axis %d label orientation to: %g", axis, orientation);
+        _cubeAxesActor->GetLabelTextProperty(axis)->SetOrientation(orientation);
+        _needsRedraw = true;
+    }
+}
+
+/**
+ * \brief Set printf style label format string
+ */
+void Renderer::setAxisLabelFormat(Axis axis, const char *format)
+{
+    if (_cubeAxesActor != NULL) {
+        TRACE("Setting axis %d label format to: '%s'", axis, format);
+        if (axis == X_AXIS) {
+            _cubeAxesActor->SetXLabelFormat(format);
+            _cubeAxesActor->XAutoLabelFormatOff();
+        } else if (axis == Y_AXIS) {
+            _cubeAxesActor->SetYLabelFormat(format);
+            _cubeAxesActor->YAutoLabelFormatOff();
+        } else if (axis == Z_AXIS) {
+            _cubeAxesActor->SetZLabelFormat(format);
+            _cubeAxesActor->ZAutoLabelFormatOff();
+        }
+        _needsRedraw = true;
+    }
+}
+
+/**
+ * \brief Notify graphics objects that color map has changed
+ */
+void Renderer::updateColorMap(ColorMap *cmap)
+{
+    TRACE("%s", cmap->getName().c_str());
+    updateGraphicsObjectColorMap<Contour2D>(cmap);
+    updateGraphicsObjectColorMap<Contour3D>(cmap);
+    updateGraphicsObjectColorMap<Cutplane>(cmap);
+    updateGraphicsObjectColorMap<Glyphs>(cmap);
+    updateGraphicsObjectColorMap<HeightMap>(cmap);
+    updateGraphicsObjectColorMap<LIC>(cmap);
+    updateGraphicsObjectColorMap<Molecule>(cmap);
+    updateGraphicsObjectColorMap<PseudoColor>(cmap);
+    updateGraphicsObjectColorMap<Streamlines>(cmap);
+    updateGraphicsObjectColorMap<Volume>(cmap);
+    updateGraphicsObjectColorMap<Warp>(cmap);
+    TRACE("Leave");
+}
+
+/**
+ * \brief Check if a ColorMap is in use by graphics objects
+ */
+bool Renderer::colorMapUsed(ColorMap *cmap)
+{
+    if (graphicsObjectColorMapUsed<Contour2D>(cmap))
+        return true;
+    if (graphicsObjectColorMapUsed<Contour3D>(cmap))
+        return true;
+    if (graphicsObjectColorMapUsed<Cutplane>(cmap))
+        return true;
+    if (graphicsObjectColorMapUsed<Glyphs>(cmap))
+        return true;
+    if (graphicsObjectColorMapUsed<HeightMap>(cmap))
+        return true;
+    if (graphicsObjectColorMapUsed<LIC>(cmap))
+        return true;
+    if (graphicsObjectColorMapUsed<Molecule>(cmap))
+        return true;
+    if (graphicsObjectColorMapUsed<PseudoColor>(cmap))
+        return true;
+    if (graphicsObjectColorMapUsed<Streamlines>(cmap))
+        return true;
+    if (graphicsObjectColorMapUsed<Volume>(cmap))
+        return true;
+    if (graphicsObjectColorMapUsed<Warp>(cmap))
+        return true;
+
+    return false;
+}
+
+/**
+ * \brief Add/replace a ColorMap for use in the Renderer
+ */
+void Renderer::addColorMap(const ColorMapId& id, ColorMap *colorMap)
+{
+    if (colorMap != NULL) {
+        colorMap->build();
+        if (getColorMap(id) != NULL) {
+            TRACE("Replacing existing ColorMap %s", id.c_str());
+            // Copy to current colormap to avoid invalidating 
+            // pointers in graphics objects using the color map
+            *_colorMaps[id] = *colorMap;
+            delete colorMap;
+            // Notify graphics objects of change
+            updateColorMap(_colorMaps[id]);
+        } else
+            _colorMaps[id] = colorMap;
+    } else {
+        ERROR("NULL ColorMap");
+    }
+}
+
+/**
+ * \brief Return the ColorMap associated with the colormap key given
+ */
+ColorMap *Renderer::getColorMap(const ColorMapId& id)
+{
+    ColorMapHashmap::iterator itr = _colorMaps.find(id);
+
+    if (itr == _colorMaps.end())
+        return NULL;
+    else
+        return itr->second;
+}
+
+/**
+ * \brief Remove the colormap associated with the key given
+ *
+ * The underlying vtkLookupTable will be deleted if it is not referenced
+ * by any other objects
+ */
+void Renderer::deleteColorMap(const ColorMapId& id)
+{
+    ColorMapHashmap::iterator itr;
+
+    bool doAll = false;
+
+    if (id.compare("all") == 0) {
+        itr = _colorMaps.begin();
+        doAll = true;
+    } else {
+        itr = _colorMaps.find(id);
+    }
+
+    if (itr == _colorMaps.end()) {
+        ERROR("Unknown ColorMap %s", id.c_str());
+        return;
+    }
+
+    do {
+        if (itr->second->getName().compare("default") == 0 ||
+            itr->second->getName().compare("grayDefault") == 0 ||
+            itr->second->getName().compare("volumeDefault") == 0 ||
+            itr->second->getName().compare("elementDefault") == 0) {
+            if (id.compare("all") != 0) {
+                WARN("Cannot delete a default color map");
+            }
+            continue;
+        } else if (colorMapUsed(itr->second)) {
+            WARN("Cannot delete color map '%s', it is in use", itr->second->getName().c_str());
+            continue;
+        }
+
+        TRACE("Deleting ColorMap %s", itr->second->getName().c_str());
+
+        delete itr->second;
+        itr = _colorMaps.erase(itr);
+    } while (doAll && itr != _colorMaps.end());
+}
+
+/**
+ * \brief Set the number of discrete colors used in the colormap's lookup table
+ *
+ * Note that the number of table entries is independent of the number of 
+ * control points in the color/alpha ramp
+ */
+void Renderer::setColorMapNumberOfTableEntries(const ColorMapId& id, int numEntries)
+{
+    ColorMapHashmap::iterator itr;
+
+    bool doAll = false;
+
+    if (id.compare("all") == 0) {
+        itr = _colorMaps.begin();
+        doAll = true;
+    } else {
+        itr = _colorMaps.find(id);
+    }
+
+    if (itr == _colorMaps.end()) {
+        ERROR("Unknown ColorMap %s", id.c_str());
+        return;
+    }
+
+    if (numEntries < 0) {
+        numEntries = 256;
+        TRACE("Setting numEntries to default value of %d", numEntries);
+    }
+
+    do {
+        if (itr->second->getName() == "elementDefault") {
+            TRACE("Can't change number of table entries for default element color map");
+        } else {
+            itr->second->setNumberOfTableEntries(numEntries);
+            updateColorMap(itr->second);
+        }
+    } while (doAll && ++itr != _colorMaps.end());
+
+    _needsRedraw = true;
+}
+
+/**
+ * \brief Render a labelled legend image for the given colormap
+ *
+ * The field is assumed to be the active scalar or vector field
+ * based on the legendType.
+ *
+ * \param[in] id ColorMap name
+ * \param[in] dataSetID DataSet name
+ * \param[in] legendType scalar or vector field legend
+ * \param[in,out] title If supplied, draw title ("#auto" means to
+ * fill in field name and draw).  If blank, do not draw title.  
+ * If title was blank or "#auto", will be filled with field name on
+ * return
+ * \param[in,out] range Data range to use in legend.  Set min > max to have
+ * range computed, will be filled with valid min and max values
+ * \param[in] width Pixel width of legend (aspect controls orientation)
+ * \param[in] height Pixel height of legend (aspect controls orientation)
+ * \param[in] opaque Flag to control if legend is rendered opaque or translucent
+ * \param[in] numLabels Number of labels to render (includes min/max)
+ * \param[in,out] imgData Pointer to array to fill with image bytes. Array
+ * will be resized if needed.
+ * \return The image is rendered into the supplied array, false is 
+ * returned if the color map is not found
+ */
+bool Renderer::renderColorMap(const ColorMapId& id, 
+                              const DataSetId& dataSetID,
+                              Renderer::LegendType legendType,
+                              std::string& title,
+                              double range[2],
+                              int width, int height,
+                              bool opaque,
+                              int numLabels,
+                              vtkUnsignedCharArray *imgData)
+{
+    DataSet *dataSet = NULL;
+    if (dataSetID.compare("all") == 0) {
+        if (_dataSets.empty()) {
+            WARN("No DataSets exist, can't fill title or range");
+            return renderColorMap(id, dataSetID, legendType,
+                                  NULL,
+                                  DataSet::POINT_DATA,
+                                  title, range, width, height, opaque, numLabels, imgData);
+        } else {
+            dataSet = _dataSets.begin()->second;
+        }
+    } else {
+        dataSet = getDataSet(dataSetID);
+        if (dataSet == NULL) {
+            ERROR("DataSet '%s' not found", dataSetID.c_str());
+            return false;
+        }
+    }
+
+    if (legendType == LEGEND_SCALAR) {
+        return renderColorMap(id, dataSetID, legendType,
+                              dataSet->getActiveScalarsName(),
+                              dataSet->getActiveScalarsType(),
+                              title, range, width, height, opaque, numLabels, imgData);
+    } else {
+        return renderColorMap(id, dataSetID, legendType,
+                              dataSet->getActiveVectorsName(),
+                              dataSet->getActiveVectorsType(),
+                              title, range, width, height, opaque, numLabels, imgData);
+    }
+}
+
+/**
+ * \brief Render a labelled legend image for the given colormap
+ *
+ * The field is assumed to be point data, if the field is not found
+ * as point data, cell data is used.
+ *
+ * \param[in] id ColorMap name
+ * \param[in] dataSetID DataSet name
+ * \param[in] legendType scalar or vector field legend
+ * \param[in] fieldName Name of the field array this legend is for
+ * \param[in,out] title If supplied, draw title ("#auto" means to
+ * fill in field name and draw).  If blank, do not draw title.  
+ * If title was blank or "#auto", will be filled with field name on
+ * return
+ * \param[in,out] range Data range to use in legend.  Set min > max to have
+ * range computed, will be filled with valid min and max values
+ * \param[in] width Pixel width of legend (aspect controls orientation)
+ * \param[in] height Pixel height of legend (aspect controls orientation)
+ * \param[in] opaque Flag to control if legend is rendered opaque or translucent
+ * \param[in] numLabels Number of labels to render (includes min/max)
+ * \param[in,out] imgData Pointer to array to fill with image bytes. Array
+ * will be resized if needed.
+ * \return The image is rendered into the supplied array, false is 
+ * returned if the color map is not found
+ */
+bool Renderer::renderColorMap(const ColorMapId& id, 
+                              const DataSetId& dataSetID,
+                              Renderer::LegendType legendType,
+                              const char *fieldName,
+                              std::string& title,
+                              double range[2],
+                              int width, int height,
+                              bool opaque,
+                              int numLabels,
+                              vtkUnsignedCharArray *imgData)
+{
+    DataSet *dataSet = NULL;
+    if (dataSetID.compare("all") == 0) {
+        if (_dataSets.empty()) {
+            WARN("No DataSets exist, can't fill title or range");
+            return renderColorMap(id, dataSetID, legendType,
+                                  NULL,
+                                  DataSet::POINT_DATA,
+                                  title, range, width, height, opaque, numLabels, imgData);
+        } else {
+            dataSet = _dataSets.begin()->second;
+        }
+    } else {
+        dataSet = getDataSet(dataSetID);
+        if (dataSet == NULL) {
+            ERROR("DataSet '%s' not found", dataSetID.c_str());
+            return false;
+        }
+    }
+
+    DataSet::DataAttributeType attrType;
+    int numComponents;
+
+    dataSet->getFieldInfo(fieldName, &attrType, &numComponents);
+
+    return renderColorMap(id, dataSetID, legendType,
+                          fieldName,
+                          attrType,
+                          title, range, width, height, opaque, numLabels, imgData);
+}
+
+/**
+ * \brief Render a labelled legend image for the given colormap
+ *
+ * \param[in] id ColorMap name
+ * \param[in] dataSetID DataSet name
+ * \param[in] legendType scalar or vector field legend
+ * \param[in] fieldName Name of the field array this legend is for
+ * \param[in] type DataAttributeType of the field
+ * \param[in,out] title If supplied, draw title ("#auto" means to
+ * fill in field name and draw).  If blank, do not draw title.  
+ * If title was blank or "#auto", will be filled with field name on
+ * return
+ * \param[in,out] range Data range to use in legend.  Set min > max to have
+ * range computed, will be filled with valid min and max values
+ * \param[in] width Pixel width of legend (aspect controls orientation)
+ * \param[in] height Pixel height of legend (aspect controls orientation)
+ * \param[in] opaque Flag to control if legend is rendered opaque or translucent
+ * \param[in] numLabels Number of labels to render (includes min/max)
+ * \param[in,out] imgData Pointer to array to fill with image bytes. Array
+ * will be resized if needed.
+ * \return The image is rendered into the supplied array, false is 
+ * returned if the color map is not found
+ */
+bool Renderer::renderColorMap(const ColorMapId& id, 
+                              const DataSetId& dataSetID,
+                              Renderer::LegendType legendType,
+                              const char *fieldName,
+                              DataSet::DataAttributeType type,
+                              std::string& title,
+                              double range[2],
+                              int width, int height,
+                              bool opaque,
+                              int numLabels,
+                              vtkUnsignedCharArray *imgData)
+{
+    TRACE("Enter");
+    ColorMap *colorMap = getColorMap(id);
+    if (colorMap == NULL)
+        return false;
+
+    if (_legendRenderWindow == NULL) {
+        _legendRenderWindow = vtkSmartPointer<vtkRenderWindow>::New();
+        _legendRenderWindow->SetMultiSamples(0);
+#ifdef USE_OFFSCREEN_RENDERING
+        _legendRenderWindow->DoubleBufferOff();
+        _legendRenderWindow->OffScreenRenderingOn();
+#else
+        _legendRenderWindow->DoubleBufferOn();
+        _legendRenderWindow->SwapBuffersOff();
+#endif
+    }
+
+    _legendRenderWindow->SetSize(width, height);
+
+    if (_legendRenderer == NULL) {
+        _legendRenderer = vtkSmartPointer<vtkRenderer>::New();
+        _legendRenderWindow->AddRenderer(_legendRenderer);
+    }
+    _legendRenderer->SetBackground(_bgColor[0], _bgColor[1], _bgColor[2]);
+
+    if (_scalarBarActor == NULL) {
+        _scalarBarActor = vtkSmartPointer<vtkScalarBarActor>::New();
+        _scalarBarActor->DrawFrameOff();
+        _scalarBarActor->DrawBackgroundOff();
+        _legendRenderer->AddViewProp(_scalarBarActor);
+    }
+
+    if (opaque) {
+        _scalarBarActor->UseOpacityOff();
+    } else {
+        _scalarBarActor->UseOpacityOn();
+    }
+
+    if (width > height) {
+        _scalarBarActor->SetOrientationToHorizontal();
+    } else {
+        _scalarBarActor->SetOrientationToVertical();
+    }
+
+    // Set viewport-relative width/height/pos
+    if (title.empty() && numLabels == 0) {
+        _scalarBarActor->SetPosition(0, 0);
+        if (width > height) {
+            // horizontal
+            _scalarBarActor->SetHeight((((double)height+1.5)/((double)height))/0.4); // VTK: floor(actorHeight * .4)
+            _scalarBarActor->SetWidth(1); // VTK: actorWidth
+        } else {
+            // vertical
+            _scalarBarActor->SetHeight((((double)height+1.5)/((double)height))/0.86); // VTK: floor(actorHeight * .86)
+            _scalarBarActor->SetWidth(((double)(width+5))/((double)width)); // VTK: actorWidth - 4 pixels
+        }
+    } else {
+        if (width > height) {
+            // horizontal
+            _scalarBarActor->SetPosition(.075, .1);
+            _scalarBarActor->SetHeight(0.8);
+            _scalarBarActor->SetWidth(0.85);
+        } else {
+            // vertical
+            _scalarBarActor->SetPosition(.1, .05);
+            _scalarBarActor->SetHeight(0.9);
+            _scalarBarActor->SetWidth(0.8);
+        }
+    }
+
+    vtkSmartPointer<vtkLookupTable> lut = colorMap->getLookupTable();
+    DataSet *dataSet = NULL;
+    bool cumulative = _useCumulativeRange;
+    if (dataSetID.compare("all") == 0) {
+        if (_dataSets.empty()) {
+            WARN("No DataSets exist, can't fill title or range");
+        } else {
+            dataSet = _dataSets.begin()->second;
+        }
+        cumulative = true;
+    } else {
+        dataSet = getDataSet(dataSetID);
+        if (dataSet == NULL) {
+            ERROR("DataSet '%s' not found", dataSetID.c_str());
+            return false;
+        }
+    }
+
+    bool drawTitle = false;
+    if (!title.empty()) {
+        drawTitle = true;
+        if (title.compare("#auto") == 0) {
+            title.clear();
+        }
+    }
+
+    bool needRange = false;
+    if (range[0] > range[1]) {
+        range[0] = 0.0;
+        range[1] = 1.0;
+        needRange = true;
+    } 
+
+    switch (legendType) {
+    case LEGEND_VECTOR_MAGNITUDE:
+        if (needRange) {
+            if (cumulative) {
+                getCumulativeDataRange(range, fieldName, type, 3);
+            } else if (dataSet != NULL) {
+                dataSet->getDataRange(range, fieldName, type);
+            }
+        }
+
+        lut->SetRange(range);
+
+        if (title.empty() && dataSet != NULL) {
+            if (fieldName != NULL) {
+                title = fieldName;
+                title.append("(mag)");
+            }
+        }
+        break;
+    case LEGEND_VECTOR_X:
+        if (needRange) {
+            if (cumulative) {
+                getCumulativeDataRange(range, fieldName, type, 3, 0);
+            } else if (dataSet != NULL) {
+                dataSet->getDataRange(range, fieldName, type, 0);
+            }
+        }
+
+        lut->SetRange(range);
+
+        if (title.empty() && dataSet != NULL) {
+            if (fieldName != NULL) {
+                title = fieldName;
+                title.append("(x)");
+            }
+        }
+        break;
+    case LEGEND_VECTOR_Y:
+        if (needRange) {
+            if (cumulative) {
+                getCumulativeDataRange(range, fieldName, type, 3, 1);
+            } else if (dataSet != NULL) {
+                dataSet->getDataRange(range, fieldName, type, 1);
+            }
+        }
+
+        lut->SetRange(range);
+
+        if (title.empty() && dataSet != NULL) {
+            if (fieldName != NULL) {
+                title = fieldName;
+                title.append("(y)");
+            }
+        }
+        break;
+    case LEGEND_VECTOR_Z:
+        if (needRange) {
+            if (cumulative) {
+                getCumulativeDataRange(range, fieldName, type, 3, 2);
+            } else if (dataSet != NULL) {
+                dataSet->getDataRange(range, fieldName, type, 1);
+            }
+        }
+
+        lut->SetRange(range);
+
+        if (title.empty() && dataSet != NULL) {
+            if (fieldName != NULL) {
+                title = fieldName;
+                title.append("(z)");
+            }
+        }
+        break;
+    case LEGEND_SCALAR:
+    default:
+        if (needRange) {
+            if (cumulative) {
+                getCumulativeDataRange(range, fieldName, type, 1);
+            } else if (dataSet != NULL) {
+                dataSet->getDataRange(range, fieldName, type);
+            }
+        }
+
+        lut->SetRange(range);
+
+        if (title.empty() && dataSet != NULL) {
+            if (fieldName != NULL)
+                title = fieldName;
+        }
+        break;
+    }
+
+    _scalarBarActor->SetLookupTable(lut);
+    _scalarBarActor->SetMaximumNumberOfColors((width > height ? width : height));
+
+    if (drawTitle) {
+        _scalarBarActor->SetTitle(title.c_str());
+    } else {
+        _scalarBarActor->SetTitle("");
+    }
+    _scalarBarActor->GetTitleTextProperty()->ItalicOff();
+    _scalarBarActor->SetNumberOfLabels(numLabels);
+    _scalarBarActor->GetLabelTextProperty()->BoldOff();
+    _scalarBarActor->GetLabelTextProperty()->ItalicOff();
+    _scalarBarActor->GetLabelTextProperty()->ShadowOff();
+
+    _legendRenderWindow->Render();
+
+#ifdef RENDER_TARGA
+    _legendRenderWindow->MakeCurrent();
+    // Must clear previous errors first.
+    while (glGetError() != GL_NO_ERROR){
+        ;
+    }
+    int bytesPerPixel = TARGA_BYTES_PER_PIXEL;
+    int size = bytesPerPixel * width * height;
+
+    if (imgData->GetMaxId() + 1 != size)
+    {
+        imgData->SetNumberOfComponents(bytesPerPixel);
+        imgData->SetNumberOfValues(size);
+    }
+    glDisable(GL_TEXTURE_2D);
+    if (_legendRenderWindow->GetDoubleBuffer()) {
+        glReadBuffer(static_cast<GLenum>(vtkOpenGLRenderWindow::SafeDownCast(_legendRenderWindow)->GetBackLeftBuffer()));
+    } else {
+        glReadBuffer(static_cast<GLenum>(vtkOpenGLRenderWindow::SafeDownCast(_legendRenderWindow)->GetFrontLeftBuffer()));
+    }
+    glPixelStorei(GL_PACK_ALIGNMENT, 1);
+    if (bytesPerPixel == 4) {
+        glReadPixels(0, 0, width, height, GL_BGRA,
+                     GL_UNSIGNED_BYTE, imgData->GetPointer(0));
+    } else {
+        glReadPixels(0, 0, width, height, GL_BGR,
+                     GL_UNSIGNED_BYTE, imgData->GetPointer(0));
+    }
+    if (glGetError() != GL_NO_ERROR) {
+        ERROR("glReadPixels");
+    }
+#else
+    _legendRenderWindow->GetPixelData(0, 0, width-1, height-1,
+                                      !_legendRenderWindow->GetDoubleBuffer(),
+                                      imgData);
+#endif
+    TRACE("Leave");
+    return true;
+}
+
+/**
+ * \brief Set camera FOV based on render window height
+ * 
+ * Computes a field-of-view angle based on some assumptions about
+ * viewer's distance to screen and pixel density
+ */
+void Renderer::setViewAngle(int height)
+{
+    // Distance of eyes from screen in inches
+    double d = 20.0;
+    // Assume 72 ppi screen
+    double h = (double)height / 72.0;
+
+    double angle = vtkMath::DegreesFromRadians(2.0 * atan((h/2.0)/d));
+    _renderer->GetActiveCamera()->SetViewAngle(angle);
+
+    TRACE("Setting view angle: %g", angle);
+}
+
+/**
+ * \brief Resize the render window (image size for renderings)
+ */
+void Renderer::setWindowSize(int width, int height)
+{
+    if (_windowWidth == width &&
+        _windowHeight == height) {
+        TRACE("No change");
+        return;
+    }
+
+    TRACE("Setting window size to %dx%d", width, height);
+
+    //setViewAngle(height);
+
+    // FIXME: Fix up panning on aspect change
+#ifdef notdef
+    if (_cameraPan[0] != 0.0) {
+        _cameraPan[0] *= ((double)_windowWidth / width);
+    }
+    if (_cameraPan[1] != 0.0) {
+        _cameraPan[1] *= ((double)_windowHeight / height);
+    }
+#endif
+    _windowWidth = width;
+    _windowHeight = height;
+    _renderWindow->SetSize(_windowWidth, _windowHeight);
+
+    if (_cameraMode == IMAGE) {
+        if (_cameraAspect == ASPECT_WINDOW) {
+            double imgWindowAspect = getImageCameraAspect();
+            TRACE("Setting object aspect to %g", imgWindowAspect);
+            setObjectAspects(imgWindowAspect);
+            initCamera();
+        } else {
+            if (_userImgWorldDims[0] > 0) {
+                _setCameraZoomRegion(_userImgWorldOrigin[0],
+                                     _userImgWorldOrigin[1],
+                                     _userImgWorldDims[0],
+                                     _userImgWorldDims[1]);
+            } else {
+                if (isCameraMaximized()) {
+                    initCamera();
+                } else {
+                    _setCameraZoomRegion(_imgWorldOrigin[0],
+                                         _imgWorldOrigin[1],
+                                         _imgWorldDims[0],
+                                         _imgWorldDims[1]);
+                }
+            }
+        }
+    }
+    _needsRedraw = true;
+}
+
+void Renderer::setObjectAspects(double aspectRatio)
+{
+    setGraphicsObjectAspect<Arc>(aspectRatio);
+    setGraphicsObjectAspect<Arrow>(aspectRatio);
+    setGraphicsObjectAspect<Box>(aspectRatio);
+    setGraphicsObjectAspect<Cone>(aspectRatio);
+    setGraphicsObjectAspect<Contour2D>(aspectRatio);
+    setGraphicsObjectAspect<Contour3D>(aspectRatio);
+    setGraphicsObjectAspect<Cutplane>(aspectRatio);
+    setGraphicsObjectAspect<Cylinder>(aspectRatio);
+    setGraphicsObjectAspect<Disk>(aspectRatio);
+    setGraphicsObjectAspect<Glyphs>(aspectRatio);
+    setGraphicsObjectAspect<HeightMap>(aspectRatio);
+    setGraphicsObjectAspect<LIC>(aspectRatio);
+    setGraphicsObjectAspect<Line>(aspectRatio);
+    setGraphicsObjectAspect<Molecule>(aspectRatio);
+    setGraphicsObjectAspect<Outline>(aspectRatio);
+    setGraphicsObjectAspect<PolyData>(aspectRatio);
+    setGraphicsObjectAspect<Polygon>(aspectRatio);
+    setGraphicsObjectAspect<PseudoColor>(aspectRatio);
+    setGraphicsObjectAspect<Sphere>(aspectRatio);
+    setGraphicsObjectAspect<Streamlines>(aspectRatio);
+    setGraphicsObjectAspect<Volume>(aspectRatio);
+    setGraphicsObjectAspect<Warp>(aspectRatio);
+}
+
+void Renderer::setCameraAspect(Aspect aspect)
+{
+    //if (_cameraAspect == aspect)
+    //    return;
+
+    _cameraAspect = aspect;
+
+    double aspectRatio = 0.0;
+    switch (aspect) {
+    case ASPECT_SQUARE:
+        aspectRatio = 1.0;
+        break;
+    case ASPECT_WINDOW:
+        aspectRatio = 1.0;
+        if (_cameraMode == IMAGE) {
+            aspectRatio = getImageCameraAspect();
+        }
+        break;
+    case ASPECT_NATIVE:
+    default:
+        aspectRatio = 0.0;
+    }
+
+    setObjectAspects(aspectRatio);
+
+    if (_cameraMode == IMAGE)
+        _needsCameraReset = true;
+    _needsRedraw = true;
+}
+
+/**
+ * \brief Change the camera type: perspective, orthographic or image view
+ *
+ * Perspective mode is a normal 3D camera.
+ *
+ * Orthogrphic mode is parallel projection.
+ *
+ * Image mode is an orthographic camera with fixed axes and a clipping region 
+ * around the plot area, use _setCameraZoomRegion to control the displayed area
+ *
+ * \param[in] mode Enum specifying camera type
+ */
+void Renderer::setCameraMode(CameraMode mode)
+{
+    if (_cameraMode == mode) return;
+
+    CameraMode origMode = _cameraMode;
+    _cameraMode = mode;
+    resetAxes();
+
+    vtkSmartPointer<vtkCamera> camera = _renderer->GetActiveCamera();
+    switch (mode) {
+    case ORTHO: {
+        TRACE("Set camera to Ortho mode");
+        camera->ParallelProjectionOn();
+        if (origMode == IMAGE) {
+            resetCamera(true);
+        }
+        break;
+    }
+    case PERSPECTIVE: {
+        TRACE("Set camera to Perspective mode");
+        camera->ParallelProjectionOff();
+        if (origMode == IMAGE) {
+            resetCamera(true);
+        }
+        break;
+    }
+    case IMAGE: {
+        camera->ParallelProjectionOn();
+        _setCameraZoomRegion(_imgWorldOrigin[0], _imgWorldOrigin[1],
+                             _imgWorldDims[0],_imgWorldDims[1]);
+        TRACE("Set camera to Image mode");
+        break;
+    }
+    default:
+        ERROR("Unkown camera mode: %d", mode);
+    }
+    _needsRedraw = true;
+}
+
+/**
+ * \brief Get the current camera mode
+ */
+Renderer::CameraMode Renderer::getCameraMode() const
+{
+    return _cameraMode;
+}
+
+/**
+ * \brief Set the VTK camera parameters based on a 4x4 view matrix
+ */
+void Renderer::setCameraFromMatrix(vtkCamera *camera, vtkMatrix4x4& mat)
+{
+    double d = camera->GetDistance();
+    double vu[3];
+    vu[0] = mat[1][0];
+    vu[1] = mat[1][1];
+    vu[2] = mat[1][2];
+    double trans[3];
+    trans[0] = mat[0][3];
+    trans[1] = mat[1][3];
+    trans[2] = mat[2][3];
+    mat[0][3] = 0;
+    mat[1][3] = 0;
+    mat[2][3] = 0;
+    double vpn[3] = {mat[2][0], mat[2][1], mat[2][2]};
+    double pos[3];
+    // With translation removed, we have an orthogonal matrix, 
+    // so the inverse is the transpose
+    mat.Transpose();
+    mat.MultiplyPoint(trans, pos);
+    pos[0] = -pos[0];
+    pos[1] = -pos[1];
+    pos[2] = -pos[2];
+    double fp[3];
+    fp[0] = pos[0] - vpn[0] * d;
+    fp[1] = pos[1] - vpn[1] * d;
+    fp[2] = pos[2] - vpn[2] * d;
+    camera->SetPosition(pos);
+    camera->SetFocalPoint(fp);
+    camera->SetViewUp(vu);
+}
+
+/**
+ * \brief Set the orientation of the camera from a quaternion
+ * rotation
+ *
+ * \param[in] quat A quaternion with scalar part first: w,x,y,z
+ * \param[in] absolute Is rotation absolute or relative?
+ */
+void Renderer::setCameraOrientation(const double quat[4], bool absolute)
+{
+    if (_cameraMode == IMAGE)
+        return;
+    vtkSmartPointer<vtkCamera> camera = _renderer->GetActiveCamera();
+    vtkSmartPointer<vtkTransform> trans = vtkSmartPointer<vtkTransform>::New();
+    vtkSmartPointer<vtkMatrix4x4> rotMat = vtkSmartPointer<vtkMatrix4x4>::New();
+
+    double q[4];
+    copyQuat(quat, q);
+
+    if (absolute) {
+        double abs[4];
+        // Save absolute rotation
+        copyQuat(q, abs);
+        // Compute relative rotation
+        quatMult(quatReciprocal(_cameraOrientation), q, q);
+        // Store absolute rotation
+        copyQuat(abs, _cameraOrientation);
+    } else {
+        // Compute new absolute rotation
+        quatMult(_cameraOrientation, q, _cameraOrientation);
+    }
+
+    quaternionToTransposeMatrix4x4(q, *rotMat);
+#ifdef DEBUG
+    TRACE("Rotation matrix:\n %g %g %g\n %g %g %g\n %g %g %g",
+          (*rotMat)[0][0], (*rotMat)[0][1], (*rotMat)[0][2],
+          (*rotMat)[1][0], (*rotMat)[1][1], (*rotMat)[1][2],
+          (*rotMat)[2][0], (*rotMat)[2][1], (*rotMat)[2][2]);
+    vtkSmartPointer<vtkMatrix4x4> camMat = vtkSmartPointer<vtkMatrix4x4>::New();
+    camMat->DeepCopy(camera->GetViewTransformMatrix());
+    TRACE("Camera matrix:\n %g %g %g %g\n %g %g %g %g\n %g %g %g %g\n %g %g %g %g",
+          (*camMat)[0][0], (*camMat)[0][1], (*camMat)[0][2], (*camMat)[0][3],
+          (*camMat)[1][0], (*camMat)[1][1], (*camMat)[1][2], (*camMat)[1][3],
+          (*camMat)[2][0], (*camMat)[2][1], (*camMat)[2][2], (*camMat)[2][3],
+          (*camMat)[3][0], (*camMat)[3][1], (*camMat)[3][2], (*camMat)[3][3]);
+    printCameraInfo(camera);
+#endif
+    trans->Translate(0, 0, -camera->GetDistance());
+    trans->Concatenate(rotMat);
+    trans->Translate(0, 0, camera->GetDistance());
+    trans->Concatenate(camera->GetViewTransformMatrix());
+    setCameraFromMatrix(camera, *trans->GetMatrix());
+
+    resetCameraClippingRange();
+    printCameraInfo(camera);
+    _needsRedraw = true;
+}
+
+/**
+ * \brief Set the position and orientation of the camera
+ *
+ * \param[in] position x,y,z position of camera in world coordinates
+ * \param[in] focalPoint x,y,z look-at point in world coordinates
+ * \param[in] viewUp x,y,z up vector of camera
+ */
+void Renderer::setCameraOrientationAndPosition(const double position[3],
+                                               const double focalPoint[3],
+                                               const double viewUp[3])
+{
+    vtkSmartPointer<vtkCamera> camera = _renderer->GetActiveCamera();
+    camera->SetPosition(position);
+    camera->SetFocalPoint(focalPoint);
+    camera->SetViewUp(viewUp);
+    resetCameraClippingRange();
+    _needsRedraw = true;
+}
+
+/**
+ * \brief Get the position and orientation of the camera
+ *
+ * \param[out] position x,y,z position of camera in world coordinates
+ * \param[out] focalPoint x,y,z look-at point in world coordinates
+ * \param[out] viewUp x,y,z up vector of camera
+ */
+void Renderer::getCameraOrientationAndPosition(double position[3],
+                                               double focalPoint[3],
+                                               double viewUp[3])
+{
+    vtkSmartPointer<vtkCamera> camera = _renderer->GetActiveCamera();
+    camera->GetPosition(position);
+    camera->GetFocalPoint(focalPoint);
+    camera->GetViewUp(viewUp);
+}
+
+void Renderer::sceneBoundsChanged()
+{
+#ifdef RESET_CAMERA_ON_SCENE_CHANGE
+    _needsCameraReset = true;
+#else
+    _needsAxesReset = true;
+    _needsCameraClippingRangeReset = true;
+#endif
+
+    _needsRedraw = true;
+}
+
+/**
+ * \brief Reset pan, zoom, clipping planes and optionally rotation
+ *
+ * \param[in] resetOrientation Reset the camera rotation/orientation also
+ */
+void Renderer::resetCamera(bool resetOrientation)
+{
+    TRACE("Enter: %d", resetOrientation ? 1 : 0);
+    vtkSmartPointer<vtkCamera> camera = _renderer->GetActiveCamera();
+    if (_cameraMode == IMAGE) {
+        initCamera();
+    } else {
+        if (resetOrientation) {
+            camera->SetPosition(0, 0, 1);
+            camera->SetFocalPoint(0, 0, 0);
+            camera->SetViewUp(0, 1, 0);
+            _cameraOrientation[0] = 1.0;
+            _cameraOrientation[1] = 0.0;
+            _cameraOrientation[2] = 0.0;
+            _cameraOrientation[3] = 0.0;
+        }
+        //setViewAngle(_windowHeight);
+        //double bounds[6];
+        //collectBounds(bounds, false);
+        //_renderer->ResetCamera(bounds);
+        if (_needsAxesReset) {
+            resetAxes();
+            _needsAxesReset = false;
+        }
+        resetVtkCamera();
+        //computeScreenWorldCoords();
+    }
+
+    printCameraInfo(camera);
+
+    _cameraZoomRatio = 1;
+    _cameraPan[0] = 0;
+    _cameraPan[1] = 0;
+
+    _needsRedraw = true;
+}
+
+void Renderer::resetVtkCamera(double *bounds)
+{
+    TRACE("Enter: bounds: %p", bounds);
+    if (bounds != NULL)
+        _renderer->ResetCamera(bounds);
+    else
+        _renderer->ResetCamera();
+    printCameraInfo(_renderer->GetActiveCamera());
+}
+
+/**
+ * \brief Set the camera near/far clipping range based on current scene bounds
+ */
+void Renderer::resetCameraClippingRange()
+{
+    _renderer->ResetCameraClippingRange();
+    vtkSmartPointer<vtkCamera> camera = _renderer->GetActiveCamera();
+    //double dist = camera->GetClippingRange()[0] + (camera->GetClippingRange()[1] - camera->GetClippingRange()[0])/2.0;
+    //camera->SetDistance(dist);
+    printCameraInfo(camera);
+}
+
+/**
+ * \brief Perform a relative rotation to current camera orientation
+ *
+ * Angles are in degrees, rotation is about focal point
+ */
+void Renderer::rotateCamera(double yaw, double pitch, double roll)
+{
+    if (_cameraMode == IMAGE)
+        return;
+    vtkSmartPointer<vtkCamera> camera = _renderer->GetActiveCamera();
+    camera->Azimuth(yaw); // Rotate about object
+    //camera->SetYaw(yaw); // Rotate about camera
+    camera->Elevation(pitch); // Rotate about object
+    //camera->SetPitch(pitch); // Rotate about camera
+    camera->Roll(roll); // Roll about camera view axis
+    resetCameraClippingRange();
+    //computeScreenWorldCoords();
+    _needsRedraw = true;
+}
+
+/**
+ * \brief Perform a 2D translation of the camera
+ *
+ * x,y pan amount are specified as signed absolute pan amount in viewport
+ * units -- i.e. 0 is no pan, .5 is half the viewport, 2 is twice the viewport,
+ * etc.
+ *
+ * \param[in] x Viewport coordinate horizontal panning (positive number pans
+ * camera left, object right)
+ * \param[in] y Viewport coordinate vertical panning (positive number pans 
+ * camera up, object down)
+ * \param[in] absolute Control if pan amount is relative to current or absolute
+ */
+void Renderer::panCamera(double x, double y, bool absolute)
+{
+    TRACE("Enter panCamera: %g %g, current abs: %g %g",
+          x, y, _cameraPan[0], _cameraPan[1]);
+
+    if (_cameraMode == IMAGE) {
+        _userImgWorldOrigin[0] = 0;
+        _userImgWorldOrigin[1] = 0;
+        _userImgWorldDims[0] = -1;
+        _userImgWorldDims[1] = -1;
+
+        // Reverse x rather than y, since we are panning the camera, and client
+        // expects to be panning/moving the object
+        x = -x * _screenWorldCoords[2];
+        y = y * _screenWorldCoords[3];
+
+        if (absolute) {
+            double panAbs[2];
+            panAbs[0] = x;
+            panAbs[1] = y;
+            x -= _cameraPan[0];
+            y -= _cameraPan[1];
+            _cameraPan[0] = panAbs[0];
+            _cameraPan[1] = panAbs[1];
+        } else {
+            _cameraPan[0] += x;
+            _cameraPan[1] += y;
+        }
+
+        _imgWorldOrigin[0] += x;
+        _imgWorldOrigin[1] += y;
+        _setCameraZoomRegion(_imgWorldOrigin[0], _imgWorldOrigin[1],
+                             _imgWorldDims[0], _imgWorldDims[1]);
+    } else {
+        y = -y;
+        if (absolute) {
+            double panAbs[2];
+            panAbs[0] = x;
+            panAbs[1] = y;
+            x -= _cameraPan[0];
+            y -= _cameraPan[1];
+            _cameraPan[0] = panAbs[0];
+            _cameraPan[1] = panAbs[1];
+        } else {
+            _cameraPan[0] += x;
+            _cameraPan[1] += y;
+        }
+
+        if (x != 0.0 || y != 0.0) {
+            vtkSmartPointer<vtkCamera> camera = _renderer->GetActiveCamera();
+            double viewFocus[4], focalDepth, viewPoint[3];
+            double newPickPoint[4], oldPickPoint[4], motionVector[3];
+
+            camera->GetFocalPoint(viewFocus);
+            computeWorldToDisplay(viewFocus[0], viewFocus[1], viewFocus[2], 
+                                  viewFocus);
+            focalDepth = viewFocus[2];
+
+            computeDisplayToWorld(( x * 2. + 1.) * _windowWidth / 2.0,
+                                  ( y * 2. + 1.) * _windowHeight / 2.0,
+                                  focalDepth, 
+                                  newPickPoint);
+
+            computeDisplayToWorld(_windowWidth / 2.0,
+                                  _windowHeight / 2.0,
+                                  focalDepth, 
+                                  oldPickPoint);
+
+            // Camera motion is reversed
+            motionVector[0] = oldPickPoint[0] - newPickPoint[0];
+            motionVector[1] = oldPickPoint[1] - newPickPoint[1];
+            motionVector[2] = oldPickPoint[2] - newPickPoint[2];
+
+            camera->GetFocalPoint(viewFocus);
+            camera->GetPosition(viewPoint);
+            camera->SetFocalPoint(motionVector[0] + viewFocus[0],
+                                  motionVector[1] + viewFocus[1],
+                                  motionVector[2] + viewFocus[2]);
+
+            camera->SetPosition(motionVector[0] + viewPoint[0],
+                                motionVector[1] + viewPoint[1],
+                                motionVector[2] + viewPoint[2]);
+
+            resetCameraClippingRange();
+            //computeScreenWorldCoords();
+        }
+    }
+
+    TRACE("Leave panCamera: %g %g, current abs: %g %g",
+          x, y, _cameraPan[0], _cameraPan[1]);
+
+    _needsRedraw = true;
+}
+
+/**
+ * \brief Dolly camera or set orthographic scaling based on camera type
+ *
+ * \param[in] z Ratio to change zoom (greater than 1 is zoom in, less than 1 is zoom out)
+ * \param[in] absolute Control if zoom factor is relative to current setting or absolute
+ */
+void Renderer::zoomCamera(double z, bool absolute)
+{
+    vtkSmartPointer<vtkCamera> camera = _renderer->GetActiveCamera();
+    TRACE("Enter Zoom: current abs: %g, z: %g, view angle %g",
+          _cameraZoomRatio, z, camera->GetViewAngle());
+
+    if (absolute) {
+        assert(_cameraZoomRatio > 0.0);
+        double zAbs = z;
+        z *= 1.0/_cameraZoomRatio;
+        _cameraZoomRatio = zAbs;
+    } else {
+        _cameraZoomRatio *= z;
+    }
+
+    if (_cameraMode == IMAGE) {
+        _userImgWorldOrigin[0] = 0;
+        _userImgWorldOrigin[1] = 0;
+        _userImgWorldDims[0] = -1;
+        _userImgWorldDims[1] = -1;
+
+        double dx = _imgWorldDims[0];
+        double dy = _imgWorldDims[1];
+        _imgWorldDims[0] /= z;
+        _imgWorldDims[1] /= z;
+        dx -= _imgWorldDims[0];
+        dy -= _imgWorldDims[1];
+        _imgWorldOrigin[0] += dx/2.0;
+        _imgWorldOrigin[1] += dy/2.0;
+        _setCameraZoomRegion(_imgWorldOrigin[0], _imgWorldOrigin[1],
+                             _imgWorldDims[0], _imgWorldDims[1]);
+    } else {
+        // Keep ortho and perspective modes in sync
+        // Move camera forward/back for perspective camera
+        camera->Dolly(z);
+        // Change ortho parallel scale
+        camera->SetParallelScale(camera->GetParallelScale()/z);
+        resetCameraClippingRange();
+        //computeScreenWorldCoords();
+    }
+
+    TRACE("Leave Zoom: rel %g, new abs: %g, view angle %g", 
+          z, _cameraZoomRatio, camera->GetViewAngle());
+
+    _needsRedraw = true;
+}
+
+bool Renderer::setCameraZoomRegionPixels(int x, int y, int width, int height)
+{
+    if (_cameraMode != IMAGE)
+        return false;
+
+    double wx, wy, ww, wh;
+
+    y = _windowHeight - y;
+    double pxToWorldX = _screenWorldCoords[2] / (double)_windowWidth;
+    double pxToWorldY = _screenWorldCoords[3] / (double)_windowHeight;
+
+    wx = _screenWorldCoords[0] + x * pxToWorldX;
+    wy = _screenWorldCoords[1] + y * pxToWorldY;
+    ww = abs(width) *  pxToWorldX;
+    wh = abs(height) * pxToWorldY;
+    setCameraZoomRegion(wx, wy, ww, wh);
+
+    TRACE("\npx: %d %d %d %d\nworld: %g %g %g %g",
+          x, y, width, height,
+          wx, wy, ww, wh);
+
+    return true;
+}
+
+bool Renderer::setCameraZoomRegion(double x, double y, double width, double height)
+{
+    if (_cameraMode != IMAGE)
+        return false;
+
+    _userImgWorldOrigin[0] = x;
+    _userImgWorldOrigin[1] = y;
+    _userImgWorldDims[0] = width;
+    _userImgWorldDims[1] = height;
+    _setCameraZoomRegion(x, y, width, height);
+
+    return true;
+}
+
+/**
+ * \brief Set the pan/zoom using a corner and dimensions in pixel coordinates
+ * 
+ * \param[in] x left pixel coordinate
+ * \param[in] y bottom  pixel coordinate (with y=0 at top of window)
+ * \param[in] width Width of zoom region in pixel coordinates
+ * \param[in] height Height of zoom region in pixel coordinates
+ */
+void Renderer::_setCameraZoomRegionPixels(int x, int y, int width, int height)
+{
+    if (_cameraMode != IMAGE) {
+        ERROR("Called while camera mode is not image");
+        return;
+    }
+
+    double wx, wy, ww, wh;
+
+    y = _windowHeight - y;
+    double pxToWorldX = _screenWorldCoords[2] / (double)_windowWidth;
+    double pxToWorldY = _screenWorldCoords[3] / (double)_windowHeight;
+
+    wx = _screenWorldCoords[0] + x * pxToWorldX;
+    wy = _screenWorldCoords[1] + y * pxToWorldY;
+    ww = abs(width) *  pxToWorldX;
+    wh = abs(height) * pxToWorldY;
+    _setCameraZoomRegion(wx, wy, ww, wh);
+
+    TRACE("\npx: %d %d %d %d\nworld: %g %g %g %g",
+          x, y, width, height,
+          wx, wy, ww, wh);
+}
+
+void Renderer::getImageCameraSizes(int *imgWidthPx, int *imgHeightPx,
+                                   int *_pxOffsetX, int *_pxOffsetY)
+{
+    int pxOffsetX, pxOffsetY;
+    pxOffsetX = (int)(0.17 * (double)_windowWidth);
+    pxOffsetX = (pxOffsetX > 100 ? 100 : pxOffsetX);
+    pxOffsetY = (int)(0.15 * (double)_windowHeight);
+    pxOffsetY = (pxOffsetY > 75 ? 75 : pxOffsetY);
+
+    int outerGutter = (int)(0.03 * (double)_windowWidth);
+    outerGutter = (outerGutter > 15 ? 15 : outerGutter);
+
+    *imgWidthPx = _windowWidth - pxOffsetX - outerGutter;
+    *imgHeightPx = _windowHeight - pxOffsetY - outerGutter;
+    if (_pxOffsetX != NULL) *_pxOffsetX = pxOffsetX;
+    if (_pxOffsetY != NULL) *_pxOffsetY = pxOffsetY;
+}
+
+double Renderer::getImageCameraAspect()
+{
+    int imgWidthPx, imgHeightPx;
+    getImageCameraSizes(&imgWidthPx, &imgHeightPx);
+    return ((double)imgWidthPx / (double)imgHeightPx);
+}
+
+/**
+ * \brief Set the pan/zoom using a corner and dimensions in world coordinates
+ * 
+ * \param[in] x left world coordinate
+ * \param[in] y bottom  world coordinate
+ * \param[in] width Width of zoom region in world coordinates
+ * \param[in] height Height of zoom region in world coordinates
+ */
+void Renderer::_setCameraZoomRegion(double x, double y, double width, double height)
+{
+    if (_cameraMode != IMAGE) {
+        ERROR("Called while camera mode is not image");
+        return;
+    }
+
+    int imgWidthPx, imgHeightPx;
+    int pxOffsetX, pxOffsetY;
+
+    getImageCameraSizes(&imgWidthPx, &imgHeightPx, &pxOffsetX, &pxOffsetY);
+
+    double imgWindowAspect = (double)imgWidthPx / (double)imgHeightPx;
+
+    double pxToWorld;
+    double imgWidthWorld;
+    double imgHeightWorld;
+
+    double requestedAspect = width / height;
+
+    if (requestedAspect >= imgWindowAspect) {
+        pxToWorld = width / (double)imgWidthPx;
+        imgWidthWorld = width;
+        imgHeightWorld = (double)imgHeightPx * pxToWorld;
+    } else {
+        pxToWorld = height / (double)imgHeightPx;
+        imgWidthWorld = (double)imgWidthPx * pxToWorld;
+        imgHeightWorld =  height;
+    }
+
+    double offsetX = pxOffsetX * pxToWorld;
+    double offsetY = pxOffsetY * pxToWorld;
+    double winWidthWorld = _windowWidth * pxToWorld;
+    double winHeightWorld = _windowHeight * pxToWorld;
+
+    TRACE("Window: %d %d", _windowWidth, _windowHeight);
+    TRACE("ZoomRegion: %g %g %g %g", x, y, width, height);
+    TRACE("pxToWorld: %g", pxToWorld);
+    TRACE("offset: %g %g", offsetX, offsetY);
+
+    _imgWorldOrigin[0] = x;
+    _imgWorldOrigin[1] = y;
+    _imgWorldDims[0] = width;
+    _imgWorldDims[1] = height;
+    _imgWindowWorldDims[0] = imgWidthWorld;
+    _imgWindowWorldDims[1] = imgHeightWorld;
+
+    double camPos[2];
+    camPos[0] = _imgWorldOrigin[0] - offsetX + winWidthWorld / 2.0;
+    camPos[1] = _imgWorldOrigin[1] - offsetY + winHeightWorld / 2.0;
+
+    vtkSmartPointer<vtkCamera> camera = _renderer->GetActiveCamera();
+    camera->ParallelProjectionOn();
+    camera->SetClippingRange(1, 2);
+    // Half of world coordinate height of viewport (Documentation is wrong)
+    camera->SetParallelScale(winHeightWorld / 2.0);
+
+    if (_imgCameraPlane == PLANE_XY) {
+        // XY plane
+        camera->SetPosition(camPos[0], camPos[1], _imgCameraOffset + 1.);
+        camera->SetFocalPoint(camPos[0], camPos[1], _imgCameraOffset);
+        camera->SetViewUp(0, 1, 0);
+        // bottom
+        _cameraClipPlanes[0]->SetOrigin(0, _imgWorldOrigin[1], 0);
+        _cameraClipPlanes[0]->SetNormal(0, 1, 0);
+        // left
+        _cameraClipPlanes[1]->SetOrigin(_imgWorldOrigin[0], 0, 0);
+        _cameraClipPlanes[1]->SetNormal(1, 0, 0);
+        // top
+        _cameraClipPlanes[2]->SetOrigin(0, _imgWorldOrigin[1] + _imgWindowWorldDims[1], 0);
+        _cameraClipPlanes[2]->SetNormal(0, -1, 0);
+        // right
+        _cameraClipPlanes[3]->SetOrigin(_imgWorldOrigin[0] + _imgWindowWorldDims[0], 0, 0);
+        _cameraClipPlanes[3]->SetNormal(-1, 0, 0);
+
+        _cubeAxesActor->SetBounds(_imgWorldOrigin[0], _imgWorldOrigin[0] + _imgWindowWorldDims[0],
+                                  _imgWorldOrigin[1], _imgWorldOrigin[1] + _imgWindowWorldDims[1],
+                                  _imgCameraOffset, _imgCameraOffset);
+        _cubeAxesActor->XAxisVisibilityOn();
+        _cubeAxesActor->YAxisVisibilityOn();
+        _cubeAxesActor->ZAxisVisibilityOff();
+    } else if (_imgCameraPlane == PLANE_ZY) {
+        // ZY plane
+        camera->SetPosition(_imgCameraOffset - 1., camPos[1], camPos[0]);
+        camera->SetFocalPoint(_imgCameraOffset, camPos[1], camPos[0]);
+        camera->SetViewUp(0, 1, 0);
+        // bottom
+        _cameraClipPlanes[0]->SetOrigin(0, _imgWorldOrigin[1], 0);
+        _cameraClipPlanes[0]->SetNormal(0, 1, 0);
+        // left
+        _cameraClipPlanes[1]->SetOrigin(0, 0, _imgWorldOrigin[0]);
+        _cameraClipPlanes[1]->SetNormal(0, 0, 1);
+        // top
+        _cameraClipPlanes[2]->SetOrigin(0, _imgWorldOrigin[1] + _imgWindowWorldDims[1], 0);
+        _cameraClipPlanes[2]->SetNormal(0, -1, 0);
+        // right
+        _cameraClipPlanes[3]->SetOrigin(0, 0, _imgWorldOrigin[0] + _imgWindowWorldDims[0]);
+        _cameraClipPlanes[3]->SetNormal(0, 0, -1);
+
+        _cubeAxesActor->SetBounds(_imgCameraOffset, _imgCameraOffset, 
+                                  _imgWorldOrigin[1], _imgWorldOrigin[1] + _imgWindowWorldDims[1],
+                                  _imgWorldOrigin[0], _imgWorldOrigin[0] + _imgWindowWorldDims[0]);
+        _cubeAxesActor->XAxisVisibilityOff();
+        _cubeAxesActor->YAxisVisibilityOn();
+        _cubeAxesActor->ZAxisVisibilityOn();
+    } else {
+        // XZ plane
+        camera->SetPosition(camPos[0], _imgCameraOffset - 1., camPos[1]);
+        camera->SetFocalPoint(camPos[0], _imgCameraOffset, camPos[1]);
+        camera->SetViewUp(0, 0, 1);
+        // bottom
+        _cameraClipPlanes[0]->SetOrigin(0, 0, _imgWorldOrigin[1]);
+        _cameraClipPlanes[0]->SetNormal(0, 0, 1);
+        // left
+        _cameraClipPlanes[1]->SetOrigin(_imgWorldOrigin[0], 0, 0);
+        _cameraClipPlanes[1]->SetNormal(1, 0, 0);
+        // top
+        _cameraClipPlanes[2]->SetOrigin(0, 0, _imgWorldOrigin[1] + _imgWorldDims[1]);
+        _cameraClipPlanes[2]->SetNormal(0, 0, -1);
+        // right
+        _cameraClipPlanes[3]->SetOrigin(_imgWorldOrigin[0] + _imgWorldDims[0], 0, 0);
+        _cameraClipPlanes[3]->SetNormal(-1, 0, 0);
+
+        _cubeAxesActor->SetBounds(_imgWorldOrigin[0], _imgWorldOrigin[0] + _imgWindowWorldDims[0],
+                                  _imgCameraOffset, _imgCameraOffset,
+                                  _imgWorldOrigin[1], _imgWorldOrigin[1] + _imgWindowWorldDims[1]);
+        _cubeAxesActor->XAxisVisibilityOn();
+        _cubeAxesActor->YAxisVisibilityOff();
+        _cubeAxesActor->ZAxisVisibilityOn();
+    }
+
+    // Fix up axis ranges based on new bounds
+    setAxesRanges();
+
+    // Compute screen world coordinates
+    computeScreenWorldCoords();
+
+#ifdef DEBUG
+    printCameraInfo(camera);
+#endif
+
+    _needsRedraw = true;
+}
+
+/**
+ * \brief Convert pixel/display coordinates to world coordinates based on current camera
+ */
+void Renderer::computeDisplayToWorld(double x, double y, double z, double worldPt[4])
+{
+    _renderer->SetDisplayPoint(x, y, z);
+    _renderer->DisplayToWorld();
+    _renderer->GetWorldPoint(worldPt);
+    if (worldPt[3]) {
+        worldPt[0] /= worldPt[3];
+        worldPt[1] /= worldPt[3];
+        worldPt[2] /= worldPt[3];
+        worldPt[3] = 1.0;
+    }
+}
+
+/**
+ * \brief Convert world coordinates to pixel/display coordinates based on current camera
+ */
+void Renderer::computeWorldToDisplay(double x, double y, double z, double displayPt[3])
+{
+    _renderer->SetWorldPoint(x, y, z, 1.0);
+    _renderer->WorldToDisplay();
+    _renderer->GetDisplayPoint(displayPt);
+}
+
+/**
+ * \brief Compute the world coordinate bounds of the display rectangle
+ */
+void Renderer::computeScreenWorldCoords()
+{
+    // Start with viewport coords [-1,1]
+    double x0 = -1;
+    double y0 = -1;
+    double z0 = -1;
+    double x1 = 1;
+    double y1 = 1;
+    double z1 = -1;
+
+    vtkMatrix4x4 *mat = vtkMatrix4x4::New();
+    double result[4];
+
+    // get the perspective transformation from the active camera
+    mat->DeepCopy(_renderer->GetActiveCamera()->
+                  GetCompositeProjectionTransformMatrix(_renderer->GetTiledAspectRatio(),0,1));
+
+    // use the inverse matrix
+    mat->Invert();
+
+    // Transform point to world coordinates
+    result[0] = x0;
+    result[1] = y0;
+    result[2] = z0;
+    result[3] = 1.0;
+
+    mat->MultiplyPoint(result, result);
+
+    // Get the transformed vector & set WorldPoint
+    // while we are at it try to keep w at one
+    if (result[3]) {
+        x0 = result[0] / result[3];
+        y0 = result[1] / result[3];
+        z0 = result[2] / result[3];
+    }
+
+    result[0] = x1;
+    result[1] = y1;
+    result[2] = z1;
+    result[3] = 1.0;
+
+    mat->MultiplyPoint(result, result);
+
+    if (result[3]) {
+        x1 = result[0] / result[3];
+        y1 = result[1] / result[3];
+        z1 = result[2] / result[3];
+    }
+
+    mat->Delete();
+
+    if (_imgCameraPlane == PLANE_XZ) {
+        _screenWorldCoords[0] = x0;
+        _screenWorldCoords[1] = z0;
+        _screenWorldCoords[2] = x1 - x0;
+        _screenWorldCoords[3] = z1 - z0;
+    } else if (_imgCameraPlane == PLANE_ZY) {
+        _screenWorldCoords[0] = z0;
+        _screenWorldCoords[1] = y0;
+        _screenWorldCoords[2] = z1 - z0;
+        _screenWorldCoords[3] = y1 - y0;
+    } else {
+        // XY
+        _screenWorldCoords[0] = x0;
+        _screenWorldCoords[1] = y0;
+        _screenWorldCoords[2] = x1 - x0;
+        _screenWorldCoords[3] = y1 - y0;
+    }
+}
+
+/**
+ * \brief Get the world coordinates of the image camera plot area
+ *
+ * \param[out] xywh Array to hold x,y,width,height world coordinates
+ */
+void Renderer::getCameraZoomRegion(double xywh[4]) const
+{
+    xywh[0] = _imgWorldOrigin[0];
+    xywh[1] = _imgWorldOrigin[1];
+    xywh[2] = _imgWorldDims[0];
+    xywh[3] = _imgWorldDims[1];
+}
+
+/**
+ * \brief Get the world origin and dimensions of the screen
+ *
+ * \param[out] xywh Array to hold x,y,width,height world coordinates
+ */
+void Renderer::getScreenWorldCoords(double xywh[4]) const
+{
+    memcpy(xywh, _screenWorldCoords, sizeof(double)*4);
+}
+
+/**
+ * \brief Compute bounding box containing the two input bounding boxes
+ *
+ * \param[out] boundsDest Union of the two input bounding boxes
+ * \param[in] bounds1 Input bounding box
+ * \param[in] bounds2 Input bounding box
+ */
+void Renderer::mergeBounds(double *boundsDest,
+                           const double *bounds1, const double *bounds2)
+{
+    assert(boundsDest != NULL);
+    assert(bounds1 != NULL);
+    if (bounds2 == NULL) {
+        WARN("NULL bounds2 array");
+        return;
+    }
+    bool b1empty = (bounds1[0] > bounds1[1]);
+    bool b2empty = (bounds2[0] > bounds2[1]);
+
+    if (b1empty && b2empty)
+        return;
+    if (b1empty) {
+        memcpy(boundsDest, bounds2, sizeof(double) * 6);
+        return;
+    } else if (b2empty) {
+        memcpy(boundsDest, bounds1, sizeof(double) * 6);
+        return;
+    }
+
+    for (int i = 0; i < 6; i++) {
+        if (i % 2 == 0)
+            boundsDest[i] = min2(bounds1[i], bounds2[i]);
+        else
+            boundsDest[i] = max2(bounds1[i], bounds2[i]);
+    }
+}
+
+/**
+ * \brief Collect bounds of all graphics objects
+ *
+ * \param[out] bounds Bounds of all scene objects
+ * \param[in] onlyVisible Only collect bounds of visible objects
+ */
+void Renderer::collectBounds(double *bounds, bool onlyVisible)
+{
+    bounds[0] = DBL_MAX;
+    bounds[1] = -DBL_MAX;
+    bounds[2] = DBL_MAX;
+    bounds[3] = -DBL_MAX;
+    bounds[4] = DBL_MAX;
+    bounds[5] = -DBL_MAX;
+
+    mergeGraphicsObjectBounds<Arc>(bounds, onlyVisible);
+    mergeGraphicsObjectBounds<Arrow>(bounds, onlyVisible);
+    mergeGraphicsObjectBounds<Box>(bounds, onlyVisible);
+    mergeGraphicsObjectBounds<Cone>(bounds, onlyVisible);
+    mergeGraphicsObjectBounds<Contour2D>(bounds, onlyVisible);
+    mergeGraphicsObjectBounds<Contour3D>(bounds, onlyVisible);
+    mergeGraphicsObjectBounds<Cutplane>(bounds, onlyVisible);
+    mergeGraphicsObjectBounds<Cylinder>(bounds, onlyVisible);
+    mergeGraphicsObjectBounds<Disk>(bounds, onlyVisible);
+    mergeGraphicsObjectBounds<Glyphs>(bounds, onlyVisible);
+    mergeGraphicsObjectBounds<HeightMap>(bounds, onlyVisible);
+    mergeGraphicsObjectBounds<LIC>(bounds, onlyVisible);
+    mergeGraphicsObjectBounds<Line>(bounds, onlyVisible);
+    mergeGraphicsObjectBounds<Molecule>(bounds, onlyVisible);
+    mergeGraphicsObjectBounds<Outline>(bounds, onlyVisible);
+    mergeGraphicsObjectBounds<PolyData>(bounds, onlyVisible);
+    mergeGraphicsObjectBounds<Polygon>(bounds, onlyVisible);
+    mergeGraphicsObjectBounds<PseudoColor>(bounds, onlyVisible);
+    mergeGraphicsObjectBounds<Sphere>(bounds, onlyVisible);
+    mergeGraphicsObjectBounds<Streamlines>(bounds, onlyVisible);
+    mergeGraphicsObjectBounds<Volume>(bounds, onlyVisible);
+    mergeGraphicsObjectBounds<Warp>(bounds, onlyVisible);
+
+    for (int i = 0; i < 6; i += 2) {
+        if (bounds[i+1] < bounds[i]) {
+            bounds[i] = -0.5;
+            bounds[i+1] = 0.5;
+        }
+    }
+
+    int numDims = 0;
+    if (bounds[0] != bounds[1])
+        numDims++;
+    if (bounds[2] != bounds[3])
+        numDims++;
+    if (bounds[4] != bounds[5])
+        numDims++;
+
+    if (numDims == 0) {
+        bounds[0] -= .5;
+        bounds[1] += .5;
+        bounds[2] -= .5;
+        bounds[3] += .5;
+    }
+
+    TRACE("Bounds: %g %g %g %g %g %g",
+          bounds[0],
+          bounds[1],
+          bounds[2],
+          bounds[3],
+          bounds[4],
+          bounds[5]);
+}
+
+/**
+ * \brief Collect bounds of all graphics objects
+ *
+ * \param[out] bounds Bounds of all scene objects
+ * \param[in] onlyVisible Only collect bounds of visible objects
+ */
+void Renderer::collectUnscaledBounds(double *bounds, bool onlyVisible)
+{
+    bounds[0] = DBL_MAX;
+    bounds[1] = -DBL_MAX;
+    bounds[2] = DBL_MAX;
+    bounds[3] = -DBL_MAX;
+    bounds[4] = DBL_MAX;
+    bounds[5] = -DBL_MAX;
+
+    mergeGraphicsObjectUnscaledBounds<Arc>(bounds, onlyVisible);
+    mergeGraphicsObjectUnscaledBounds<Arrow>(bounds, onlyVisible);
+    mergeGraphicsObjectUnscaledBounds<Box>(bounds, onlyVisible);
+    mergeGraphicsObjectUnscaledBounds<Cone>(bounds, onlyVisible);
+    mergeGraphicsObjectUnscaledBounds<Contour2D>(bounds, onlyVisible);
+    mergeGraphicsObjectUnscaledBounds<Contour3D>(bounds, onlyVisible);
+    mergeGraphicsObjectUnscaledBounds<Cutplane>(bounds, onlyVisible);
+    mergeGraphicsObjectUnscaledBounds<Cylinder>(bounds, onlyVisible);
+    mergeGraphicsObjectUnscaledBounds<Disk>(bounds, onlyVisible);
+    mergeGraphicsObjectUnscaledBounds<Glyphs>(bounds, onlyVisible);
+    mergeGraphicsObjectUnscaledBounds<HeightMap>(bounds, onlyVisible);
+    mergeGraphicsObjectUnscaledBounds<LIC>(bounds, onlyVisible);
+    mergeGraphicsObjectUnscaledBounds<Line>(bounds, onlyVisible);
+    mergeGraphicsObjectUnscaledBounds<Molecule>(bounds, onlyVisible);
+    mergeGraphicsObjectUnscaledBounds<Outline>(bounds, onlyVisible);
+    mergeGraphicsObjectUnscaledBounds<PolyData>(bounds, onlyVisible);
+    mergeGraphicsObjectUnscaledBounds<Polygon>(bounds, onlyVisible);
+    mergeGraphicsObjectUnscaledBounds<PseudoColor>(bounds, onlyVisible);
+    mergeGraphicsObjectUnscaledBounds<Sphere>(bounds, onlyVisible);
+    mergeGraphicsObjectUnscaledBounds<Streamlines>(bounds, onlyVisible);
+    mergeGraphicsObjectUnscaledBounds<Volume>(bounds, onlyVisible);
+    mergeGraphicsObjectUnscaledBounds<Warp>(bounds, onlyVisible);
+
+    for (int i = 0; i < 6; i += 2) {
+        if (bounds[i+1] < bounds[i]) {
+            bounds[i] = -0.5;
+            bounds[i+1] = 0.5;
+        }
+    }
+
+    int numDims = 0;
+    if (bounds[0] != bounds[1])
+        numDims++;
+    if (bounds[2] != bounds[3])
+        numDims++;
+    if (bounds[4] != bounds[5])
+        numDims++;
+
+    if (numDims == 0) {
+        bounds[0] -= .5;
+        bounds[1] += .5;
+        bounds[2] -= .5;
+        bounds[3] += .5;
+    }
+
+    TRACE("Bounds: %g %g %g %g %g %g",
+          bounds[0],
+          bounds[1],
+          bounds[2],
+          bounds[3],
+          bounds[4],
+          bounds[5]);
+}
+
+/**
+ * \brief Update data ranges for color-mapping and contours
+ */
+void Renderer::updateFieldRanges()
+{
+    collectDataRanges();
+
+    updateGraphicsObjectFieldRanges<Contour2D>();
+    updateGraphicsObjectFieldRanges<Contour3D>();
+    updateGraphicsObjectFieldRanges<Cutplane>();
+    updateGraphicsObjectFieldRanges<Glyphs>();
+    updateGraphicsObjectFieldRanges<HeightMap>();
+    updateGraphicsObjectFieldRanges<LIC>();
+    updateGraphicsObjectFieldRanges<Molecule>();
+    updateGraphicsObjectFieldRanges<PseudoColor>();
+    updateGraphicsObjectFieldRanges<Streamlines>();
+    updateGraphicsObjectFieldRanges<Volume>();
+    updateGraphicsObjectFieldRanges<Warp>();
+}
+
+/**
+ * \brief Collect cumulative data range of all DataSets
+ *
+ * \param[out] range Data range of all DataSets
+ * \param[in] name Field name
+ * \param[in] type Attribute type: e.g. POINT_DATA, CELL_DATA
+ * \param[in] component Array component or -1 for magnitude
+ * \param[in] onlyVisible Only collect range of visible DataSets
+ */
+void Renderer::collectDataRanges(double *range, const char *name,
+                                 DataSet::DataAttributeType type,
+                                 int component, bool onlyVisible)
+{
+    range[0] = DBL_MAX;
+    range[1] = -DBL_MAX;
+
+    for (DataSetHashmap::iterator itr = _dataSets.begin();
+         itr != _dataSets.end(); ++itr) {
+        if (!onlyVisible || itr->second->getVisibility()) {
+            double r[2];
+            r[0] = DBL_MAX;
+            r[1] = -DBL_MAX;
+            itr->second->getDataRange(r, name, type, component);
+            range[0] = min2(range[0], r[0]);
+            range[1] = max2(range[1], r[1]);
+        }
+    }
+    if (range[0] == DBL_MAX)
+        range[0] = 0;
+    if (range[1] == -DBL_MAX)
+        range[1] = 1;
+    
+    TRACE("n:'%s' t:%d c:%d [%g,%g]", name, type, component,
+          range[0], range[1]);
+}
+
+/**
+ * \brief Clear field range hashtables and free memory
+ */
+void Renderer::clearFieldRanges()
+{
+    TRACE("Deleting Field Ranges");
+    for (FieldRangeHashmap::iterator itr = _scalarPointDataRange.begin();
+         itr != _scalarPointDataRange.end(); ++itr) {
+        delete [] itr->second;
+    }
+    _scalarPointDataRange.clear();
+    for (FieldRangeHashmap::iterator itr = _scalarCellDataRange.begin();
+         itr != _scalarCellDataRange.end(); ++itr) {
+        delete [] itr->second;
+    }
+    _scalarCellDataRange.clear();
+    for (FieldRangeHashmap::iterator itr = _vectorPointDataRange.begin();
+         itr != _vectorPointDataRange.end(); ++itr) {
+        delete [] itr->second;
+    }
+    _vectorPointDataRange.clear();
+    for (int i = 0; i < 3; i++) {
+        for (FieldRangeHashmap::iterator itr = _vectorCompPointDataRange[i].begin();
+             itr != _vectorCompPointDataRange[i].end(); ++itr) {
+            delete [] itr->second;
+        }
+        _vectorCompPointDataRange[i].clear();
+    }
+    for (FieldRangeHashmap::iterator itr = _vectorCellDataRange.begin();
+         itr != _vectorCellDataRange.end(); ++itr) {
+        delete [] itr->second;
+    }
+    _vectorCellDataRange.clear();
+    for (int i = 0; i < 3; i++) {
+        for (FieldRangeHashmap::iterator itr = _vectorCompCellDataRange[i].begin();
+             itr != _vectorCompCellDataRange[i].end(); ++itr) {
+            delete [] itr->second;
+        }
+        _vectorCompCellDataRange[i].clear();
+    }
+}
+
+/**
+ * \brief Clear user-defined field range hashtables and free memory
+ */
+void Renderer::clearUserFieldRanges()
+{
+    TRACE("Deleting User Field Ranges");
+    for (FieldRangeHashmap::iterator itr = _userScalarPointDataRange.begin();
+         itr != _userScalarPointDataRange.end(); ++itr) {
+        delete [] itr->second;
+    }
+    _userScalarPointDataRange.clear();
+    for (FieldRangeHashmap::iterator itr = _userScalarCellDataRange.begin();
+         itr != _userScalarCellDataRange.end(); ++itr) {
+        delete [] itr->second;
+    }
+    _userScalarCellDataRange.clear();
+    for (FieldRangeHashmap::iterator itr = _userVectorPointDataRange.begin();
+         itr != _userVectorPointDataRange.end(); ++itr) {
+        delete [] itr->second;
+    }
+    _userVectorPointDataRange.clear();
+    for (int i = 0; i < 3; i++) {
+        for (FieldRangeHashmap::iterator itr = _userVectorCompPointDataRange[i].begin();
+             itr != _userVectorCompPointDataRange[i].end(); ++itr) {
+            delete [] itr->second;
+        }
+        _userVectorCompPointDataRange[i].clear();
+    }
+    for (FieldRangeHashmap::iterator itr = _userVectorCellDataRange.begin();
+         itr != _userVectorCellDataRange.end(); ++itr) {
+        delete [] itr->second;
+    }
+    _userVectorCellDataRange.clear();
+    for (int i = 0; i < 3; i++) {
+        for (FieldRangeHashmap::iterator itr = _userVectorCompCellDataRange[i].begin();
+             itr != _userVectorCompCellDataRange[i].end(); ++itr) {
+            delete [] itr->second;
+        }
+        _userVectorCompCellDataRange[i].clear();
+    }
+}
+
+/**
+ * \brief Set up hashtables for min/max values of all fields from loaded 
+ * datasets
+ *
+ * Note that this method does not set the ranges, it just creates the table 
+ * entries
+ */
+void Renderer::initFieldRanges()
+{
+    clearFieldRanges();
+
+    for (DataSetHashmap::iterator itr = _dataSets.begin();
+         itr != _dataSets.end(); ++itr) {
+        DataSet *ds = itr->second;
+        std::vector<std::string> names;
+        ds->getFieldNames(names, DataSet::POINT_DATA, 1);
+        for (std::vector<std::string>::iterator itr = names.begin();
+             itr != names.end(); ++itr) {
+            FieldRangeHashmap::iterator fritr = 
+                _scalarPointDataRange.find(*itr);
+            if (fritr == _scalarPointDataRange.end()) {
+                _scalarPointDataRange[*itr] = new double[2];
+                _scalarPointDataRange[*itr][0] = 0;
+                _scalarPointDataRange[*itr][1] = 1;
+            }
+        }
+        names.clear();
+        ds->getFieldNames(names, DataSet::CELL_DATA, 1);
+        for (std::vector<std::string>::iterator itr = names.begin();
+             itr != names.end(); ++itr) {
+            FieldRangeHashmap::iterator fritr = 
+                _scalarCellDataRange.find(*itr);
+            if (fritr == _scalarCellDataRange.end()) {
+                _scalarCellDataRange[*itr] = new double[2];
+                _scalarCellDataRange[*itr][0] = 0;
+                _scalarCellDataRange[*itr][1] = 1;
+            }
+        }
+        names.clear();
+        ds->getFieldNames(names, DataSet::POINT_DATA, 3);
+        for (std::vector<std::string>::iterator itr = names.begin();
+             itr != names.end(); ++itr) {
+            FieldRangeHashmap::iterator fritr = 
+                _vectorPointDataRange.find(*itr);
+            if (fritr == _vectorPointDataRange.end()) {
+                _vectorPointDataRange[*itr] = new double[2];
+                _vectorPointDataRange[*itr][0] = 0;
+                _vectorPointDataRange[*itr][1] = 1;
+            }
+            for (int i = 0; i < 3; i++) {
+                fritr = _vectorCompPointDataRange[i].find(*itr);
+                if (fritr == _vectorCompPointDataRange[i].end()) {
+                    _vectorCompPointDataRange[i][*itr] = new double[2];
+                    _vectorCompPointDataRange[i][*itr][0] = 0;
+                    _vectorCompPointDataRange[i][*itr][1] = 1;
+                }
+            }
+        }
+        names.clear();
+        ds->getFieldNames(names, DataSet::CELL_DATA, 3);
+        for (std::vector<std::string>::iterator itr = names.begin();
+             itr != names.end(); ++itr) {
+            FieldRangeHashmap::iterator fritr = 
+                _vectorCellDataRange.find(*itr);
+            if (fritr == _vectorCellDataRange.end()) {
+                _vectorCellDataRange[*itr] = new double[2];
+                _vectorCellDataRange[*itr][0] = 0;
+                _vectorCellDataRange[*itr][1] = 1;
+            }
+            for (int i = 0; i < 3; i++) {
+                fritr = _vectorCompCellDataRange[i].find(*itr);
+                if (fritr == _vectorCompCellDataRange[i].end()) {
+                    _vectorCompCellDataRange[i][*itr] = new double[2];
+                    _vectorCompCellDataRange[i][*itr][0] = 0;
+                    _vectorCompCellDataRange[i][*itr][1] = 1;
+                }
+            }
+        }
+    }
+}
+
+/**
+ * \brief Returns boolean flag indicating if cumulative data ranges 
+ * should be used
+ */
+bool Renderer::getUseCumulativeRange()
+{
+    return _useCumulativeRange;
+}
+
+/**
+ * \brief Set explicit range to use for mapping fields
+ */
+bool Renderer::setCumulativeDataRange(double *range, const char *name,
+                                      DataSet::DataAttributeType type,
+                                      int numComponents,
+                                      int component)
+{
+    if (range == NULL || name == NULL)
+        return false;
+
+    _useCumulativeRange = true;
+    bool found = false;
+
+    switch (type) {
+    case DataSet::POINT_DATA: {
+        FieldRangeHashmap::iterator itr;
+        if (numComponents == 1) {
+            itr = _userScalarPointDataRange.find(name);
+            if (itr == _userScalarPointDataRange.end()) {
+                _userScalarPointDataRange[name] = new double[2];
+                memcpy(_userScalarPointDataRange[name], range, sizeof(double)*2);
+            } else {
+                found = true;
+                memcpy(itr->second, range, sizeof(double)*2);
+            }
+        } else if (numComponents == 3) {
+            if (component == -1) {
+                itr = _userVectorPointDataRange.find(name);
+                if (itr == _userVectorPointDataRange.end()) {
+                    _userVectorPointDataRange[name] = new double[2];
+                    memcpy(itr->second, _userVectorPointDataRange[name], sizeof(double)*2);
+                } else {
+                    found = true;
+                    memcpy(itr->second, range, sizeof(double)*2);
+                }
+                return found;
+            } else if (component >= 0 && component <= 3) {
+                itr = _userVectorCompPointDataRange[component].find(name);
+                if (itr == _userVectorCompPointDataRange[component].end()) {
+                    _userVectorCompPointDataRange[component][name] = new double[2];
+                    memcpy(_userVectorCompPointDataRange[component][name], range, sizeof(double)*2);
+                } else {
+                    found = true;
+                    memcpy(itr->second, range, sizeof(double)*2);
+                }
+            }
+        }
+    }
+        break;
+    case DataSet::CELL_DATA: {
+        FieldRangeHashmap::iterator itr;
+        if (numComponents == 1) {
+            itr = _userScalarCellDataRange.find(name);
+            if (itr == _userScalarCellDataRange.end()) {
+                _userScalarCellDataRange[name] = new double[2];
+                memcpy(_userScalarCellDataRange[name], range, sizeof(double)*2);
+            } else {
+                found = true;
+                memcpy(itr->second, range, sizeof(double)*2);
+            }
+        } else if (numComponents == 3) {
+            if (component == -1) {
+                itr = _userVectorCellDataRange.find(name);
+                if (itr == _userVectorCellDataRange.end()) {
+                    _userVectorCellDataRange[name] = new double[2];
+                    memcpy(_userVectorCellDataRange[name], range, sizeof(double)*2);
+                } else {
+                    found = true;
+                    memcpy(itr->second, range, sizeof(double)*2);
+                }
+            } else if (component >= 0 && component <= 3) {
+                itr = _userVectorCompCellDataRange[component].find(name);
+                if (itr == _userVectorCompCellDataRange[component].end()) {
+                    _userVectorCompCellDataRange[component][name] = new double[2];
+                    memcpy(_userVectorCompCellDataRange[component][name], range, sizeof(double)*2);
+                } else {
+                    found = true;
+                    memcpy(itr->second, range, sizeof(double)*2);
+                }
+            }
+        }
+    }
+        break;
+    default:
+        ERROR("Bad Field Type");
+    }
+
+    // Notify graphics objects of new ranges
+    updateFieldRanges();
+    // Bounds may have changed
+    sceneBoundsChanged();
+    _needsRedraw = true;
+
+    TRACE("Field: %s found: %d range: %g %g", name, (found ? 1 : 0), range[0], range[1]);
+    return found;
+}
+
+/**
+ * \brief Get the cumulative range across all DataSets for a point
+ * data field if it exists, otherwise a cell data field if it exists
+ *
+ * \param[out] range Pointer to an array of 2 doubles
+ * \param[in] name Field name
+ * \param[in] numComponents Number of components in field
+ * \param[in] component Index of component or -1 for magnitude/scalar
+ * \return boolean indicating if field was found
+ */
+bool Renderer::getCumulativeDataRange(double *range, const char *name,
+                                      int numComponents,
+                                      int component)
+{
+    bool ret;
+    if (!(ret = getCumulativeDataRange(range, name, DataSet::POINT_DATA,
+                                       numComponents, component)))
+        ret = getCumulativeDataRange(range, name, DataSet::CELL_DATA,
+                                     numComponents, component);
+    return ret;
+}
+
+/**
+ * \brief Get the cumulative range across all DataSets for a field
+ *
+ * \param[out] range Pointer to an array of 2 doubles
+ * \param[in] name Field name
+ * \param[in] type DataAttributeType of field
+ * \param[in] numComponents Number of components in field
+ * \param[in] component Index of component or -1 for magnitude/scalar
+ * \return boolean indicating if field was found
+ */
+bool Renderer::getCumulativeDataRange(double *range, const char *name,
+                                      DataSet::DataAttributeType type,
+                                      int numComponents,
+                                      int component)
+{
+    if (range == NULL || name == NULL)
+        return false;
+
+    switch (type) {
+    case DataSet::POINT_DATA: {
+        FieldRangeHashmap::iterator itr;
+        if (numComponents == 1) {
+            itr = _userScalarPointDataRange.find(name);
+            if (itr == _userScalarPointDataRange.end()) {
+                itr = _scalarPointDataRange.find(name);
+                if (itr == _scalarPointDataRange.end()) {
+                    return false;
+                }
+            }
+            memcpy(range, itr->second, sizeof(double)*2);
+            return true;
+        } else if (numComponents == 3) {
+            if (component == -1) {
+                itr = _userVectorPointDataRange.find(name);
+                if (itr == _userVectorPointDataRange.end()) {
+                    itr = _vectorPointDataRange.find(name);
+                    if (itr == _vectorPointDataRange.end()) {
+                        return false;
+                    }
+                }
+                memcpy(range, itr->second, sizeof(double)*2);
+                return true;
+            } else if (component >= 0 && component <= 3) {
+                itr = _userVectorCompPointDataRange[component].find(name);
+                if (itr == _userVectorCompPointDataRange[component].end()) {
+                    itr = _vectorCompPointDataRange[component].find(name);
+                    if (itr == _vectorCompPointDataRange[component].end()) {
+                        return false;
+                    }
+                }
+                memcpy(range, itr->second, sizeof(double)*2);
+                return true;
+            }
+        }
+    }
+        break;
+    case DataSet::CELL_DATA: {
+        FieldRangeHashmap::iterator itr;
+        if (numComponents == 1) {
+            itr = _userScalarCellDataRange.find(name);
+            if (itr == _userScalarCellDataRange.end()) {
+                itr = _scalarCellDataRange.find(name);
+                if (itr == _scalarCellDataRange.end()) {
+                    return false;
+                }
+            }
+            memcpy(range, itr->second, sizeof(double)*2);
+            return true;
+        } else if (numComponents == 3) {
+            if (component == -1) {
+                itr = _userVectorCellDataRange.find(name);
+                if (itr == _userVectorCellDataRange.end()) {
+                    itr = _vectorCellDataRange.find(name);
+                    if (itr == _vectorCellDataRange.end()) {
+                        return false;
+                    }
+                }
+                memcpy(range, itr->second, sizeof(double)*2);
+                return true;
+            } else if (component >= 0 && component <= 3) {
+                itr = _userVectorCompCellDataRange[component].find(name);
+                if (itr == _userVectorCompCellDataRange[component].end()) {
+                    itr = _vectorCompCellDataRange[component].find(name);
+                    if (itr == _vectorCompCellDataRange[component].end()) {
+                        return false;
+                    }
+                }
+                memcpy(range, itr->second, sizeof(double)*2);
+                return true;
+            }
+        }
+    }
+        break;
+    default:
+        break;
+    }
+    return false;
+}
+
+void Renderer::collectDataRanges()
+{
+    for (FieldRangeHashmap::iterator itr = _scalarPointDataRange.begin();
+         itr != _scalarPointDataRange.end(); ++itr) {
+        collectDataRanges(itr->second, itr->first.c_str(),
+                          DataSet::POINT_DATA, -1,
+                          _cumulativeRangeOnlyVisible);
+    }
+    for (FieldRangeHashmap::iterator itr = _scalarCellDataRange.begin();
+         itr != _scalarCellDataRange.end(); ++itr) {
+        collectDataRanges(itr->second, itr->first.c_str(),
+                          DataSet::CELL_DATA, -1,
+                          _cumulativeRangeOnlyVisible);
+    }
+    for (FieldRangeHashmap::iterator itr = _vectorPointDataRange.begin();
+         itr != _vectorPointDataRange.end(); ++itr) {
+        collectDataRanges(itr->second, itr->first.c_str(),
+                          DataSet::POINT_DATA, -1,
+                          _cumulativeRangeOnlyVisible);
+    }
+    for (int i = 0; i < 3; i++) {
+        for (FieldRangeHashmap::iterator itr = _vectorCompPointDataRange[i].begin();
+             itr != _vectorCompPointDataRange[i].end(); ++itr) {
+            collectDataRanges(itr->second, itr->first.c_str(),
+                              DataSet::POINT_DATA, i,
+                              _cumulativeRangeOnlyVisible);
+        }
+    }
+    for (FieldRangeHashmap::iterator itr = _vectorCellDataRange.begin();
+         itr != _vectorCellDataRange.end(); ++itr) {
+        collectDataRanges(itr->second, itr->first.c_str(),
+                          DataSet::CELL_DATA, -1,
+                          _cumulativeRangeOnlyVisible);
+    }
+    for (int i = 0; i < 3; i++) {
+        for (FieldRangeHashmap::iterator itr = _vectorCompCellDataRange[i].begin();
+             itr != _vectorCompCellDataRange[i].end(); ++itr) {
+            collectDataRanges(itr->second, itr->first.c_str(),
+                              DataSet::CELL_DATA, i,
+                              _cumulativeRangeOnlyVisible);
+        }
+    }
+}
+
+/**
+ * \brief Determines if AABB lies in a principal axis plane
+ * and if so, returns the plane normal
+ */
+bool Renderer::is2D(const double bounds[6],
+                    PrincipalPlane *plane,
+                    double *offset) const
+{
+    if (bounds[4] == bounds[5]) {
+        // Z = 0, XY plane
+        if (plane)
+            *plane = PLANE_XY;
+        if (offset)
+            *offset = bounds[4];
+        return true;
+    } else if (bounds[0] == bounds[1]) {
+        // X = 0, ZY plane
+        if (plane)
+            *plane = PLANE_ZY;
+        if (offset)
+            *offset = bounds[0];
+        return true;
+    } else if (bounds[2] == bounds[3]) {
+        // Y = 0, XZ plane
+        if (plane)
+            *plane = PLANE_XZ;
+        if (offset)
+            *offset = bounds[2];
+        return true;
+    }
+    *plane = PLANE_XY;
+    *offset = 0;
+    return false;
+}
+
+/**
+ * \brief Initialize the camera zoom region to include the bounding volume given
+ */
+void Renderer::initCamera(bool initCameraMode)
+{
+#ifdef WANT_TRACE
+    switch (_cameraMode) {
+    case IMAGE:
+        TRACE("Image camera");
+        break;
+    case ORTHO:
+        TRACE("Ortho camera");
+        break;
+    case PERSPECTIVE:
+        TRACE("Perspective camera");
+        break;
+    default:
+        TRACE("Unknown camera mode");
+    }
+#endif
+    // Clear user requested zoom region
+    _userImgWorldOrigin[0] = 0;
+    _userImgWorldOrigin[1] = 0;
+    _userImgWorldDims[0] = -1;
+    _userImgWorldDims[1] = -1;
+
+    double bounds[6];
+    collectBounds(bounds, false);
+    bool twod = is2D(bounds, &_imgCameraPlane, &_imgCameraOffset);
+    if (twod) {
+        if (initCameraMode) {
+            TRACE("Changing camera mode to image");
+            _cameraMode = IMAGE;
+        }
+        if (_imgCameraPlane == PLANE_ZY) {
+            _imgWorldOrigin[0] = bounds[4];
+            _imgWorldOrigin[1] = bounds[2];
+            _imgWorldDims[0] = bounds[5] - bounds[4];
+            _imgWorldDims[1] = bounds[3] - bounds[2];
+        } else if (_imgCameraPlane == PLANE_XZ) {
+            _imgWorldOrigin[0] = bounds[0];
+            _imgWorldOrigin[1] = bounds[4];
+            _imgWorldDims[0] = bounds[1] - bounds[0];
+            _imgWorldDims[1] = bounds[5] - bounds[4];
+        } else {
+            _imgWorldOrigin[0] = bounds[0];
+            _imgWorldOrigin[1] = bounds[2];
+            _imgWorldDims[0] = bounds[1] - bounds[0];
+            _imgWorldDims[1] = bounds[3] - bounds[2];
+        }
+    } else {
+        _imgWorldOrigin[0] = bounds[0];
+        _imgWorldOrigin[1] = bounds[2];
+        _imgWorldDims[0] = bounds[1] - bounds[0];
+        _imgWorldDims[1] = bounds[3] - bounds[2];
+    }
+
+    _cameraPan[0] = 0;
+    _cameraPan[1] = 0;
+    _cameraZoomRatio = 1;
+
+    switch (_cameraMode) {
+    case IMAGE:
+        //_renderer->ResetCamera(bounds);
+        _setCameraZoomRegion(_imgWorldOrigin[0], _imgWorldOrigin[1],
+                             _imgWorldDims[0], _imgWorldDims[1]);
+        resetAxes(bounds);
+        break;
+    case ORTHO:
+        _renderer->GetActiveCamera()->ParallelProjectionOn();
+        resetAxes(bounds);
+        //_renderer->ResetCamera(bounds);
+        resetVtkCamera();
+        //computeScreenWorldCoords();
+        break;
+    case PERSPECTIVE:
+        _renderer->GetActiveCamera()->ParallelProjectionOff();
+        resetAxes(bounds);
+        //_renderer->ResetCamera(bounds);
+        resetVtkCamera();
+        //computeScreenWorldCoords();
+        break;
+    default:
+        ERROR("Unknown camera mode");
+    }
+
+#ifdef WANT_TRACE
+    printCameraInfo(_renderer->GetActiveCamera());
+#endif
+}
+
+#if 0
+/**
+ * \brief Print debugging info about a vtkCamera
+ */
+void Renderer::printCameraInfo(vtkCamera *camera)
+{
+    TRACE("pscale: %g, angle: %g, d: %g pos: %g %g %g, fpt: %g %g %g, vup: %g %g %g, clip: %g %g",
+          camera->GetParallelScale(),
+          camera->GetViewAngle(),
+          camera->GetDistance(),
+          camera->GetPosition()[0],
+          camera->GetPosition()[1],
+          camera->GetPosition()[2], 
+          camera->GetFocalPoint()[0],
+          camera->GetFocalPoint()[1],
+          camera->GetFocalPoint()[2],
+          camera->GetViewUp()[0],
+          camera->GetViewUp()[1],
+          camera->GetViewUp()[2],
+          camera->GetClippingRange()[0],
+          camera->GetClippingRange()[1]);
+}
+#endif
+
+/**
+ * \brief Set the RGB background color to render into the image
+ */
+void Renderer::setBackgroundColor(float color[3])
+{
+    _bgColor[0] = color[0];
+    _bgColor[1] = color[1];
+    _bgColor[2] = color[2];
+    _renderer->SetBackground(_bgColor[0], _bgColor[1], _bgColor[2]);
+    _needsRedraw = true;
+}
+
+/**
+ * \brief Set the opacity of the specified DataSet's associated graphics objects
+ */
+void Renderer::setDataSetOpacity(const DataSetId& id, double opacity)
+{
+    DataSetHashmap::iterator itr;
+
+    bool doAll = false;
+
+    if (id.compare("all") == 0) {
+        itr = _dataSets.begin();
+        if (itr == _dataSets.end())
+            return;
+        doAll = true;
+    } else {
+        itr = _dataSets.find(id);
+    }
+    if (itr == _dataSets.end()) {
+        ERROR("Unknown dataset %s", id.c_str());
+        return;
+    }
+
+    do {
+        itr->second->setOpacity(opacity);
+    } while (doAll && ++itr != _dataSets.end());
+
+    if (id.compare("all") == 0 || getGraphicsObject<Contour2D>(id) != NULL)
+        setGraphicsObjectOpacity<Contour2D>(id, opacity);
+    if (id.compare("all") == 0 || getGraphicsObject<Contour3D>(id) != NULL)
+        setGraphicsObjectOpacity<Contour3D>(id, opacity);
+    if (id.compare("all") == 0 || getGraphicsObject<Cutplane>(id) != NULL)
+        setGraphicsObjectOpacity<Cutplane>(id, opacity);
+    if (id.compare("all") == 0 || getGraphicsObject<Glyphs>(id) != NULL)
+        setGraphicsObjectOpacity<Glyphs>(id, opacity);
+    if (id.compare("all") == 0 || getGraphicsObject<HeightMap>(id) != NULL)
+        setGraphicsObjectOpacity<HeightMap>(id, opacity);
+    if (id.compare("all") == 0 || getGraphicsObject<LIC>(id) != NULL)
+        setGraphicsObjectOpacity<LIC>(id, opacity);
+    if (id.compare("all") == 0 || getGraphicsObject<Molecule>(id) != NULL)
+        setGraphicsObjectOpacity<Molecule>(id, opacity);
+    if (id.compare("all") == 0 || getGraphicsObject<Outline>(id) != NULL)
+        setGraphicsObjectOpacity<Outline>(id, opacity);
+    if (id.compare("all") == 0 || getGraphicsObject<PolyData>(id) != NULL)
+        setGraphicsObjectOpacity<PolyData>(id, opacity);
+    if (id.compare("all") == 0 || getGraphicsObject<PseudoColor>(id) != NULL)
+        setGraphicsObjectOpacity<PseudoColor>(id, opacity);
+    if (id.compare("all") == 0 || getGraphicsObject<Streamlines>(id) != NULL)
+        setGraphicsObjectOpacity<Streamlines>(id, opacity);
+    if (id.compare("all") == 0 || getGraphicsObject<Volume>(id) != NULL)
+        setGraphicsObjectOpacity<Volume>(id, opacity);
+    if (id.compare("all") == 0 || getGraphicsObject<Warp>(id) != NULL)
+        setGraphicsObjectOpacity<Warp>(id, opacity);
+
+    _needsRedraw = true;
+}
+
+/**
+ * \brief Turn on/off rendering of the specified DataSet's associated graphics objects
+ */
+void Renderer::setDataSetVisibility(const DataSetId& id, bool state)
+{
+    DataSetHashmap::iterator itr;
+
+    bool doAll = false;
+
+    if (id.compare("all") == 0) {
+        itr = _dataSets.begin();
+        doAll = true;
+        if (itr == _dataSets.end())
+            return;
+    } else {
+        itr = _dataSets.find(id);
+    }
+    if (itr == _dataSets.end()) {
+        ERROR("Unknown dataset %s", id.c_str());
+        return;
+    }
+
+    do {
+        itr->second->setVisibility(state);
+    } while (doAll && ++itr != _dataSets.end());
+
+    if (id.compare("all") == 0 || getGraphicsObject<Contour2D>(id) != NULL)
+        setGraphicsObjectVisibility<Contour2D>(id, state);
+    if (id.compare("all") == 0 || getGraphicsObject<Contour3D>(id) != NULL)
+        setGraphicsObjectVisibility<Contour3D>(id, state);
+    if (id.compare("all") == 0 || getGraphicsObject<Cutplane>(id) != NULL)
+        setGraphicsObjectVisibility<Cutplane>(id, state);
+    if (id.compare("all") == 0 || getGraphicsObject<Glyphs>(id) != NULL)
+        setGraphicsObjectVisibility<Glyphs>(id, state);
+    if (id.compare("all") == 0 || getGraphicsObject<HeightMap>(id) != NULL)
+        setGraphicsObjectVisibility<HeightMap>(id, state);
+    if (id.compare("all") == 0 || getGraphicsObject<LIC>(id) != NULL)
+        setGraphicsObjectVisibility<LIC>(id, state);
+    if (id.compare("all") == 0 || getGraphicsObject<Molecule>(id) != NULL)
+        setGraphicsObjectVisibility<Molecule>(id, state);
+    if (id.compare("all") == 0 || getGraphicsObject<Outline>(id) != NULL)
+        setGraphicsObjectVisibility<Outline>(id, state);
+    if (id.compare("all") == 0 || getGraphicsObject<PolyData>(id) != NULL)
+        setGraphicsObjectVisibility<PolyData>(id, state);
+    if (id.compare("all") == 0 || getGraphicsObject<PseudoColor>(id) != NULL)
+        setGraphicsObjectVisibility<PseudoColor>(id, state);
+    if (id.compare("all") == 0 || getGraphicsObject<Streamlines>(id) != NULL)
+        setGraphicsObjectVisibility<Streamlines>(id, state);
+    if (id.compare("all") == 0 || getGraphicsObject<Volume>(id) != NULL)
+        setGraphicsObjectVisibility<Volume>(id, state);
+    if (id.compare("all") == 0 || getGraphicsObject<Warp>(id) != NULL)
+        setGraphicsObjectVisibility<Warp>(id, state);
+
+    _needsRedraw = true;
+}
+
+/**
+ * \brief Set a user clipping plane
+ *
+ * TODO: Fix clip plane positions after a change in actor bounds
+ */
+void Renderer::setClipPlane(Axis axis, double ratio, int direction)
+{
+    double bounds[6];
+    collectBounds(bounds, false);
+
+    switch (axis) {
+    case X_AXIS:
+        if (direction > 0) {
+            if (ratio > 0.0) {
+                if (_userClipPlanes[0] == NULL) {
+                    _userClipPlanes[0] = vtkSmartPointer<vtkPlane>::New();
+                    _userClipPlanes[0]->SetNormal(1, 0, 0);
+                }
+                _userClipPlanes[0]->SetOrigin(bounds[0] + (bounds[1]-bounds[0])*ratio, 0, 0);
+            } else {
+                _userClipPlanes[0] = NULL;
+            }
+        } else {
+            if (ratio < 1.0) {
+                if (_userClipPlanes[1] == NULL) {
+                    _userClipPlanes[1] = vtkSmartPointer<vtkPlane>::New();
+                    _userClipPlanes[1]->SetNormal(-1, 0, 0);
+                }
+                _userClipPlanes[1]->SetOrigin(bounds[0] + (bounds[1]-bounds[0])*ratio, 0, 0);
+            } else {
+                _userClipPlanes[1] = NULL;
+            }
+        }
+        break;
+    case Y_AXIS:
+        if (direction > 0) {
+            if (ratio > 0.0) {
+                if (_userClipPlanes[2] == NULL) {
+                    _userClipPlanes[2] = vtkSmartPointer<vtkPlane>::New();
+                    _userClipPlanes[2]->SetNormal(0, 1, 0);
+                }
+                _userClipPlanes[2]->SetOrigin(0, bounds[2] + (bounds[3]-bounds[2])*ratio, 0);
+            } else {
+                _userClipPlanes[2] = NULL;
+            }
+        } else {
+            if (ratio < 1.0) {
+                if (_userClipPlanes[3] == NULL) {
+                    _userClipPlanes[3] = vtkSmartPointer<vtkPlane>::New();
+                    _userClipPlanes[3]->SetNormal(0, -1, 0);
+                }
+                _userClipPlanes[3]->SetOrigin(0, bounds[2] + (bounds[3]-bounds[2])*ratio, 0);
+            } else {
+                _userClipPlanes[3] = NULL;
+            }
+        }
+        break;
+    case Z_AXIS:
+        if (direction > 0) {
+            if (ratio > 0.0) {
+                if (_userClipPlanes[4] == NULL) {
+                    _userClipPlanes[4] = vtkSmartPointer<vtkPlane>::New();
+                    _userClipPlanes[4]->SetNormal(0, 0, 1);
+                }
+                _userClipPlanes[4]->SetOrigin(0, 0, bounds[4] + (bounds[5]-bounds[4])*ratio);
+            } else {
+                _userClipPlanes[4] = NULL;
+            }
+        } else {
+            if (ratio < 1.0) {
+                if (_userClipPlanes[5] == NULL) {
+                    _userClipPlanes[5] = vtkSmartPointer<vtkPlane>::New();
+                    _userClipPlanes[5]->SetNormal(0, 0, -1);
+                }
+                _userClipPlanes[5]->SetOrigin(0, 0, bounds[4] + (bounds[5]-bounds[4])*ratio);
+            } else {
+                _userClipPlanes[5] = NULL;
+            }
+        }
+        break;
+    default:
+        ;
+    }
+
+    _needsRedraw = true;
+}
+
+/**
+ * \brief Set up clipping planes for image camera mode if needed
+ */
+void Renderer::setCameraClippingPlanes()
+{
+    /* XXX: Note that there appears to be a bug with setting the 
+     * clipping plane collection to NULL in the VTK Mappers -- 
+     * the old clip planes are still applied.  The workaround here 
+     * is to keep the PlaneCollection and add/remove the planes 
+     * to/from the PlaneCollection as needed.
+     */
+    if (_cameraMode == IMAGE) {
+        if (_activeClipPlanes->GetNumberOfItems() == 0) {
+            for (int i = 0; i < 4; i++)
+                _activeClipPlanes->AddItem(_cameraClipPlanes[i]);
+        }
+    } else {
+        if (_activeClipPlanes->GetNumberOfItems() > 0)
+            _activeClipPlanes->RemoveAllItems();
+        for (int i = 0; i < 6; i++) {
+            if (_userClipPlanes[i] != NULL) {
+                _activeClipPlanes->AddItem(_userClipPlanes[i]);
+            }
+        }
+    }
+
+    /* Ensure all Mappers are using the PlaneCollection
+     * This will not change the state or timestamp of 
+     * Mappers already using the PlaneCollection
+     */
+    setGraphicsObjectClippingPlanes<Arc>(_activeClipPlanes);
+    setGraphicsObjectClippingPlanes<Arrow>(_activeClipPlanes);
+    setGraphicsObjectClippingPlanes<Box>(_activeClipPlanes);
+    setGraphicsObjectClippingPlanes<Cone>(_activeClipPlanes);
+    setGraphicsObjectClippingPlanes<Contour2D>(_activeClipPlanes);
+    setGraphicsObjectClippingPlanes<Contour3D>(_activeClipPlanes);
+    setGraphicsObjectClippingPlanes<Cutplane>(_activeClipPlanes);
+    setGraphicsObjectClippingPlanes<Cylinder>(_activeClipPlanes);
+    setGraphicsObjectClippingPlanes<Disk>(_activeClipPlanes);
+    setGraphicsObjectClippingPlanes<Glyphs>(_activeClipPlanes);
+    setGraphicsObjectClippingPlanes<Group>(_activeClipPlanes);
+    setGraphicsObjectClippingPlanes<HeightMap>(_activeClipPlanes);
+    setGraphicsObjectClippingPlanes<LIC>(_activeClipPlanes);
+    setGraphicsObjectClippingPlanes<Line>(_activeClipPlanes);
+    setGraphicsObjectClippingPlanes<Molecule>(_activeClipPlanes);
+    setGraphicsObjectClippingPlanes<Outline>(_activeClipPlanes);
+    setGraphicsObjectClippingPlanes<PolyData>(_activeClipPlanes);
+    setGraphicsObjectClippingPlanes<Polygon>(_activeClipPlanes);
+    setGraphicsObjectClippingPlanes<PseudoColor>(_activeClipPlanes);
+    setGraphicsObjectClippingPlanes<Sphere>(_activeClipPlanes);
+    setGraphicsObjectClippingPlanes<Streamlines>(_activeClipPlanes);
+    setGraphicsObjectClippingPlanes<Volume>(_activeClipPlanes);
+    setGraphicsObjectClippingPlanes<Warp>(_activeClipPlanes);
+}
+
+/**
+ * \brief Control the use of two sided lighting
+ */
+void Renderer::setUseTwoSidedLighting(bool state)
+{
+    _renderer->SetTwoSidedLighting(state ? 1 : 0);
+    _needsRedraw = true;
+}
+
+/**
+ * \brief Control the use of the depth peeling algorithm for transparency
+ */
+void Renderer::setUseDepthPeeling(bool state)
+{
+    _renderer->SetUseDepthPeeling(state ? 1 : 0);
+    _needsRedraw = true;
+}
+
+/**
+ * \brief Sets flag to trigger rendering next time render() is called
+ */
+void Renderer::eventuallyRender()
+{
+    _needsRedraw = true;
+}
+
+/**
+ * \brief Cause the rendering to render a new image if needed
+ *
+ * The _needsRedraw flag indicates if a state change has occured since
+ * the last rendered frame
+ */
+bool Renderer::render()
+{
+    TRACE("Enter: redraw: %d axesReset: %d cameraReset: %d clippingRangeReset: %d",
+          _needsRedraw ? 1 : 0, _needsAxesReset ? 1 : 0, _needsCameraReset ? 1 : 0, _needsCameraClippingRangeReset ? 1 : 0);
+    if (_needsRedraw) {
+         if (_needsAxesReset) {
+            resetAxes();
+            _needsAxesReset = false;
+        }
+        if (_needsCameraReset) {
+            initCamera();
+            _needsCameraReset = false;
+            _needsCameraClippingRangeReset = false;
+        } else if (_needsCameraClippingRangeReset && _cameraMode != IMAGE) {
+            resetCameraClippingRange();
+            _needsCameraClippingRangeReset = false;
+        }
+        setCameraClippingPlanes();
+        _renderWindow->Render();
+        _needsRedraw = false;
+        return true;
+    } else
+        return false;
+}
+
+/// Get the pixel width of the render window/image
+int Renderer::getWindowWidth() const
+{
+    return _windowWidth;
+}
+
+/// Get the pixel height of the render window/image
+int Renderer::getWindowHeight() const
+{
+    return _windowHeight;
+}
+
+/**
+ * \brief Read back the rendered framebuffer image
+ */
+void Renderer::getRenderedFrame(vtkUnsignedCharArray *imgData)
+{
+#ifdef RENDER_TARGA
+    _renderWindow->MakeCurrent();
+    // Must clear previous errors first.
+    while (glGetError() != GL_NO_ERROR){
+        ;
+    }
+    int bytesPerPixel = TARGA_BYTES_PER_PIXEL;
+    int size = bytesPerPixel * _windowWidth * _windowHeight;
+
+    if (imgData->GetMaxId() + 1 != size)
+    {
+        imgData->SetNumberOfComponents(bytesPerPixel);
+        imgData->SetNumberOfValues(size);
+    }
+    glDisable(GL_TEXTURE_2D);
+    if (_renderWindow->GetDoubleBuffer()) {
+        glReadBuffer(static_cast<GLenum>(vtkOpenGLRenderWindow::SafeDownCast(_renderWindow)->GetBackLeftBuffer()));
+    } else {
+        glReadBuffer(static_cast<GLenum>(vtkOpenGLRenderWindow::SafeDownCast(_renderWindow)->GetFrontLeftBuffer()));
+    }
+    glPixelStorei(GL_PACK_ALIGNMENT, 1);
+#ifdef WANT_TRACE
+    struct timeval t1, t2;
+    glFinish();
+    gettimeofday(&t1, 0);
+#endif
+    if (bytesPerPixel == 4) {
+        glReadPixels(0, 0, _windowWidth, _windowHeight, GL_BGRA,
+                     GL_UNSIGNED_BYTE, imgData->GetPointer(0));
+    } else {
+        glReadPixels(0, 0, _windowWidth, _windowHeight, GL_BGR,
+                     GL_UNSIGNED_BYTE, imgData->GetPointer(0));
+    }
+#ifdef WANT_TRACE
+    gettimeofday(&t2, 0);
+    static unsigned int numFrames = 0;
+    static double accum = 0;
+    numFrames++;
+    accum += MSECS_ELAPSED(t1, t2);
+#endif
+    TRACE("Readback time: %g ms", MSECS_ELAPSED(t1, t2));
+    TRACE("Readback avg: %g ms", accum/numFrames);
+    if (glGetError() != GL_NO_ERROR) {
+        ERROR("glReadPixels");
+    }
+#else
+    _renderWindow->GetPixelData(0, 0, _windowWidth-1, _windowHeight-1,
+                                !_renderWindow->GetDoubleBuffer(), imgData);
+#endif
+    TRACE("Image data size: %d", imgData->GetSize());
+}
+
+/**
+ * \brief Get nearest data value given display coordinates x,y
+ *
+ * FIXME: This doesn't work when actors are scaled
+ *
+ * Note: no interpolation is performed on data
+ */
+bool Renderer::getScalarValueAtPixel(const DataSetId& id, int x, int y, double *value)
+{
+    vtkSmartPointer<vtkCoordinate> coord = vtkSmartPointer<vtkCoordinate>::New();
+    coord->SetCoordinateSystemToDisplay();
+    coord->SetValue(x, _windowHeight - y, 0);
+    double *worldCoords = coord->GetComputedWorldValue(_renderer);
+
+    TRACE("Pixel coords: %d, %d\nWorld coords: %g, %g, %g", x, y,
+          worldCoords[0], 
+          worldCoords[1], 
+          worldCoords[2]);
+
+    return getScalarValue(id, worldCoords[0], worldCoords[1], worldCoords[2], value);
+}
+
+/**
+ * \brief Get nearest data value given world coordinates x,y,z
+ *
+ * Note: no interpolation is performed on data
+ */
+bool Renderer::getScalarValue(const DataSetId& id, double x, double y, double z, double *value)
+{
+    DataSet *ds = getDataSet(id);
+    if (ds == NULL)
+        return false;
+
+    return ds->getScalarValue(x, y, z, value);
+}
+
+/**
+ * \brief Get nearest data value given display coordinates x,y
+ *
+ * Note: no interpolation is performed on data
+ */
+bool Renderer::getVectorValueAtPixel(const DataSetId& id, int x, int y, double vector[3])
+{
+    vtkSmartPointer<vtkCoordinate> coord = vtkSmartPointer<vtkCoordinate>::New();
+    coord->SetCoordinateSystemToDisplay();
+    coord->SetValue(x, _windowHeight - y, 0);
+    double *worldCoords = coord->GetComputedWorldValue(_renderer);
+
+    TRACE("Pixel coords: %d, %d\nWorld coords: %g, %g, %g", x, y,
+          worldCoords[0], 
+          worldCoords[1], 
+          worldCoords[2]);
+
+    return getVectorValue(id, worldCoords[0], worldCoords[1], worldCoords[2], vector);
+}
+
+/**
+ * \brief Get nearest data value given world coordinates x,y,z
+ *
+ * Note: no interpolation is performed on data
+ */
+bool Renderer::getVectorValue(const DataSetId& id, double x, double y, double z, double vector[3])
+{
+    DataSet *ds = getDataSet(id);
+    if (ds == NULL)
+        return false;
+
+    return ds->getVectorValue(x, y, z, vector);
+}
Index: /trunk/packages/vizservers/vtkvis/VtkRenderer.h
===================================================================
--- /trunk/packages/vizservers/vtkvis/VtkRenderer.h	(revision 3616)
+++ /trunk/packages/vizservers/vtkvis/VtkRenderer.h	(revision 3616)
@@ -0,0 +1,996 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (C) 2004-2012  HUBzero Foundation, LLC
+ *
+ * Author: Leif Delgass <ldelgass@purdue.edu>
+ */
+
+#ifndef VTKVIS_RENDERER_H
+#define VTKVIS_RENDERER_H
+
+#include <string>
+#include <vector>
+#include <tr1/unordered_map>
+#include <typeinfo>
+
+#include <vtkSmartPointer.h>
+#ifdef USE_CUSTOM_AXES
+#include "vtkRpCubeAxesActor.h"
+#else
+#include <vtkCubeAxesActor.h>
+#endif
+#include <vtkScalarBarActor.h>
+#include <vtkRenderer.h>
+#include <vtkRenderWindow.h>
+#include <vtkUnsignedCharArray.h>
+
+#include "ColorMap.h"
+#include "Types.h"
+#include "VtkDataSet.h"
+#include "Arc.h"
+#include "Arrow.h"
+#include "Box.h"
+#include "Cone.h"
+#include "Contour2D.h"
+#include "Contour3D.h"
+#include "Cutplane.h"
+#include "Cylinder.h"
+#include "Disk.h"
+#include "Glyphs.h"
+#include "Group.h"
+#include "HeightMap.h"
+#include "LIC.h"
+#include "Line.h"
+#include "Molecule.h"
+#include "Outline.h"
+#include "PolyData.h"
+#include "Polygon.h"
+#include "PseudoColor.h"
+#include "Sphere.h"
+#include "Streamlines.h"
+#include "Volume.h"
+#include "Warp.h"
+#include "Trace.h"
+
+// Controls if TGA format is sent to client
+//#define RENDER_TARGA
+#define TARGA_BYTES_PER_PIXEL 3
+
+namespace VtkVis {
+
+/**
+ * \brief VTK Renderer
+ */
+class Renderer
+{
+public:
+    Renderer();
+    virtual ~Renderer();
+
+    enum AxisRangeMode {
+        RANGE_AUTO = 0,
+        RANGE_SCALE_BOUNDS,
+        RANGE_EXPLICIT
+    };
+
+    enum AxesFlyMode {
+        FLY_OUTER_EDGES = 0,
+        FLY_CLOSEST_TRIAD,
+        FLY_FURTHEST_TRIAD,
+        FLY_STATIC_EDGES,
+        FLY_STATIC_TRIAD
+    };
+
+    enum AxesTickPosition {
+        TICKS_INSIDE,
+        TICKS_OUTSIDE,
+        TICKS_BOTH
+    };
+
+    enum CameraMode {
+        PERSPECTIVE,
+        ORTHO,
+        IMAGE
+    };
+
+    enum Aspect {
+        ASPECT_NATIVE,
+        ASPECT_SQUARE,
+        ASPECT_WINDOW
+    };
+
+    enum LegendType {
+        LEGEND_SCALAR,
+        LEGEND_VECTOR_MAGNITUDE,
+        LEGEND_VECTOR_X,
+        LEGEND_VECTOR_Y,
+        LEGEND_VECTOR_Z
+    };
+
+    typedef std::string DataSetId;
+    typedef std::string ColorMapId;
+    typedef std::string FieldId;
+
+    // Data sets
+
+    void addDataSet(const DataSetId& id);
+
+    void deleteDataSet(const DataSetId& id);
+
+    DataSet *getDataSet(const DataSetId& id);
+
+    void getDataSetNames(std::vector<std::string>& names);
+
+    bool setData(const DataSetId& id, char *data, int nbytes);
+
+    bool setDataFile(const DataSetId& id, const char *filename);
+
+    bool setDataSetActiveScalars(const DataSetId& id, const char *scalarName);
+
+    bool setDataSetActiveVectors(const DataSetId& id, const char *vectorName);
+
+    bool getScalarValueAtPixel(const DataSetId& id, int x, int y, double *value);
+
+    bool getScalarValue(const DataSetId& id, double x, double y, double z, double *value);
+
+    bool getVectorValueAtPixel(const DataSetId& id, int x, int y, double vector[3]);
+
+    bool getVectorValue(const DataSetId& id, double x, double y, double z, double vector[3]);
+
+    void setDataSetOpacity(const DataSetId& id, double opacity);
+
+    void setDataSetVisibility(const DataSetId& id, bool state);
+
+    void setUseCumulativeDataRange(bool state, bool onlyVisible = false);
+
+    bool getUseCumulativeRange();
+
+    bool setCumulativeDataRange(double *range, const char *name,
+                                DataSet::DataAttributeType type,
+                                int numComponents,
+                                int component = -1);
+
+    bool getCumulativeDataRange(double *range, const char *name,
+                                int numComponents,
+                                int component = -1);
+
+    bool getCumulativeDataRange(double *range, const char *name,
+                                DataSet::DataAttributeType type,
+                                int numComponents,
+                                int component = -1);
+
+    // Render window
+
+    /// Get the VTK render window object this Renderer uses
+    vtkRenderWindow *getRenderWindow()
+    {
+        return _renderWindow;
+    }
+
+    void setWindowSize(int width, int height);
+
+    int getWindowWidth() const;
+
+    int getWindowHeight() const;
+
+    // Camera controls
+
+    void setViewAngle(int height);
+
+    /// Return the VTK camera object this Renderer uses
+    vtkCamera *getVtkCamera()
+    {
+        if (_renderer != NULL)
+            return _renderer->GetActiveCamera();
+        else
+            return NULL;
+    }
+
+    bool isCameraMaximized()
+    {
+        return (_cameraZoomRatio == 1.0 &&
+                _cameraPan[0] == 0.0 &&
+                _cameraPan[1] == 0.0);
+    }
+
+    void getImageCameraSizes(int *imgWidthPx, int *imgHeightPx,
+                             int *_pxOffsetX = NULL, int *_pxOffsetY = NULL);
+
+    double getImageCameraAspect();
+
+    void setCameraMode(CameraMode mode);
+
+    CameraMode getCameraMode() const;
+
+    void setCameraAspect(Aspect aspect);
+
+    void resetVtkCamera(double *bounds = NULL);
+
+    void resetCamera(bool resetOrientation = true);
+
+    void resetCameraClippingRange();
+
+    bool setCameraZoomRegionPixels(int x, int y, int width, int height);
+
+    bool setCameraZoomRegion(double x, double y, double width, double height);
+
+    void getCameraZoomRegion(double xywh[4]) const;
+
+    void getScreenWorldCoords(double xywh[4]) const;
+
+    void rotateCamera(double yaw, double pitch, double roll);
+
+    void setCameraOrientation(const double quat[4], bool absolute = true);
+
+    void panCamera(double x, double y, bool absolute = true);
+
+    void zoomCamera(double z, bool absolute = true);
+
+    void setCameraOrientationAndPosition(const double position[3],
+                                         const double focalPoint[3],
+                                         const double viewUp[3]);
+
+    void getCameraOrientationAndPosition(double position[3],
+                                         double focalPoint[3],
+                                         double viewUp[3]);
+
+    void eventuallyResetCamera()
+    {
+        _needsCameraReset = true;
+    }
+
+    bool needsCameraReset()
+    {
+        return _needsCameraReset;
+    }
+
+    void eventuallyResetCameraClippingRange()
+    {
+        _needsCameraClippingRangeReset = true;
+    }
+
+    bool needsCameraClippingRangeReset()
+    {
+        return _needsCameraClippingRangeReset;
+    }
+
+    // Rendering an image
+
+    void setBackgroundColor(float color[3]);
+
+    void setClipPlane(Axis axis, double ratio, int direction);
+
+    void setUseTwoSidedLighting(bool state);
+
+    void setUseDepthPeeling(bool state);
+
+    void eventuallyRender();
+
+    bool render();
+
+    void getRenderedFrame(vtkUnsignedCharArray *imgData);
+
+    // Axes
+
+    void setAxesOrigin(double x, double y, double z, bool useCustom = true);
+
+    void setAxesAutoBounds(bool state);
+
+    void setAxesBounds(double min, double max);
+
+    void setAxesAutoRange(bool state);
+
+    void setAxisBounds(Axis axis, double min, double max);
+
+    void setAxesScale(double scale);
+
+    void setAxesRange(double min, double max);
+
+    void setAxesLabelPowerScaling(int xPow, int yPow, int zPow, bool useCustom = true);
+
+    void setAxisAutoBounds(Axis axis, bool state);
+
+    void setAxisAutoRange(Axis axis, bool state);
+
+    void setAxisScale(Axis axis, double scale);
+
+    void setAxisRange(Axis axis, double min, double max);
+
+    void setAxesFlyMode(AxesFlyMode mode);
+
+    void setAxesVisibility(bool state);
+
+    void setAxesGridVisibility(bool state);
+
+    void setAxesInnerGridVisibility(bool state);
+
+    void setAxesGridpolysVisibility(bool state);
+
+    void setAxesLabelVisibility(bool state);
+
+    void setAxesTickVisibility(bool state);
+
+    void setAxesMinorTickVisibility(bool state);
+
+    void setAxesTickPosition(AxesTickPosition pos);
+
+    void setAxesColor(double color[3], double opacity = 1.0);
+
+    void setAxesTitleColor(double color[3], double opacity = 1.0);
+
+    void setAxesLabelColor(double color[3], double opacity = 1.0);
+
+    void setAxesLinesColor(double color[3], double opacity = 1.0);
+
+    void setAxesGridlinesColor(double color[3], double opacity = 1.0);
+
+    void setAxesInnerGridlinesColor(double color[3], double opacity = 1.0);
+
+    void setAxesGridpolysColor(double color[3], double opacity = 1.0);
+
+    void setAxesLabelScaling(bool autoScale, int xpow, int ypow, int zpow);
+
+    void setAxesPixelFontSize(double screenSize);
+
+    void setAxesTitleFont(const char *fontName);
+
+    void setAxesTitleFontSize(int sz);
+
+    void setAxesTitleOrientation(double orientation);
+
+    void setAxesLabelFont(const char *fontName);
+
+    void setAxesLabelFontSize(int sz);
+
+    void setAxesLabelOrientation(double orientation);
+
+    void setAxesLabelFormat(const char *format);
+
+    void setAxisVisibility(Axis axis, bool state);
+
+    void setAxisGridVisibility(Axis axis, bool state);
+
+    void setAxisInnerGridVisibility(Axis axis, bool state);
+
+    void setAxisGridpolysVisibility(Axis axis, bool state);
+
+    void setAxisLabelVisibility(Axis axis, bool state);
+
+    void setAxisTickVisibility(Axis axis, bool state);
+
+    void setAxisMinorTickVisibility(Axis axis, bool state);
+
+    void setAxisColor(Axis axis, double color[3], double opacity = 1.0);
+
+    void setAxisTitleColor(Axis axis, double color[3], double opacity = 1.0);
+
+    void setAxisLabelColor(Axis axis, double color[3], double opacity = 1.0);
+
+    void setAxisLinesColor(Axis axis, double color[3], double opacity = 1.0);
+
+    void setAxisGridlinesColor(Axis axis, double color[3], double opacity = 1.0);
+
+    void setAxisInnerGridlinesColor(Axis axis, double color[3], double opacity = 1.0);
+
+    void setAxisGridpolysColor(Axis axis, double color[3], double opacity = 1.0);
+
+    void setAxisTitle(Axis axis, const char *title);
+
+    void setAxisUnits(Axis axis, const char *units);
+
+    void setAxisTitleFont(Axis axis, const char *fontName);
+
+    void setAxisTitleFontSize(Axis axis, int sz);
+
+    void setAxisTitleOrientation(Axis axis, double orientation);
+
+    void setAxisLabelFont(Axis axis, const char *fontName);
+
+    void setAxisLabelFontSize(Axis axis, int sz);
+
+    void setAxisLabelOrientation(Axis axis, double orientation);
+
+    void setAxisLabelFormat(Axis axis, const char *format);
+
+    void eventuallyResetAxes()
+    {
+        _needsAxesReset = true;
+    }
+
+    bool needsAxesReset()
+    {
+        return _needsAxesReset;
+    }
+
+    // Colormaps
+
+    void addColorMap(const ColorMapId& id, ColorMap *colorMap);
+
+    void deleteColorMap(const ColorMapId& id);
+
+    ColorMap *getColorMap(const ColorMapId& id);
+
+    void setColorMapNumberOfTableEntries(const ColorMapId& id, int numEntries);
+
+    bool renderColorMap(const ColorMapId& id, 
+                        const DataSetId& dataSetID,
+                        LegendType legendType,
+                        const char *fieldName,
+                        DataSet::DataAttributeType type,
+                        std::string& title,
+                        double range[2],
+                        int width, int height,
+                        bool opaque,
+                        int numLabels,
+                        vtkUnsignedCharArray *imgData);
+
+    bool renderColorMap(const ColorMapId& id, 
+                        const DataSetId& dataSetID,
+                        LegendType legendType,
+                        const char *fieldName,
+                        std::string& title,
+                        double range[2],
+                        int width, int height,
+                        bool opaque,
+                        int numLabels,
+                        vtkUnsignedCharArray *imgData);
+
+    bool renderColorMap(const ColorMapId& id, 
+                        const DataSetId& dataSetID,
+                        LegendType legendType,
+                        std::string& title,
+                        double range[2],
+                        int width, int height,
+                        bool opaque,
+                        int numLabels,
+                        vtkUnsignedCharArray *imgData);
+
+    // Generic VtkGraphicsObject methods
+
+    template<class GraphicsObject>
+    GraphicsObject *getGraphicsObject(const DataSetId& id);
+
+    template<class GraphicsObject>
+    bool addGraphicsObject(const DataSetId& id);
+
+    template<class GraphicsObject>
+    void deleteGraphicsObject(const DataSetId& id);
+
+    template<class GraphicsObject>
+    void deleteAllGraphicsObjects();
+
+    template<class GraphicsObject>
+    void mergeGraphicsObjectBounds(double *bounds, bool onlyVisible);
+
+    template<class GraphicsObject>
+    void mergeGraphicsObjectUnscaledBounds(double *bounds, bool onlyVisible);
+
+    template<class GraphicsObject>
+    void updateGraphicsObjectFieldRanges();
+
+    template<class GraphicsObject>
+    void setGraphicsObjectClippingPlanes(vtkPlaneCollection *planes);
+
+    template<class GraphicsObject>
+    void setGraphicsObjectAspect(double aspectRatio);
+
+    template<class GraphicsObject>
+    void setGraphicsObjectInterpolateBeforeMapping(const DataSetId& id, bool state);
+
+    template<class GraphicsObject>
+    void setGraphicsObjectColorMap(const DataSetId& id, const ColorMapId& colorMapId);
+
+    template<class GraphicsObject>
+    void updateGraphicsObjectColorMap(ColorMap *cmap);
+
+    template<class GraphicsObject>
+    bool graphicsObjectColorMapUsed(ColorMap *cmap);
+
+    template<class GraphicsObject>
+    void setGraphicsObjectVolumeSlice(const DataSetId& id, Axis axis, double ratio);
+
+    //   Prop/Prop3D properties
+
+    template<class GraphicsObject>
+    void setGraphicsObjectOrientation(const DataSetId& id, double quat[4]);
+
+    template<class GraphicsObject>
+    void setGraphicsObjectOrientation(const DataSetId& id, double angle, double axis[3]);
+
+    template<class GraphicsObject>
+    void setGraphicsObjectPosition(const DataSetId& id, double pos[3]);
+
+    template<class GraphicsObject>
+    void setGraphicsObjectAspect(const DataSetId& id, double aspect);
+
+    template<class GraphicsObject>
+    void setGraphicsObjectScale(const DataSetId& id, double scale[3]);
+
+    template<class GraphicsObject>
+    void setGraphicsObjectTransform(const DataSetId& id, vtkMatrix4x4 *trans);
+
+    template<class GraphicsObject>
+    void setGraphicsObjectVisibility(const DataSetId& id, bool state);
+
+    //   Actor properties
+
+    template<class GraphicsObject>
+    void setGraphicsObjectColor(const DataSetId& id, float color[3]);
+
+    template<class GraphicsObject>
+    void setGraphicsObjectEdgeVisibility(const DataSetId& id, bool state);
+
+    template<class GraphicsObject>
+    void setGraphicsObjectEdgeColor(const DataSetId& id, float color[3]);
+
+    template<class GraphicsObject>
+    void setGraphicsObjectEdgeWidth(const DataSetId& id, float edgeWidth);
+
+    template<class GraphicsObject>
+    void setGraphicsObjectAmbient(const DataSetId& id, double coeff);
+
+    template<class GraphicsObject>
+    void setGraphicsObjectDiffuse(const DataSetId& id, double coeff);
+
+    template<class GraphicsObject>
+    void setGraphicsObjectSpecular(const DataSetId& id, double coeff, double power);
+
+    template<class GraphicsObject>
+    void setGraphicsObjectLighting(const DataSetId& id, bool state);
+
+    template<class GraphicsObject>
+    void setGraphicsObjectOpacity(const DataSetId& id, double opacity);
+
+    template<class GraphicsObject>
+    void setGraphicsObjectPointSize(const DataSetId& id, float size);
+
+    template<class GraphicsObject>
+    void setGraphicsObjectWireframe(const DataSetId& id, bool state);
+
+    // Arcs
+
+    bool addArc(const DataSetId& id, double pt1[3], double pt2[3]);
+
+    void setArcResolution(const DataSetId& id, int res);
+
+    // Arrows
+
+    bool addArrow(const DataSetId& id, double tipRadius, double shaftRadius, double tipLength);
+
+    void setArrowResolution(const DataSetId& id, int resTip, int resShaft);
+
+    // Cones
+
+    bool addCone(const DataSetId& id, double radius, double height, bool cap);
+
+    void setConeResolution(const DataSetId& id, int res);
+
+    // 2D Contour plots
+
+    bool addContour2D(const DataSetId& id, int numContours);
+
+    bool addContour2D(const DataSetId& id, const std::vector<double>& contours);
+
+    void setContour2DContourField(const DataSetId& id, const char *fieldName);
+
+    void setContour2DNumContours(const DataSetId& id, int numContours);
+
+    void setContour2DContourList(const DataSetId& id, const std::vector<double>& contours);
+
+    void setContour2DColorMode(const DataSetId& id,
+                               Contour2D::ColorMode mode,
+                               const char *name, double range[2] = NULL);
+
+    void setContour2DColorMode(const DataSetId& id,
+                               Contour2D::ColorMode mode,
+                               DataSet::DataAttributeType type,
+                               const char *name, double range[2] = NULL);
+
+    // 3D Contour (isosurface) plots
+
+    bool addContour3D(const DataSetId& id, int numContours);
+
+    bool addContour3D(const DataSetId& id, const std::vector<double>& contours);
+
+    void setContour3DContourField(const DataSetId& id, const char *fieldName);
+
+    void setContour3DNumContours(const DataSetId& id, int numContours);
+
+    void setContour3DContourList(const DataSetId& id, const std::vector<double>& contours);
+
+    void setContour3DColorMode(const DataSetId& id,
+                               Contour3D::ColorMode mode,
+                               const char *name, double range[2] = NULL);
+
+    void setContour3DColorMode(const DataSetId& id,
+                               Contour3D::ColorMode mode,
+                               DataSet::DataAttributeType type,
+                               const char *name, double range[2] = NULL);
+
+    // Cutplanes
+
+    void setCutplaneOutlineVisibility(const DataSetId& id, bool state);
+
+    void setCutplaneSliceVisibility(const DataSetId& id, Axis axis, bool state);
+
+    void setCutplaneColorMode(const DataSetId& id,
+                              Cutplane::ColorMode mode,
+                              const char *name, double range[2] = NULL);
+
+    void setCutplaneColorMode(const DataSetId& id,
+                              Cutplane::ColorMode mode,
+                              DataSet::DataAttributeType type,
+                              const char *name, double range[2] = NULL);
+
+    // Cylinders
+
+    bool addCylinder(const DataSetId& id, double radius, double height, bool cap);
+
+    void setCylinderResolution(const DataSetId& id, int res);
+
+    // Disks
+
+    bool addDisk(const DataSetId& id, double innerRadius, double outerRadius);
+
+    void setDiskResolution(const DataSetId& id, int resRadial, int resCircum);
+
+    // Glyphs
+
+    bool addGlyphs(const DataSetId& id, Glyphs::GlyphShape shape);
+
+    void setGlyphsShape(const DataSetId& id, Glyphs::GlyphShape shape);
+
+    void setGlyphsOrientMode(const DataSetId& id, bool state, const char *name);
+
+    void setGlyphsColorMode(const DataSetId& id,
+                            Glyphs::ColorMode mode,
+                            const char *name,
+                            double range[2] = NULL);
+
+    void setGlyphsScalingMode(const DataSetId& id,
+                              Glyphs::ScalingMode mode,
+                              const char *name,
+                              double range[2] = NULL);
+
+    void setGlyphsNormalizeScale(const DataSetId& id, bool normalize);
+
+    void setGlyphsScaleFactor(const DataSetId& id, double scale);
+
+    // Height maps
+
+    bool addHeightMap(const DataSetId& id, int numContours, double heightScale);
+
+    bool addHeightMap(const DataSetId& id, const std::vector<double>& contours, double heightScale);
+
+    void setHeightMapHeightScale(const DataSetId& id, double scale);
+
+    void setHeightMapNumContours(const DataSetId& id, int numContours);
+
+    void setHeightMapContourList(const DataSetId& id, const std::vector<double>& contours);
+
+    void setHeightMapContourSurfaceVisibility(const DataSetId& id, bool state);
+
+    void setHeightMapContourLineVisibility(const DataSetId& id, bool state);
+
+    void setHeightMapContourLineColorMapEnabled(const DataSetId& id, bool mode);
+
+    void setHeightMapContourEdgeColor(const DataSetId& id, float color[3]);
+
+    void setHeightMapContourEdgeWidth(const DataSetId& id, float edgeWidth);
+
+    void setHeightMapColorMode(const DataSetId& id,
+                               HeightMap::ColorMode mode,
+                               const char *name, double range[2] = NULL);
+
+    void setHeightMapColorMode(const DataSetId& id,
+                               HeightMap::ColorMode mode,
+                               DataSet::DataAttributeType type,
+                               const char *name, double range[2] = NULL);
+
+
+    // Lines
+
+    bool addLine(const DataSetId& id, double pt1[3], double pt2[3]);
+
+    // Molecules
+
+    void setMoleculeAtomRadiusScale(const DataSetId& id, double scale);
+
+    void setMoleculeBondRadiusScale(const DataSetId& id, double scale);
+
+    void setMoleculeAtomScaling(const DataSetId& id, Molecule::AtomScaling scaling);
+
+    void setMoleculeAtomVisibility(const DataSetId& id, bool state);
+
+    void setMoleculeAtomLabelVisibility(const DataSetId& id, bool state);
+
+    void setMoleculeBondVisibility(const DataSetId& id, bool state);
+
+    void setMoleculeBondStyle(const DataSetId& id, Molecule::BondStyle style);
+
+    void setMoleculeBondColorMode(const DataSetId& id, Molecule::BondColorMode mode);
+
+    void setMoleculeBondColor(const DataSetId& id, float color[3]);
+
+    void setMoleculeColorMode(const DataSetId& id,
+                              Molecule::ColorMode mode,
+                              const char *name, double range[2] = NULL);
+
+    void setMoleculeColorMode(const DataSetId& id,
+                              Molecule::ColorMode mode,
+                              DataSet::DataAttributeType type,
+                              const char *name, double range[2] = NULL);
+
+    // N-sided Regular Polygons
+
+    bool addPolygon(const DataSetId& id, int numSides);
+
+    // Color-mapped surfaces
+
+    void setPseudoColorColorMode(const DataSetId& id,
+                                 PseudoColor::ColorMode mode,
+                                 const char *name, double range[2] = NULL);
+
+    void setPseudoColorColorMode(const DataSetId& id,
+                                 PseudoColor::ColorMode mode,
+                                 DataSet::DataAttributeType type,
+                                 const char *name, double range[2] = NULL);
+
+    // Spheres
+
+    void setSphereSection(const DataSetId& id, double thetaStart, double thetaEnd,
+                          double phiStart, double phiEnd);
+
+    void setSphereResolution(const DataSetId& id, int thetaRes, int phiRes);
+
+    // Streamlines
+
+    void setStreamlinesNumberOfSeedPoints(const DataSetId& id, int numPoints);
+
+    void setStreamlinesSeedToMeshPoints(const DataSetId& id);
+
+    void setStreamlinesSeedToFilledMesh(const DataSetId& id, int numPoints);
+
+    bool setStreamlinesSeedToMeshPoints(const DataSetId& id,
+                                        char *data, size_t nbytes);
+
+    bool setStreamlinesSeedToFilledMesh(const DataSetId& id,
+                                        char *data, size_t nbytes,
+                                        int numPoints);
+
+    void setStreamlinesSeedToRake(const DataSetId& id,
+                                  double start[3], double end[3],
+                                  int numPoints);
+
+    void setStreamlinesSeedToDisk(const DataSetId& id,
+                                  double center[3], double normal[3],
+                                  double radius, double innerRadius,
+                                  int numPoints);
+
+    void setStreamlinesSeedToPolygon(const DataSetId& id,
+                                     double center[3], double normal[3],
+                                     double angle, double radius,
+                                     int numSides);
+
+    void setStreamlinesSeedToFilledPolygon(const DataSetId& id,
+                                           double center[3], double normal[3],
+                                           double angle, double radius,
+                                           int numSides, int numPoints);
+
+    void setStreamlinesLength(const DataSetId& id, double length);
+
+    void setStreamlinesTypeToLines(const DataSetId& id);
+
+    void setStreamlinesTypeToTubes(const DataSetId& id, int numSides, double radius);
+
+    void setStreamlinesTypeToRibbons(const DataSetId& id, double width, double angle);
+
+    void setStreamlinesSeedVisibility(const DataSetId& id, bool state);
+
+    void setStreamlinesColorMode(const DataSetId& id,
+                                 Streamlines::ColorMode mode,
+                                 const char *name, double range[2] = NULL);
+
+    void setStreamlinesColorMode(const DataSetId& id,
+                                 Streamlines::ColorMode mode,
+                                 DataSet::DataAttributeType type,
+                                 const char *name, double range[2] = NULL);
+
+    void setStreamlinesSeedColor(const DataSetId& id, float color[3]);
+
+    // Volumes
+
+    void setVolumeSampleDistance(const DataSetId& id, double distance);
+
+    // Warps
+
+    void setWarpColorMode(const DataSetId& id,
+                          Warp::ColorMode mode,
+                          const char *name, double range[2] = NULL);
+
+    void setWarpColorMode(const DataSetId& id,
+                          Warp::ColorMode mode,
+                          DataSet::DataAttributeType type,
+                          const char *name, double range[2] = NULL);
+
+
+    void setWarpWarpScale(const DataSetId& id, double scale);
+
+private:
+    typedef std::tr1::unordered_map<DataSetId, DataSet *> DataSetHashmap;
+    typedef std::tr1::unordered_map<FieldId, double *> FieldRangeHashmap;
+    typedef std::tr1::unordered_map<ColorMapId, ColorMap *> ColorMapHashmap;
+
+    typedef std::tr1::unordered_map<DataSetId, Arc *> ArcHashmap;
+    typedef std::tr1::unordered_map<DataSetId, Arrow *> ArrowHashmap;
+    typedef std::tr1::unordered_map<DataSetId, Box *> BoxHashmap;
+    typedef std::tr1::unordered_map<DataSetId, Cone *> ConeHashmap;
+    typedef std::tr1::unordered_map<DataSetId, Contour2D *> Contour2DHashmap;
+    typedef std::tr1::unordered_map<DataSetId, Contour3D *> Contour3DHashmap;
+    typedef std::tr1::unordered_map<DataSetId, Cutplane *> CutplaneHashmap;
+    typedef std::tr1::unordered_map<DataSetId, Cylinder *> CylinderHashmap;
+    typedef std::tr1::unordered_map<DataSetId, Disk *> DiskHashmap;
+    typedef std::tr1::unordered_map<DataSetId, Glyphs *> GlyphsHashmap;
+    typedef std::tr1::unordered_map<DataSetId, Group *> GroupHashmap;
+    typedef std::tr1::unordered_map<DataSetId, HeightMap *> HeightMapHashmap;
+    typedef std::tr1::unordered_map<DataSetId, LIC *> LICHashmap;
+    typedef std::tr1::unordered_map<DataSetId, Line *> LineHashmap;
+    typedef std::tr1::unordered_map<DataSetId, Molecule *> MoleculeHashmap;
+    typedef std::tr1::unordered_map<DataSetId, Outline *> OutlineHashmap;
+    typedef std::tr1::unordered_map<DataSetId, PolyData *> PolyDataHashmap;
+    typedef std::tr1::unordered_map<DataSetId, Polygon *> PolygonHashmap;
+    typedef std::tr1::unordered_map<DataSetId, PseudoColor *> PseudoColorHashmap;
+    typedef std::tr1::unordered_map<DataSetId, Sphere *> SphereHashmap;
+    typedef std::tr1::unordered_map<DataSetId, Streamlines *> StreamlinesHashmap;
+    typedef std::tr1::unordered_map<DataSetId, Volume *> VolumeHashmap;
+    typedef std::tr1::unordered_map<DataSetId, Warp *> WarpHashmap;
+
+    void _setCameraZoomRegionPixels(int x, int y, int width, int height);
+
+    void _setCameraZoomRegion(double x, double y, double width, double height);
+
+    //static void printCameraInfo(vtkCamera *camera);
+
+    static void setCameraFromMatrix(vtkCamera *camera, vtkMatrix4x4 &mat);
+
+    static void mergeBounds(double *boundsDest, const double *bounds1, const double *bounds2);
+
+    template<class GraphicsObject>
+    std::tr1::unordered_map<DataSetId, GraphicsObject *>&getGraphicsObjectHashmap();
+
+    void setObjectAspects(double aspectRatio);
+
+    void collectBounds(double *bounds, bool onlyVisible);
+
+    void collectUnscaledBounds(double *bounds, bool onlyVisible);
+
+    void collectDataRanges();
+
+    void collectDataRanges(double *range, const char *name,
+                           DataSet::DataAttributeType type,
+                           int component, bool onlyVisible);
+
+    void clearFieldRanges();
+
+    void clearUserFieldRanges();
+
+    void initFieldRanges();
+
+    void updateFieldRanges();
+
+    void updateColorMap(ColorMap *cmap);
+
+    bool colorMapUsed(ColorMap *cmap);
+
+    void computeDisplayToWorld(double x, double y, double z, double worldPt[4]);
+
+    void computeWorldToDisplay(double x, double y, double z, double displayPt[3]);
+
+    void computeScreenWorldCoords();
+
+    bool is2D(const double bounds[6],
+              PrincipalPlane *plane,
+              double *offset) const;
+
+    void initCamera(bool initCameraMode = false);
+
+    void sceneBoundsChanged();
+
+    void initAxes();
+
+    void resetAxes(double bounds[6] = NULL);
+
+    void setAxesBounds(double bounds[6] = NULL);
+
+    void setAxesRanges();
+
+    void computeAxesScale();
+
+    void setCameraClippingPlanes();
+
+    bool _needsRedraw;
+    bool _needsAxesReset;
+    bool _needsCameraClippingRangeReset;
+    bool _needsCameraReset;
+
+    int _windowWidth, _windowHeight;
+    CameraMode _cameraMode;
+    Aspect _cameraAspect;
+    double _imgWorldOrigin[2];
+    double _imgWorldDims[2];
+    double _imgWindowWorldDims[2];
+    double _userImgWorldOrigin[2];
+    double _userImgWorldDims[2];
+    PrincipalPlane _imgCameraPlane;
+    double _imgCameraOffset;
+    double _screenWorldCoords[4];
+    double _cameraOrientation[4];
+    double _cameraZoomRatio;
+    double _cameraPan[2];
+    float _bgColor[3];
+    bool _useCumulativeRange;
+    bool _cumulativeRangeOnlyVisible;
+
+    FieldRangeHashmap _scalarPointDataRange;
+    FieldRangeHashmap _vectorPointDataRange;
+    FieldRangeHashmap _vectorCompPointDataRange[3];
+    FieldRangeHashmap _scalarCellDataRange;
+    FieldRangeHashmap _vectorCellDataRange;
+    FieldRangeHashmap _vectorCompCellDataRange[3];
+
+    FieldRangeHashmap _userScalarPointDataRange;
+    FieldRangeHashmap _userVectorPointDataRange;
+    FieldRangeHashmap _userVectorCompPointDataRange[3];
+    FieldRangeHashmap _userScalarCellDataRange;
+    FieldRangeHashmap _userVectorCellDataRange;
+    FieldRangeHashmap _userVectorCompCellDataRange[3];
+
+    bool _axesAutoBounds[3];
+    double _axesUserBounds[6];
+    AxisRangeMode _axesRangeMode[3];
+    double _axesScale[3];
+
+    ColorMapHashmap _colorMaps;
+    DataSetHashmap _dataSets;
+    ArcHashmap _arcs;
+    ArrowHashmap _arrows;
+    BoxHashmap _boxes;
+    ConeHashmap _cones;
+    Contour2DHashmap _contour2Ds;
+    Contour3DHashmap _contour3Ds;
+    CutplaneHashmap _cutplanes;
+    CylinderHashmap _cylinders;
+    DiskHashmap _disks;
+    GlyphsHashmap _glyphs;
+    GroupHashmap _groups;
+    HeightMapHashmap _heightMaps;
+    LICHashmap _lics;
+    LineHashmap _lines;
+    MoleculeHashmap _molecules;
+    OutlineHashmap _outlines;
+    PolyDataHashmap _polyDatas;
+    PolygonHashmap _polygons;
+    PseudoColorHashmap _pseudoColors;
+    SphereHashmap _spheres;
+    StreamlinesHashmap _streamlines;
+    VolumeHashmap _volumes;
+    WarpHashmap _warps;
+
+    vtkSmartPointer<vtkPlane> _cameraClipPlanes[4];
+    vtkSmartPointer<vtkPlane> _userClipPlanes[6];
+    vtkSmartPointer<vtkPlaneCollection> _activeClipPlanes;
+#ifdef USE_CUSTOM_AXES
+    vtkSmartPointer<vtkRpCubeAxesActor> _cubeAxesActor;
+#else
+    vtkSmartPointer<vtkCubeAxesActor> _cubeAxesActor;
+#endif
+    vtkSmartPointer<vtkScalarBarActor> _scalarBarActor;
+    vtkSmartPointer<vtkRenderer> _renderer;
+    vtkSmartPointer<vtkRenderer> _legendRenderer;
+    vtkSmartPointer<vtkRenderWindow> _renderWindow;
+    vtkSmartPointer<vtkRenderWindow> _legendRenderWindow;
+};
+
+}
+
+#endif
Index: /trunk/packages/vizservers/vtkvis/VtkRendererCmd.cpp
===================================================================
--- /trunk/packages/vizservers/vtkvis/VtkRendererCmd.cpp	(revision 3616)
+++ /trunk/packages/vizservers/vtkvis/VtkRendererCmd.cpp	(revision 3616)
@@ -0,0 +1,10206 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (C) 2004-2012  HUBzero Foundation, LLC
+ *
+ * Author: Leif Delgass <ldelgass@purdue.edu>
+ */
+
+#include <cstdlib>
+#include <cstdio>
+#include <cstring>
+#include <cfloat>
+#include <cerrno>
+#include <string>
+#include <sstream>
+#include <unistd.h>
+#include <sys/select.h>
+#include <sys/uio.h>
+#include <tcl.h>
+
+#include "Trace.h"
+#include "CmdProc.h"
+#include "ReadBuffer.h"
+#include "Types.h"
+#include "VtkRendererCmd.h"
+#include "VtkRenderServer.h"
+#include "VtkRenderer.h"
+#include "VtkRendererGraphicsObjs.h"
+#include "PPMWriter.h"
+#include "TGAWriter.h"
+#ifdef USE_THREADS
+#include "ResponseQueue.h"
+#endif
+
+using namespace VtkVis;
+
+static int lastCmdStatus;
+
+#ifdef USE_THREADS
+void
+VtkVis::queueResponse(ClientData clientData,
+                      const void *bytes, size_t len, 
+                      Response::AllocationType allocType,
+                      Response::ResponseType type)
+{
+    ResponseQueue *queue = (ResponseQueue *)clientData;
+
+    Response *response = new Response(type);
+    response->setMessage((unsigned char *)bytes, len, allocType);
+    queue->enqueue(response);
+}
+#else
+
+static ssize_t
+SocketWrite(const void *bytes, size_t len)
+{
+    size_t ofs = 0;
+    ssize_t bytesWritten;
+    while ((bytesWritten = write(g_fdOut, (const char *)bytes + ofs, len - ofs)) > 0) {
+        ofs += bytesWritten;
+        if (ofs == len)
+            break;
+    }
+    if (bytesWritten < 0) {
+        ERROR("write: %s", strerror(errno));
+    }
+    return bytesWritten;
+}
+
+#endif  /*USE_THREADS*/
+
+static bool
+SocketRead(char *bytes, size_t len)
+{
+    ReadBuffer::BufferStatus status;
+    status = g_inBufPtr->followingData((unsigned char *)bytes, len);
+    TRACE("followingData status: %d", status);
+    return (status == ReadBuffer::OK);
+}
+
+static int
+ExecuteCommand(Tcl_Interp *interp, Tcl_DString *dsPtr) 
+{
+    int result;
+#ifdef WANT_TRACE
+    char *str = Tcl_DStringValue(dsPtr);
+    std::string cmd(str);
+    cmd.erase(cmd.find_last_not_of(" \n\r\t")+1);
+    TRACE("command %lu: '%s'", g_stats.nCommands+1, cmd.c_str());
+#endif
+    lastCmdStatus = TCL_OK;
+    result = Tcl_EvalEx(interp, Tcl_DStringValue(dsPtr), 
+                        Tcl_DStringLength(dsPtr), 
+                        TCL_EVAL_DIRECT | TCL_EVAL_GLOBAL);
+    Tcl_DStringSetLength(dsPtr, 0);
+    if (lastCmdStatus == TCL_BREAK) {
+        return TCL_BREAK;
+    }
+    lastCmdStatus = result;
+    if (result != TCL_OK) {
+        TRACE("Error: %d", result);
+    }
+    return result;
+}
+
+static int
+GetBooleanFromObj(Tcl_Interp *interp, Tcl_Obj *objPtr, bool *boolPtr)
+{
+    int value;
+
+    if (Tcl_GetBooleanFromObj(interp, objPtr, &value) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    *boolPtr = (bool)value;
+    return TCL_OK;
+}
+
+static int
+GetFloatFromObj(Tcl_Interp *interp, Tcl_Obj *objPtr, float *valuePtr)
+{
+    double value;
+
+    if (Tcl_GetDoubleFromObj(interp, objPtr, &value) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    *valuePtr = (float)value;
+    return TCL_OK;
+}
+
+static int
+ArcAddOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+         Tcl_Obj *const *objv)
+{
+    double pt1[3];
+    double pt2[3];
+    if (Tcl_GetDoubleFromObj(interp, objv[2], &pt1[0]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[3], &pt1[1]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[4], &pt1[2]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[5], &pt2[0]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[6], &pt2[1]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[7], &pt2[2]) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    const char *name = Tcl_GetString(objv[8]);
+    if (!g_renderer->addArc(name, pt1, pt2)) {
+        Tcl_AppendResult(interp, "Failed to create arc", (char*)NULL);
+        return TCL_ERROR;
+    }
+    return TCL_OK;
+}
+
+static int
+ArcDeleteOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+             Tcl_Obj *const *objv)
+{
+    if (objc == 3) {
+        const char *name = Tcl_GetString(objv[2]);
+        g_renderer->deleteGraphicsObject<Arc>(name);
+    } else {
+        g_renderer->deleteGraphicsObject<Arc>("all");
+    }
+    return TCL_OK;
+}
+
+static int
+ArcColorOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+           Tcl_Obj *const *objv)
+{
+    float color[3];
+    if (GetFloatFromObj(interp, objv[2], &color[0]) != TCL_OK ||
+        GetFloatFromObj(interp, objv[3], &color[1]) != TCL_OK ||
+        GetFloatFromObj(interp, objv[4], &color[2]) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 6) {
+        const char *name = Tcl_GetString(objv[5]);
+        g_renderer->setGraphicsObjectColor<Arc>(name, color);
+    } else {
+        g_renderer->setGraphicsObjectColor<Arc>("all", color);
+    }
+    return TCL_OK;
+}
+
+static int
+ArcLineWidthOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+               Tcl_Obj *const *objv)
+{
+    float width;
+    if (GetFloatFromObj(interp, objv[2], &width) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 4) {
+        const char *name = Tcl_GetString(objv[3]);
+        g_renderer->setGraphicsObjectEdgeWidth<Arc>(name, width);
+    } else {
+        g_renderer->setGraphicsObjectEdgeWidth<Arc>("all", width);
+    }
+    return TCL_OK;
+}
+
+static int
+ArcOpacityOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+             Tcl_Obj *const *objv)
+{
+    double opacity;
+    if (Tcl_GetDoubleFromObj(interp, objv[2], &opacity) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 4) {
+        const char *name = Tcl_GetString(objv[3]);
+        g_renderer->setGraphicsObjectOpacity<Arc>(name, opacity);
+    } else {
+        g_renderer->setGraphicsObjectOpacity<Arc>("all", opacity);
+    }
+    return TCL_OK;
+}
+
+static int
+ArcOrientOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+            Tcl_Obj *const *objv)
+{
+    double quat[4];
+    if (Tcl_GetDoubleFromObj(interp, objv[2], &quat[0]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[3], &quat[1]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[4], &quat[2]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[5], &quat[3]) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 7) {
+        const char *name = Tcl_GetString(objv[6]);
+        g_renderer->setGraphicsObjectOrientation<Arc>(name, quat);
+    } else {
+        g_renderer->setGraphicsObjectOrientation<Arc>("all", quat);
+    }
+    return TCL_OK;
+}
+
+static int
+ArcPositionOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+              Tcl_Obj *const *objv)
+{
+    double pos[3];
+    if (Tcl_GetDoubleFromObj(interp, objv[2], &pos[0]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[3], &pos[1]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[4], &pos[2]) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 6) {
+        const char *name = Tcl_GetString(objv[5]);
+        g_renderer->setGraphicsObjectPosition<Arc>(name, pos);
+    } else {
+        g_renderer->setGraphicsObjectPosition<Arc>("all", pos);
+    }
+    return TCL_OK;
+}
+
+static int
+ArcResolutionOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                Tcl_Obj *const *objv)
+{
+    int res;
+    if (Tcl_GetIntFromObj(interp, objv[2], &res) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 4) {
+        const char *name = Tcl_GetString(objv[3]);
+        g_renderer->setArcResolution(name, res);
+    } else {
+        g_renderer->setArcResolution("all", res);
+    }
+    return TCL_OK;
+}
+
+static int
+ArcScaleOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+            Tcl_Obj *const *objv)
+{
+    double scale[3];
+    if (Tcl_GetDoubleFromObj(interp, objv[2], &scale[0]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[3], &scale[1]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[4], &scale[2]) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 6) {
+        const char *name = Tcl_GetString(objv[5]);
+        g_renderer->setGraphicsObjectScale<Arc>(name, scale);
+    } else {
+        g_renderer->setGraphicsObjectScale<Arc>("all", scale);
+    }
+    return TCL_OK;
+}
+
+static int
+ArcVisibleOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+             Tcl_Obj *const *objv)
+{
+    bool state;
+    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 4) {
+        const char *name = Tcl_GetString(objv[3]);
+        g_renderer->setGraphicsObjectVisibility<Arc>(name, state);
+    } else {
+        g_renderer->setGraphicsObjectVisibility<Arc>("all", state);
+    }
+    return TCL_OK;
+}
+
+static Rappture::CmdSpec arcOps[] = {
+    {"add",       1, ArcAddOp, 9, 9, "x1 y1 z1 x2 y2 z2 name"},
+    {"color",     1, ArcColorOp, 5, 6, "r g b ?name?"},
+    {"delete",    1, ArcDeleteOp, 2, 3, "?name?"},
+    {"linecolor", 5, ArcColorOp, 5, 6, "r g b ?name?"},
+    {"linewidth", 5, ArcLineWidthOp, 3, 4, "width ?name?"},
+    {"opacity",   2, ArcOpacityOp, 3, 4, "value ?name?"},
+    {"orient",    2, ArcOrientOp, 6, 7, "qw qx qy qz ?name?"},
+    {"pos",       2, ArcPositionOp, 5, 6, "x y z ?name?"},
+    {"resolution",1, ArcResolutionOp, 3, 4, "res ?name?"},
+    {"scale",     2, ArcScaleOp, 5, 6, "sx sy sz ?name?"},
+    {"visible",   1, ArcVisibleOp, 3, 4, "bool ?name?"}
+};
+static int nArcOps = NumCmdSpecs(arcOps);
+
+static int
+ArcCmd(ClientData clientData, Tcl_Interp *interp, int objc, 
+       Tcl_Obj *const *objv)
+{
+    Tcl_ObjCmdProc *proc;
+
+    proc = Rappture::GetOpFromObj(interp, nArcOps, arcOps,
+                                  Rappture::CMDSPEC_ARG1, objc, objv, 0);
+    if (proc == NULL) {
+        return TCL_ERROR;
+    }
+    return (*proc) (clientData, interp, objc, objv);
+}
+
+static int
+ArrowAddOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+           Tcl_Obj *const *objv)
+{
+    double tipRadius, shaftRadius, tipLength;
+    if (Tcl_GetDoubleFromObj(interp, objv[2], &tipRadius) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[3], &shaftRadius) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[4], &tipLength) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    const char *name = Tcl_GetString(objv[5]);
+    if (!g_renderer->addArrow(name, tipRadius, shaftRadius, tipLength)) {
+        Tcl_AppendResult(interp, "Failed to create arrow", (char*)NULL);
+        return TCL_ERROR;
+    }
+    return TCL_OK;
+}
+
+static int
+ArrowDeleteOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+              Tcl_Obj *const *objv)
+{
+    if (objc == 3) {
+        const char *name = Tcl_GetString(objv[2]);
+        g_renderer->deleteGraphicsObject<Arrow>(name);
+    } else {
+        g_renderer->deleteGraphicsObject<Arrow>("all");
+    }
+    return TCL_OK;
+}
+
+static int
+ArrowColorOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+             Tcl_Obj *const *objv)
+{
+    float color[3];
+    if (GetFloatFromObj(interp, objv[2], &color[0]) != TCL_OK ||
+        GetFloatFromObj(interp, objv[3], &color[1]) != TCL_OK ||
+        GetFloatFromObj(interp, objv[4], &color[2]) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 6) {
+        const char *name = Tcl_GetString(objv[5]);
+        g_renderer->setGraphicsObjectColor<Arrow>(name, color);
+    } else {
+        g_renderer->setGraphicsObjectColor<Arrow>("all", color);
+    }
+    return TCL_OK;
+}
+
+static int
+ArrowEdgeVisibilityOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                      Tcl_Obj *const *objv)
+{
+    bool state;
+    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 4) {
+        const char *name = Tcl_GetString(objv[3]);
+        g_renderer->setGraphicsObjectEdgeVisibility<Arrow>(name, state);
+    } else {
+        g_renderer->setGraphicsObjectEdgeVisibility<Arrow>("all", state);
+    }
+    return TCL_OK;
+}
+
+static int
+ArrowLightingOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                Tcl_Obj *const *objv)
+{
+    bool state;
+    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 4) {
+        const char *name = Tcl_GetString(objv[3]);
+        g_renderer->setGraphicsObjectLighting<Arrow>(name, state);
+    } else {
+        g_renderer->setGraphicsObjectLighting<Arrow>("all", state);
+    }
+    return TCL_OK;
+}
+
+static int
+ArrowLineColorOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                 Tcl_Obj *const *objv)
+{
+    float color[3];
+    if (GetFloatFromObj(interp, objv[2], &color[0]) != TCL_OK ||
+        GetFloatFromObj(interp, objv[3], &color[1]) != TCL_OK ||
+        GetFloatFromObj(interp, objv[4], &color[2]) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 6) {
+        const char *name = Tcl_GetString(objv[5]);
+        g_renderer->setGraphicsObjectEdgeColor<Arrow>(name, color);
+    } else {
+        g_renderer->setGraphicsObjectEdgeColor<Arrow>("all", color);
+    }
+    return TCL_OK;
+}
+
+static int
+ArrowLineWidthOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                 Tcl_Obj *const *objv)
+{
+    float width;
+    if (GetFloatFromObj(interp, objv[2], &width) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 4) {
+        const char *name = Tcl_GetString(objv[3]);
+        g_renderer->setGraphicsObjectEdgeWidth<Arrow>(name, width);
+    } else {
+        g_renderer->setGraphicsObjectEdgeWidth<Arrow>("all", width);
+    }
+    return TCL_OK;
+}
+
+static int
+ArrowMaterialOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                Tcl_Obj *const *objv)
+{
+    double ambient, diffuse, specCoeff, specPower;
+    if (Tcl_GetDoubleFromObj(interp, objv[2], &ambient) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[3], &diffuse) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[4], &specCoeff) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[5], &specPower) != TCL_OK) {
+        return TCL_ERROR;
+    }
+
+    if (objc == 7) {
+        const char *name = Tcl_GetString(objv[6]);
+        g_renderer->setGraphicsObjectAmbient<Arrow>(name, ambient);
+        g_renderer->setGraphicsObjectDiffuse<Arrow>(name, diffuse);
+        g_renderer->setGraphicsObjectSpecular<Arrow>(name, specCoeff, specPower);
+    } else {
+        g_renderer->setGraphicsObjectAmbient<Arrow>("all", ambient);
+        g_renderer->setGraphicsObjectDiffuse<Arrow>("all", diffuse);
+        g_renderer->setGraphicsObjectSpecular<Arrow>("all", specCoeff, specPower);
+    }
+    return TCL_OK;
+}
+
+static int
+ArrowOpacityOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+               Tcl_Obj *const *objv)
+{
+    double opacity;
+    if (Tcl_GetDoubleFromObj(interp, objv[2], &opacity) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 4) {
+        const char *name = Tcl_GetString(objv[3]);
+        g_renderer->setGraphicsObjectOpacity<Arrow>(name, opacity);
+    } else {
+        g_renderer->setGraphicsObjectOpacity<Arrow>("all", opacity);
+    }
+    return TCL_OK;
+}
+
+static int
+ArrowOrientOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+              Tcl_Obj *const *objv)
+{
+    double quat[4];
+    if (Tcl_GetDoubleFromObj(interp, objv[2], &quat[0]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[3], &quat[1]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[4], &quat[2]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[5], &quat[3]) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 7) {
+        const char *name = Tcl_GetString(objv[6]);
+        g_renderer->setGraphicsObjectOrientation<Arrow>(name, quat);
+    } else {
+        g_renderer->setGraphicsObjectOrientation<Arrow>("all", quat);
+    }
+    return TCL_OK;
+}
+
+static int
+ArrowPositionOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                Tcl_Obj *const *objv)
+{
+    double pos[3];
+    if (Tcl_GetDoubleFromObj(interp, objv[2], &pos[0]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[3], &pos[1]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[4], &pos[2]) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 6) {
+        const char *name = Tcl_GetString(objv[5]);
+        g_renderer->setGraphicsObjectPosition<Arrow>(name, pos);
+    } else {
+        g_renderer->setGraphicsObjectPosition<Arrow>("all", pos);
+    }
+    return TCL_OK;
+}
+
+static int
+ArrowResolutionOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                  Tcl_Obj *const *objv)
+{
+    int tipRes, shaftRes;
+    if (Tcl_GetIntFromObj(interp, objv[2], &tipRes) != TCL_OK ||
+        Tcl_GetIntFromObj(interp, objv[3], &shaftRes) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 4) {
+        const char *name = Tcl_GetString(objv[4]);
+        g_renderer->setArrowResolution(name, tipRes, shaftRes);
+    } else {
+        g_renderer->setArrowResolution("all", tipRes, shaftRes);
+    }
+    return TCL_OK;
+}
+
+static int
+ArrowScaleOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+             Tcl_Obj *const *objv)
+{
+    double scale[3];
+    if (Tcl_GetDoubleFromObj(interp, objv[2], &scale[0]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[3], &scale[1]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[4], &scale[2]) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 6) {
+        const char *name = Tcl_GetString(objv[5]);
+        g_renderer->setGraphicsObjectScale<Arrow>(name, scale);
+    } else {
+        g_renderer->setGraphicsObjectScale<Arrow>("all", scale);
+    }
+    return TCL_OK;
+}
+
+static int
+ArrowVisibleOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+               Tcl_Obj *const *objv)
+{
+    bool state;
+    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 4) {
+        const char *name = Tcl_GetString(objv[3]);
+        g_renderer->setGraphicsObjectVisibility<Arrow>(name, state);
+    } else {
+        g_renderer->setGraphicsObjectVisibility<Arrow>("all", state);
+    }
+    return TCL_OK;
+}
+
+static int
+ArrowWireframeOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                 Tcl_Obj *const *objv)
+{
+    bool state;
+    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 4) {
+        const char *name = Tcl_GetString(objv[3]);
+        g_renderer->setGraphicsObjectWireframe<Arrow>(name, state);
+    } else {
+        g_renderer->setGraphicsObjectWireframe<Arrow>("all", state);
+    }
+    return TCL_OK;
+}
+
+static Rappture::CmdSpec arrowOps[] = {
+    {"add",       1, ArrowAddOp, 6, 6, "tipRadius shaftRadius tipLength name"},
+    {"color",     1, ArrowColorOp, 5, 6, "r g b ?name?"},
+    {"delete",    1, ArrowDeleteOp, 2, 3, "?name?"},
+    {"edges",     1, ArrowEdgeVisibilityOp, 3, 4, "bool ?name?"},
+    {"lighting",  3, ArrowLightingOp, 3, 4, "bool ?name?"},
+    {"linecolor", 5, ArrowLineColorOp, 5, 6, "r g b ?name?"},
+    {"linewidth", 5, ArrowLineWidthOp, 3, 4, "width ?name?"},
+    {"material",  1, ArrowMaterialOp, 6, 7, "ambientCoeff diffuseCoeff specularCoeff specularPower ?name?"},
+    {"opacity",   2, ArrowOpacityOp, 3, 4, "value ?name?"},
+    {"orient",    2, ArrowOrientOp, 6, 7, "qw qx qy qz ?name?"},
+    {"pos",       2, ArrowPositionOp, 5, 6, "x y z ?name?"},
+    {"resolution",1, ArrowResolutionOp, 4, 5, "tipRes shaftRes ?name?"},
+    {"scale",     1, ArrowScaleOp, 5, 6, "sx sy sz ?name?"},
+    {"visible",   1, ArrowVisibleOp, 3, 4, "bool ?name?"},
+    {"wireframe", 1, ArrowWireframeOp, 3, 4, "bool ?name?"}
+};
+static int nArrowOps = NumCmdSpecs(arrowOps);
+
+static int
+ArrowCmd(ClientData clientData, Tcl_Interp *interp, int objc, 
+       Tcl_Obj *const *objv)
+{
+    Tcl_ObjCmdProc *proc;
+
+    proc = Rappture::GetOpFromObj(interp, nArrowOps, arrowOps,
+                                  Rappture::CMDSPEC_ARG1, objc, objv, 0);
+    if (proc == NULL) {
+        return TCL_ERROR;
+    }
+    return (*proc) (clientData, interp, objc, objv);
+}
+
+static int
+AxisAutoBoundsOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                 Tcl_Obj *const *objv)
+{
+    bool enableAuto;
+    if (GetBooleanFromObj(interp, objv[3], &enableAuto) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    const char *string = Tcl_GetString(objv[2]);
+    char c = string[0];
+    if ((c == 'x') && (strcmp(string, "x") == 0)) {
+        g_renderer->setAxisAutoBounds(X_AXIS, enableAuto);
+    } else if ((c == 'y') && (strcmp(string, "y") == 0)) {
+        g_renderer->setAxisAutoBounds(Y_AXIS, enableAuto);
+    } else if ((c == 'z') && (strcmp(string, "z") == 0)) {
+        g_renderer->setAxisAutoBounds(Z_AXIS, enableAuto);
+    } else if ((c == 'a') && (strcmp(string, "all") == 0)) {
+        g_renderer->setAxesAutoBounds(enableAuto);
+    } else {
+        Tcl_AppendResult(interp, "bad axis option \"", string,
+                         "\": should be axisName", (char*)NULL);
+        return TCL_ERROR;
+    }
+    return TCL_OK;
+}
+
+static int
+AxisAutoRangeOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                Tcl_Obj *const *objv)
+{
+    bool enableAuto;
+    if (GetBooleanFromObj(interp, objv[3], &enableAuto) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    const char *string = Tcl_GetString(objv[2]);
+    char c = string[0];
+    if ((c == 'x') && (strcmp(string, "x") == 0)) {
+        g_renderer->setAxisAutoRange(X_AXIS, enableAuto);
+    } else if ((c == 'y') && (strcmp(string, "y") == 0)) {
+        g_renderer->setAxisAutoRange(Y_AXIS, enableAuto);
+    } else if ((c == 'z') && (strcmp(string, "z") == 0)) {
+        g_renderer->setAxisAutoRange(Z_AXIS, enableAuto);
+    } else if ((c == 'a') && (strcmp(string, "all") == 0)) {
+        g_renderer->setAxesAutoRange(enableAuto);
+    } else {
+        Tcl_AppendResult(interp, "bad axis option \"", string,
+                         "\": should be axisName", (char*)NULL);
+        return TCL_ERROR;
+    }
+    return TCL_OK;
+}
+
+static int
+AxisColorOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+            Tcl_Obj *const *objv)
+{
+    double color[3];
+    if (Tcl_GetDoubleFromObj(interp, objv[3], &color[0]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[4], &color[1]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[5], &color[2]) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    double opacity = 1.0;
+    if (objc > 6) {
+        if (Tcl_GetDoubleFromObj(interp, objv[6], &opacity) != TCL_OK) {
+            return TCL_ERROR;
+        }
+    }
+    const char *string = Tcl_GetString(objv[2]);
+    char c = string[0];
+    if ((c == 'x') && (strcmp(string, "x") == 0)) {
+        g_renderer->setAxisColor(X_AXIS, color, opacity);
+    } else if ((c == 'y') && (strcmp(string, "y") == 0)) {
+        g_renderer->setAxisColor(Y_AXIS, color, opacity);
+    } else if ((c == 'z') && (strcmp(string, "z") == 0)) {
+        g_renderer->setAxisColor(Z_AXIS, color, opacity);
+    } else if ((c == 'a') && (strcmp(string, "all") == 0)) {
+        g_renderer->setAxesColor(color, opacity);
+    } else {
+        Tcl_AppendResult(interp, "bad axis option \"", string,
+                         "\": should be axisName", (char*)NULL);
+        return TCL_ERROR;
+    }
+    return TCL_OK;
+}
+
+static int
+AxisBoundsOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+             Tcl_Obj *const *objv)
+{
+    double min, max;
+    if (Tcl_GetDoubleFromObj(interp, objv[3], &min) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[4], &max) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    const char *string = Tcl_GetString(objv[2]);
+    char c = string[0];
+    if ((c == 'x') && (strcmp(string, "x") == 0)) {
+        g_renderer->setAxisBounds(X_AXIS, min, max);
+    } else if ((c == 'y') && (strcmp(string, "y") == 0)) {
+        g_renderer->setAxisBounds(Y_AXIS, min, max);
+    } else if ((c == 'z') && (strcmp(string, "z") == 0)) {
+        g_renderer->setAxisBounds(Z_AXIS, min, max);
+    } else if ((c == 'a') && (strcmp(string, "all") == 0)) {
+        g_renderer->setAxesBounds(min, max);
+    } else {
+        Tcl_AppendResult(interp, "bad axis option \"", string,
+                         "\": should be axisName", (char*)NULL);
+        return TCL_ERROR;
+    }
+    return TCL_OK;
+}
+
+static int
+AxisExponentOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+               Tcl_Obj *const *objv)
+{
+    int xPow, yPow, zPow;
+    bool useCustom = true;
+    if (Tcl_GetIntFromObj(interp, objv[2], &xPow) != TCL_OK ||
+        Tcl_GetIntFromObj(interp, objv[3], &yPow) != TCL_OK ||
+        Tcl_GetIntFromObj(interp, objv[4], &zPow) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc > 5) {
+        if (GetBooleanFromObj(interp, objv[5], &useCustom) != TCL_OK) {
+            return TCL_ERROR;
+        }
+        g_renderer->setAxesLabelPowerScaling(xPow, yPow, zPow, useCustom);
+    } else {
+        g_renderer->setAxesLabelPowerScaling(xPow, yPow, zPow);
+    }
+    return TCL_OK;
+}
+
+static int
+AxisFlyModeOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+              Tcl_Obj *const *objv)
+{
+    const char *string = Tcl_GetString(objv[2]);
+    char c = string[0];
+    Renderer::AxesFlyMode mode;
+    if ((c == 's') && (strcmp(string, "static_edges") == 0)) {
+        mode = Renderer::FLY_STATIC_EDGES;
+    } else if ((c == 's') && (strcmp(string, "static_triad") == 0)) {
+        mode = Renderer::FLY_STATIC_TRIAD;
+    } else if ((c == 'o') && (strcmp(string, "outer_edges") == 0)) {
+        mode = Renderer::FLY_OUTER_EDGES;
+    } else if ((c == 'f') && (strcmp(string, "furthest_triad") == 0)) {
+        mode = Renderer::FLY_FURTHEST_TRIAD;
+    } else if ((c == 'c') && (strcmp(string, "closest_triad") == 0)) {
+        mode = Renderer::FLY_CLOSEST_TRIAD;
+    } else {
+        Tcl_AppendResult(interp, "bad axis flymode option \"", string,
+                         "\": should be static_edges, static_triad, outer_edges, furthest_triad, or closest_triad", (char*)NULL);
+        return TCL_ERROR;
+    }
+    g_renderer->setAxesFlyMode(mode);
+    return TCL_OK;
+}
+
+static int
+AxisFontSizeOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+               Tcl_Obj *const *objv)
+{
+    double screenSize;
+    if (Tcl_GetDoubleFromObj(interp, objv[2], &screenSize) != TCL_OK) {
+        return TCL_ERROR;
+    }
+
+    g_renderer->setAxesPixelFontSize(screenSize);
+    return TCL_OK;
+}
+
+static int
+AxisGridOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+           Tcl_Obj *const *objv)
+{
+    bool visible;
+    if (GetBooleanFromObj(interp, objv[3], &visible) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    const char *string = Tcl_GetString(objv[2]);
+    char c = string[0];
+    if ((c == 'x') && (strcmp(string, "x") == 0)) {
+        g_renderer->setAxisGridVisibility(X_AXIS, visible);
+    } else if ((c == 'y') && (strcmp(string, "y") == 0)) {
+        g_renderer->setAxisGridVisibility(Y_AXIS, visible);
+    } else if ((c == 'z') && (strcmp(string, "z") == 0)) {
+        g_renderer->setAxisGridVisibility(Z_AXIS, visible);
+    } else if ((c == 'a') && (strcmp(string, "all") == 0)) {
+        g_renderer->setAxesGridVisibility(visible);
+    } else {
+        Tcl_AppendResult(interp, "bad axis option \"", string,
+                         "\": should be axisName", (char*)NULL);
+        return TCL_ERROR;
+    }
+    return TCL_OK;
+}
+
+static int
+AxisGridColorOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                Tcl_Obj *const *objv)
+{
+    double color[3];
+    if (Tcl_GetDoubleFromObj(interp, objv[3], &color[0]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[4], &color[1]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[5], &color[2]) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    double opacity = 1.0;
+    if (objc > 6) {
+        if (Tcl_GetDoubleFromObj(interp, objv[6], &opacity) != TCL_OK) {
+            return TCL_ERROR;
+        }
+    }
+    const char *string = Tcl_GetString(objv[2]);
+    char c = string[0];
+    if ((c == 'x') && (strcmp(string, "x") == 0)) {
+        g_renderer->setAxisGridlinesColor(X_AXIS, color, opacity);
+    } else if ((c == 'y') && (strcmp(string, "y") == 0)) {
+        g_renderer->setAxisGridlinesColor(Y_AXIS, color, opacity);
+    } else if ((c == 'z') && (strcmp(string, "z") == 0)) {
+        g_renderer->setAxisGridlinesColor(Z_AXIS, color, opacity);
+    } else if ((c == 'a') && (strcmp(string, "all") == 0)) {
+        g_renderer->setAxesGridlinesColor(color, opacity);
+    } else {
+        Tcl_AppendResult(interp, "bad axis option \"", string,
+                         "\": should be axisName", (char*)NULL);
+        return TCL_ERROR;
+    }
+    return TCL_OK;
+}
+
+static int
+AxisGridpolysOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                Tcl_Obj *const *objv)
+{
+    bool visible;
+    if (GetBooleanFromObj(interp, objv[3], &visible) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    const char *string = Tcl_GetString(objv[2]);
+    char c = string[0];
+    if ((c == 'x') && (strcmp(string, "x") == 0)) {
+        g_renderer->setAxisGridpolysVisibility(X_AXIS, visible);
+    } else if ((c == 'y') && (strcmp(string, "y") == 0)) {
+        g_renderer->setAxisGridpolysVisibility(Y_AXIS, visible);
+    } else if ((c == 'z') && (strcmp(string, "z") == 0)) {
+        g_renderer->setAxisGridpolysVisibility(Z_AXIS, visible);
+    } else if ((c == 'a') && (strcmp(string, "all") == 0)) {
+        g_renderer->setAxesGridpolysVisibility(visible);
+    } else {
+        Tcl_AppendResult(interp, "bad axis option \"", string,
+                         "\": should be axisName", (char*)NULL);
+        return TCL_ERROR;
+    }
+    return TCL_OK;
+}
+
+static int
+AxisGridpolysColorOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                     Tcl_Obj *const *objv)
+{
+    double color[3];
+    if (Tcl_GetDoubleFromObj(interp, objv[3], &color[0]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[4], &color[1]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[5], &color[2]) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    double opacity = 1.0;
+    if (objc > 6) {
+        if (Tcl_GetDoubleFromObj(interp, objv[6], &opacity) != TCL_OK) {
+            return TCL_ERROR;
+        }
+    }
+    const char *string = Tcl_GetString(objv[2]);
+    char c = string[0];
+    if ((c == 'x') && (strcmp(string, "x") == 0)) {
+        g_renderer->setAxisGridpolysColor(X_AXIS, color, opacity);
+    } else if ((c == 'y') && (strcmp(string, "y") == 0)) {
+        g_renderer->setAxisGridpolysColor(Y_AXIS, color, opacity);
+    } else if ((c == 'z') && (strcmp(string, "z") == 0)) {
+        g_renderer->setAxisGridpolysColor(Z_AXIS, color, opacity);
+    } else if ((c == 'a') && (strcmp(string, "all") == 0)) {
+        g_renderer->setAxesGridpolysColor(color, opacity);
+    } else {
+        Tcl_AppendResult(interp, "bad axis option \"", string,
+                         "\": should be axisName", (char*)NULL);
+        return TCL_ERROR;
+    }
+    return TCL_OK;
+}
+
+static int
+AxisInnerGridOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                Tcl_Obj *const *objv)
+{
+    bool visible;
+    if (GetBooleanFromObj(interp, objv[3], &visible) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    const char *string = Tcl_GetString(objv[2]);
+    char c = string[0];
+    if ((c == 'x') && (strcmp(string, "x") == 0)) {
+        g_renderer->setAxisInnerGridVisibility(X_AXIS, visible);
+    } else if ((c == 'y') && (strcmp(string, "y") == 0)) {
+        g_renderer->setAxisInnerGridVisibility(Y_AXIS, visible);
+    } else if ((c == 'z') && (strcmp(string, "z") == 0)) {
+        g_renderer->setAxisInnerGridVisibility(Z_AXIS, visible);
+    } else if ((c == 'a') && (strcmp(string, "all") == 0)) {
+        g_renderer->setAxesInnerGridVisibility(visible);
+    } else {
+        Tcl_AppendResult(interp, "bad axis option \"", string,
+                         "\": should be axisName", (char*)NULL);
+        return TCL_ERROR;
+    }
+    return TCL_OK;
+}
+
+static int
+AxisInnerGridColorOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                     Tcl_Obj *const *objv)
+{
+    double color[3];
+    if (Tcl_GetDoubleFromObj(interp, objv[3], &color[0]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[4], &color[1]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[5], &color[2]) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    double opacity = 1.0;
+    if (objc > 6) {
+        if (Tcl_GetDoubleFromObj(interp, objv[6], &opacity) != TCL_OK) {
+            return TCL_ERROR;
+        }
+    }
+    const char *string = Tcl_GetString(objv[2]);
+    char c = string[0];
+    if ((c == 'x') && (strcmp(string, "x") == 0)) {
+        g_renderer->setAxisInnerGridlinesColor(X_AXIS, color, opacity);
+    } else if ((c == 'y') && (strcmp(string, "y") == 0)) {
+        g_renderer->setAxisInnerGridlinesColor(Y_AXIS, color, opacity);
+    } else if ((c == 'z') && (strcmp(string, "z") == 0)) {
+        g_renderer->setAxisInnerGridlinesColor(Z_AXIS, color, opacity);
+    } else if ((c == 'a') && (strcmp(string, "all") == 0)) {
+        g_renderer->setAxesInnerGridlinesColor(color, opacity);
+    } else {
+        Tcl_AppendResult(interp, "bad axis option \"", string,
+                         "\": should be axisName", (char*)NULL);
+        return TCL_ERROR;
+    }
+    return TCL_OK;
+}
+
+static int
+AxisLabelColorOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                 Tcl_Obj *const *objv)
+{
+    double color[3];
+    if (Tcl_GetDoubleFromObj(interp, objv[3], &color[0]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[4], &color[1]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[5], &color[2]) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    double opacity = 1.0;
+    if (objc > 6) {
+        if (Tcl_GetDoubleFromObj(interp, objv[6], &opacity) != TCL_OK) {
+            return TCL_ERROR;
+        }
+    }
+    const char *string = Tcl_GetString(objv[2]);
+    char c = string[0];
+    if ((c == 'x') && (strcmp(string, "x") == 0)) {
+        g_renderer->setAxisLabelColor(X_AXIS, color, opacity);
+    } else if ((c == 'y') && (strcmp(string, "y") == 0)) {
+        g_renderer->setAxisLabelColor(Y_AXIS, color, opacity);
+    } else if ((c == 'z') && (strcmp(string, "z") == 0)) {
+        g_renderer->setAxisLabelColor(Z_AXIS, color, opacity);
+    } else if ((c == 'a') && (strcmp(string, "all") == 0)) {
+        g_renderer->setAxesLabelColor(color, opacity);
+    } else {
+        Tcl_AppendResult(interp, "bad axis option \"", string,
+                         "\": should be axisName", (char*)NULL);
+        return TCL_ERROR;
+    }
+    return TCL_OK;
+}
+
+static int
+AxisLabelFontOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                Tcl_Obj *const *objv)
+{
+    const char *fontName = Tcl_GetString(objv[3]);
+
+    const char *string = Tcl_GetString(objv[2]);
+    char c = string[0];
+    if ((c == 'x') && (strcmp(string, "x") == 0)) {
+        g_renderer->setAxisLabelFont(X_AXIS, fontName);
+    } else if ((c == 'y') && (strcmp(string, "y") == 0)) {
+        g_renderer->setAxisLabelFont(Y_AXIS, fontName);
+    } else if ((c == 'z') && (strcmp(string, "z") == 0)) {
+        g_renderer->setAxisLabelFont(Z_AXIS, fontName);
+    } else if ((c == 'a') && (strcmp(string, "all") == 0)) {
+        g_renderer->setAxesLabelFont(fontName);
+    } else {
+        Tcl_AppendResult(interp, "bad axis option \"", string,
+                         "\": should be axisName", (char*)NULL);
+        return TCL_ERROR;
+    }
+    return TCL_OK;
+}
+
+static int
+AxisLabelFormatOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                  Tcl_Obj *const *objv)
+{
+    const char *format = Tcl_GetString(objv[3]);
+
+    const char *string = Tcl_GetString(objv[2]);
+    char c = string[0];
+    if ((c == 'x') && (strcmp(string, "x") == 0)) {
+        g_renderer->setAxisLabelFormat(X_AXIS, format);
+    } else if ((c == 'y') && (strcmp(string, "y") == 0)) {
+        g_renderer->setAxisLabelFormat(Y_AXIS, format);
+    } else if ((c == 'z') && (strcmp(string, "z") == 0)) {
+        g_renderer->setAxisLabelFormat(Z_AXIS, format);
+    } else if ((c == 'a') && (strcmp(string, "all") == 0)) {
+        g_renderer->setAxesLabelFormat(format);
+    } else {
+        Tcl_AppendResult(interp, "bad axis option \"", string,
+                         "\": should be axisName", (char*)NULL);
+        return TCL_ERROR;
+    }
+    return TCL_OK;
+}
+
+static int
+AxisLabelFontSizeOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                    Tcl_Obj *const *objv)
+{
+    int fontSize;
+    if (Tcl_GetIntFromObj(interp, objv[3], &fontSize) != TCL_OK) {
+        return TCL_ERROR;
+    }
+
+    const char *string = Tcl_GetString(objv[2]);
+    char c = string[0];
+    if ((c == 'x') && (strcmp(string, "x") == 0)) {
+        g_renderer->setAxisLabelFontSize(X_AXIS, fontSize);
+    } else if ((c == 'y') && (strcmp(string, "y") == 0)) {
+        g_renderer->setAxisLabelFontSize(Y_AXIS, fontSize);
+    } else if ((c == 'z') && (strcmp(string, "z") == 0)) {
+        g_renderer->setAxisLabelFontSize(Z_AXIS, fontSize);
+    } else if ((c == 'a') && (strcmp(string, "all") == 0)) {
+        g_renderer->setAxesLabelFontSize(fontSize);
+    } else {
+        Tcl_AppendResult(interp, "bad axis option \"", string,
+                         "\": should be axisName", (char*)NULL);
+        return TCL_ERROR;
+    }
+    return TCL_OK;
+}
+
+static int
+AxisLabelOrientationOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                       Tcl_Obj *const *objv)
+{
+    double rot;
+    if (Tcl_GetDoubleFromObj(interp, objv[3], &rot) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    const char *string = Tcl_GetString(objv[2]);
+    char c = string[0];
+    if ((c == 'x') && (strcmp(string, "x") == 0)) {
+        g_renderer->setAxisLabelOrientation(X_AXIS, rot);
+    } else if ((c == 'y') && (strcmp(string, "y") == 0)) {
+        g_renderer->setAxisLabelOrientation(Y_AXIS, rot);
+    } else if ((c == 'z') && (strcmp(string, "z") == 0)) {
+        g_renderer->setAxisLabelOrientation(Z_AXIS, rot);
+    } else if ((c == 'a') && (strcmp(string, "all") == 0)) {
+        g_renderer->setAxesLabelOrientation(rot);
+    } else {
+        Tcl_AppendResult(interp, "bad axis option \"", string,
+                         "\": should be axisName", (char*)NULL);
+        return TCL_ERROR;
+    }
+    return TCL_OK;
+}
+
+static int
+AxisLabelScaleOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                 Tcl_Obj *const *objv)
+{
+    bool autoScale;
+    int xpow, ypow, zpow;
+    if (GetBooleanFromObj(interp, objv[3], &autoScale) != TCL_OK ||
+        Tcl_GetIntFromObj(interp, objv[4], &xpow) != TCL_OK ||
+        Tcl_GetIntFromObj(interp, objv[5], &ypow) != TCL_OK ||
+        Tcl_GetIntFromObj(interp, objv[6], &zpow) != TCL_OK) {
+        return TCL_ERROR;
+    }
+
+    g_renderer->setAxesLabelScaling(autoScale, xpow, ypow, zpow);
+    return TCL_OK;
+}
+
+static int
+AxisLabelsVisibleOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                    Tcl_Obj *const *objv)
+{
+    bool visible;
+    if (GetBooleanFromObj(interp, objv[3], &visible) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    const char *string = Tcl_GetString(objv[2]);
+    char c = string[0];
+    if ((c == 'x') && (strcmp(string, "x") == 0)) {
+        g_renderer->setAxisLabelVisibility(X_AXIS, visible);
+    } else if ((c == 'y') && (strcmp(string, "y") == 0)) {
+        g_renderer->setAxisLabelVisibility(Y_AXIS, visible);
+    } else if ((c == 'z') && (strcmp(string, "z") == 0)) {
+        g_renderer->setAxisLabelVisibility(Z_AXIS, visible);
+    } else if ((c == 'a') && (strcmp(string, "all") == 0)) {
+        g_renderer->setAxesLabelVisibility(visible);
+    } else {
+        Tcl_AppendResult(interp, "bad axis option \"", string,
+                         "\": should be axisName", (char*)NULL);
+        return TCL_ERROR;
+    }
+    return TCL_OK;
+}
+
+static int
+AxisLineColorOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                Tcl_Obj *const *objv)
+{
+    double color[3];
+    if (Tcl_GetDoubleFromObj(interp, objv[3], &color[0]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[4], &color[1]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[5], &color[2]) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    double opacity = 1.0;
+    if (objc > 6) {
+        if (Tcl_GetDoubleFromObj(interp, objv[6], &opacity) != TCL_OK) {
+            return TCL_ERROR;
+        }
+    }
+    const char *string = Tcl_GetString(objv[2]);
+    char c = string[0];
+    if ((c == 'x') && (strcmp(string, "x") == 0)) {
+        g_renderer->setAxisLinesColor(X_AXIS, color, opacity);
+    } else if ((c == 'y') && (strcmp(string, "y") == 0)) {
+        g_renderer->setAxisLinesColor(Y_AXIS, color, opacity);
+    } else if ((c == 'z') && (strcmp(string, "z") == 0)) {
+        g_renderer->setAxisLinesColor(Z_AXIS, color, opacity);
+    } else if ((c == 'a') && (strcmp(string, "all") == 0)) {
+        g_renderer->setAxesLinesColor(color, opacity);
+    } else {
+        Tcl_AppendResult(interp, "bad axis option \"", string,
+                         "\": should be axisName", (char*)NULL);
+        return TCL_ERROR;
+    }
+    return TCL_OK;
+}
+
+static int
+AxisNameOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+           Tcl_Obj *const *objv)
+{
+    const char *title = Tcl_GetString(objv[3]);
+    if (strlen(title) > 30) {
+        Tcl_AppendResult(interp, "axis name \"", title,
+                         "\" is too long", (char*)NULL);
+        return TCL_ERROR;
+    }
+    const char *string = Tcl_GetString(objv[2]);
+    char c = string[0];
+    if ((c == 'x') && (strcmp(string, "x") == 0)) {
+        g_renderer->setAxisTitle(X_AXIS, title);
+    } else if ((c == 'y') && (strcmp(string, "y") == 0)) {
+        g_renderer->setAxisTitle(Y_AXIS, title);
+    } else if ((c == 'z') && (strcmp(string, "z") == 0)) {
+        g_renderer->setAxisTitle(Z_AXIS, title);
+    } else {
+        Tcl_AppendResult(interp, "bad axis option \"", string,
+                         "\": should be axisName", (char*)NULL);
+        return TCL_ERROR;
+    }
+    return TCL_OK;
+}
+
+static int
+AxisOriginOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+             Tcl_Obj *const *objv)
+{
+    double x, y, z;
+    bool useCustom = true;
+    if (Tcl_GetDoubleFromObj(interp, objv[2], &x) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[3], &y) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[4], &z) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc > 5) {
+        if (GetBooleanFromObj(interp, objv[5], &useCustom) != TCL_OK) {
+            return TCL_ERROR;
+        }
+        g_renderer->setAxesOrigin(x, y, z, useCustom);
+    } else {
+        g_renderer->setAxesOrigin(x, y, z);
+    }
+    return TCL_OK;
+}
+
+static int
+AxisRangeOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+            Tcl_Obj *const *objv)
+{
+    double min, max;
+    if (Tcl_GetDoubleFromObj(interp, objv[3], &min) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[4], &max) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    const char *string = Tcl_GetString(objv[2]);
+    char c = string[0];
+    if ((c == 'x') && (strcmp(string, "x") == 0)) {
+        g_renderer->setAxisRange(X_AXIS, min, max);
+    } else if ((c == 'y') && (strcmp(string, "y") == 0)) {
+        g_renderer->setAxisRange(Y_AXIS, min, max);
+    } else if ((c == 'z') && (strcmp(string, "z") == 0)) {
+        g_renderer->setAxisRange(Z_AXIS, min, max);
+    } else if ((c == 'a') && (strcmp(string, "all") == 0)) {
+        g_renderer->setAxesRange(min, max);
+    } else {
+        Tcl_AppendResult(interp, "bad axis option \"", string,
+                         "\": should be axisName", (char*)NULL);
+        return TCL_ERROR;
+    }
+    return TCL_OK;
+}
+
+static int
+AxisScaleOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+            Tcl_Obj *const *objv)
+{
+    double scale;
+    if (Tcl_GetDoubleFromObj(interp, objv[3], &scale) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    const char *string = Tcl_GetString(objv[2]);
+    char c = string[0];
+    if ((c == 'x') && (strcmp(string, "x") == 0)) {
+        g_renderer->setAxisScale(X_AXIS, scale);
+    } else if ((c == 'y') && (strcmp(string, "y") == 0)) {
+        g_renderer->setAxisScale(Y_AXIS, scale);
+    } else if ((c == 'z') && (strcmp(string, "z") == 0)) {
+        g_renderer->setAxisScale(Z_AXIS, scale);
+    } else if ((c == 'a') && (strcmp(string, "all") == 0)) {
+        g_renderer->setAxesScale(scale);
+    } else {
+        Tcl_AppendResult(interp, "bad axis option \"", string,
+                         "\": should be axisName", (char*)NULL);
+        return TCL_ERROR;
+    }
+    return TCL_OK;
+}
+
+static int
+AxisTicksVisibleOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                   Tcl_Obj *const *objv)
+{
+    bool visible;
+    if (GetBooleanFromObj(interp, objv[3], &visible) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    const char *string = Tcl_GetString(objv[2]);
+    char c = string[0];
+    if ((c == 'x') && (strcmp(string, "x") == 0)) {
+        g_renderer->setAxisTickVisibility(X_AXIS, visible);
+    } else if ((c == 'y') && (strcmp(string, "y") == 0)) {
+        g_renderer->setAxisTickVisibility(Y_AXIS, visible);
+    } else if ((c == 'z') && (strcmp(string, "z") == 0)) {
+        g_renderer->setAxisTickVisibility(Z_AXIS, visible);
+    } else if ((c == 'a') && (strcmp(string, "all") == 0)) {
+        g_renderer->setAxesTickVisibility(visible);
+    } else {
+        Tcl_AppendResult(interp, "bad axis option \"", string,
+                         "\": should be axisName", (char*)NULL);
+        return TCL_ERROR;
+    }
+    return TCL_OK;
+}
+
+static int
+AxisMinorTicksVisibleOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                        Tcl_Obj *const *objv)
+{
+    bool visible;
+    if (GetBooleanFromObj(interp, objv[3], &visible) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    const char *string = Tcl_GetString(objv[2]);
+    char c = string[0];
+    if ((c == 'x') && (strcmp(string, "x") == 0)) {
+        g_renderer->setAxisMinorTickVisibility(X_AXIS, visible);
+    } else if ((c == 'y') && (strcmp(string, "y") == 0)) {
+        g_renderer->setAxisMinorTickVisibility(Y_AXIS, visible);
+    } else if ((c == 'z') && (strcmp(string, "z") == 0)) {
+        g_renderer->setAxisMinorTickVisibility(Z_AXIS, visible);
+    } else if ((c == 'a') && (strcmp(string, "all") == 0)) {
+        g_renderer->setAxesMinorTickVisibility(visible);
+    } else {
+        Tcl_AppendResult(interp, "bad axis option \"", string,
+                         "\": should be axisName", (char*)NULL);
+        return TCL_ERROR;
+    }
+    return TCL_OK;
+}
+
+static int
+AxisTickPositionOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                   Tcl_Obj *const *objv)
+{
+    const char *string = Tcl_GetString(objv[2]);
+    char c = string[0];
+    if ((c == 'i') && (strcmp(string, "inside") == 0)) {
+        g_renderer->setAxesTickPosition(Renderer::TICKS_INSIDE);
+    } else if ((c == 'o') && (strcmp(string, "outside") == 0)) {
+        g_renderer->setAxesTickPosition(Renderer::TICKS_OUTSIDE);
+    } else if ((c == 'b') && (strcmp(string, "both") == 0)) {
+        g_renderer->setAxesTickPosition(Renderer::TICKS_BOTH);
+    } else {
+        Tcl_AppendResult(interp, "bad axis option \"", string,
+                         "\": should be inside, outside or both", (char*)NULL);
+        return TCL_ERROR;
+    }
+    return TCL_OK;
+}
+
+static int
+AxisTitleColorOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                 Tcl_Obj *const *objv)
+{
+    double color[3];
+    if (Tcl_GetDoubleFromObj(interp, objv[3], &color[0]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[4], &color[1]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[5], &color[2]) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    double opacity = 1.0;
+    if (objc > 6) {
+        if (Tcl_GetDoubleFromObj(interp, objv[6], &opacity) != TCL_OK) {
+            return TCL_ERROR;
+        }
+    }
+    const char *string = Tcl_GetString(objv[2]);
+    char c = string[0];
+    if ((c == 'x') && (strcmp(string, "x") == 0)) {
+        g_renderer->setAxisTitleColor(X_AXIS, color, opacity);
+    } else if ((c == 'y') && (strcmp(string, "y") == 0)) {
+        g_renderer->setAxisTitleColor(Y_AXIS, color, opacity);
+    } else if ((c == 'z') && (strcmp(string, "z") == 0)) {
+        g_renderer->setAxisTitleColor(Z_AXIS, color, opacity);
+    } else if ((c == 'a') && (strcmp(string, "all") == 0)) {
+        g_renderer->setAxesTitleColor(color, opacity);
+    } else {
+        Tcl_AppendResult(interp, "bad axis option \"", string,
+                         "\": should be axisName", (char*)NULL);
+        return TCL_ERROR;
+    }
+    return TCL_OK;
+}
+
+static int
+AxisTitleFontOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                Tcl_Obj *const *objv)
+{
+    const char *fontName = Tcl_GetString(objv[3]);
+
+    const char *string = Tcl_GetString(objv[2]);
+    char c = string[0];
+    if ((c == 'x') && (strcmp(string, "x") == 0)) {
+        g_renderer->setAxisTitleFont(X_AXIS, fontName);
+    } else if ((c == 'y') && (strcmp(string, "y") == 0)) {
+        g_renderer->setAxisTitleFont(Y_AXIS, fontName);
+    } else if ((c == 'z') && (strcmp(string, "z") == 0)) {
+        g_renderer->setAxisTitleFont(Z_AXIS, fontName);
+    } else if ((c == 'a') && (strcmp(string, "all") == 0)) {
+        g_renderer->setAxesTitleFont(fontName);
+    } else {
+        Tcl_AppendResult(interp, "bad axis option \"", string,
+                         "\": should be axisName", (char*)NULL);
+        return TCL_ERROR;
+    }
+    return TCL_OK;
+}
+
+static int
+AxisTitleFontSizeOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                    Tcl_Obj *const *objv)
+{
+    int fontSize;
+    if (Tcl_GetIntFromObj(interp, objv[3], &fontSize) != TCL_OK) {
+        return TCL_ERROR;
+    }
+
+    const char *string = Tcl_GetString(objv[2]);
+    char c = string[0];
+    if ((c == 'x') && (strcmp(string, "x") == 0)) {
+        g_renderer->setAxisTitleFontSize(X_AXIS, fontSize);
+    } else if ((c == 'y') && (strcmp(string, "y") == 0)) {
+        g_renderer->setAxisTitleFontSize(Y_AXIS, fontSize);
+    } else if ((c == 'z') && (strcmp(string, "z") == 0)) {
+        g_renderer->setAxisTitleFontSize(Z_AXIS, fontSize);
+    } else if ((c == 'a') && (strcmp(string, "all") == 0)) {
+        g_renderer->setAxesTitleFontSize(fontSize);
+    } else {
+        Tcl_AppendResult(interp, "bad axis option \"", string,
+                         "\": should be axisName", (char*)NULL);
+        return TCL_ERROR;
+    }
+    return TCL_OK;
+}
+
+static int
+AxisTitleOrientationOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                       Tcl_Obj *const *objv)
+{
+    double rot;
+    if (Tcl_GetDoubleFromObj(interp, objv[3], &rot) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    const char *string = Tcl_GetString(objv[2]);
+    char c = string[0];
+    if ((c == 'x') && (strcmp(string, "x") == 0)) {
+        g_renderer->setAxisTitleOrientation(X_AXIS, rot);
+    } else if ((c == 'y') && (strcmp(string, "y") == 0)) {
+        g_renderer->setAxisTitleOrientation(Y_AXIS, rot);
+    } else if ((c == 'z') && (strcmp(string, "z") == 0)) {
+        g_renderer->setAxisTitleOrientation(Z_AXIS, rot);
+    } else if ((c == 'a') && (strcmp(string, "all") == 0)) {
+        g_renderer->setAxesTitleOrientation(rot);
+    } else {
+        Tcl_AppendResult(interp, "bad axis option \"", string,
+                         "\": should be axisName", (char*)NULL);
+        return TCL_ERROR;
+    }
+    return TCL_OK;
+}
+
+static int
+AxisUnitsOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+            Tcl_Obj *const *objv)
+{
+    const char *units = Tcl_GetString(objv[3]);
+    if (strlen(units) > 10) {
+        Tcl_AppendResult(interp, "axis units name \"", units,
+                         "\" is too long", (char*)NULL);
+        return TCL_ERROR;
+    }
+    const char *string = Tcl_GetString(objv[2]);
+    char c = string[0];
+    if ((c == 'x') && (strcmp(string, "x") == 0)) {
+        g_renderer->setAxisUnits(X_AXIS, units);
+    } else if ((c == 'y') && (strcmp(string, "y") == 0)) {
+        g_renderer->setAxisUnits(Y_AXIS, units);
+    } else if ((c == 'z') && (strcmp(string, "z") == 0)) {
+        g_renderer->setAxisUnits(Z_AXIS, units);
+    } else if ((c == 'a') && (strcmp(string, "all") == 0)) {
+        g_renderer->setAxisUnits(X_AXIS, units);
+        g_renderer->setAxisUnits(Y_AXIS, units);
+        g_renderer->setAxisUnits(Z_AXIS, units);
+    } else {
+        Tcl_AppendResult(interp, "bad axis option \"", string,
+                         "\": should be axisName", (char*)NULL);
+        return TCL_ERROR;
+    }
+    return TCL_OK;
+}
+
+static int
+AxisVisibleOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+              Tcl_Obj *const *objv)
+{
+    bool visible;
+    if (GetBooleanFromObj(interp, objv[3], &visible) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    const char *string = Tcl_GetString(objv[2]);
+    char c = string[0];
+    if ((c == 'x') && (strcmp(string, "x") == 0)) {
+        g_renderer->setAxisVisibility(X_AXIS, visible);
+    } else if ((c == 'y') && (strcmp(string, "y") == 0)) {
+        g_renderer->setAxisVisibility(Y_AXIS, visible);
+    } else if ((c == 'z') && (strcmp(string, "z") == 0)) {
+        g_renderer->setAxisVisibility(Z_AXIS, visible);
+    } else if ((c == 'a') && (strcmp(string, "all") == 0)) {
+        g_renderer->setAxesVisibility(visible);
+    } else {
+        Tcl_AppendResult(interp, "bad axis option \"", string,
+                         "\": should be axisName", (char*)NULL);
+        return TCL_ERROR;
+    }
+    return TCL_OK;
+}
+
+static Rappture::CmdSpec axisOps[] = {
+    {"autobounds", 5, AxisAutoBoundsOp, 4, 4, "axis bool"},
+    {"autorange",  5, AxisAutoRangeOp, 4, 4, "axis bool"},
+    {"bounds",     1, AxisBoundsOp, 5, 5, "axis min max"},
+    {"color",      1, AxisColorOp, 6, 7, "axis r g b ?opacity?"},
+    {"exp",        1, AxisExponentOp, 5, 6, "xPow yPow zPow ?useCustom?"},
+    {"flymode",    2, AxisFlyModeOp, 3, 3, "mode"},
+    {"fontsz",     2, AxisFontSizeOp, 3, 3, "fontPixelSize"},
+    {"gpcolor",    3, AxisGridpolysColorOp, 6, 7, "axis r g b ?opacity?"},
+    {"gpolys",     3, AxisGridpolysOp, 4, 4, "axis bool"},
+    {"grcolor",    3, AxisGridColorOp, 6, 7, "axis r g b ?opacity?"},
+    {"grid",       3, AxisGridOp, 4, 4, "axis bool"},
+    {"igcolor",    3, AxisInnerGridColorOp, 6, 7, "axis r g b ?opacity?"},
+    {"igrid",      3, AxisInnerGridOp, 4, 4, "axis bool"},
+    {"labels",     2, AxisLabelsVisibleOp, 4, 4, "axis bool"},
+    {"lcolor",     2, AxisLabelColorOp, 6, 7, "axis r g b ?opacity?"},
+    {"lfont",      4, AxisLabelFontOp, 4, 4, "axis font"},
+    {"lformat",    4, AxisLabelFormatOp, 4, 4, "axis format"},
+    {"lfsize",     3, AxisLabelFontSizeOp, 4, 4, "axis fontSize"},
+    {"linecolor",  2, AxisLineColorOp, 6, 7, "axis r g b ?opacity?"},
+    {"lrot",       2, AxisLabelOrientationOp, 4, 4, "axis rot"},
+    {"lscale",     2, AxisLabelScaleOp, 7, 7, "axis bool xpow ypow zpow"},
+    {"minticks",   1, AxisMinorTicksVisibleOp, 4, 4, "axis bool"},
+    {"name",       1, AxisNameOp, 4, 4, "axis title"},
+    {"origin",     1, AxisOriginOp, 5, 6, "x y z ?useCustom?"},
+    {"range",      1, AxisRangeOp, 5, 5, "axis min max"},
+    {"scale",      1, AxisScaleOp, 4, 4, "axis scale"},
+    {"tcolor",     2, AxisTitleColorOp, 6, 7, "axis r g b ?opacity?"},
+    {"tfont",      3, AxisTitleFontOp, 4, 4, "axis font"},
+    {"tfsize",     3, AxisTitleFontSizeOp, 4, 4, "axis fontSize"},
+    {"tickpos",    5, AxisTickPositionOp, 3, 3, "position"},
+    {"ticks",      5, AxisTicksVisibleOp, 4, 4, "axis bool"},
+    {"trot",       2, AxisTitleOrientationOp, 4, 4, "axis rot"},
+    {"units",      1, AxisUnitsOp, 4, 4, "axis units"},
+    {"visible",    1, AxisVisibleOp, 4, 4, "axis bool"}
+};
+static int nAxisOps = NumCmdSpecs(axisOps);
+
+static int
+AxisCmd(ClientData clientData, Tcl_Interp *interp, int objc, 
+        Tcl_Obj *const *objv)
+{
+    Tcl_ObjCmdProc *proc;
+
+    proc = Rappture::GetOpFromObj(interp, nAxisOps, axisOps,
+                                  Rappture::CMDSPEC_ARG1, objc, objv, 0);
+    if (proc == NULL) {
+        return TCL_ERROR;
+    }
+    return (*proc) (clientData, interp, objc, objv);
+}
+
+static int
+BoxAddOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+         Tcl_Obj *const *objv)
+{
+    const char *name = Tcl_GetString(objv[2]);
+    if (!g_renderer->addGraphicsObject<Box>(name)) {
+        Tcl_AppendResult(interp, "Failed to create box", (char*)NULL);
+        return TCL_ERROR;
+    }
+    return TCL_OK;
+}
+
+static int
+BoxDeleteOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+            Tcl_Obj *const *objv)
+{
+    if (objc == 3) {
+        const char *name = Tcl_GetString(objv[2]);
+        g_renderer->deleteGraphicsObject<Box>(name);
+    } else {
+        g_renderer->deleteGraphicsObject<Box>("all");
+    }
+    return TCL_OK;
+}
+
+static int
+BoxColorOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+           Tcl_Obj *const *objv)
+{
+    float color[3];
+    if (GetFloatFromObj(interp, objv[2], &color[0]) != TCL_OK ||
+        GetFloatFromObj(interp, objv[3], &color[1]) != TCL_OK ||
+        GetFloatFromObj(interp, objv[4], &color[2]) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 6) {
+        const char *name = Tcl_GetString(objv[5]);
+        g_renderer->setGraphicsObjectColor<Box>(name, color);
+    } else {
+        g_renderer->setGraphicsObjectColor<Box>("all", color);
+    }
+    return TCL_OK;
+}
+
+static int
+BoxEdgeVisibilityOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                    Tcl_Obj *const *objv)
+{
+    bool state;
+    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 4) {
+        const char *name = Tcl_GetString(objv[3]);
+        g_renderer->setGraphicsObjectEdgeVisibility<Box>(name, state);
+    } else {
+        g_renderer->setGraphicsObjectEdgeVisibility<Box>("all", state);
+    }
+    return TCL_OK;
+}
+
+static int
+BoxLightingOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+              Tcl_Obj *const *objv)
+{
+    bool state;
+    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 4) {
+        const char *name = Tcl_GetString(objv[3]);
+        g_renderer->setGraphicsObjectLighting<Box>(name, state);
+    } else {
+        g_renderer->setGraphicsObjectLighting<Box>("all", state);
+    }
+    return TCL_OK;
+}
+
+static int
+BoxLineColorOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+               Tcl_Obj *const *objv)
+{
+    float color[3];
+    if (GetFloatFromObj(interp, objv[2], &color[0]) != TCL_OK ||
+        GetFloatFromObj(interp, objv[3], &color[1]) != TCL_OK ||
+        GetFloatFromObj(interp, objv[4], &color[2]) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 6) {
+        const char *name = Tcl_GetString(objv[5]);
+        g_renderer->setGraphicsObjectEdgeColor<Box>(name, color);
+    } else {
+        g_renderer->setGraphicsObjectEdgeColor<Box>("all", color);
+    }
+    return TCL_OK;
+}
+
+static int
+BoxLineWidthOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+               Tcl_Obj *const *objv)
+{
+    float width;
+    if (GetFloatFromObj(interp, objv[2], &width) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 4) {
+        const char *name = Tcl_GetString(objv[3]);
+        g_renderer->setGraphicsObjectEdgeWidth<Box>(name, width);
+    } else {
+        g_renderer->setGraphicsObjectEdgeWidth<Box>("all", width);
+    }
+    return TCL_OK;
+}
+
+static int
+BoxMaterialOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+              Tcl_Obj *const *objv)
+{
+    double ambient, diffuse, specCoeff, specPower;
+    if (Tcl_GetDoubleFromObj(interp, objv[2], &ambient) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[3], &diffuse) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[4], &specCoeff) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[5], &specPower) != TCL_OK) {
+        return TCL_ERROR;
+    }
+
+    if (objc == 7) {
+        const char *name = Tcl_GetString(objv[6]);
+        g_renderer->setGraphicsObjectAmbient<Box>(name, ambient);
+        g_renderer->setGraphicsObjectDiffuse<Box>(name, diffuse);
+        g_renderer->setGraphicsObjectSpecular<Box>(name, specCoeff, specPower);
+    } else {
+        g_renderer->setGraphicsObjectAmbient<Box>("all", ambient);
+        g_renderer->setGraphicsObjectDiffuse<Box>("all", diffuse);
+        g_renderer->setGraphicsObjectSpecular<Box>("all", specCoeff, specPower);
+    }
+    return TCL_OK;
+}
+
+static int
+BoxOpacityOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+             Tcl_Obj *const *objv)
+{
+    double opacity;
+    if (Tcl_GetDoubleFromObj(interp, objv[2], &opacity) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 4) {
+        const char *name = Tcl_GetString(objv[3]);
+        g_renderer->setGraphicsObjectOpacity<Box>(name, opacity);
+    } else {
+        g_renderer->setGraphicsObjectOpacity<Box>("all", opacity);
+    }
+    return TCL_OK;
+}
+
+static int
+BoxOrientOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+            Tcl_Obj *const *objv)
+{
+    double quat[4];
+    if (Tcl_GetDoubleFromObj(interp, objv[2], &quat[0]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[3], &quat[1]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[4], &quat[2]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[5], &quat[3]) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 7) {
+        const char *name = Tcl_GetString(objv[6]);
+        g_renderer->setGraphicsObjectOrientation<Box>(name, quat);
+    } else {
+        g_renderer->setGraphicsObjectOrientation<Box>("all", quat);
+    }
+    return TCL_OK;
+}
+
+static int
+BoxPositionOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+              Tcl_Obj *const *objv)
+{
+    double pos[3];
+    if (Tcl_GetDoubleFromObj(interp, objv[2], &pos[0]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[3], &pos[1]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[4], &pos[2]) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 6) {
+        const char *name = Tcl_GetString(objv[5]);
+        g_renderer->setGraphicsObjectPosition<Box>(name, pos);
+    } else {
+        g_renderer->setGraphicsObjectPosition<Box>("all", pos);
+    }
+    return TCL_OK;
+}
+
+static int
+BoxScaleOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+           Tcl_Obj *const *objv)
+{
+    double scale[3];
+    if (Tcl_GetDoubleFromObj(interp, objv[2], &scale[0]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[3], &scale[1]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[4], &scale[2]) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 6) {
+        const char *name = Tcl_GetString(objv[5]);
+        g_renderer->setGraphicsObjectScale<Box>(name, scale);
+    } else {
+        g_renderer->setGraphicsObjectScale<Box>("all", scale);
+    }
+    return TCL_OK;
+}
+
+static int
+BoxVisibleOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+             Tcl_Obj *const *objv)
+{
+    bool state;
+    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 4) {
+        const char *name = Tcl_GetString(objv[3]);
+        g_renderer->setGraphicsObjectVisibility<Box>(name, state);
+    } else {
+        g_renderer->setGraphicsObjectVisibility<Box>("all", state);
+    }
+    return TCL_OK;
+}
+
+static int
+BoxWireframeOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+               Tcl_Obj *const *objv)
+{
+    bool state;
+    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 4) {
+        const char *name = Tcl_GetString(objv[3]);
+        g_renderer->setGraphicsObjectWireframe<Box>(name, state);
+    } else {
+        g_renderer->setGraphicsObjectWireframe<Box>("all", state);
+    }
+    return TCL_OK;
+}
+
+static Rappture::CmdSpec boxOps[] = {
+    {"add",       1, BoxAddOp, 3, 3, "name"},
+    {"color",     1, BoxColorOp, 5, 6, "r g b ?name?"},
+    {"delete",    1, BoxDeleteOp, 2, 3, "?name?"},
+    {"edges",     1, BoxEdgeVisibilityOp, 3, 4, "bool ?name?"},
+    {"lighting",  3, BoxLightingOp, 3, 4, "bool ?name?"},
+    {"linecolor", 5, BoxLineColorOp, 5, 6, "r g b ?name?"},
+    {"linewidth", 5, BoxLineWidthOp, 3, 4, "width ?name?"},
+    {"material",  1, BoxMaterialOp, 6, 7, "ambientCoeff diffuseCoeff specularCoeff specularPower ?name?"},
+    {"opacity",   2, BoxOpacityOp, 3, 4, "value ?name?"},
+    {"orient",    2, BoxOrientOp, 6, 7, "qw qx qy qz ?name?"},
+    {"pos",       2, BoxPositionOp, 5, 6, "x y z ?name?"},
+    {"scale",     1, BoxScaleOp, 5, 6, "sx sy sz ?name?"},
+    {"visible",   1, BoxVisibleOp, 3, 4, "bool ?name?"},
+    {"wireframe", 1, BoxWireframeOp, 3, 4, "bool ?name?"}
+};
+static int nBoxOps = NumCmdSpecs(boxOps);
+
+static int
+BoxCmd(ClientData clientData, Tcl_Interp *interp, int objc, 
+       Tcl_Obj *const *objv)
+{
+    Tcl_ObjCmdProc *proc;
+
+    proc = Rappture::GetOpFromObj(interp, nBoxOps, boxOps,
+                                  Rappture::CMDSPEC_ARG1, objc, objv, 0);
+    if (proc == NULL) {
+        return TCL_ERROR;
+    }
+    return (*proc) (clientData, interp, objc, objv);
+}
+
+static int
+CameraAspectOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+               Tcl_Obj *const *objv)
+{
+    Renderer::Aspect aspect;
+    const char *string = Tcl_GetString(objv[2]);
+    if ((strcmp(string, "native") == 0)) {
+        aspect = Renderer::ASPECT_NATIVE;
+    } else if ((strcmp(string, "square") == 0)) {
+        aspect = Renderer::ASPECT_SQUARE;
+    } else if ((strcmp(string, "window") == 0)) {
+        aspect = Renderer::ASPECT_WINDOW;
+    } else {
+        Tcl_AppendResult(interp, "bad camera aspect option \"", string,
+                         "\": should be native, square or window", (char*)NULL);
+        return TCL_ERROR;
+    }
+    g_renderer->setCameraAspect(aspect);
+    return TCL_OK;
+}
+
+static int
+CameraModeOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+             Tcl_Obj *const *objv)
+{
+    Renderer::CameraMode mode;
+    const char *string = Tcl_GetString(objv[2]);
+    if ((strcmp(string, "persp") == 0)) {
+        mode = Renderer::PERSPECTIVE;
+    } else if ((strcmp(string, "ortho") == 0)) {
+        mode = Renderer::ORTHO;
+    } else if ((strcmp(string, "image") == 0)) {
+        mode = Renderer::IMAGE;
+    } else {
+        Tcl_AppendResult(interp, "bad camera mode option \"", string,
+                         "\": should be persp, ortho or image", (char*)NULL);
+        return TCL_ERROR;
+    }
+    g_renderer->setCameraMode(mode);
+    return TCL_OK;
+}
+
+static int
+CameraGetOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+            Tcl_Obj *const *objv)
+{
+    double pos[3];
+    double focalPt[3];
+    double viewUp[3];
+
+    g_renderer->getCameraOrientationAndPosition(pos, focalPt, viewUp);
+
+    char buf[256];
+    snprintf(buf, sizeof(buf), "nv>camera set %.12e %.12e %.12e %.12e %.12e %.12e %.12e %.12e %.12e\n", 
+             pos[0], pos[1], pos[2], focalPt[0], focalPt[1], focalPt[2], viewUp[0], viewUp[1], viewUp[2]);
+
+#ifdef USE_THREADS
+    queueResponse(clientData, buf, strlen(buf), Response::VOLATILE);
+#else 
+    ssize_t bytesWritten = SocketWrite(buf, strlen(buf));
+    if (bytesWritten < 0) {
+        return TCL_ERROR;
+    }
+#endif
+    return TCL_OK;
+}
+
+static int
+CameraOrientOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+               Tcl_Obj *const *objv)
+{
+    double quat[4];
+
+    if (Tcl_GetDoubleFromObj(interp, objv[2], &quat[0]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[3], &quat[1]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[4], &quat[2]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[5], &quat[3]) != TCL_OK) {
+        return TCL_ERROR;
+    }
+
+    g_renderer->setCameraOrientation(quat);
+    return TCL_OK;
+}
+
+static int
+CameraOrthoOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+              Tcl_Obj *const *objv)
+{
+    const char *string = Tcl_GetString(objv[2]);
+
+    if (string[0] == 'p' && strcmp(string, "pixel") == 0) {
+        int x, y, width, height;
+        if (Tcl_GetIntFromObj(interp, objv[3], &x) != TCL_OK ||
+            Tcl_GetIntFromObj(interp, objv[4], &y) != TCL_OK ||
+            Tcl_GetIntFromObj(interp, objv[5], &width) != TCL_OK ||
+            Tcl_GetIntFromObj(interp, objv[6], &height) != TCL_OK) {
+            return TCL_ERROR;
+        }
+        if (!g_renderer->setCameraZoomRegionPixels(x, y, width, height)) {
+            Tcl_AppendResult(interp, "Camera mode is not image", (char*)NULL);
+            return TCL_ERROR;
+        }
+    } else if (string[0] == 'w' && strcmp(string, "world") == 0) {
+        double x, y, width, height;
+        if (Tcl_GetDoubleFromObj(interp, objv[3], &x) != TCL_OK ||
+            Tcl_GetDoubleFromObj(interp, objv[4], &y) != TCL_OK ||
+            Tcl_GetDoubleFromObj(interp, objv[5], &width) != TCL_OK ||
+            Tcl_GetDoubleFromObj(interp, objv[6], &height) != TCL_OK) {
+            return TCL_ERROR;
+        }
+        if (!g_renderer->setCameraZoomRegion(x, y, width, height)) {
+            Tcl_AppendResult(interp, "Camera mode is not image", (char*)NULL);
+            return TCL_ERROR;
+        }
+    } else {
+        Tcl_AppendResult(interp, "bad camera ortho option \"", string,
+                         "\": should be pixel or world", (char*)NULL);
+        return TCL_ERROR;
+    }
+
+    return TCL_OK;
+}
+
+static int
+CameraPanOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+            Tcl_Obj *const *objv)
+{
+    double x, y;
+
+    if (Tcl_GetDoubleFromObj(interp, objv[2], &x) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[3], &y) != TCL_OK) {
+        return TCL_ERROR;
+    }
+
+    g_renderer->panCamera(x, y);
+    return TCL_OK;
+}
+
+static int
+CameraResetOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+              Tcl_Obj *const *objv)
+{
+    if (objc == 3) {
+        const char *string = Tcl_GetString(objv[2]);
+        char c = string[0];
+        if ((c != 'a') || (strcmp(string, "all") != 0)) {
+            Tcl_AppendResult(interp, "bad camera reset option \"", string,
+                         "\": should be all", (char*)NULL);
+            return TCL_ERROR;
+        }
+        g_renderer->resetCamera(true);
+    } else {
+        g_renderer->resetCamera(false);
+    }
+    return TCL_OK;
+}
+
+static int
+CameraRotateOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+               Tcl_Obj *const *objv)
+{
+    double yaw, pitch, roll;
+
+    if (Tcl_GetDoubleFromObj(interp, objv[2], &yaw) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[3], &pitch) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[4], &roll) != TCL_OK) {
+        return TCL_ERROR;
+    }
+
+    g_renderer->rotateCamera(yaw, pitch, roll);
+    return TCL_OK;
+}
+
+static int
+CameraSetOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+            Tcl_Obj *const *objv)
+{
+    double pos[3];
+    double focalPt[3];
+    double viewUp[3];
+
+    if (Tcl_GetDoubleFromObj(interp, objv[2], &pos[0]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[3], &pos[1]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[4], &pos[2]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[5], &focalPt[0]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[6], &focalPt[1]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[7], &focalPt[2]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[8], &viewUp[0]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[9], &viewUp[1]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[10], &viewUp[2]) != TCL_OK) {
+        return TCL_ERROR;
+    }
+
+    g_renderer->setCameraOrientationAndPosition(pos, focalPt, viewUp);
+    return TCL_OK;
+}
+
+static int
+CameraZoomOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+            Tcl_Obj *const *objv)
+{
+    double z;
+
+    if (Tcl_GetDoubleFromObj(interp, objv[2], &z) != TCL_OK) {
+        return TCL_ERROR;
+    }
+
+    g_renderer->zoomCamera(z);
+    return TCL_OK;
+}
+
+static Rappture::CmdSpec cameraOps[] = {
+    {"aspect", 1, CameraAspectOp, 3, 3, "aspect"},
+    {"get",    1, CameraGetOp, 2, 2, ""},
+    {"mode",   1, CameraModeOp, 3, 3, "mode"},
+    {"orient", 3, CameraOrientOp, 6, 6, "qw qx qy qz"},
+    {"ortho",  1, CameraOrthoOp, 7, 7, "coordMode x y width height"},
+    {"pan",    1, CameraPanOp, 4, 4, "panX panY"},
+    {"reset",  2, CameraResetOp, 2, 3, "?all?"},
+    {"rotate", 2, CameraRotateOp, 5, 5, "angle angle angle"},
+    {"set",    1, CameraSetOp, 11, 11, "posX posY posZ focalPtX focalPtY focalPtZ viewUpX viewUpY viewUpZ"},
+    {"zoom",   1, CameraZoomOp, 3, 3, "zoomAmount"}
+};
+static int nCameraOps = NumCmdSpecs(cameraOps);
+
+static int
+CameraCmd(ClientData clientData, Tcl_Interp *interp, int objc, 
+          Tcl_Obj *const *objv)
+{
+    Tcl_ObjCmdProc *proc;
+
+    proc = Rappture::GetOpFromObj(interp, nCameraOps, cameraOps,
+                                  Rappture::CMDSPEC_ARG1, objc, objv, 0);
+    if (proc == NULL) {
+        return TCL_ERROR;
+    }
+    return (*proc) (clientData, interp, objc, objv);
+}
+
+static int
+ClientInfoCmd(ClientData clientData, Tcl_Interp *interp, int objc, 
+              Tcl_Obj *const *objv)
+{
+    Tcl_DString ds;
+    Tcl_Obj *objPtr, *listObjPtr, **items;
+    int numItems;
+    char buf[BUFSIZ];
+    const char *string;
+    int length;
+    int result;
+    static bool first = true;
+
+    /* Use the initial client key value pairs as the parts for a generating
+     * a unique file name. */
+    int fd = VtkVis::getStatsFile(interp, objv[1]);
+    if (fd < 0) {
+	Tcl_AppendResult(interp, "can't open stats file: ", 
+                         Tcl_PosixError(interp), (char *)NULL);
+	return TCL_ERROR;
+    }
+    listObjPtr = Tcl_NewListObj(0, (Tcl_Obj **)NULL);
+    Tcl_IncrRefCount(listObjPtr);
+    if (first) {
+        first = false;
+        objPtr = Tcl_NewStringObj("render_start", 12);
+        Tcl_ListObjAppendElement(interp, listObjPtr, objPtr);
+        /* server */
+        objPtr = Tcl_NewStringObj("server", 6);
+        Tcl_ListObjAppendElement(interp, listObjPtr, objPtr);
+        objPtr = Tcl_NewStringObj("vtkvis", 6);
+        Tcl_ListObjAppendElement(interp, listObjPtr, objPtr);
+        /* pid */
+        objPtr = Tcl_NewStringObj("pid", 3);
+        Tcl_ListObjAppendElement(interp, listObjPtr, objPtr);
+        Tcl_ListObjAppendElement(interp, listObjPtr, Tcl_NewIntObj(getpid()));
+        /* machine */
+        objPtr = Tcl_NewStringObj("machine", 7);
+        Tcl_ListObjAppendElement(interp, listObjPtr, objPtr);
+        gethostname(buf, BUFSIZ-1);
+        buf[BUFSIZ-1] = '\0';
+        objPtr = Tcl_NewStringObj(buf, -1);
+        Tcl_ListObjAppendElement(interp, listObjPtr, objPtr);
+    } else {
+        objPtr = Tcl_NewStringObj("render_info", 11);
+        Tcl_ListObjAppendElement(interp, listObjPtr, objPtr);
+    }
+    /* date */
+    Tcl_ListObjAppendElement(interp, listObjPtr, Tcl_NewStringObj("date", 4));
+    strcpy(buf, ctime(&VtkVis::g_stats.start.tv_sec));
+    buf[strlen(buf) - 1] = '\0';
+    Tcl_ListObjAppendElement(interp, listObjPtr, Tcl_NewStringObj(buf, -1));
+    /* date_secs */
+    Tcl_ListObjAppendElement(interp, listObjPtr, 
+                             Tcl_NewStringObj("date_secs", 9));
+    Tcl_ListObjAppendElement(interp, listObjPtr, 
+                             Tcl_NewLongObj(VtkVis::g_stats.start.tv_sec));
+    /* Client arguments. */
+    if (Tcl_ListObjGetElements(interp, objv[1], &numItems, &items) != TCL_OK) {
+	return TCL_ERROR;
+    }
+    for (int i = 0; i < numItems; i++) {
+        Tcl_ListObjAppendElement(interp, listObjPtr, items[i]);
+    }
+    Tcl_DStringInit(&ds);
+    string = Tcl_GetStringFromObj(listObjPtr, &length);
+    Tcl_DStringAppend(&ds, string, length);
+    Tcl_DStringAppend(&ds, "\n", 1);
+    result = VtkVis::writeToStatsFile(fd, Tcl_DStringValue(&ds), 
+                                      Tcl_DStringLength(&ds));
+    Tcl_DStringFree(&ds);
+    Tcl_DecrRefCount(listObjPtr);
+    return result;
+}
+
+static int
+ColorMapAddOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+              Tcl_Obj *const *objv)
+{
+    const char *name = Tcl_GetString(objv[2]);
+    int cmapc, omapc;
+    Tcl_Obj **cmapv = NULL;
+    Tcl_Obj **omapv = NULL;
+
+    if (Tcl_ListObjGetElements(interp, objv[3], &cmapc, &cmapv) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if ((cmapc % 4) != 0) {
+        Tcl_AppendResult(interp, "wrong # elements in colormap: should be ",
+                         "{ value r g b ... }", (char*)NULL);
+        return TCL_ERROR;
+    }
+
+    ColorMap *colorMap = new ColorMap(name);
+    colorMap->setNumberOfTableEntries(256);
+
+    for (int i = 0; i < cmapc; i += 4) {
+        double val[4];
+        for (int j = 0; j < 4; j++) {
+            if (Tcl_GetDoubleFromObj(interp, cmapv[i+j], &val[j]) != TCL_OK) {
+                delete colorMap;
+                return TCL_ERROR;
+            }
+            if ((val[j] < 0.0) || (val[j] > 1.0)) {
+                Tcl_AppendResult(interp, "bad colormap value \"",
+                                 Tcl_GetString(cmapv[i+j]),
+                                 "\": should be in the range [0,1]", (char*)NULL);
+                delete colorMap;
+                return TCL_ERROR;
+            }
+        }
+        ColorMap::ControlPoint cp;
+        cp.value = val[0];
+        for (int c = 0; c < 3; c++) {
+            cp.color[c] = val[c+1];
+        }
+        colorMap->addControlPoint(cp);
+    }
+
+    if (Tcl_ListObjGetElements(interp, objv[4], &omapc, &omapv) != TCL_OK) {
+        delete colorMap;
+        return TCL_ERROR;
+    }
+    if ((omapc % 2) != 0) {
+        Tcl_AppendResult(interp, "wrong # elements in opacitymap: should be ",
+                         "{ value alpha ... }", (char*)NULL);
+        delete colorMap;
+        return TCL_ERROR;
+    }
+    for (int i = 0; i < omapc; i += 2) {
+        double val[2];
+        for (int j = 0; j < 2; j++) {
+            if (Tcl_GetDoubleFromObj(interp, omapv[i+j], &val[j]) != TCL_OK) {
+                delete colorMap;
+                return TCL_ERROR;
+            }
+            if ((val[j] < 0.0) || (val[j] > 1.0)) {
+                Tcl_AppendResult(interp, "bad opacitymap value \"",
+                                 Tcl_GetString(omapv[i+j]),
+                                 "\": should be in the range [0,1]", (char*)NULL);
+                delete colorMap;
+                return TCL_ERROR;
+            }
+        }
+        ColorMap::OpacityControlPoint ocp;
+        ocp.value = val[0];
+        ocp.alpha = val[1];
+        colorMap->addOpacityControlPoint(ocp);
+    }
+
+    colorMap->build();
+    g_renderer->addColorMap(name, colorMap);
+    return TCL_OK;
+}
+
+static int
+ColorMapDeleteOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                 Tcl_Obj *const *objv)
+{
+    if (objc == 3) {
+        const char *name = Tcl_GetString(objv[2]);
+        g_renderer->deleteColorMap(name);
+    } else {
+        g_renderer->deleteColorMap("all");
+    }
+    return TCL_OK;
+}
+
+static int
+ColorMapNumTableEntriesOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                          Tcl_Obj *const *objv)
+{
+    int numEntries;
+    if (Tcl_GetIntFromObj(interp, objv[2], &numEntries) != TCL_OK) {
+        const char *str = Tcl_GetString(objv[2]);
+        if (strcmp(str, "default") == 0) {
+            numEntries = -1;
+        } else {
+            Tcl_AppendResult(interp, "bad colormap resolution value \"", str,
+                             "\": should be a positive integer or \"default\"", (char*)NULL);
+            return TCL_ERROR;
+        }
+    } else if (numEntries < 1) {
+        Tcl_AppendResult(interp, "bad colormap resolution value \"", Tcl_GetString(objv[2]),
+                         "\": should be a positive integer or \"default\"", (char*)NULL);
+        return TCL_ERROR;
+    }
+    if (objc == 4) {
+        const char *name = Tcl_GetString(objv[3]);
+
+        g_renderer->setColorMapNumberOfTableEntries(name, numEntries);
+    } else {
+        g_renderer->setColorMapNumberOfTableEntries("all", numEntries);
+    }
+    return TCL_OK;
+}
+
+static Rappture::CmdSpec colorMapOps[] = {
+    {"add",    1, ColorMapAddOp,             5, 5, "colorMapName colormap alphamap"},
+    {"delete", 1, ColorMapDeleteOp,          2, 3, "?colorMapName?"},
+    {"res",    1, ColorMapNumTableEntriesOp, 3, 4, "numTableEntries ?colorMapName?"}
+};
+static int nColorMapOps = NumCmdSpecs(colorMapOps);
+
+static int
+ColorMapCmd(ClientData clientData, Tcl_Interp *interp, int objc, 
+            Tcl_Obj *const *objv)
+{
+    Tcl_ObjCmdProc *proc;
+
+    proc = Rappture::GetOpFromObj(interp, nColorMapOps, colorMapOps,
+                                  Rappture::CMDSPEC_ARG1, objc, objv, 0);
+    if (proc == NULL) {
+        return TCL_ERROR;
+    }
+    return (*proc) (clientData, interp, objc, objv);
+}
+
+static int
+ConeAddOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+          Tcl_Obj *const *objv)
+{
+    double radius, height;
+    bool cap;
+    if (Tcl_GetDoubleFromObj(interp, objv[2], &radius) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[3], &height) != TCL_OK ||
+        GetBooleanFromObj(interp, objv[4], &cap) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    const char *name = Tcl_GetString(objv[5]);
+    if (!g_renderer->addCone(name, radius, height, cap)) {
+        Tcl_AppendResult(interp, "Failed to create cone", (char*)NULL);
+        return TCL_ERROR;
+    }
+    return TCL_OK;
+}
+
+static int
+ConeDeleteOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+             Tcl_Obj *const *objv)
+{
+    if (objc == 3) {
+        const char *name = Tcl_GetString(objv[2]);
+        g_renderer->deleteGraphicsObject<Cone>(name);
+    } else {
+        g_renderer->deleteGraphicsObject<Cone>("all");
+    }
+    return TCL_OK;
+}
+
+static int
+ConeColorOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+            Tcl_Obj *const *objv)
+{
+    float color[3];
+    if (GetFloatFromObj(interp, objv[2], &color[0]) != TCL_OK ||
+        GetFloatFromObj(interp, objv[3], &color[1]) != TCL_OK ||
+        GetFloatFromObj(interp, objv[4], &color[2]) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 6) {
+        const char *name = Tcl_GetString(objv[5]);
+        g_renderer->setGraphicsObjectColor<Cone>(name, color);
+    } else {
+        g_renderer->setGraphicsObjectColor<Cone>("all", color);
+    }
+    return TCL_OK;
+}
+
+static int
+ConeEdgeVisibilityOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                     Tcl_Obj *const *objv)
+{
+    bool state;
+    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 4) {
+        const char *name = Tcl_GetString(objv[3]);
+        g_renderer->setGraphicsObjectEdgeVisibility<Cone>(name, state);
+    } else {
+        g_renderer->setGraphicsObjectEdgeVisibility<Cone>("all", state);
+    }
+    return TCL_OK;
+}
+
+static int
+ConeLightingOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+               Tcl_Obj *const *objv)
+{
+    bool state;
+    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 4) {
+        const char *name = Tcl_GetString(objv[3]);
+        g_renderer->setGraphicsObjectLighting<Cone>(name, state);
+    } else {
+        g_renderer->setGraphicsObjectLighting<Cone>("all", state);
+    }
+    return TCL_OK;
+}
+
+static int
+ConeLineColorOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                Tcl_Obj *const *objv)
+{
+    float color[3];
+    if (GetFloatFromObj(interp, objv[2], &color[0]) != TCL_OK ||
+        GetFloatFromObj(interp, objv[3], &color[1]) != TCL_OK ||
+        GetFloatFromObj(interp, objv[4], &color[2]) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 6) {
+        const char *name = Tcl_GetString(objv[5]);
+        g_renderer->setGraphicsObjectEdgeColor<Cone>(name, color);
+    } else {
+        g_renderer->setGraphicsObjectEdgeColor<Cone>("all", color);
+    }
+    return TCL_OK;
+}
+
+static int
+ConeLineWidthOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                Tcl_Obj *const *objv)
+{
+    float width;
+    if (GetFloatFromObj(interp, objv[2], &width) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 4) {
+        const char *name = Tcl_GetString(objv[3]);
+        g_renderer->setGraphicsObjectEdgeWidth<Cone>(name, width);
+    } else {
+        g_renderer->setGraphicsObjectEdgeWidth<Cone>("all", width);
+    }
+    return TCL_OK;
+}
+
+static int
+ConeMaterialOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+               Tcl_Obj *const *objv)
+{
+    double ambient, diffuse, specCoeff, specPower;
+    if (Tcl_GetDoubleFromObj(interp, objv[2], &ambient) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[3], &diffuse) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[4], &specCoeff) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[5], &specPower) != TCL_OK) {
+        return TCL_ERROR;
+    }
+
+    if (objc == 7) {
+        const char *name = Tcl_GetString(objv[6]);
+        g_renderer->setGraphicsObjectAmbient<Cone>(name, ambient);
+        g_renderer->setGraphicsObjectDiffuse<Cone>(name, diffuse);
+        g_renderer->setGraphicsObjectSpecular<Cone>(name, specCoeff, specPower);
+    } else {
+        g_renderer->setGraphicsObjectAmbient<Cone>("all", ambient);
+        g_renderer->setGraphicsObjectDiffuse<Cone>("all", diffuse);
+        g_renderer->setGraphicsObjectSpecular<Cone>("all", specCoeff, specPower);
+    }
+    return TCL_OK;
+}
+
+static int
+ConeOpacityOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+              Tcl_Obj *const *objv)
+{
+    double opacity;
+    if (Tcl_GetDoubleFromObj(interp, objv[2], &opacity) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 4) {
+        const char *name = Tcl_GetString(objv[3]);
+        g_renderer->setGraphicsObjectOpacity<Cone>(name, opacity);
+    } else {
+        g_renderer->setGraphicsObjectOpacity<Cone>("all", opacity);
+    }
+    return TCL_OK;
+}
+
+static int
+ConeOrientOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+             Tcl_Obj *const *objv)
+{
+    double quat[4];
+    if (Tcl_GetDoubleFromObj(interp, objv[2], &quat[0]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[3], &quat[1]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[4], &quat[2]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[5], &quat[3]) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 7) {
+        const char *name = Tcl_GetString(objv[6]);
+        g_renderer->setGraphicsObjectOrientation<Cone>(name, quat);
+    } else {
+        g_renderer->setGraphicsObjectOrientation<Cone>("all", quat);
+    }
+    return TCL_OK;
+}
+
+static int
+ConePositionOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+               Tcl_Obj *const *objv)
+{
+    double pos[3];
+    if (Tcl_GetDoubleFromObj(interp, objv[2], &pos[0]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[3], &pos[1]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[4], &pos[2]) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 6) {
+        const char *name = Tcl_GetString(objv[5]);
+        g_renderer->setGraphicsObjectPosition<Cone>(name, pos);
+    } else {
+        g_renderer->setGraphicsObjectPosition<Cone>("all", pos);
+    }
+    return TCL_OK;
+}
+
+static int
+ConeResolutionOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                 Tcl_Obj *const *objv)
+{
+    int res;
+    if (Tcl_GetIntFromObj(interp, objv[2], &res) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 4) {
+        const char *name = Tcl_GetString(objv[3]);
+        g_renderer->setConeResolution(name, res);
+    } else {
+        g_renderer->setConeResolution("all", res);
+    }
+    return TCL_OK;
+}
+
+static int
+ConeScaleOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+            Tcl_Obj *const *objv)
+{
+    double scale[3];
+    if (Tcl_GetDoubleFromObj(interp, objv[2], &scale[0]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[3], &scale[1]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[4], &scale[2]) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 6) {
+        const char *name = Tcl_GetString(objv[5]);
+        g_renderer->setGraphicsObjectScale<Cone>(name, scale);
+    } else {
+        g_renderer->setGraphicsObjectScale<Cone>("all", scale);
+    }
+    return TCL_OK;
+}
+
+static int
+ConeVisibleOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+              Tcl_Obj *const *objv)
+{
+    bool state;
+    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 4) {
+        const char *name = Tcl_GetString(objv[3]);
+        g_renderer->setGraphicsObjectVisibility<Cone>(name, state);
+    } else {
+        g_renderer->setGraphicsObjectVisibility<Cone>("all", state);
+    }
+    return TCL_OK;
+}
+
+static int
+ConeWireframeOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                Tcl_Obj *const *objv)
+{
+    bool state;
+    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 4) {
+        const char *name = Tcl_GetString(objv[3]);
+        g_renderer->setGraphicsObjectWireframe<Cone>(name, state);
+    } else {
+        g_renderer->setGraphicsObjectWireframe<Cone>("all", state);
+    }
+    return TCL_OK;
+}
+
+static Rappture::CmdSpec coneOps[] = {
+    {"add",       1, ConeAddOp, 6, 6, "radius height cap name"},
+    {"color",     1, ConeColorOp, 5, 6, "r g b ?name?"},
+    {"delete",    1, ConeDeleteOp, 2, 3, "?name?"},
+    {"edges",     1, ConeEdgeVisibilityOp, 3, 4, "bool ?name?"},
+    {"lighting",  3, ConeLightingOp, 3, 4, "bool ?name?"},
+    {"linecolor", 5, ConeLineColorOp, 5, 6, "r g b ?name?"},
+    {"linewidth", 5, ConeLineWidthOp, 3, 4, "width ?name?"},
+    {"material",  1, ConeMaterialOp, 6, 7, "ambientCoeff diffuseCoeff specularCoeff specularPower ?name?"},
+    {"opacity",   2, ConeOpacityOp, 3, 4, "value ?name?"},
+    {"orient",    2, ConeOrientOp, 6, 7, "qw qx qy qz ?name?"},
+    {"pos",       2, ConePositionOp, 5, 6, "x y z ?name?"},
+    {"resolution",1, ConeResolutionOp, 3, 4, "res ?name?"},
+    {"scale",     1, ConeScaleOp, 5, 6, "sx sy sz ?name?"},
+    {"visible",   1, ConeVisibleOp, 3, 4, "bool ?name?"},
+    {"wireframe", 1, ConeWireframeOp, 3, 4, "bool ?name?"}
+};
+static int nConeOps = NumCmdSpecs(coneOps);
+
+static int
+ConeCmd(ClientData clientData, Tcl_Interp *interp, int objc, 
+       Tcl_Obj *const *objv)
+{
+    Tcl_ObjCmdProc *proc;
+
+    proc = Rappture::GetOpFromObj(interp, nConeOps, coneOps,
+                                  Rappture::CMDSPEC_ARG1, objc, objv, 0);
+    if (proc == NULL) {
+        return TCL_ERROR;
+    }
+    return (*proc) (clientData, interp, objc, objv);
+}
+
+static int
+Contour2DAddContourListOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                          Tcl_Obj *const *objv)
+{
+    std::vector<double> contourList;
+
+    int clistc;
+    Tcl_Obj **clistv;
+
+    if (Tcl_ListObjGetElements(interp, objv[3], &clistc, &clistv) != TCL_OK) {
+        return TCL_ERROR;
+    }
+
+    for (int i = 0; i < clistc; i++) {
+        double val;
+        if (Tcl_GetDoubleFromObj(interp, clistv[i], &val) != TCL_OK) {
+            return TCL_ERROR;
+        }
+        contourList.push_back(val);
+    }
+
+    if (objc == 5) {
+        const char *name = Tcl_GetString(objv[4]);
+        if (!g_renderer->addContour2D(name, contourList)) {
+            Tcl_AppendResult(interp, "Failed to create contour2d", (char*)NULL);
+            return TCL_ERROR;
+        }
+    } else {
+        if (!g_renderer->addContour2D("all", contourList)) {
+            Tcl_AppendResult(interp, "Failed to create contour2d for one or more data sets", (char*)NULL);
+            return TCL_ERROR;
+        }
+    }
+    return TCL_OK;
+}
+
+static int
+Contour2DAddNumContoursOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                          Tcl_Obj *const *objv)
+{
+    int numContours;
+    if (Tcl_GetIntFromObj(interp, objv[3], &numContours) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 5) {
+        const char *name = Tcl_GetString(objv[4]);
+        if (!g_renderer->addContour2D(name, numContours)) {
+            Tcl_AppendResult(interp, "Failed to create contour2d", (char*)NULL);
+            return TCL_ERROR;
+        }
+    } else {
+       if (!g_renderer->addContour2D("all", numContours)) {
+            Tcl_AppendResult(interp, "Failed to create contour2d for one or more data sets", (char*)NULL);
+            return TCL_ERROR;
+       }
+    }
+    return TCL_OK;
+}
+
+static Rappture::CmdSpec contour2dAddOps[] = {
+    {"contourlist", 1, Contour2DAddContourListOp, 4, 5, "contourList ?dataSetName?"},
+    {"numcontours", 1, Contour2DAddNumContoursOp, 4, 5, "numContours ?dataSetName?"}
+};
+static int nContour2dAddOps = NumCmdSpecs(contour2dAddOps);
+
+static int
+Contour2DAddOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+               Tcl_Obj *const *objv)
+{
+    Tcl_ObjCmdProc *proc;
+
+    proc = Rappture::GetOpFromObj(interp, nContour2dAddOps, contour2dAddOps,
+                                  Rappture::CMDSPEC_ARG2, objc, objv, 0);
+    if (proc == NULL) {
+        return TCL_ERROR;
+    }
+    return (*proc) (clientData, interp, objc, objv);
+}
+
+static int
+Contour2DDeleteOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                  Tcl_Obj *const *objv)
+{
+    if (objc == 3) {
+        const char *name = Tcl_GetString(objv[2]);
+        g_renderer->deleteGraphicsObject<Contour2D>(name);
+    } else {
+        g_renderer->deleteGraphicsObject<Contour2D>("all");
+    }
+    return TCL_OK;
+}
+
+static int
+Contour2DColorMapOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                    Tcl_Obj *const *objv)
+{
+    const char *colorMapName = Tcl_GetString(objv[2]);
+    if (objc == 4) {
+        const char *dataSetName = Tcl_GetString(objv[3]);
+        g_renderer->setGraphicsObjectColorMap<Contour2D>(dataSetName, colorMapName);
+    } else {
+        g_renderer->setGraphicsObjectColorMap<Contour2D>("all", colorMapName);
+    }
+    return TCL_OK;
+}
+
+static int
+Contour2DColorModeOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                     Tcl_Obj *const *objv)
+{
+    Contour2D::ColorMode mode;
+    const char *str = Tcl_GetString(objv[2]);
+    if (str[0] == 'c' && strcmp(str, "ccolor") == 0) {
+        mode = Contour2D::COLOR_CONSTANT;
+    } else if (str[0] == 's' && strcmp(str, "scalar") == 0) {
+        mode = Contour2D::COLOR_BY_SCALAR;
+    } else if (str[0] == 'v' && strcmp(str, "vmag") == 0) {
+        mode = Contour2D::COLOR_BY_VECTOR_MAGNITUDE;
+    } else if (str[0] == 'v' && strcmp(str, "vx") == 0) {
+        mode = Contour2D::COLOR_BY_VECTOR_X;
+    } else if (str[0] == 'v' && strcmp(str, "vy") == 0) {
+        mode = Contour2D::COLOR_BY_VECTOR_Y;
+    } else if (str[0] == 'v' && strcmp(str, "vz") == 0) {
+        mode = Contour2D::COLOR_BY_VECTOR_Z;
+    } else {
+        Tcl_AppendResult(interp, "bad color mode option \"", str,
+                         "\": should be one of: 'scalar', 'vmag', 'vx', 'vy', 'vz', 'ccolor'", (char*)NULL);
+        return TCL_ERROR;
+    }
+    const char *fieldName = Tcl_GetString(objv[3]);
+    if (mode == Contour2D::COLOR_CONSTANT) {
+        fieldName = NULL;
+    }
+    if (objc == 5) {
+        const char *name = Tcl_GetString(objv[4]);
+        g_renderer->setContour2DColorMode(name, mode, fieldName);
+    } else {
+        g_renderer->setContour2DColorMode("all", mode, fieldName);
+    }
+    return TCL_OK;
+}
+
+static int
+Contour2DContourListOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                       Tcl_Obj *const *objv)
+{
+    std::vector<double> contourList;
+
+    int clistc;
+    Tcl_Obj **clistv;
+
+    if (Tcl_ListObjGetElements(interp, objv[2], &clistc, &clistv) != TCL_OK) {
+        return TCL_ERROR;
+    }
+
+    for (int i = 0; i < clistc; i++) {
+        double val;
+        if (Tcl_GetDoubleFromObj(interp, clistv[i], &val) != TCL_OK) {
+            return TCL_ERROR;
+        }
+        contourList.push_back(val);
+    }
+
+    if (objc == 4) {
+        const char *name = Tcl_GetString(objv[3]);
+        g_renderer->setContour2DContourList(name, contourList);
+    } else {
+        g_renderer->setContour2DContourList("all", contourList);
+    }
+    return TCL_OK;
+}
+
+static int
+Contour2DLightingOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                    Tcl_Obj *const *objv)
+{
+    bool state;
+    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 4) {
+        const char *name = Tcl_GetString(objv[3]);
+        g_renderer->setGraphicsObjectLighting<Contour2D>(name, state);
+    } else {
+        g_renderer->setGraphicsObjectLighting<Contour2D>("all", state);
+    }
+    return TCL_OK;
+}
+
+static int
+Contour2DLineColorOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                     Tcl_Obj *const *objv)
+{
+    float color[3];
+    if (GetFloatFromObj(interp, objv[2], &color[0]) != TCL_OK ||
+        GetFloatFromObj(interp, objv[3], &color[1]) != TCL_OK ||
+        GetFloatFromObj(interp, objv[4], &color[2]) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 6) {
+        const char *name = Tcl_GetString(objv[5]);
+        g_renderer->setGraphicsObjectColor<Contour2D>(name, color);
+    } else {
+        g_renderer->setGraphicsObjectColor<Contour2D>("all", color);
+    }
+    return TCL_OK;
+}
+
+static int
+Contour2DLineWidthOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                     Tcl_Obj *const *objv)
+{
+    float width;
+    if (GetFloatFromObj(interp, objv[2], &width) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 4) {
+        const char *name = Tcl_GetString(objv[3]);
+        g_renderer->setGraphicsObjectEdgeWidth<Contour2D>(name, width);
+    } else {
+        g_renderer->setGraphicsObjectEdgeWidth<Contour2D>("all", width);
+    }
+    return TCL_OK;
+}
+
+
+static int
+Contour2DNumContoursOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                       Tcl_Obj *const *objv)
+{
+    int numContours;
+
+    if (Tcl_GetIntFromObj(interp, objv[2], &numContours) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 4) {
+        const char *name = Tcl_GetString(objv[3]);
+        g_renderer->setContour2DNumContours(name, numContours);
+    } else {
+        g_renderer->setContour2DNumContours("all", numContours);
+    }
+    return TCL_OK;
+}
+
+static int
+Contour2DOpacityOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                   Tcl_Obj *const *objv)
+{
+    double opacity;
+    if (Tcl_GetDoubleFromObj(interp, objv[2], &opacity) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 4) {
+        const char *name = Tcl_GetString(objv[3]);
+        g_renderer->setGraphicsObjectOpacity<Contour2D>(name, opacity);
+    } else {
+        g_renderer->setGraphicsObjectOpacity<Contour2D>("all", opacity);
+    }
+    return TCL_OK;
+}
+
+static int
+Contour2DOrientOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                  Tcl_Obj *const *objv)
+{
+    double quat[4];
+    if (Tcl_GetDoubleFromObj(interp, objv[2], &quat[0]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[3], &quat[1]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[4], &quat[2]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[5], &quat[3]) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 7) {
+        const char *name = Tcl_GetString(objv[6]);
+        g_renderer->setGraphicsObjectOrientation<Contour2D>(name, quat);
+    } else {
+        g_renderer->setGraphicsObjectOrientation<Contour2D>("all", quat);
+    }
+    return TCL_OK;
+}
+
+static int
+Contour2DPositionOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                    Tcl_Obj *const *objv)
+{
+    double pos[3];
+    if (Tcl_GetDoubleFromObj(interp, objv[2], &pos[0]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[3], &pos[1]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[4], &pos[2]) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 6) {
+        const char *name = Tcl_GetString(objv[5]);
+        g_renderer->setGraphicsObjectPosition<Contour2D>(name, pos);
+    } else {
+        g_renderer->setGraphicsObjectPosition<Contour2D>("all", pos);
+    }
+    return TCL_OK;
+}
+
+static int
+Contour2DScaleOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                 Tcl_Obj *const *objv)
+{
+    double scale[3];
+    if (Tcl_GetDoubleFromObj(interp, objv[2], &scale[0]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[3], &scale[1]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[4], &scale[2]) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 6) {
+        const char *name = Tcl_GetString(objv[5]);
+        g_renderer->setGraphicsObjectScale<Contour2D>(name, scale);
+    } else {
+        g_renderer->setGraphicsObjectScale<Contour2D>("all", scale);
+    }
+    return TCL_OK;
+}
+
+static int
+Contour2DVisibleOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                   Tcl_Obj *const *objv)
+{
+    bool state;
+    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 4) {
+        const char *name = Tcl_GetString(objv[3]);
+        g_renderer->setGraphicsObjectVisibility<Contour2D>(name, state);
+    } else {
+        g_renderer->setGraphicsObjectVisibility<Contour2D>("all", state);
+    }
+    return TCL_OK;
+}
+
+static Rappture::CmdSpec contour2dOps[] = {
+    {"add",          1, Contour2DAddOp, 4, 5, "oper value ?dataSetName?"},
+    {"ccolor",       2, Contour2DLineColorOp, 5, 6, "r g b ?dataSetName?"},
+    {"colormap",     7, Contour2DColorMapOp, 3, 4, "colorMapName ?dataSetName?"},
+    {"colormode",    7, Contour2DColorModeOp, 4, 5, "mode fieldName ?dataSetName?"},
+    {"contourlist",  3, Contour2DContourListOp, 3, 4, "contourList ?dataSetName?"},
+    {"delete",       1, Contour2DDeleteOp, 2, 3, "?dataSetName?"},
+    {"lighting",     3, Contour2DLightingOp, 3, 4, "bool ?dataSetName?"},
+    {"linecolor",    5, Contour2DLineColorOp, 5, 6, "r g b ?dataSetName?"},
+    {"linewidth",    5, Contour2DLineWidthOp, 3, 4, "width ?dataSetName?"},
+    {"numcontours",  1, Contour2DNumContoursOp, 3, 4, "numContours ?dataSetName?"},
+    {"opacity",      2, Contour2DOpacityOp, 3, 4, "value ?dataSetName?"},
+    {"orient",       2, Contour2DOrientOp, 6, 7, "qw qx qy qz ?dataSetName?"},
+    {"pos",          1, Contour2DPositionOp, 5, 6, "x y z ?dataSetName?"},
+    {"scale",        1, Contour2DScaleOp, 5, 6, "sx sy sz ?dataSetName?"},
+    {"visible",      1, Contour2DVisibleOp, 3, 4, "bool ?dataSetName?"}
+};
+static int nContour2dOps = NumCmdSpecs(contour2dOps);
+
+static int
+Contour2DCmd(ClientData clientData, Tcl_Interp *interp, int objc, 
+             Tcl_Obj *const *objv)
+{
+    Tcl_ObjCmdProc *proc;
+
+    proc = Rappture::GetOpFromObj(interp, nContour2dOps, contour2dOps,
+                                  Rappture::CMDSPEC_ARG1, objc, objv, 0);
+    if (proc == NULL) {
+        return TCL_ERROR;
+    }
+    return (*proc) (clientData, interp, objc, objv);
+}
+
+static int
+Contour3DAddContourListOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                          Tcl_Obj *const *objv)
+{
+    std::vector<double> contourList;
+
+    int clistc;
+    Tcl_Obj **clistv;
+
+    if (Tcl_ListObjGetElements(interp, objv[3], &clistc, &clistv) != TCL_OK) {
+        return TCL_ERROR;
+    }
+
+    for (int i = 0; i < clistc; i++) {
+        double val;
+        if (Tcl_GetDoubleFromObj(interp, clistv[i], &val) != TCL_OK) {
+            return TCL_ERROR;
+        }
+        contourList.push_back(val);
+    }
+
+    if (objc == 5) {
+        const char *name = Tcl_GetString(objv[4]);
+        if (!g_renderer->addContour3D(name, contourList)) {
+            Tcl_AppendResult(interp, "Failed to create contour3d", (char*)NULL);
+            return TCL_ERROR;
+        }
+    } else {
+        if (!g_renderer->addContour3D("all", contourList)) {
+            Tcl_AppendResult(interp, "Failed to create contour3d for one or more data sets", (char*)NULL);
+            return TCL_ERROR;
+        }
+    }
+    return TCL_OK;
+}
+
+static int
+Contour3DAddNumContoursOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                          Tcl_Obj *const *objv)
+{
+    int numContours;
+    if (Tcl_GetIntFromObj(interp, objv[3], &numContours) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 5) {
+        const char *name = Tcl_GetString(objv[4]);
+        if (!g_renderer->addContour3D(name, numContours)) {
+            Tcl_AppendResult(interp, "Failed to create contour3d", (char*)NULL);
+            return TCL_ERROR;
+        }
+    } else {
+        if (!g_renderer->addContour3D("all", numContours)) {
+            Tcl_AppendResult(interp, "Failed to create contour3d for one or more data sets", (char*)NULL);
+            return TCL_ERROR;
+        }
+    }
+    return TCL_OK;
+}
+
+static Rappture::CmdSpec contour3dAddOps[] = {
+    {"contourlist", 1, Contour3DAddContourListOp, 4, 5, "contourList ?dataSetName?"},
+    {"numcontours", 1, Contour3DAddNumContoursOp, 4, 5, "numContours ?dataSetName?"}
+};
+static int nContour3dAddOps = NumCmdSpecs(contour3dAddOps);
+
+static int
+Contour3DAddOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+               Tcl_Obj *const *objv)
+{
+    Tcl_ObjCmdProc *proc;
+
+    proc = Rappture::GetOpFromObj(interp, nContour3dAddOps, contour3dAddOps,
+                                  Rappture::CMDSPEC_ARG2, objc, objv, 0);
+    if (proc == NULL) {
+        return TCL_ERROR;
+    }
+    return (*proc) (clientData, interp, objc, objv);
+}
+
+static int
+Contour3DColorOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                 Tcl_Obj *const *objv)
+{
+    float color[3];
+    if (GetFloatFromObj(interp, objv[2], &color[0]) != TCL_OK ||
+        GetFloatFromObj(interp, objv[3], &color[1]) != TCL_OK ||
+        GetFloatFromObj(interp, objv[4], &color[2]) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 6) {
+        const char *name = Tcl_GetString(objv[5]);
+        g_renderer->setGraphicsObjectColor<Contour3D>(name, color);
+    } else {
+        g_renderer->setGraphicsObjectColor<Contour3D>("all", color);
+    }
+    return TCL_OK;
+}
+
+static int
+Contour3DColorMapOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                    Tcl_Obj *const *objv)
+{
+    const char *colorMapName = Tcl_GetString(objv[2]);
+    if (objc == 4) {
+        const char *dataSetName = Tcl_GetString(objv[3]);
+        g_renderer->setGraphicsObjectColorMap<Contour3D>(dataSetName, colorMapName);
+    } else {
+        g_renderer->setGraphicsObjectColorMap<Contour3D>("all", colorMapName);
+    }
+    return TCL_OK;
+}
+
+static int
+Contour3DColorModeOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                     Tcl_Obj *const *objv)
+{
+    Contour3D::ColorMode mode;
+    const char *str = Tcl_GetString(objv[2]);
+    if (str[0] == 'c' && strcmp(str, "ccolor") == 0) {
+        mode = Contour3D::COLOR_CONSTANT;
+    } else if (str[0] == 's' && strcmp(str, "scalar") == 0) {
+        mode = Contour3D::COLOR_BY_SCALAR;
+    } else if (str[0] == 'v' && strcmp(str, "vmag") == 0) {
+        mode = Contour3D::COLOR_BY_VECTOR_MAGNITUDE;
+    } else if (str[0] == 'v' && strcmp(str, "vx") == 0) {
+        mode = Contour3D::COLOR_BY_VECTOR_X;
+    } else if (str[0] == 'v' && strcmp(str, "vy") == 0) {
+        mode = Contour3D::COLOR_BY_VECTOR_Y;
+    } else if (str[0] == 'v' && strcmp(str, "vz") == 0) {
+        mode = Contour3D::COLOR_BY_VECTOR_Z;
+    } else {
+        Tcl_AppendResult(interp, "bad color mode option \"", str,
+                         "\": should be one of: 'scalar', 'vmag', 'vx', 'vy', 'vz', 'ccolor'", (char*)NULL);
+        return TCL_ERROR;
+    }
+    const char *fieldName = Tcl_GetString(objv[3]);
+    if (mode == Contour3D::COLOR_CONSTANT) {
+        fieldName = NULL;
+    }
+    if (objc == 5) {
+        const char *name = Tcl_GetString(objv[4]);
+        g_renderer->setContour3DColorMode(name, mode, fieldName);
+    } else {
+        g_renderer->setContour3DColorMode("all", mode, fieldName);
+    }
+    return TCL_OK;
+}
+
+static int
+Contour3DContourFieldOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                        Tcl_Obj *const *objv)
+{
+    const char *fieldName = Tcl_GetString(objv[2]);
+    if (objc == 4) {
+        const char *dataSetName = Tcl_GetString(objv[3]);
+        g_renderer->setContour3DContourField(dataSetName, fieldName);
+    } else {
+        g_renderer->setContour3DContourField("all", fieldName);
+    }
+    return TCL_OK;
+}
+
+static int
+Contour3DContourListOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                       Tcl_Obj *const *objv)
+{
+    std::vector<double> contourList;
+
+    int clistc;
+    Tcl_Obj **clistv;
+
+    if (Tcl_ListObjGetElements(interp, objv[2], &clistc, &clistv) != TCL_OK) {
+        return TCL_ERROR;
+    }
+
+    for (int i = 0; i < clistc; i++) {
+        double val;
+        if (Tcl_GetDoubleFromObj(interp, clistv[i], &val) != TCL_OK) {
+            return TCL_ERROR;
+        }
+        contourList.push_back(val);
+    }
+
+    if (objc == 4) {
+        const char *name = Tcl_GetString(objv[3]);
+        g_renderer->setContour3DContourList(name, contourList);
+    } else {
+        g_renderer->setContour3DContourList("all", contourList);
+    }
+    return TCL_OK;
+}
+
+static int
+Contour3DDeleteOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                  Tcl_Obj *const *objv)
+{
+    if (objc == 3) {
+        const char *name = Tcl_GetString(objv[2]);
+        g_renderer->deleteGraphicsObject<Contour3D>(name);
+    } else {
+        g_renderer->deleteGraphicsObject<Contour3D>("all");
+    }
+    return TCL_OK;
+}
+
+static int
+Contour3DEdgeVisibilityOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                          Tcl_Obj *const *objv)
+{
+    bool state;
+    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 4) {
+        const char *name = Tcl_GetString(objv[3]);
+        g_renderer->setGraphicsObjectEdgeVisibility<Contour3D>(name, state);
+    } else {
+        g_renderer->setGraphicsObjectEdgeVisibility<Contour3D>("all", state);
+    }
+    return TCL_OK;
+}
+
+static int
+Contour3DLightingOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                    Tcl_Obj *const *objv)
+{
+    bool state;
+    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 4) {
+        const char *name = Tcl_GetString(objv[3]);
+        g_renderer->setGraphicsObjectLighting<Contour3D>(name, state);
+    } else {
+        g_renderer->setGraphicsObjectLighting<Contour3D>("all", state);
+    }
+    return TCL_OK;
+}
+
+static int
+Contour3DLineColorOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                     Tcl_Obj *const *objv)
+{
+    float color[3];
+    if (GetFloatFromObj(interp, objv[2], &color[0]) != TCL_OK ||
+        GetFloatFromObj(interp, objv[3], &color[1]) != TCL_OK ||
+        GetFloatFromObj(interp, objv[4], &color[2]) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 6) {
+        const char *name = Tcl_GetString(objv[5]);
+        g_renderer->setGraphicsObjectEdgeColor<Contour3D>(name, color);
+    } else {
+        g_renderer->setGraphicsObjectEdgeColor<Contour3D>("all", color);
+    }
+    return TCL_OK;
+}
+
+static int
+Contour3DLineWidthOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                     Tcl_Obj *const *objv)
+{
+    float width;
+    if (GetFloatFromObj(interp, objv[2], &width) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 4) {
+        const char *name = Tcl_GetString(objv[3]);
+        g_renderer->setGraphicsObjectEdgeWidth<Contour3D>(name, width);
+    } else {
+        g_renderer->setGraphicsObjectEdgeWidth<Contour3D>("all", width);
+    }
+    return TCL_OK;
+}
+
+static int
+Contour3DNumContoursOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                       Tcl_Obj *const *objv)
+{
+    int numContours;
+
+    if (Tcl_GetIntFromObj(interp, objv[2], &numContours) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 4) {
+        const char *name = Tcl_GetString(objv[3]);
+        g_renderer->setContour3DNumContours(name, numContours);
+    } else {
+        g_renderer->setContour3DNumContours("all", numContours);
+    }
+    return TCL_OK;
+}
+
+static int
+Contour3DOpacityOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                   Tcl_Obj *const *objv)
+{
+    double opacity;
+    if (Tcl_GetDoubleFromObj(interp, objv[2], &opacity) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 4) {
+        const char *name = Tcl_GetString(objv[3]);
+        g_renderer->setGraphicsObjectOpacity<Contour3D>(name, opacity);
+    } else {
+        g_renderer->setGraphicsObjectOpacity<Contour3D>("all", opacity);
+    }
+    return TCL_OK;
+}
+
+static int
+Contour3DOrientOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                  Tcl_Obj *const *objv)
+{
+    double quat[4];
+    if (Tcl_GetDoubleFromObj(interp, objv[2], &quat[0]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[3], &quat[1]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[4], &quat[2]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[5], &quat[3]) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 7) {
+        const char *name = Tcl_GetString(objv[6]);
+        g_renderer->setGraphicsObjectOrientation<Contour3D>(name, quat);
+    } else {
+        g_renderer->setGraphicsObjectOrientation<Contour3D>("all", quat);
+    }
+    return TCL_OK;
+}
+
+static int
+Contour3DPositionOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                    Tcl_Obj *const *objv)
+{
+    double pos[3];
+    if (Tcl_GetDoubleFromObj(interp, objv[2], &pos[0]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[3], &pos[1]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[4], &pos[2]) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 6) {
+        const char *name = Tcl_GetString(objv[5]);
+        g_renderer->setGraphicsObjectPosition<Contour3D>(name, pos);
+    } else {
+        g_renderer->setGraphicsObjectPosition<Contour3D>("all", pos);
+    }
+    return TCL_OK;
+}
+
+static int
+Contour3DScaleOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                 Tcl_Obj *const *objv)
+{
+    double scale[3];
+    if (Tcl_GetDoubleFromObj(interp, objv[2], &scale[0]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[3], &scale[1]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[4], &scale[2]) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 6) {
+        const char *name = Tcl_GetString(objv[5]);
+        g_renderer->setGraphicsObjectScale<Contour3D>(name, scale);
+    } else {
+        g_renderer->setGraphicsObjectScale<Contour3D>("all", scale);
+    }
+    return TCL_OK;
+}
+
+static int
+Contour3DVisibleOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                   Tcl_Obj *const *objv)
+{
+    bool state;
+    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 4) {
+        const char *name = Tcl_GetString(objv[3]);
+        g_renderer->setGraphicsObjectVisibility<Contour3D>(name, state);
+    } else {
+        g_renderer->setGraphicsObjectVisibility<Contour3D>("all", state);
+    }
+    return TCL_OK;
+}
+
+static int
+Contour3DWireframeOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                     Tcl_Obj *const *objv)
+{
+    bool state;
+    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 4) {
+        const char *name = Tcl_GetString(objv[3]);
+        g_renderer->setGraphicsObjectWireframe<Contour3D>(name, state);
+    } else {
+        g_renderer->setGraphicsObjectWireframe<Contour3D>("all", state);
+    }
+    return TCL_OK;
+}
+
+static Rappture::CmdSpec contour3dOps[] = {
+    {"add",          1, Contour3DAddOp, 4, 5, "oper value ?dataSetName?"},
+    {"ccolor",       2, Contour3DColorOp, 5, 6, "r g b ?dataSetName?"},
+    {"colormap",     7, Contour3DColorMapOp, 3, 4, "colorMapName ?dataSetName?"},
+    {"colormode",    7, Contour3DColorModeOp, 4, 5, "mode fieldName ?dataSetName?"},
+    {"contourfield", 8, Contour3DContourFieldOp, 3, 4, "fieldName ?dataSetName?"},
+    {"contourlist",  8, Contour3DContourListOp, 3, 4, "contourList ?dataSetName?"},
+    {"delete",       1, Contour3DDeleteOp, 2, 3, "?dataSetName?"},
+    {"edges",        1, Contour3DEdgeVisibilityOp, 3, 4, "bool ?dataSetName?"},
+    {"lighting",     3, Contour3DLightingOp, 3, 4, "bool ?dataSetName?"},
+    {"linecolor",    5, Contour3DLineColorOp, 5, 6, "r g b ?dataSetName?"},
+    {"linewidth",    5, Contour3DLineWidthOp, 3, 4, "width ?dataSetName?"},
+    {"numcontours",  1, Contour3DNumContoursOp, 3, 4, "numContours ?dataSetName?"},
+    {"opacity",      2, Contour3DOpacityOp, 3, 4, "value ?dataSetName?"},
+    {"orient",       2, Contour3DOrientOp, 6, 7, "qw qx qy qz ?dataSetName?"},
+    {"pos",          1, Contour3DPositionOp, 5, 6, "x y z ?dataSetName?"},
+    {"scale",        1, Contour3DScaleOp, 5, 6, "sx sy sz ?dataSetName?"},
+    {"visible",      1, Contour3DVisibleOp, 3, 4, "bool ?dataSetName?"},
+    {"wireframe",    1, Contour3DWireframeOp, 3, 4, "bool ?dataSetName?"}
+};
+static int nContour3dOps = NumCmdSpecs(contour3dOps);
+
+static int
+Contour3DCmd(ClientData clientData, Tcl_Interp *interp, int objc, 
+             Tcl_Obj *const *objv)
+{
+    Tcl_ObjCmdProc *proc;
+
+    proc = Rappture::GetOpFromObj(interp, nContour3dOps, contour3dOps,
+                                  Rappture::CMDSPEC_ARG1, objc, objv, 0);
+    if (proc == NULL) {
+        return TCL_ERROR;
+    }
+    return (*proc) (clientData, interp, objc, objv);
+}
+
+static int
+CutplaneAddOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+              Tcl_Obj *const *objv)
+{
+    if (objc == 3) {
+        const char *name = Tcl_GetString(objv[2]);
+        if (!g_renderer->addGraphicsObject<Cutplane>(name)) {
+            Tcl_AppendResult(interp, "Failed to create cutplane", (char*)NULL);
+            return TCL_ERROR;
+        }
+    } else {
+        if (!g_renderer->addGraphicsObject<Cutplane>("all")) {
+            Tcl_AppendResult(interp, "Failed to create cutplane for one or more data sets", (char*)NULL);
+            return TCL_ERROR;
+        }
+    }
+    return TCL_OK;
+}
+
+static int
+CutplaneColorOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                Tcl_Obj *const *objv)
+{
+    float color[3];
+    if (GetFloatFromObj(interp, objv[2], &color[0]) != TCL_OK ||
+        GetFloatFromObj(interp, objv[3], &color[1]) != TCL_OK ||
+        GetFloatFromObj(interp, objv[4], &color[2]) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 6) {
+        const char *name = Tcl_GetString(objv[5]);
+        g_renderer->setGraphicsObjectColor<Cutplane>(name, color);
+    } else {
+        g_renderer->setGraphicsObjectColor<Cutplane>("all", color);
+    }
+    return TCL_OK;
+}
+
+static int
+CutplaneColorMapOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                   Tcl_Obj *const *objv)
+{
+    const char *colorMapName = Tcl_GetString(objv[2]);
+    if (objc == 4) {
+        const char *dataSetName = Tcl_GetString(objv[3]);
+        g_renderer->setGraphicsObjectColorMap<Cutplane>(dataSetName, colorMapName);
+    } else {
+        g_renderer->setGraphicsObjectColorMap<Cutplane>("all", colorMapName);
+    }
+    return TCL_OK;
+}
+
+static int
+CutplaneColorModeOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                    Tcl_Obj *const *objv)
+{
+    Cutplane::ColorMode mode;
+    const char *str = Tcl_GetString(objv[2]);
+    if (str[0] == 's' && strcmp(str, "scalar") == 0) {
+        mode = Cutplane::COLOR_BY_SCALAR;
+    } else if (str[0] == 'v' && strcmp(str, "vmag") == 0) {
+        mode = Cutplane::COLOR_BY_VECTOR_MAGNITUDE;
+    } else if (str[0] == 'v' && strcmp(str, "vx") == 0) {
+        mode = Cutplane::COLOR_BY_VECTOR_X;
+    } else if (str[0] == 'v' && strcmp(str, "vy") == 0) {
+        mode = Cutplane::COLOR_BY_VECTOR_Y;
+    } else if (str[0] == 'v' && strcmp(str, "vz") == 0) {
+        mode = Cutplane::COLOR_BY_VECTOR_Z;
+    } else {
+        Tcl_AppendResult(interp, "bad color mode option \"", str,
+                         "\": should be one of: 'scalar', 'vmag', 'vx', 'vy', 'vz'", (char*)NULL);
+        return TCL_ERROR;
+    }
+    const char *fieldName = Tcl_GetString(objv[3]);
+    if (objc == 5) {
+        const char *name = Tcl_GetString(objv[4]);
+        g_renderer->setCutplaneColorMode(name, mode, fieldName);
+    } else {
+        g_renderer->setCutplaneColorMode("all", mode, fieldName);
+    }
+    return TCL_OK;
+}
+
+static int
+CutplaneDeleteOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                 Tcl_Obj *const *objv)
+{
+    if (objc == 3) {
+        const char *name = Tcl_GetString(objv[2]);
+        g_renderer->deleteGraphicsObject<Cutplane>(name);
+    } else {
+        g_renderer->deleteGraphicsObject<Cutplane>("all");
+    }
+    return TCL_OK;
+}
+
+static int
+CutplaneEdgeVisibilityOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                         Tcl_Obj *const *objv)
+{
+    bool state;
+    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 4) {
+        const char *name = Tcl_GetString(objv[3]);
+        g_renderer->setGraphicsObjectEdgeVisibility<Cutplane>(name, state);
+    } else {
+        g_renderer->setGraphicsObjectEdgeVisibility<Cutplane>("all", state);
+    }
+    return TCL_OK;
+}
+
+static int
+CutplaneLightingOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                   Tcl_Obj *const *objv)
+{
+    bool state;
+    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 4) {
+        const char *name = Tcl_GetString(objv[3]);
+        g_renderer->setGraphicsObjectLighting<Cutplane>(name, state);
+    } else {
+        g_renderer->setGraphicsObjectLighting<Cutplane>("all", state);
+    }
+    return TCL_OK;
+}
+
+static int
+CutplaneLineColorOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                    Tcl_Obj *const *objv)
+{
+    float color[3];
+    if (GetFloatFromObj(interp, objv[2], &color[0]) != TCL_OK ||
+        GetFloatFromObj(interp, objv[3], &color[1]) != TCL_OK ||
+        GetFloatFromObj(interp, objv[4], &color[2]) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 6) {
+        const char *name = Tcl_GetString(objv[5]);
+        g_renderer->setGraphicsObjectEdgeColor<Cutplane>(name, color);
+    } else {
+        g_renderer->setGraphicsObjectEdgeColor<Cutplane>("all", color);
+    }
+    return TCL_OK;
+}
+
+static int
+CutplaneLineWidthOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                    Tcl_Obj *const *objv)
+{
+    float width;
+    if (GetFloatFromObj(interp, objv[2], &width) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 4) {
+        const char *name = Tcl_GetString(objv[3]);
+        g_renderer->setGraphicsObjectEdgeWidth<Cutplane>(name, width);
+    } else {
+        g_renderer->setGraphicsObjectEdgeWidth<Cutplane>("all", width);
+    }
+    return TCL_OK;
+}
+
+static int
+CutplaneOpacityOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                  Tcl_Obj *const *objv)
+{
+    double opacity;
+    if (Tcl_GetDoubleFromObj(interp, objv[2], &opacity) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 4) {
+        const char *name = Tcl_GetString(objv[3]);
+        g_renderer->setGraphicsObjectOpacity<Cutplane>(name, opacity);
+    } else {
+        g_renderer->setGraphicsObjectOpacity<Cutplane>("all", opacity);
+    }
+    return TCL_OK;
+}
+
+static int
+CutplaneOrientOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                 Tcl_Obj *const *objv)
+{
+    double quat[4];
+    if (Tcl_GetDoubleFromObj(interp, objv[2], &quat[0]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[3], &quat[1]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[4], &quat[2]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[5], &quat[3]) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 7) {
+        const char *name = Tcl_GetString(objv[6]);
+        g_renderer->setGraphicsObjectOrientation<Cutplane>(name, quat);
+    } else {
+        g_renderer->setGraphicsObjectOrientation<Cutplane>("all", quat);
+    }
+    return TCL_OK;
+}
+
+static int
+CutplaneOutlineOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                  Tcl_Obj *const *objv)
+{
+    bool state;
+    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 4) {
+        const char *name = Tcl_GetString(objv[3]);
+        g_renderer->setCutplaneOutlineVisibility(name, state);
+    } else {
+        g_renderer->setCutplaneOutlineVisibility("all", state);
+    }
+    return TCL_OK;
+}
+
+static int
+CutplanePositionOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                   Tcl_Obj *const *objv)
+{
+    double pos[3];
+    if (Tcl_GetDoubleFromObj(interp, objv[2], &pos[0]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[3], &pos[1]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[4], &pos[2]) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 6) {
+        const char *name = Tcl_GetString(objv[5]);
+        g_renderer->setGraphicsObjectPosition<Cutplane>(name, pos);
+    } else {
+        g_renderer->setGraphicsObjectPosition<Cutplane>("all", pos);
+    }
+    return TCL_OK;
+}
+
+static int
+CutplanePreInterpOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                    Tcl_Obj *const *objv)
+{
+    bool state;
+    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 4) {
+        const char *name = Tcl_GetString(objv[3]);
+        g_renderer->setGraphicsObjectInterpolateBeforeMapping<Cutplane>(name, state);
+    } else {
+        g_renderer->setGraphicsObjectInterpolateBeforeMapping<Cutplane>("all", state);
+    }
+    return TCL_OK;
+}
+
+static int
+CutplaneScaleOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                Tcl_Obj *const *objv)
+{
+    double scale[3];
+    if (Tcl_GetDoubleFromObj(interp, objv[2], &scale[0]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[3], &scale[1]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[4], &scale[2]) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 6) {
+        const char *name = Tcl_GetString(objv[5]);
+        g_renderer->setGraphicsObjectScale<Cutplane>(name, scale);
+    } else {
+        g_renderer->setGraphicsObjectScale<Cutplane>("all", scale);
+    }
+    return TCL_OK;
+}
+
+static int
+CutplaneSliceVisibilityOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                          Tcl_Obj *const *objv)
+{
+    bool state;
+    if (GetBooleanFromObj(interp, objv[3], &state) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    const char *string = Tcl_GetString(objv[2]);
+    char c = string[0];
+    Axis axis;
+    if ((c == 'x') && (strcmp(string, "x") == 0)) {
+        axis = X_AXIS;
+    } else if ((c == 'y') && (strcmp(string, "y") == 0)) {
+        axis = Y_AXIS;
+    } else if ((c == 'z') && (strcmp(string, "z") == 0)) {
+        axis = Z_AXIS;
+    } else {
+        Tcl_AppendResult(interp, "bad axis option \"", string,
+                         "\": should be axisName bool", (char*)NULL);
+        return TCL_ERROR;
+    }
+    if (objc == 5) {
+        const char *name = Tcl_GetString(objv[4]);
+        g_renderer->setCutplaneSliceVisibility(name, axis, state);
+    } else {
+        g_renderer->setCutplaneSliceVisibility("all", axis, state);
+    }
+    return TCL_OK;
+}
+
+static int
+CutplaneVisibleOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                  Tcl_Obj *const *objv)
+{
+    bool state;
+    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 4) {
+        const char *name = Tcl_GetString(objv[3]);
+        g_renderer->setGraphicsObjectVisibility<Cutplane>(name, state);
+    } else {
+        g_renderer->setGraphicsObjectVisibility<Cutplane>("all", state);
+    }
+    return TCL_OK;
+}
+
+static int
+CutplaneVolumeSliceOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                      Tcl_Obj *const *objv)
+{
+    double ratio;
+    if (Tcl_GetDoubleFromObj(interp, objv[3], &ratio) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    const char *string = Tcl_GetString(objv[2]);
+    char c = string[0];
+    Axis axis;
+    if ((c == 'x') && (strcmp(string, "x") == 0)) {
+        axis = X_AXIS;
+    } else if ((c == 'y') && (strcmp(string, "y") == 0)) {
+        axis = Y_AXIS;
+    } else if ((c == 'z') && (strcmp(string, "z") == 0)) {
+        axis = Z_AXIS;
+    } else {
+        Tcl_AppendResult(interp, "bad axis option \"", string,
+                         "\": should be axisName ratio", (char*)NULL);
+        return TCL_ERROR;
+    }
+    if (objc == 5) {
+        const char *name = Tcl_GetString(objv[4]);
+        g_renderer->setGraphicsObjectVolumeSlice<Cutplane>(name, axis, ratio);
+    } else {
+        g_renderer->setGraphicsObjectVolumeSlice<Cutplane>("all", axis, ratio);
+    }
+    return TCL_OK;
+}
+
+static int
+CutplaneWireframeOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                    Tcl_Obj *const *objv)
+{
+    bool state;
+    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 4) {
+        const char *name = Tcl_GetString(objv[3]);
+        g_renderer->setGraphicsObjectWireframe<Cutplane>(name, state);
+    } else {
+        g_renderer->setGraphicsObjectWireframe<Cutplane>("all", state);
+    }
+    return TCL_OK;
+}
+
+static Rappture::CmdSpec cutplaneOps[] = {
+    {"add",          2, CutplaneAddOp, 2, 3, "oper value ?dataSetName?"},
+    {"axis",         2, CutplaneSliceVisibilityOp, 4, 5, "axis bool ?dataSetName?"},
+    {"ccolor",       2, CutplaneColorOp, 5, 6, "r g b ?dataSetName?"},
+    {"colormap",     7, CutplaneColorMapOp, 3, 4, "colorMapName ?dataSetName?"},
+    {"colormode",    7, CutplaneColorModeOp, 4, 5, "mode fieldName ?dataSetName?"},
+    {"delete",       1, CutplaneDeleteOp, 2, 3, "?dataSetName?"},
+    {"edges",        1, CutplaneEdgeVisibilityOp, 3, 4, "bool ?dataSetName?"},
+    {"lighting",     3, CutplaneLightingOp, 3, 4, "bool ?dataSetName?"},
+    {"linecolor",    5, CutplaneLineColorOp, 5, 6, "r g b ?dataSetName?"},
+    {"linewidth",    5, CutplaneLineWidthOp, 3, 4, "width ?dataSetName?"},
+    {"opacity",      2, CutplaneOpacityOp, 3, 4, "value ?dataSetName?"},
+    {"orient",       2, CutplaneOrientOp, 6, 7, "qw qx qy qz ?dataSetName?"},
+    {"outline",      2, CutplaneOutlineOp, 3, 4, "bool ?dataSetName?"},
+    {"pos",          2, CutplanePositionOp, 5, 6, "x y z ?dataSetName?"},
+    {"preinterp",    2, CutplanePreInterpOp, 3, 4, "bool ?dataSetName?"},
+    {"scale",        2, CutplaneScaleOp, 5, 6, "sx sy sz ?dataSetName?"},
+    {"slice",        2, CutplaneVolumeSliceOp, 4, 5, "axis ratio ?dataSetName?"},
+    {"visible",      1, CutplaneVisibleOp, 3, 4, "bool ?dataSetName?"},
+    {"wireframe",    1, CutplaneWireframeOp, 3, 4, "bool ?dataSetName?"}
+};
+static int nCutplaneOps = NumCmdSpecs(cutplaneOps);
+
+static int
+CutplaneCmd(ClientData clientData, Tcl_Interp *interp, int objc, 
+             Tcl_Obj *const *objv)
+{
+    Tcl_ObjCmdProc *proc;
+
+    proc = Rappture::GetOpFromObj(interp, nCutplaneOps, cutplaneOps,
+                                  Rappture::CMDSPEC_ARG1, objc, objv, 0);
+    if (proc == NULL) {
+        return TCL_ERROR;
+    }
+    return (*proc) (clientData, interp, objc, objv);
+}
+
+static int
+CylinderAddOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+              Tcl_Obj *const *objv)
+{
+    double radius, height;
+    bool cap = true;
+    if (Tcl_GetDoubleFromObj(interp, objv[2], &radius) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[3], &height) != TCL_OK ||
+        GetBooleanFromObj(interp, objv[4], &cap) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    const char *name = Tcl_GetString(objv[5]);
+    if (!g_renderer->addCylinder(name, radius, height, cap)) {
+        Tcl_AppendResult(interp, "Failed to create cylinder", (char*)NULL);
+        return TCL_ERROR;
+    }
+    return TCL_OK;
+}
+
+static int
+CylinderDeleteOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                 Tcl_Obj *const *objv)
+{
+    if (objc == 3) {
+        const char *name = Tcl_GetString(objv[2]);
+        g_renderer->deleteGraphicsObject<Cylinder>(name);
+    } else {
+        g_renderer->deleteGraphicsObject<Cylinder>("all");
+    }
+    return TCL_OK;
+}
+
+static int
+CylinderColorOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                Tcl_Obj *const *objv)
+{
+    float color[3];
+    if (GetFloatFromObj(interp, objv[2], &color[0]) != TCL_OK ||
+        GetFloatFromObj(interp, objv[3], &color[1]) != TCL_OK ||
+        GetFloatFromObj(interp, objv[4], &color[2]) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 6) {
+        const char *name = Tcl_GetString(objv[5]);
+        g_renderer->setGraphicsObjectColor<Cylinder>(name, color);
+    } else {
+        g_renderer->setGraphicsObjectColor<Cylinder>("all", color);
+    }
+    return TCL_OK;
+}
+
+static int
+CylinderEdgeVisibilityOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                         Tcl_Obj *const *objv)
+{
+    bool state;
+    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 4) {
+        const char *name = Tcl_GetString(objv[3]);
+        g_renderer->setGraphicsObjectEdgeVisibility<Cylinder>(name, state);
+    } else {
+        g_renderer->setGraphicsObjectEdgeVisibility<Cylinder>("all", state);
+    }
+    return TCL_OK;
+}
+
+static int
+CylinderLightingOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                   Tcl_Obj *const *objv)
+{
+    bool state;
+    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 4) {
+        const char *name = Tcl_GetString(objv[3]);
+        g_renderer->setGraphicsObjectLighting<Cylinder>(name, state);
+    } else {
+        g_renderer->setGraphicsObjectLighting<Cylinder>("all", state);
+    }
+    return TCL_OK;
+}
+
+static int
+CylinderLineColorOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                    Tcl_Obj *const *objv)
+{
+    float color[3];
+    if (GetFloatFromObj(interp, objv[2], &color[0]) != TCL_OK ||
+        GetFloatFromObj(interp, objv[3], &color[1]) != TCL_OK ||
+        GetFloatFromObj(interp, objv[4], &color[2]) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 6) {
+        const char *name = Tcl_GetString(objv[5]);
+        g_renderer->setGraphicsObjectEdgeColor<Cylinder>(name, color);
+    } else {
+        g_renderer->setGraphicsObjectEdgeColor<Cylinder>("all", color);
+    }
+    return TCL_OK;
+}
+
+static int
+CylinderLineWidthOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                    Tcl_Obj *const *objv)
+{
+    float width;
+    if (GetFloatFromObj(interp, objv[2], &width) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 4) {
+        const char *name = Tcl_GetString(objv[3]);
+        g_renderer->setGraphicsObjectEdgeWidth<Cylinder>(name, width);
+    } else {
+        g_renderer->setGraphicsObjectEdgeWidth<Cylinder>("all", width);
+    }
+    return TCL_OK;
+}
+
+static int
+CylinderMaterialOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                   Tcl_Obj *const *objv)
+{
+    double ambient, diffuse, specCoeff, specPower;
+    if (Tcl_GetDoubleFromObj(interp, objv[2], &ambient) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[3], &diffuse) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[4], &specCoeff) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[5], &specPower) != TCL_OK) {
+        return TCL_ERROR;
+    }
+
+    if (objc == 7) {
+        const char *name = Tcl_GetString(objv[6]);
+        g_renderer->setGraphicsObjectAmbient<Cylinder>(name, ambient);
+        g_renderer->setGraphicsObjectDiffuse<Cylinder>(name, diffuse);
+        g_renderer->setGraphicsObjectSpecular<Cylinder>(name, specCoeff, specPower);
+    } else {
+        g_renderer->setGraphicsObjectAmbient<Cylinder>("all", ambient);
+        g_renderer->setGraphicsObjectDiffuse<Cylinder>("all", diffuse);
+        g_renderer->setGraphicsObjectSpecular<Cylinder>("all", specCoeff, specPower);
+    }
+    return TCL_OK;
+}
+
+static int
+CylinderOpacityOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                  Tcl_Obj *const *objv)
+{
+    double opacity;
+    if (Tcl_GetDoubleFromObj(interp, objv[2], &opacity) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 4) {
+        const char *name = Tcl_GetString(objv[3]);
+        g_renderer->setGraphicsObjectOpacity<Cylinder>(name, opacity);
+    } else {
+        g_renderer->setGraphicsObjectOpacity<Cylinder>("all", opacity);
+    }
+    return TCL_OK;
+}
+
+static int
+CylinderOrientOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                 Tcl_Obj *const *objv)
+{
+    double quat[4];
+    if (Tcl_GetDoubleFromObj(interp, objv[2], &quat[0]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[3], &quat[1]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[4], &quat[2]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[5], &quat[3]) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 7) {
+        const char *name = Tcl_GetString(objv[6]);
+        g_renderer->setGraphicsObjectOrientation<Cylinder>(name, quat);
+    } else {
+        g_renderer->setGraphicsObjectOrientation<Cylinder>("all", quat);
+    }
+    return TCL_OK;
+}
+
+static int
+CylinderPositionOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                   Tcl_Obj *const *objv)
+{
+    double pos[3];
+    if (Tcl_GetDoubleFromObj(interp, objv[2], &pos[0]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[3], &pos[1]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[4], &pos[2]) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 6) {
+        const char *name = Tcl_GetString(objv[5]);
+        g_renderer->setGraphicsObjectPosition<Cylinder>(name, pos);
+    } else {
+        g_renderer->setGraphicsObjectPosition<Cylinder>("all", pos);
+    }
+    return TCL_OK;
+}
+
+static int
+CylinderResolutionOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                     Tcl_Obj *const *objv)
+{
+    int res;
+    if (Tcl_GetIntFromObj(interp, objv[2], &res) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 4) {
+        const char *name = Tcl_GetString(objv[3]);
+        g_renderer->setCylinderResolution(name, res);
+    } else {
+        g_renderer->setCylinderResolution("all", res);
+    }
+    return TCL_OK;
+}
+
+static int
+CylinderScaleOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                Tcl_Obj *const *objv)
+{
+    double scale[3];
+    if (Tcl_GetDoubleFromObj(interp, objv[2], &scale[0]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[3], &scale[1]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[4], &scale[2]) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 6) {
+        const char *name = Tcl_GetString(objv[5]);
+        g_renderer->setGraphicsObjectScale<Cylinder>(name, scale);
+    } else {
+        g_renderer->setGraphicsObjectScale<Cylinder>("all", scale);
+    }
+    return TCL_OK;
+}
+
+static int
+CylinderVisibleOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                  Tcl_Obj *const *objv)
+{
+    bool state;
+    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 4) {
+        const char *name = Tcl_GetString(objv[3]);
+        g_renderer->setGraphicsObjectVisibility<Cylinder>(name, state);
+    } else {
+        g_renderer->setGraphicsObjectVisibility<Cylinder>("all", state);
+    }
+    return TCL_OK;
+}
+
+static int
+CylinderWireframeOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                    Tcl_Obj *const *objv)
+{
+    bool state;
+    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 4) {
+        const char *name = Tcl_GetString(objv[3]);
+        g_renderer->setGraphicsObjectWireframe<Cylinder>(name, state);
+    } else {
+        g_renderer->setGraphicsObjectWireframe<Cylinder>("all", state);
+    }
+    return TCL_OK;
+}
+
+static Rappture::CmdSpec cylinderOps[] = {
+    {"add",       1, CylinderAddOp, 6, 6, " radius height cap name"},
+    {"color",     1, CylinderColorOp, 5, 6, "r g b ?name?"},
+    {"delete",    1, CylinderDeleteOp, 2, 3, "?name?"},
+    {"edges",     1, CylinderEdgeVisibilityOp, 3, 4, "bool ?name?"},
+    {"lighting",  3, CylinderLightingOp, 3, 4, "bool ?name?"},
+    {"linecolor", 5, CylinderLineColorOp, 5, 6, "r g b ?name?"},
+    {"linewidth", 5, CylinderLineWidthOp, 3, 4, "width ?name?"},
+    {"material",  1, CylinderMaterialOp, 6, 7, "ambientCoeff diffuseCoeff specularCoeff specularPower ?name?"},
+    {"opacity",   2, CylinderOpacityOp, 3, 4, "value ?name?"},
+    {"orient",    2, CylinderOrientOp, 6, 7, "qw qx qy qz ?name?"},
+    {"pos",       2, CylinderPositionOp, 5, 6, "x y z ?name?"},
+    {"resolution",1, CylinderResolutionOp, 3, 4, "res ?name?"},
+    {"scale",     1, CylinderScaleOp, 5, 6, "sx sy sz ?name?"},
+    {"visible",   1, CylinderVisibleOp, 3, 4, "bool ?name?"},
+    {"wireframe", 1, CylinderWireframeOp, 3, 4, "bool ?name?"}
+};
+static int nCylinderOps = NumCmdSpecs(cylinderOps);
+
+static int
+CylinderCmd(ClientData clientData, Tcl_Interp *interp, int objc, 
+       Tcl_Obj *const *objv)
+{
+    Tcl_ObjCmdProc *proc;
+
+    proc = Rappture::GetOpFromObj(interp, nCylinderOps, cylinderOps,
+                                  Rappture::CMDSPEC_ARG1, objc, objv, 0);
+    if (proc == NULL) {
+        return TCL_ERROR;
+    }
+    return (*proc) (clientData, interp, objc, objv);
+}
+
+static int
+DataSetActiveScalarsOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                       Tcl_Obj *const *objv)
+{
+    const char *scalarName = Tcl_GetString(objv[2]);
+    if (objc == 4) {
+        const char *name = Tcl_GetString(objv[3]);
+        if (!g_renderer->setDataSetActiveScalars(name, scalarName)) {
+            Tcl_AppendResult(interp, "scalar \"", scalarName,
+                         "\" not found", (char*)NULL);
+            return TCL_ERROR;
+        }
+    } else {
+        if (!g_renderer->setDataSetActiveScalars("all", scalarName)) {
+            Tcl_AppendResult(interp, "scalar \"", scalarName,
+                         "\" not found in one or more data sets", (char*)NULL);
+            return TCL_ERROR;
+        }
+    }
+    return TCL_OK;
+}
+
+static int
+DataSetActiveVectorsOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                       Tcl_Obj *const *objv)
+{
+    const char *vectorName = Tcl_GetString(objv[2]);
+    if (objc == 4) {
+        const char *name = Tcl_GetString(objv[3]);
+        if (!g_renderer->setDataSetActiveVectors(name, vectorName)) {
+            Tcl_AppendResult(interp, "vector \"", vectorName,
+                         "\" not found", (char*)NULL);
+            return TCL_ERROR;
+        }
+    } else {
+        if (!g_renderer->setDataSetActiveVectors("all", vectorName)) {
+            Tcl_AppendResult(interp, "vector \"", vectorName,
+                         "\" not found in one or more data sets", (char*)NULL);
+            return TCL_ERROR;
+        }
+    }
+    return TCL_OK;
+}
+
+static int
+DataSetAddOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+             Tcl_Obj *const *objv)
+{
+    const char *name = Tcl_GetString(objv[2]);
+    const char *string = Tcl_GetString(objv[3]);
+    char c = string[0];
+    if ((c != 'd') || (strcmp(string, "data") != 0)) {
+        Tcl_AppendResult(interp, "bad dataset option \"", string,
+                         "\": should be data", (char*)NULL);
+        return TCL_ERROR;
+    }
+    string = Tcl_GetString(objv[4]);
+    c = string[0];
+    if ((c != 'f') || (strcmp(string, "follows") != 0)) {
+        Tcl_AppendResult(interp, "bad dataset option \"", string,
+                         "\": should be follows", (char*)NULL);
+        return TCL_ERROR;
+    }
+    int nbytes = 0;
+    if (Tcl_GetIntFromObj(interp, objv[5], &nbytes) != TCL_OK ||
+        nbytes < 0) {
+        return TCL_ERROR;
+    }
+    char *data = (char *)malloc(nbytes);
+    if (!SocketRead(data, nbytes)) {
+        free(data);
+        return TCL_ERROR;
+    }
+    g_renderer->addDataSet(name);
+    if (!g_renderer->setData(name, data, nbytes)) {
+        USER_ERROR("Failed to load data for dataset \"%s\"", name);
+        free(data);
+        return TCL_ERROR;
+    }
+    g_stats.nDataSets++;
+    g_stats.nDataBytes += nbytes;
+    free(data);
+    return TCL_OK;
+}
+
+static int
+DataSetDeleteOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                Tcl_Obj *const *objv)
+{
+    if (objc == 3) {
+        const char *name = Tcl_GetString(objv[2]);
+        TRACE("Deleting dataset %s", name);
+        g_renderer->deleteDataSet(name);
+    } else {
+        g_renderer->deleteDataSet("all");
+    }
+    return TCL_OK;
+}
+
+static int
+DataSetGetScalarPixelOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                        Tcl_Obj *const *objv)
+{
+    const char *name = Tcl_GetString(objv[5]);
+    int x, y;
+    if (Tcl_GetIntFromObj(interp, objv[3], &x) != TCL_OK ||
+        Tcl_GetIntFromObj(interp, objv[4], &y) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    double value;
+    if (!g_renderer->getScalarValueAtPixel(name, x, y, &value)) {
+        Tcl_AppendResult(interp, "Pixel out of dataset bounds or no scalar data available", (char*)NULL);
+        return TCL_ERROR;
+    }
+
+    char buf[256];
+    int length;
+
+    length = snprintf(buf, sizeof(buf), "nv>dataset scalar pixel %d %d %g %s\n",
+                      x, y, value, name);
+
+#ifdef USE_THREADS
+    queueResponse(clientData, buf, length, Response::VOLATILE);
+#else
+    ssize_t bytesWritten = SocketWrite(buf, length);
+
+    if (bytesWritten < 0) {
+        return TCL_ERROR;
+    }
+#endif
+    return TCL_OK;
+}
+
+static int
+DataSetGetScalarWorldOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                        Tcl_Obj *const *objv)
+{
+    const char *name = Tcl_GetString(objv[6]);
+    double x, y, z;
+    if (Tcl_GetDoubleFromObj(interp, objv[3], &x) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[4], &y) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[5], &z) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    double value;
+    if (!g_renderer->getScalarValue(name, x, y, z, &value)) {
+        Tcl_AppendResult(interp, "Coordinate out of dataset bounds or no scalar data available", (char*)NULL);
+        return TCL_ERROR;
+    }
+
+    char buf[256];
+    int length;
+
+    length = snprintf(buf, sizeof(buf), 
+                      "nv>dataset scalar world %g %g %g %g %s\n",
+                      x, y, z, value, name);
+
+#ifdef USE_THREADS
+    queueResponse(clientData, buf, length, Response::VOLATILE);
+#else 
+    ssize_t bytesWritten = SocketWrite(buf, length);
+    if (bytesWritten < 0) {
+        return TCL_ERROR;
+    }
+#endif
+    return TCL_OK;
+}
+
+static Rappture::CmdSpec dataSetGetScalarOps[] = {
+    {"pixel", 1, DataSetGetScalarPixelOp, 6, 6, "x y dataSetName"},
+    {"world", 1, DataSetGetScalarWorldOp, 7, 7, "x y z dataSetName"}
+};
+static int nDataSetGetScalarOps = NumCmdSpecs(dataSetGetScalarOps);
+
+static int
+DataSetGetScalarOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                   Tcl_Obj *const *objv)
+{
+    Tcl_ObjCmdProc *proc;
+
+    proc = Rappture::GetOpFromObj(interp, nDataSetGetScalarOps, dataSetGetScalarOps,
+                                  Rappture::CMDSPEC_ARG2, objc, objv, 0);
+    if (proc == NULL) {
+        return TCL_ERROR;
+    }
+    return (*proc) (clientData, interp, objc, objv);
+}
+
+static int
+DataSetGetVectorPixelOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                        Tcl_Obj *const *objv)
+{
+    const char *name = Tcl_GetString(objv[5]);
+    int x, y;
+    if (Tcl_GetIntFromObj(interp, objv[3], &x) != TCL_OK ||
+        Tcl_GetIntFromObj(interp, objv[4], &y) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    double value[3];
+    if (!g_renderer->getVectorValueAtPixel(name, x, y, value)) {
+        Tcl_AppendResult(interp, "Pixel out of dataset bounds or no vector data available", (char*)NULL);
+        return TCL_ERROR;
+    }
+
+    char buf[256];
+    int length; 
+    length = snprintf(buf, sizeof(buf), 
+                      "nv>dataset vector pixel %d %d %g %g %g %s\n",
+                      x, y,
+                      value[0], value[1], value[2], name);
+
+#ifdef USE_THREADS
+    queueResponse(clientData, buf, length, Response::VOLATILE);
+#else 
+    ssize_t bytesWritten = SocketWrite(buf, length);
+
+    if (bytesWritten < 0) {
+        return TCL_ERROR;
+    }
+#endif /*USE_THREADS*/
+    return TCL_OK;
+}
+
+static int
+DataSetGetVectorWorldOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                        Tcl_Obj *const *objv)
+{
+    const char *name = Tcl_GetString(objv[6]);
+    double x, y, z;
+    if (Tcl_GetDoubleFromObj(interp, objv[3], &x) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[4], &y) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[5], &z) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    double value[3];
+    if (!g_renderer->getVectorValue(name, x, y, z, value)) {
+        Tcl_AppendResult(interp, "Coordinate out of dataset bounds or no vector data available", (char*)NULL);
+        return TCL_ERROR;
+    }
+
+    char buf[256];
+    int length;
+    length = snprintf(buf, sizeof(buf), 
+                      "nv>dataset vector world %g %g %g %g %g %g %s\n",
+                      x, y, z,
+                      value[0], value[1], value[2], name);
+#ifdef USE_THREADS
+    queueResponse(clientData, buf, length, Response::VOLATILE);
+#else 
+    ssize_t bytesWritten = SocketWrite(buf, length);
+
+    if (bytesWritten < 0) {
+        return TCL_ERROR;
+    }
+#endif /*USE_THREADS*/
+    return TCL_OK;
+}
+
+static Rappture::CmdSpec dataSetGetVectorOps[] = {
+    {"pixel", 1, DataSetGetVectorPixelOp, 6, 6, "x y dataSetName"},
+    {"world", 1, DataSetGetVectorWorldOp, 7, 7, "x y z dataSetName"}
+};
+static int nDataSetGetVectorOps = NumCmdSpecs(dataSetGetVectorOps);
+
+static int
+DataSetGetVectorOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                   Tcl_Obj *const *objv)
+{
+    Tcl_ObjCmdProc *proc;
+
+    proc = Rappture::GetOpFromObj(interp, nDataSetGetVectorOps, dataSetGetVectorOps,
+                                  Rappture::CMDSPEC_ARG2, objc, objv, 0);
+    if (proc == NULL) {
+        return TCL_ERROR;
+    }
+    return (*proc) (clientData, interp, objc, objv);
+}
+
+static int
+DataSetMapRangeOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                  Tcl_Obj *const *objv)
+{
+    const char *value = Tcl_GetString(objv[2]);
+    if (strcmp(value, "all") == 0) {
+        g_renderer->setUseCumulativeDataRange(true);
+    } else if (strcmp(value, "explicit") == 0) {
+        if (objc < 6 || objc > 9) {
+            Tcl_AppendResult(interp, "wrong number of arguments for explicit maprange", (char*)NULL);
+            return TCL_ERROR;
+        }
+        double range[2];
+        if (Tcl_GetDoubleFromObj(interp, objv[3], &range[0]) != TCL_OK ||
+            Tcl_GetDoubleFromObj(interp, objv[4], &range[1]) != TCL_OK) {
+            return TCL_ERROR;
+        }
+        const char *fieldName = Tcl_GetString(objv[5]);
+
+        DataSet::DataAttributeType type = DataSet::POINT_DATA;
+        int numComponents = 1;
+        int component = -1;
+        if (objc > 6) {
+            const char *fieldType = Tcl_GetString(objv[6]);
+            if (strcmp(fieldType, "point_data") == 0) {
+                type = DataSet::POINT_DATA;
+            } else if (strcmp(fieldType, "cell_data") == 0) {
+                type = DataSet::CELL_DATA;
+            } else if (strcmp(fieldType, "field_data") == 0) {
+                type = DataSet::FIELD_DATA;
+            } else {
+                Tcl_AppendResult(interp, "bad field type option \"", fieldType,
+                                 "\": should be point_data, cell_data or field_data", (char*)NULL);
+                return TCL_ERROR;
+            }
+            if (objc > 7) {
+                if (Tcl_GetIntFromObj(interp, objv[7], &numComponents) != TCL_OK) {
+                    return TCL_ERROR;
+                }
+                if (objc == 9) {
+                    if (Tcl_GetIntFromObj(interp, objv[8], &component) != TCL_OK) {
+                        return TCL_ERROR;
+                    }
+                }
+            }
+        }
+        g_renderer->setCumulativeDataRange(range, fieldName, type, numComponents, component);
+    } else if (strcmp(value, "separate") == 0) {
+        g_renderer->setUseCumulativeDataRange(false);
+    } else if (strcmp(value, "visible") == 0) {
+        g_renderer->setUseCumulativeDataRange(true, true);
+    } else {
+        Tcl_AppendResult(interp, "bad maprange option \"", value,
+                         "\": should be all, explicit, separate or visible", (char*)NULL);
+        return TCL_ERROR;
+    }
+    return TCL_OK;
+}
+
+static int
+DataSetNamesOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+               Tcl_Obj *const *objv)
+{
+    std::vector<std::string> dataSets;
+    g_renderer->getDataSetNames(dataSets);
+    std::ostringstream oss;
+    size_t len = 0;
+    oss << "nv>dataset names {";
+    len += 18;
+    for (size_t i = 0; i < dataSets.size(); i++) {
+        oss << "\"" << dataSets[i] << "\"";
+        len += 2 + dataSets[i].length();
+        if (i < dataSets.size() - 1) {
+            oss << " ";
+            len++;
+        }
+    }
+    oss << "}\n";
+    len += 2;
+#ifdef USE_THREADS
+    queueResponse(clientData, oss.str().c_str(), len, Response::VOLATILE);
+#else 
+    ssize_t bytesWritten = SocketWrite(oss.str().c_str(), len);
+
+    if (bytesWritten < 0) {
+        return TCL_ERROR;
+    }
+#endif /*USE_THREADS*/
+    return TCL_OK;
+}
+
+static int
+DataSetOpacityOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                 Tcl_Obj *const *objv)
+{
+    double opacity;
+    if (Tcl_GetDoubleFromObj(interp, objv[2], &opacity) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 4) {
+        const char *name = Tcl_GetString(objv[3]);
+        g_renderer->setDataSetOpacity(name, opacity);
+    } else {
+        g_renderer->setDataSetOpacity("all", opacity);
+    }
+    return TCL_OK;
+}
+
+static int
+DataSetVisibleOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                 Tcl_Obj *const *objv)
+{
+    bool state;
+    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 4) {
+        const char *name = Tcl_GetString(objv[3]);
+        g_renderer->setDataSetVisibility(name, state);
+    } else {
+        g_renderer->setDataSetVisibility("all", state);
+    }
+    return TCL_OK;
+}
+
+static Rappture::CmdSpec dataSetOps[] = {
+    {"add",       1, DataSetAddOp, 6, 6, "name data follows nBytes"},
+    {"delete",    1, DataSetDeleteOp, 2, 3, "?name?"},
+    {"getscalar", 4, DataSetGetScalarOp, 6, 7, "oper x y ?z? name"},
+    {"getvector", 4, DataSetGetVectorOp, 6, 7, "oper x y ?z? name"},
+    {"maprange",  1, DataSetMapRangeOp, 3, 9, "value ?min? ?max? ?fieldName? ?fieldType? ?fieldNumComp? ?compIdx?"},
+    {"names",     1, DataSetNamesOp, 2, 2, ""},
+    {"opacity",   2, DataSetOpacityOp, 3, 4, "value ?name?"},
+    {"scalar",    1, DataSetActiveScalarsOp, 3, 4, "scalarName ?name?"},
+    {"vector",    2, DataSetActiveVectorsOp, 3, 4, "vectorName ?name?"},
+    {"visible",   2, DataSetVisibleOp, 3, 4, "bool ?name?"}
+};
+static int nDataSetOps = NumCmdSpecs(dataSetOps);
+
+static int
+DataSetCmd(ClientData clientData, Tcl_Interp *interp, int objc, 
+           Tcl_Obj *const *objv)
+{
+    Tcl_ObjCmdProc *proc;
+
+    proc = Rappture::GetOpFromObj(interp, nDataSetOps, dataSetOps,
+                                  Rappture::CMDSPEC_ARG1, objc, objv, 0);
+    if (proc == NULL) {
+        return TCL_ERROR;
+    }
+    return (*proc) (clientData, interp, objc, objv);
+}
+
+static int
+DiskAddOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+          Tcl_Obj *const *objv)
+{
+    double innerRadius, outerRadius;
+    if (Tcl_GetDoubleFromObj(interp, objv[2], &innerRadius) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[3], &outerRadius) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    const char *name = Tcl_GetString(objv[4]);
+    if (!g_renderer->addDisk(name, innerRadius, outerRadius)) {
+        Tcl_AppendResult(interp, "Failed to create disk", (char*)NULL);
+        return TCL_ERROR;
+    }
+    return TCL_OK;
+}
+
+static int
+DiskDeleteOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+             Tcl_Obj *const *objv)
+{
+    if (objc == 3) {
+        const char *name = Tcl_GetString(objv[2]);
+        g_renderer->deleteGraphicsObject<Disk>(name);
+    } else {
+        g_renderer->deleteGraphicsObject<Disk>("all");
+    }
+    return TCL_OK;
+}
+
+static int
+DiskColorOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+            Tcl_Obj *const *objv)
+{
+    float color[3];
+    if (GetFloatFromObj(interp, objv[2], &color[0]) != TCL_OK ||
+        GetFloatFromObj(interp, objv[3], &color[1]) != TCL_OK ||
+        GetFloatFromObj(interp, objv[4], &color[2]) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 6) {
+        const char *name = Tcl_GetString(objv[5]);
+        g_renderer->setGraphicsObjectColor<Disk>(name, color);
+    } else {
+        g_renderer->setGraphicsObjectColor<Disk>("all", color);
+    }
+    return TCL_OK;
+}
+
+static int
+DiskEdgeVisibilityOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                     Tcl_Obj *const *objv)
+{
+    bool state;
+    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 4) {
+        const char *name = Tcl_GetString(objv[3]);
+        g_renderer->setGraphicsObjectEdgeVisibility<Disk>(name, state);
+    } else {
+        g_renderer->setGraphicsObjectEdgeVisibility<Disk>("all", state);
+    }
+    return TCL_OK;
+}
+
+static int
+DiskLightingOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+               Tcl_Obj *const *objv)
+{
+    bool state;
+    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 4) {
+        const char *name = Tcl_GetString(objv[3]);
+        g_renderer->setGraphicsObjectLighting<Disk>(name, state);
+    } else {
+        g_renderer->setGraphicsObjectLighting<Disk>("all", state);
+    }
+    return TCL_OK;
+}
+
+static int
+DiskLineColorOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                Tcl_Obj *const *objv)
+{
+    float color[3];
+    if (GetFloatFromObj(interp, objv[2], &color[0]) != TCL_OK ||
+        GetFloatFromObj(interp, objv[3], &color[1]) != TCL_OK ||
+        GetFloatFromObj(interp, objv[4], &color[2]) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 6) {
+        const char *name = Tcl_GetString(objv[5]);
+        g_renderer->setGraphicsObjectEdgeColor<Disk>(name, color);
+    } else {
+        g_renderer->setGraphicsObjectEdgeColor<Disk>("all", color);
+    }
+    return TCL_OK;
+}
+
+static int
+DiskLineWidthOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                Tcl_Obj *const *objv)
+{
+    float width;
+    if (GetFloatFromObj(interp, objv[2], &width) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 4) {
+        const char *name = Tcl_GetString(objv[3]);
+        g_renderer->setGraphicsObjectEdgeWidth<Disk>(name, width);
+    } else {
+        g_renderer->setGraphicsObjectEdgeWidth<Disk>("all", width);
+    }
+    return TCL_OK;
+}
+
+static int
+DiskMaterialOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+               Tcl_Obj *const *objv)
+{
+    double ambient, diffuse, specCoeff, specPower;
+    if (Tcl_GetDoubleFromObj(interp, objv[2], &ambient) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[3], &diffuse) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[4], &specCoeff) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[5], &specPower) != TCL_OK) {
+        return TCL_ERROR;
+    }
+
+    if (objc == 7) {
+        const char *name = Tcl_GetString(objv[6]);
+        g_renderer->setGraphicsObjectAmbient<Disk>(name, ambient);
+        g_renderer->setGraphicsObjectDiffuse<Disk>(name, diffuse);
+        g_renderer->setGraphicsObjectSpecular<Disk>(name, specCoeff, specPower);
+    } else {
+        g_renderer->setGraphicsObjectAmbient<Disk>("all", ambient);
+        g_renderer->setGraphicsObjectDiffuse<Disk>("all", diffuse);
+        g_renderer->setGraphicsObjectSpecular<Disk>("all", specCoeff, specPower);
+    }
+    return TCL_OK;
+}
+
+static int
+DiskOpacityOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+              Tcl_Obj *const *objv)
+{
+    double opacity;
+    if (Tcl_GetDoubleFromObj(interp, objv[2], &opacity) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 4) {
+        const char *name = Tcl_GetString(objv[3]);
+        g_renderer->setGraphicsObjectOpacity<Disk>(name, opacity);
+    } else {
+        g_renderer->setGraphicsObjectOpacity<Disk>("all", opacity);
+    }
+    return TCL_OK;
+}
+
+static int
+DiskOrientOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+             Tcl_Obj *const *objv)
+{
+    double quat[4];
+    if (Tcl_GetDoubleFromObj(interp, objv[2], &quat[0]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[3], &quat[1]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[4], &quat[2]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[5], &quat[3]) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 7) {
+        const char *name = Tcl_GetString(objv[6]);
+        g_renderer->setGraphicsObjectOrientation<Disk>(name, quat);
+    } else {
+        g_renderer->setGraphicsObjectOrientation<Disk>("all", quat);
+    }
+    return TCL_OK;
+}
+
+static int
+DiskPositionOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+               Tcl_Obj *const *objv)
+{
+    double pos[3];
+    if (Tcl_GetDoubleFromObj(interp, objv[2], &pos[0]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[3], &pos[1]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[4], &pos[2]) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 6) {
+        const char *name = Tcl_GetString(objv[5]);
+        g_renderer->setGraphicsObjectPosition<Disk>(name, pos);
+    } else {
+        g_renderer->setGraphicsObjectPosition<Disk>("all", pos);
+    }
+    return TCL_OK;
+}
+
+static int
+DiskResolutionOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                 Tcl_Obj *const *objv)
+{
+    int radial, circum;
+    if (Tcl_GetIntFromObj(interp, objv[2], &radial) != TCL_OK ||
+        Tcl_GetIntFromObj(interp, objv[3], &circum) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 5) {
+        const char *name = Tcl_GetString(objv[4]);
+        g_renderer->setDiskResolution(name, radial, circum);
+    } else {
+        g_renderer->setDiskResolution("all", radial, circum);
+    }
+    return TCL_OK;
+}
+
+static int
+DiskScaleOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+            Tcl_Obj *const *objv)
+{
+    double scale[3];
+    if (Tcl_GetDoubleFromObj(interp, objv[2], &scale[0]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[3], &scale[1]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[4], &scale[2]) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 6) {
+        const char *name = Tcl_GetString(objv[5]);
+        g_renderer->setGraphicsObjectScale<Disk>(name, scale);
+    } else {
+        g_renderer->setGraphicsObjectScale<Disk>("all", scale);
+    }
+    return TCL_OK;
+}
+
+static int
+DiskVisibleOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+              Tcl_Obj *const *objv)
+{
+    bool state;
+    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 4) {
+        const char *name = Tcl_GetString(objv[3]);
+        g_renderer->setGraphicsObjectVisibility<Disk>(name, state);
+    } else {
+        g_renderer->setGraphicsObjectVisibility<Disk>("all", state);
+    }
+    return TCL_OK;
+}
+
+static int
+DiskWireframeOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                Tcl_Obj *const *objv)
+{
+    bool state;
+    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 4) {
+        const char *name = Tcl_GetString(objv[3]);
+        g_renderer->setGraphicsObjectWireframe<Disk>(name, state);
+    } else {
+        g_renderer->setGraphicsObjectWireframe<Disk>("all", state);
+    }
+    return TCL_OK;
+}
+
+static Rappture::CmdSpec diskOps[] = {
+    {"add",       1, DiskAddOp, 5, 5, "innerRadius outerRadius name"},
+    {"color",     1, DiskColorOp, 5, 6, "r g b ?name?"},
+    {"delete",    1, DiskDeleteOp, 2, 3, "?name?"},
+    {"edges",     1, DiskEdgeVisibilityOp, 3, 4, "bool ?name?"},
+    {"lighting",  3, DiskLightingOp, 3, 4, "bool ?name?"},
+    {"linecolor", 5, DiskLineColorOp, 5, 6, "r g b ?name?"},
+    {"linewidth", 5, DiskLineWidthOp, 3, 4, "width ?name?"},
+    {"material",  1, DiskMaterialOp, 6, 7, "ambientCoeff diffuseCoeff specularCoeff specularPower ?name?"},
+    {"opacity",   2, DiskOpacityOp, 3, 4, "value ?name?"},
+    {"orient",    2, DiskOrientOp, 6, 7, "qw qx qy qz ?name?"},
+    {"pos",       2, DiskPositionOp, 5, 6, "x y z ?name?"},
+    {"resolution",1, DiskResolutionOp, 4, 5, "resRadial resCircum ?name?"},
+    {"scale",     1, DiskScaleOp, 5, 6, "sx sy sz ?name?"},
+    {"visible",   1, DiskVisibleOp, 3, 4, "bool ?name?"},
+    {"wireframe", 1, DiskWireframeOp, 3, 4, "bool ?name?"}
+};
+static int nDiskOps = NumCmdSpecs(diskOps);
+
+static int
+DiskCmd(ClientData clientData, Tcl_Interp *interp, int objc, 
+        Tcl_Obj *const *objv)
+{
+    Tcl_ObjCmdProc *proc;
+
+    proc = Rappture::GetOpFromObj(interp, nDiskOps, diskOps,
+                                  Rappture::CMDSPEC_ARG1, objc, objv, 0);
+    if (proc == NULL) {
+        return TCL_ERROR;
+    }
+    return (*proc) (clientData, interp, objc, objv);
+}
+
+static int
+GlyphsAddOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+            Tcl_Obj *const *objv)
+{
+    Glyphs::GlyphShape shape;
+
+    const char *shapeOpt = Tcl_GetString(objv[2]);
+    if (shapeOpt[0] == 'a' && strcmp(shapeOpt, "arrow") == 0) {
+        shape = Glyphs::ARROW;
+    } else if (shapeOpt[0] == 'c' && strcmp(shapeOpt, "cone") == 0) {
+        shape = Glyphs::CONE;
+    } else if (shapeOpt[0] == 'c' && strcmp(shapeOpt, "cube") == 0) {
+        shape = Glyphs::CUBE;
+    } else if (shapeOpt[0] == 'c' && strcmp(shapeOpt, "cylinder") == 0) {
+        shape = Glyphs::CYLINDER;
+    } else if (shapeOpt[0] == 'd' && strcmp(shapeOpt, "dodecahedron") == 0) {
+        shape = Glyphs::DODECAHEDRON;
+    } else if (shapeOpt[0] == 'i' && strcmp(shapeOpt, "icosahedron") == 0) {
+        shape = Glyphs::ICOSAHEDRON;
+    } else if (shapeOpt[0] == 'l' && strcmp(shapeOpt, "line") == 0) {
+        shape = Glyphs::LINE;
+    } else if (shapeOpt[0] == 'o' && strcmp(shapeOpt, "octahedron") == 0) {
+        shape = Glyphs::OCTAHEDRON;
+    } else if (shapeOpt[0] == 's' && strcmp(shapeOpt, "sphere") == 0) {
+        shape = Glyphs::SPHERE;
+    } else if (shapeOpt[0] == 't' && strcmp(shapeOpt, "tetrahedron") == 0) {
+        shape = Glyphs::TETRAHEDRON;
+    } else {
+        Tcl_AppendResult(interp, "bad shape option \"", shapeOpt,
+                         "\": should be one of: 'arrow', 'cone', 'cube', 'cylinder', 'dodecahedron', 'icosahedron', 'octahedron', 'sphere', 'tetrahedron'", (char*)NULL);
+        return TCL_ERROR;
+    }
+
+    if (objc == 4) {
+        const char *name = Tcl_GetString(objv[3]);
+        if (!g_renderer->addGlyphs(name, shape)) {
+            Tcl_AppendResult(interp, "Failed to create glyphs", (char*)NULL);
+            return TCL_ERROR;
+        }
+    } else {
+        if (!g_renderer->addGlyphs("all", shape)) {
+            Tcl_AppendResult(interp, "Failed to create glyphs for one or more data sets", (char*)NULL);
+            return TCL_ERROR;
+        }
+    }
+    return TCL_OK;
+}
+
+static int
+GlyphsColorOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+              Tcl_Obj *const *objv)
+{
+    float color[3];
+    if (GetFloatFromObj(interp, objv[2], &color[0]) != TCL_OK ||
+        GetFloatFromObj(interp, objv[3], &color[1]) != TCL_OK ||
+        GetFloatFromObj(interp, objv[4], &color[2]) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 6) {
+        const char *name = Tcl_GetString(objv[5]);
+        g_renderer->setGraphicsObjectColor<Glyphs>(name, color);
+    } else {
+        g_renderer->setGraphicsObjectColor<Glyphs>("all", color);
+    }
+    return TCL_OK;
+}
+
+static int
+GlyphsColorMapOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                 Tcl_Obj *const *objv)
+{
+    const char *colorMapName = Tcl_GetString(objv[2]);
+    if (objc == 4) {
+        const char *dataSetName = Tcl_GetString(objv[3]);
+        g_renderer->setGraphicsObjectColorMap<Glyphs>(dataSetName, colorMapName);
+    } else {
+        g_renderer->setGraphicsObjectColorMap<Glyphs>("all", colorMapName);
+    }
+    return TCL_OK;
+}
+
+static int
+GlyphsColorModeOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                  Tcl_Obj *const *objv)
+{
+    Glyphs::ColorMode mode;
+    const char *str = Tcl_GetString(objv[2]);
+    if (str[0] == 'c' && strcmp(str, "ccolor") == 0) {
+        mode = Glyphs::COLOR_CONSTANT;
+    } else if (str[0] == 's' && strcmp(str, "scalar") == 0) {
+        mode = Glyphs::COLOR_BY_SCALAR;
+    } else if (str[0] == 'v' && strcmp(str, "vmag") == 0) {
+        mode = Glyphs::COLOR_BY_VECTOR_MAGNITUDE;
+    } else if (str[0] == 'v' && strcmp(str, "vx") == 0) {
+        mode = Glyphs::COLOR_BY_VECTOR_X;
+    } else if (str[0] == 'v' && strcmp(str, "vy") == 0) {
+        mode = Glyphs::COLOR_BY_VECTOR_Y;
+    } else if (str[0] == 'v' && strcmp(str, "vz") == 0) {
+        mode = Glyphs::COLOR_BY_VECTOR_Z;
+    } else {
+        Tcl_AppendResult(interp, "bad color mode option \"", str,
+                         "\": should be one of: 'scalar', 'vmag', 'vx', 'vy', 'vz', 'ccolor'", (char*)NULL);
+        return TCL_ERROR;
+    }
+    const char *fieldName = Tcl_GetString(objv[3]);
+    if (mode == Glyphs::COLOR_CONSTANT) {
+        fieldName = NULL;
+    }
+    if (objc == 5) {
+        const char *name = Tcl_GetString(objv[4]);
+        g_renderer->setGlyphsColorMode(name, mode, fieldName);
+    } else {
+        g_renderer->setGlyphsColorMode("all", mode, fieldName);
+    }
+    return TCL_OK;
+}
+
+static int
+GlyphsDeleteOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+               Tcl_Obj *const *objv)
+{
+    if (objc == 3) {
+        const char *name = Tcl_GetString(objv[2]);
+        g_renderer->deleteGraphicsObject<Glyphs>(name);
+    } else {
+        g_renderer->deleteGraphicsObject<Glyphs>("all");
+    }
+    return TCL_OK;
+}
+
+static int
+GlyphsEdgeVisibilityOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                       Tcl_Obj *const *objv)
+{
+    bool state;
+    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 4) {
+        const char *name = Tcl_GetString(objv[3]);
+        g_renderer->setGraphicsObjectEdgeVisibility<Glyphs>(name, state);
+    } else {
+        g_renderer->setGraphicsObjectEdgeVisibility<Glyphs>("all", state);
+    }
+    return TCL_OK;
+}
+
+static int
+GlyphsLightingOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                 Tcl_Obj *const *objv)
+{
+    bool state;
+    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 4) {
+        const char *name = Tcl_GetString(objv[3]);
+        g_renderer->setGraphicsObjectLighting<Glyphs>(name, state);
+    } else {
+        g_renderer->setGraphicsObjectLighting<Glyphs>("all", state);
+    }
+    return TCL_OK;
+}
+
+static int
+GlyphsLineColorOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                  Tcl_Obj *const *objv)
+{
+    float color[3];
+    if (GetFloatFromObj(interp, objv[2], &color[0]) != TCL_OK ||
+        GetFloatFromObj(interp, objv[3], &color[1]) != TCL_OK ||
+        GetFloatFromObj(interp, objv[4], &color[2]) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 6) {
+        const char *name = Tcl_GetString(objv[5]);
+        g_renderer->setGraphicsObjectEdgeColor<Glyphs>(name, color);
+    } else {
+        g_renderer->setGraphicsObjectEdgeColor<Glyphs>("all", color);
+    }
+    return TCL_OK;
+}
+
+static int
+GlyphsLineWidthOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                  Tcl_Obj *const *objv)
+{
+    float width;
+    if (GetFloatFromObj(interp, objv[2], &width) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 4) {
+        const char *name = Tcl_GetString(objv[3]);
+        g_renderer->setGraphicsObjectEdgeWidth<Glyphs>(name, width);
+    } else {
+        g_renderer->setGraphicsObjectEdgeWidth<Glyphs>("all", width);
+    }
+    return TCL_OK;
+}
+
+static int
+GlyphsNormalizeScaleOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                       Tcl_Obj *const *objv)
+{
+    bool normalize;
+    if (GetBooleanFromObj(interp, objv[2], &normalize) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 4) {
+        const char *name = Tcl_GetString(objv[3]);
+        g_renderer->setGlyphsNormalizeScale(name, normalize);
+    } else {
+        g_renderer->setGlyphsNormalizeScale("all", normalize);
+    }
+    return TCL_OK;
+}
+
+static int
+GlyphsOpacityOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                Tcl_Obj *const *objv)
+{
+    double opacity;
+    if (Tcl_GetDoubleFromObj(interp, objv[2], &opacity) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 4) {
+        const char *name = Tcl_GetString(objv[3]);
+        g_renderer->setGraphicsObjectOpacity<Glyphs>(name, opacity);
+    } else {
+        g_renderer->setGraphicsObjectOpacity<Glyphs>("all", opacity);
+    }
+    return TCL_OK;
+}
+
+static int
+GlyphsOrientOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+               Tcl_Obj *const *objv)
+{
+    double quat[4];
+    if (Tcl_GetDoubleFromObj(interp, objv[2], &quat[0]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[3], &quat[1]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[4], &quat[2]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[5], &quat[3]) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 7) {
+        const char *name = Tcl_GetString(objv[6]);
+        g_renderer->setGraphicsObjectOrientation<Glyphs>(name, quat);
+    } else {
+        g_renderer->setGraphicsObjectOrientation<Glyphs>("all", quat);
+    }
+    return TCL_OK;
+}
+
+static int
+GlyphsOrientGlyphsOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                     Tcl_Obj *const *objv)
+{
+    bool state;
+    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    const char *fieldName = Tcl_GetString(objv[3]);
+    if (objc == 5) {
+        const char *name = Tcl_GetString(objv[4]);
+        g_renderer->setGlyphsOrientMode(name, state, fieldName);
+    } else {
+        g_renderer->setGlyphsOrientMode("all", state, fieldName);
+    }
+    return TCL_OK;
+}
+
+static int
+GlyphsPositionOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                 Tcl_Obj *const *objv)
+{
+    double pos[3];
+    if (Tcl_GetDoubleFromObj(interp, objv[2], &pos[0]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[3], &pos[1]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[4], &pos[2]) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 6) {
+        const char *name = Tcl_GetString(objv[5]);
+        g_renderer->setGraphicsObjectPosition<Glyphs>(name, pos);
+    } else {
+        g_renderer->setGraphicsObjectPosition<Glyphs>("all", pos);
+    }
+    return TCL_OK;
+}
+
+static int
+GlyphsScaleOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+              Tcl_Obj *const *objv)
+{
+    double scale[3];
+    if (Tcl_GetDoubleFromObj(interp, objv[2], &scale[0]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[3], &scale[1]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[4], &scale[2]) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 6) {
+        const char *name = Tcl_GetString(objv[5]);
+        g_renderer->setGraphicsObjectScale<Glyphs>(name, scale);
+    } else {
+        g_renderer->setGraphicsObjectScale<Glyphs>("all", scale);
+    }
+    return TCL_OK;
+}
+
+static int
+GlyphsScaleFactorOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                    Tcl_Obj *const *objv)
+{
+    double scale;
+    if (Tcl_GetDoubleFromObj(interp, objv[2], &scale) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 4) {
+        const char *name = Tcl_GetString(objv[3]);
+        g_renderer->setGlyphsScaleFactor(name, scale);
+    } else {
+        g_renderer->setGlyphsScaleFactor("all", scale);
+    }
+    return TCL_OK;
+}
+
+static int
+GlyphsScalingModeOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                    Tcl_Obj *const *objv)
+{
+    Glyphs::ScalingMode mode;
+    const char *str = Tcl_GetString(objv[2]);
+    if (str[0] == 's' && strcmp(str, "scalar") == 0) {
+        mode = Glyphs::SCALE_BY_SCALAR;
+    } else if (str[0] == 'v' && strcmp(str, "vmag") == 0) {
+        mode = Glyphs::SCALE_BY_VECTOR_MAGNITUDE;
+    } else if (str[0] == 'v' && strcmp(str, "vcomp") == 0) {
+        mode = Glyphs::SCALE_BY_VECTOR_COMPONENTS;
+    } else if (str[0] == 'o' && strcmp(str, "off") == 0) {
+        mode = Glyphs::SCALING_OFF;
+    } else {
+        Tcl_AppendResult(interp, "bad scaling mode option \"", str,
+                         "\": should be one of: 'scalar', 'vmag', 'vcomp', 'off'", (char*)NULL);
+        return TCL_ERROR;
+    }
+    const char *fieldName = Tcl_GetString(objv[3]);
+    if (objc == 5) {
+        const char *name = Tcl_GetString(objv[4]);
+        g_renderer->setGlyphsScalingMode(name, mode, fieldName);
+    } else {
+        g_renderer->setGlyphsScalingMode("all", mode, fieldName);
+    }
+    return TCL_OK;
+}
+
+static int
+GlyphsShapeOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+              Tcl_Obj *const *objv)
+{
+    Glyphs::GlyphShape shape;
+
+    const char *shapeOpt = Tcl_GetString(objv[2]);
+    if (shapeOpt[0] == 'a' && strcmp(shapeOpt, "arrow") == 0) {
+        shape = Glyphs::ARROW;
+    } else if (shapeOpt[0] == 'c' && strcmp(shapeOpt, "cone") == 0) {
+        shape = Glyphs::CONE;
+    } else if (shapeOpt[0] == 'c' && strcmp(shapeOpt, "cube") == 0) {
+        shape = Glyphs::CUBE;
+    } else if (shapeOpt[0] == 'c' && strcmp(shapeOpt, "cylinder") == 0) {
+        shape = Glyphs::CYLINDER;
+    } else if (shapeOpt[0] == 'd' && strcmp(shapeOpt, "dodecahedron") == 0) {
+        shape = Glyphs::DODECAHEDRON;
+    } else if (shapeOpt[0] == 'i' && strcmp(shapeOpt, "icosahedron") == 0) {
+        shape = Glyphs::ICOSAHEDRON;
+    } else if (shapeOpt[0] == 'l' && strcmp(shapeOpt, "line") == 0) {
+        shape = Glyphs::LINE;
+    } else if (shapeOpt[0] == 'o' && strcmp(shapeOpt, "octahedron") == 0) {
+        shape = Glyphs::OCTAHEDRON;
+    } else if (shapeOpt[0] == 's' && strcmp(shapeOpt, "sphere") == 0) {
+        shape = Glyphs::SPHERE;
+    } else if (shapeOpt[0] == 't' && strcmp(shapeOpt, "tetrahedron") == 0) {
+        shape = Glyphs::TETRAHEDRON;
+    } else {
+        Tcl_AppendResult(interp, "bad shape option \"", shapeOpt,
+                         "\": should be one of: 'arrow', 'cone', 'cube', 'cylinder', 'dodecahedron', 'icosahedron', 'line', 'octahedron', 'sphere', 'tetrahedron'", (char*)NULL);
+        return TCL_ERROR;
+    }
+
+    if (objc == 4) {
+        const char *name = Tcl_GetString(objv[3]);
+        g_renderer->setGlyphsShape(name, shape);
+    } else {
+        g_renderer->setGlyphsShape("all", shape);
+    }
+    return TCL_OK;
+}
+
+static int
+GlyphsVisibleOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                Tcl_Obj *const *objv)
+{
+    bool state;
+    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 4) {
+        const char *name = Tcl_GetString(objv[3]);
+        g_renderer->setGraphicsObjectVisibility<Glyphs>(name, state);
+    } else {
+        g_renderer->setGraphicsObjectVisibility<Glyphs>("all", state);
+    }
+    return TCL_OK;
+}
+
+static int
+GlyphsWireframeOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                  Tcl_Obj *const *objv)
+{
+    bool state;
+    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 4) {
+        const char *name = Tcl_GetString(objv[3]);
+        g_renderer->setGraphicsObjectWireframe<Glyphs>(name, state);
+    } else {
+        g_renderer->setGraphicsObjectWireframe<Glyphs>("all", state);
+    }
+    return TCL_OK;
+}
+
+static Rappture::CmdSpec glyphsOps[] = {
+    {"add",          1, GlyphsAddOp, 3, 4, "shape ?dataSetName?"},
+    {"ccolor",       2, GlyphsColorOp, 5, 6, "r g b ?dataSetName?"},
+    {"colormap",     7, GlyphsColorMapOp, 3, 4, "colorMapName ?dataSetName?"},
+    {"colormode",    7, GlyphsColorModeOp, 4, 5, "mode fieldName ?dataSetName?"},
+    {"delete",       1, GlyphsDeleteOp, 2, 3, "?dataSetName?"},
+    {"edges",        1, GlyphsEdgeVisibilityOp, 3, 4, "bool ?dataSetName?"},
+    {"gorient",      2, GlyphsOrientGlyphsOp, 4, 5, "bool fieldName ?dataSetName?"},
+    {"gscale",       2, GlyphsScaleFactorOp, 3, 4, "scaleFactor ?dataSetName?"},
+    {"lighting",     3, GlyphsLightingOp, 3, 4, "bool ?dataSetName?"},
+    {"linecolor",    5, GlyphsLineColorOp, 5, 6, "r g b ?dataSetName?"},
+    {"linewidth",    5, GlyphsLineWidthOp, 3, 4, "width ?dataSetName?"},
+    {"normscale",    1, GlyphsNormalizeScaleOp, 3, 4, "bool ?dataSetName?"},
+    {"opacity",      2, GlyphsOpacityOp, 3, 4, "value ?dataSetName?"},
+    {"orient",       2, GlyphsOrientOp, 6, 7, "qw qx qy qz ?dataSetName?"},
+    {"pos",          1, GlyphsPositionOp, 5, 6, "x y z ?dataSetName?"},
+    {"scale",        2, GlyphsScaleOp, 5, 6, "sx sy sz ?dataSetName?"},
+    {"shape",        2, GlyphsShapeOp, 3, 4, "shapeVal ?dataSetName?"},
+    {"smode",        2, GlyphsScalingModeOp, 4, 5, "mode fieldName ?dataSetName?"},
+    {"visible",      1, GlyphsVisibleOp, 3, 4, "bool ?dataSetName?"},
+    {"wireframe",    1, GlyphsWireframeOp, 3, 4, "bool ?dataSetName?"}
+};
+static int nGlyphsOps = NumCmdSpecs(glyphsOps);
+
+static int
+GlyphsCmd(ClientData clientData, Tcl_Interp *interp, int objc, 
+          Tcl_Obj *const *objv)
+{
+    Tcl_ObjCmdProc *proc;
+
+    proc = Rappture::GetOpFromObj(interp, nGlyphsOps, glyphsOps,
+                                  Rappture::CMDSPEC_ARG1, objc, objv, 0);
+    if (proc == NULL) {
+        return TCL_ERROR;
+    }
+    return (*proc) (clientData, interp, objc, objv);
+}
+
+static int
+HeightMapAddContourListOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                          Tcl_Obj *const *objv)
+{
+    std::vector<double> contourList;
+    double heightScale;
+
+    int clistc;
+    Tcl_Obj **clistv;
+
+    if (Tcl_ListObjGetElements(interp, objv[3], &clistc, &clistv) != TCL_OK) {
+        return TCL_ERROR;
+    }
+
+    for (int i = 0; i < clistc; i++) {
+        double val;
+        if (Tcl_GetDoubleFromObj(interp, clistv[i], &val) != TCL_OK) {
+            return TCL_ERROR;
+        }
+        contourList.push_back(val);
+    }
+
+    if (Tcl_GetDoubleFromObj(interp, objv[4], &heightScale) != TCL_OK) {
+        return TCL_ERROR;
+    }
+
+    if (objc == 6) {
+        const char *name = Tcl_GetString(objv[5]);
+        if (!g_renderer->addHeightMap(name, contourList, heightScale)) {
+            Tcl_AppendResult(interp, "Failed to create heightmap", (char*)NULL);
+            return TCL_ERROR;
+        }
+    } else {
+        if (!g_renderer->addHeightMap("all", contourList, heightScale)) {
+            Tcl_AppendResult(interp, "Failed to create heightmap for one or more data sets", (char*)NULL);
+            return TCL_ERROR;
+        }
+    }
+    return TCL_OK;
+}
+
+static int
+HeightMapAddNumContoursOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                          Tcl_Obj *const *objv)
+{
+    int numContours;
+    double heightScale;
+    if (Tcl_GetIntFromObj(interp, objv[3], &numContours) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (Tcl_GetDoubleFromObj(interp, objv[4], &heightScale) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 6) {
+        const char *name = Tcl_GetString(objv[5]);
+        if (!g_renderer->addHeightMap(name, numContours, heightScale)) {
+            Tcl_AppendResult(interp, "Failed to create heightmap", (char*)NULL);
+            return TCL_ERROR;
+        }
+    } else {
+        if (!g_renderer->addHeightMap("all", numContours, heightScale)) {
+            Tcl_AppendResult(interp, "Failed to create heightmap for one or more data sets", (char*)NULL);
+            return TCL_ERROR;
+        }
+    }
+    return TCL_OK;
+}
+
+static Rappture::CmdSpec heightmapAddOps[] = {
+    {"contourlist", 1, HeightMapAddContourListOp, 5, 6, "contourList heightscale ?dataSetName?"},
+    {"numcontours", 1, HeightMapAddNumContoursOp, 5, 6, "numContours heightscale ?dataSetName?"}
+};
+static int nHeightmapAddOps = NumCmdSpecs(heightmapAddOps);
+
+static int
+HeightMapAddOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+               Tcl_Obj *const *objv)
+{
+    Tcl_ObjCmdProc *proc;
+
+    proc = Rappture::GetOpFromObj(interp, nHeightmapAddOps, heightmapAddOps,
+                                  Rappture::CMDSPEC_ARG2, objc, objv, 0);
+    if (proc == NULL) {
+        return TCL_ERROR;
+    }
+    return (*proc) (clientData, interp, objc, objv);
+}
+
+static int
+HeightMapAspectOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                  Tcl_Obj *const *objv)
+{
+    double aspect;
+    if (Tcl_GetDoubleFromObj(interp, objv[2], &aspect) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 4) {
+        const char *name = Tcl_GetString(objv[3]);
+        g_renderer->setGraphicsObjectAspect<HeightMap>(name, aspect);
+    } else {
+        g_renderer->setGraphicsObjectAspect<HeightMap>("all", aspect);
+    }
+    return TCL_OK;
+}
+
+static int
+HeightMapColorOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                 Tcl_Obj *const *objv)
+{
+    float color[3];
+    if (GetFloatFromObj(interp, objv[2], &color[0]) != TCL_OK ||
+        GetFloatFromObj(interp, objv[3], &color[1]) != TCL_OK ||
+        GetFloatFromObj(interp, objv[4], &color[2]) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 6) {
+        const char *name = Tcl_GetString(objv[5]);
+        g_renderer->setGraphicsObjectColor<HeightMap>(name, color);
+    } else {
+        g_renderer->setGraphicsObjectColor<HeightMap>("all", color);
+    }
+    return TCL_OK;
+}
+
+static int
+HeightMapColorMapOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                    Tcl_Obj *const *objv)
+{
+    const char *colorMapName = Tcl_GetString(objv[2]);
+    if (objc == 4) {
+        const char *dataSetName = Tcl_GetString(objv[3]);
+        g_renderer->setGraphicsObjectColorMap<HeightMap>(dataSetName, colorMapName);
+    } else {
+        g_renderer->setGraphicsObjectColorMap<HeightMap>("all", colorMapName);
+    }
+    return TCL_OK;
+}
+
+static int
+HeightMapColorModeOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                     Tcl_Obj *const *objv)
+{
+    HeightMap::ColorMode mode;
+    const char *str = Tcl_GetString(objv[2]);
+    if (str[0] == 'c' && strcmp(str, "ccolor") == 0) {
+        mode = HeightMap::COLOR_CONSTANT;
+    } else if (str[0] == 's' && strcmp(str, "scalar") == 0) {
+        mode = HeightMap::COLOR_BY_SCALAR;
+    } else if (str[0] == 'v' && strcmp(str, "vmag") == 0) {
+        mode = HeightMap::COLOR_BY_VECTOR_MAGNITUDE;
+    } else if (str[0] == 'v' && strcmp(str, "vx") == 0) {
+        mode = HeightMap::COLOR_BY_VECTOR_X;
+    } else if (str[0] == 'v' && strcmp(str, "vy") == 0) {
+        mode = HeightMap::COLOR_BY_VECTOR_Y;
+    } else if (str[0] == 'v' && strcmp(str, "vz") == 0) {
+        mode = HeightMap::COLOR_BY_VECTOR_Z;
+    } else {
+        Tcl_AppendResult(interp, "bad color mode option \"", str,
+                         "\": should be one of: 'scalar', 'vmag', 'vx', 'vy', 'vz', 'ccolor'", (char*)NULL);
+        return TCL_ERROR;
+    }
+    const char *fieldName = Tcl_GetString(objv[3]);
+    if (mode == HeightMap::COLOR_CONSTANT) {
+        fieldName = NULL;
+    }
+    if (objc == 5) {
+        const char *name = Tcl_GetString(objv[4]);
+        g_renderer->setHeightMapColorMode(name, mode, fieldName);
+    } else {
+        g_renderer->setHeightMapColorMode("all", mode, fieldName);
+    }
+    return TCL_OK;
+}
+
+static int
+HeightMapContourLineColorMapOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                               Tcl_Obj *const *objv)
+{
+    bool state;
+    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 4) {
+        const char *name = Tcl_GetString(objv[3]);
+        g_renderer->setHeightMapContourLineColorMapEnabled(name, state);
+    } else {
+        g_renderer->setHeightMapContourLineColorMapEnabled("all", state);
+    }
+    return TCL_OK;
+}
+
+static int
+HeightMapContourLineColorOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                            Tcl_Obj *const *objv)
+{
+    float color[3];
+    if (GetFloatFromObj(interp, objv[2], &color[0]) != TCL_OK ||
+        GetFloatFromObj(interp, objv[3], &color[1]) != TCL_OK ||
+        GetFloatFromObj(interp, objv[4], &color[2]) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 6) {
+        const char *name = Tcl_GetString(objv[5]);
+        g_renderer->setHeightMapContourEdgeColor(name, color);
+    } else {
+        g_renderer->setHeightMapContourEdgeColor("all", color);
+    }
+    return TCL_OK;
+}
+
+static int
+HeightMapContourLineWidthOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                            Tcl_Obj *const *objv)
+{
+    float width;
+    if (GetFloatFromObj(interp, objv[2], &width) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 4) {
+        const char *name = Tcl_GetString(objv[3]);
+        g_renderer->setHeightMapContourEdgeWidth(name, width);
+    } else {
+        g_renderer->setHeightMapContourEdgeWidth("all", width);
+    }
+    return TCL_OK;
+}
+
+static int
+HeightMapContourListOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                       Tcl_Obj *const *objv)
+{
+    std::vector<double> contourList;
+
+    int clistc;
+    Tcl_Obj **clistv;
+
+    if (Tcl_ListObjGetElements(interp, objv[2], &clistc, &clistv) != TCL_OK) {
+        return TCL_ERROR;
+    }
+
+    for (int i = 0; i < clistc; i++) {
+        double val;
+        if (Tcl_GetDoubleFromObj(interp, clistv[i], &val) != TCL_OK) {
+            return TCL_ERROR;
+        }
+        contourList.push_back(val);
+    }
+
+    if (objc == 4) {
+        const char *name = Tcl_GetString(objv[3]);
+        g_renderer->setHeightMapContourList(name, contourList);
+    } else {
+        g_renderer->setHeightMapContourList("all", contourList);
+    }
+    return TCL_OK;
+}
+
+static int
+HeightMapContourLineVisibleOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                              Tcl_Obj *const *objv)
+{
+    bool state;
+    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 4) {
+        const char *name = Tcl_GetString(objv[3]);
+        g_renderer->setHeightMapContourLineVisibility(name, state);
+    } else {
+        g_renderer->setHeightMapContourLineVisibility("all", state);
+    }
+    return TCL_OK;
+}
+
+static int
+HeightMapContourSurfaceVisibleOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                                 Tcl_Obj *const *objv)
+{
+    bool state;
+    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 4) {
+        const char *name = Tcl_GetString(objv[3]);
+        g_renderer->setHeightMapContourSurfaceVisibility(name, state);
+    } else {
+        g_renderer->setHeightMapContourSurfaceVisibility("all", state);
+    }
+    return TCL_OK;
+}
+
+static int
+HeightMapDeleteOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                  Tcl_Obj *const *objv)
+{
+    if (objc == 3) {
+        const char *name = Tcl_GetString(objv[2]);
+        g_renderer->deleteGraphicsObject<HeightMap>(name);
+    } else {
+        g_renderer->deleteGraphicsObject<HeightMap>("all");
+    }
+    return TCL_OK;
+}
+
+static int
+HeightMapEdgeVisibilityOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                          Tcl_Obj *const *objv)
+{
+    bool state;
+    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 4) {
+        const char *name = Tcl_GetString(objv[3]);
+        g_renderer->setGraphicsObjectEdgeVisibility<HeightMap>(name, state);
+    } else {
+        g_renderer->setGraphicsObjectEdgeVisibility<HeightMap>("all", state);
+    }
+    return TCL_OK;
+}
+
+static int
+HeightMapHeightScaleOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                       Tcl_Obj *const *objv)
+{
+    double scale;
+    if (Tcl_GetDoubleFromObj(interp, objv[2], &scale) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 4) {
+        const char *name = Tcl_GetString(objv[3]);
+        g_renderer->setHeightMapHeightScale(name, scale);
+    } else {
+        g_renderer->setHeightMapHeightScale("all", scale);
+    }
+    return TCL_OK;
+}
+
+static int
+HeightMapLightingOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                    Tcl_Obj *const *objv)
+{
+    bool state;
+    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 4) {
+        const char *name = Tcl_GetString(objv[3]);
+        g_renderer->setGraphicsObjectLighting<HeightMap>(name, state);
+    } else {
+        g_renderer->setGraphicsObjectLighting<HeightMap>("all", state);
+    }
+    return TCL_OK;
+}
+
+static int
+HeightMapLineColorOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                     Tcl_Obj *const *objv)
+{
+    float color[3];
+    if (GetFloatFromObj(interp, objv[2], &color[0]) != TCL_OK ||
+        GetFloatFromObj(interp, objv[3], &color[1]) != TCL_OK ||
+        GetFloatFromObj(interp, objv[4], &color[2]) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 6) {
+        const char *name = Tcl_GetString(objv[5]);
+        g_renderer->setGraphicsObjectEdgeColor<HeightMap>(name, color);
+    } else {
+        g_renderer->setGraphicsObjectEdgeColor<HeightMap>("all", color);
+    }
+    return TCL_OK;
+}
+
+static int
+HeightMapLineWidthOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                     Tcl_Obj *const *objv)
+{
+    float width;
+    if (GetFloatFromObj(interp, objv[2], &width) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 4) {
+        const char *name = Tcl_GetString(objv[3]);
+        g_renderer->setGraphicsObjectEdgeWidth<HeightMap>(name, width);
+    } else {
+        g_renderer->setGraphicsObjectEdgeWidth<HeightMap>("all", width);
+    }
+    return TCL_OK;
+}
+
+static int
+HeightMapNumContoursOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                       Tcl_Obj *const *objv)
+{
+    int numContours;
+
+    if (Tcl_GetIntFromObj(interp, objv[2], &numContours) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 4) {
+        const char *name = Tcl_GetString(objv[3]);
+        g_renderer->setHeightMapNumContours(name, numContours);
+    } else {
+        g_renderer->setHeightMapNumContours("all", numContours);
+    }
+    return TCL_OK;
+}
+
+static int
+HeightMapOpacityOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                   Tcl_Obj *const *objv)
+{
+    double opacity;
+    if (Tcl_GetDoubleFromObj(interp, objv[2], &opacity) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 4) {
+        const char *name = Tcl_GetString(objv[3]);
+        g_renderer->setGraphicsObjectOpacity<HeightMap>(name, opacity);
+    } else {
+        g_renderer->setGraphicsObjectOpacity<HeightMap>("all", opacity);
+    }
+    return TCL_OK;
+}
+
+static int
+HeightMapOrientOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                  Tcl_Obj *const *objv)
+{
+    double quat[4];
+    if (Tcl_GetDoubleFromObj(interp, objv[2], &quat[0]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[3], &quat[1]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[4], &quat[2]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[5], &quat[3]) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 7) {
+        const char *name = Tcl_GetString(objv[6]);
+        g_renderer->setGraphicsObjectOrientation<HeightMap>(name, quat);
+    } else {
+        g_renderer->setGraphicsObjectOrientation<HeightMap>("all", quat);
+    }
+    return TCL_OK;
+}
+
+static int
+HeightMapPositionOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                    Tcl_Obj *const *objv)
+{
+    double pos[3];
+    if (Tcl_GetDoubleFromObj(interp, objv[2], &pos[0]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[3], &pos[1]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[4], &pos[2]) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 6) {
+        const char *name = Tcl_GetString(objv[5]);
+        g_renderer->setGraphicsObjectPosition<HeightMap>(name, pos);
+    } else {
+        g_renderer->setGraphicsObjectPosition<HeightMap>("all", pos);
+    }
+    return TCL_OK;
+}
+
+static int
+HeightMapPreInterpOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                     Tcl_Obj *const *objv)
+{
+    bool state;
+    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 4) {
+        const char *name = Tcl_GetString(objv[3]);
+        g_renderer->setGraphicsObjectInterpolateBeforeMapping<HeightMap>(name, state);
+    } else {
+        g_renderer->setGraphicsObjectInterpolateBeforeMapping<HeightMap>("all", state);
+    }
+    return TCL_OK;
+}
+
+static int
+HeightMapScaleOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                 Tcl_Obj *const *objv)
+{
+    double scale[3];
+    if (Tcl_GetDoubleFromObj(interp, objv[2], &scale[0]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[3], &scale[1]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[4], &scale[2]) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 6) {
+        const char *name = Tcl_GetString(objv[5]);
+        g_renderer->setGraphicsObjectScale<HeightMap>(name, scale);
+    } else {
+        g_renderer->setGraphicsObjectScale<HeightMap>("all", scale);
+    }
+    return TCL_OK;
+}
+
+static int
+HeightMapVisibleOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                   Tcl_Obj *const *objv)
+{
+    bool state;
+    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 4) {
+        const char *name = Tcl_GetString(objv[3]);
+        g_renderer->setGraphicsObjectVisibility<HeightMap>(name, state);
+    } else {
+        g_renderer->setGraphicsObjectVisibility<HeightMap>("all", state);
+    }
+    return TCL_OK;
+}
+
+static int
+HeightMapVolumeSliceOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                       Tcl_Obj *const *objv)
+{
+    double ratio;
+    if (Tcl_GetDoubleFromObj(interp, objv[3], &ratio) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    const char *string = Tcl_GetString(objv[2]);
+    char c = string[0];
+    Axis axis;
+    if ((c == 'x') && (strcmp(string, "x") == 0)) {
+        axis = X_AXIS;
+    } else if ((c == 'y') && (strcmp(string, "y") == 0)) {
+        axis = Y_AXIS;
+    } else if ((c == 'z') && (strcmp(string, "z") == 0)) {
+        axis = Z_AXIS;
+    } else {
+        Tcl_AppendResult(interp, "bad axis option \"", string,
+                         "\": should be axisName ratio", (char*)NULL);
+        return TCL_ERROR;
+    }
+    if (objc == 5) {
+        const char *name = Tcl_GetString(objv[4]);
+        g_renderer->setGraphicsObjectVolumeSlice<HeightMap>(name, axis, ratio);
+    } else {
+        g_renderer->setGraphicsObjectVolumeSlice<HeightMap>("all", axis, ratio);
+    }
+    return TCL_OK;
+}
+
+static int
+HeightMapWireframeOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                     Tcl_Obj *const *objv)
+{
+    bool state;
+    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 4) {
+        const char *name = Tcl_GetString(objv[3]);
+        g_renderer->setGraphicsObjectWireframe<HeightMap>(name, state);
+    } else {
+        g_renderer->setGraphicsObjectWireframe<HeightMap>("all", state);
+    }
+    return TCL_OK;
+}
+
+static Rappture::CmdSpec heightmapOps[] = {
+    {"add",          2, HeightMapAddOp, 5, 6, "oper value heightscale ?dataSetName?"},
+    {"aspect",       2, HeightMapAspectOp, 3, 4, "aspect ?dataSetName?"},
+    {"ccolor",       2, HeightMapColorOp, 5, 6, "r g b ?dataSetName?"},
+    {"colormap",     7, HeightMapColorMapOp, 3, 4, "colorMapName ?dataSetName?"},
+    {"colormode",    7, HeightMapColorModeOp, 4, 5, "mode fieldName ?dataSetName?"},
+    {"contourlist",  3, HeightMapContourListOp, 3, 4, "contourList ?dataSetName?"},
+    {"delete",       1, HeightMapDeleteOp, 2, 3, "?dataSetName?"},
+    {"edges",        1, HeightMapEdgeVisibilityOp, 3, 4, "bool ?dataSetName?"},
+    {"heightscale",  1, HeightMapHeightScaleOp, 3, 4, "value ?dataSetName?"},
+    {"isolinecmap",  9, HeightMapContourLineColorMapOp, 3, 4, "bool ?dataSetName?"},
+    {"isolinecolor", 9, HeightMapContourLineColorOp, 5, 6, "r g b ?dataSetName?"},
+    {"isolines",     8, HeightMapContourLineVisibleOp, 3, 4, "bool ?dataSetName?"},
+    {"isolinewidth", 8, HeightMapContourLineWidthOp, 3, 4, "width ?dataSetName?"},
+    {"lighting",     3, HeightMapLightingOp, 3, 4, "bool ?dataSetName?"},
+    {"linecolor",    5, HeightMapLineColorOp, 5, 6, "r g b ?dataSetName?"},
+    {"linewidth",    5, HeightMapLineWidthOp, 3, 4, "width ?dataSetName?"},
+    {"numcontours",  1, HeightMapNumContoursOp, 3, 4, "numContours ?dataSetName?"},
+    {"opacity",      2, HeightMapOpacityOp, 3, 4, "value ?dataSetName?"},
+    {"orient",       2, HeightMapOrientOp, 6, 7, "qw qx qy qz ?dataSetName?"},
+    {"pos",          2, HeightMapPositionOp, 5, 6, "x y z ?dataSetName?"},
+    {"preinterp",    2, HeightMapPreInterpOp, 3, 4, "bool ?dataSetName?"},
+    {"scale",        2, HeightMapScaleOp, 5, 6, "sx sy sz ?dataSetName?"},
+    {"slice",        2, HeightMapVolumeSliceOp, 4, 5, "axis ratio ?dataSetName?"},
+    {"surface",      2, HeightMapContourSurfaceVisibleOp, 3, 4, "bool ?dataSetName?"},
+    {"visible",      1, HeightMapVisibleOp, 3, 4, "bool ?dataSetName?"},
+    {"wireframe",    1, HeightMapWireframeOp, 3, 4, "bool ?dataSetName?"}
+};
+static int nHeightmapOps = NumCmdSpecs(heightmapOps);
+
+static int
+HeightMapCmd(ClientData clientData, Tcl_Interp *interp, int objc, 
+             Tcl_Obj *const *objv)
+{
+    Tcl_ObjCmdProc *proc;
+
+    proc = Rappture::GetOpFromObj(interp, nHeightmapOps, heightmapOps,
+                                  Rappture::CMDSPEC_ARG1, objc, objv, 0);
+    if (proc == NULL) {
+        return TCL_ERROR;
+    }
+    return (*proc) (clientData, interp, objc, objv);
+}
+
+static int
+ImageFlushCmd(ClientData clientData, Tcl_Interp *interp, int objc, 
+              Tcl_Obj *const *objv)
+{
+    lastCmdStatus = TCL_BREAK;
+    return TCL_OK;
+}
+
+static int
+LegendCmd(ClientData clientData, Tcl_Interp *interp, int objc, 
+          Tcl_Obj *const *objv)
+{
+    if (objc < 8) {
+        Tcl_AppendResult(interp, "wrong # args: should be \"",
+                Tcl_GetString(objv[0]), " colormapName legendType fieldName title width height numLabels ?dataSetName?\"", (char*)NULL);
+        return TCL_ERROR;
+    }
+    const char *colorMapName = Tcl_GetString(objv[1]);
+    const char *typeStr = Tcl_GetString(objv[2]);
+    Renderer::LegendType legendType;
+    if (typeStr[0] == 's' && strcmp(typeStr, "scalar") == 0) {
+        legendType = Renderer::LEGEND_SCALAR;
+    } else if (typeStr[0] == 'v' && strcmp(typeStr, "vmag") == 0) {
+        legendType = Renderer::LEGEND_VECTOR_MAGNITUDE;
+    } else if (typeStr[0] == 'v' && strcmp(typeStr, "vx") == 0) {
+        legendType = Renderer::LEGEND_VECTOR_X;
+    } else if (typeStr[0] == 'v' && strcmp(typeStr, "vy") == 0) {
+        legendType = Renderer::LEGEND_VECTOR_Y;
+    } else if (typeStr[0] == 'v' && strcmp(typeStr, "vz") == 0) {
+        legendType = Renderer::LEGEND_VECTOR_Z;
+    } else {
+        Tcl_AppendResult(interp, "Bad legendType option \"",
+                         typeStr, "\", should be one of 'scalar', 'vmag', 'vx', 'vy', 'vz'", (char*)NULL);
+        return TCL_ERROR;
+    }
+
+    const char *fieldName = Tcl_GetString(objv[3]);
+
+    std::string title(Tcl_GetString(objv[4]));
+    int width, height, numLabels;
+
+    if (Tcl_GetIntFromObj(interp, objv[5], &width) != TCL_OK ||
+        Tcl_GetIntFromObj(interp, objv[6], &height) != TCL_OK ||
+        Tcl_GetIntFromObj(interp, objv[7], &numLabels) != TCL_OK) {
+        return TCL_ERROR;
+    }
+
+    vtkSmartPointer<vtkUnsignedCharArray> imgData = 
+        vtkSmartPointer<vtkUnsignedCharArray>::New();
+
+    double range[2];
+    range[0] = DBL_MAX;
+    range[1] = -DBL_MAX;
+
+    if (objc == 9) {
+        const char *dataSetName = Tcl_GetString(objv[8]);
+        if (!g_renderer->renderColorMap(colorMapName, dataSetName, legendType, fieldName, title,
+                                        range, width, height, true, numLabels, imgData)) {
+            Tcl_AppendResult(interp, "Color map \"",
+                             colorMapName, "\" or dataset \"",
+                             dataSetName, "\" was not found", (char*)NULL);
+            return TCL_ERROR;
+        }
+    } else {
+        if (!g_renderer->renderColorMap(colorMapName, "all", legendType, fieldName, title,
+                                        range, width, height, true, numLabels, imgData)) {
+            Tcl_AppendResult(interp, "Color map \"",
+                             colorMapName, "\" was not found", (char*)NULL);
+            return TCL_ERROR;
+        }
+    }
+
+#ifdef DEBUG
+# ifdef RENDER_TARGA
+    writeTGAFile("/tmp/legend.tga", imgData->GetPointer(0), width, height,
+                 TARGA_BYTES_PER_PIXEL);
+# else
+    writeTGAFile("/tmp/legend.tga", imgData->GetPointer(0), width, height,
+                 TARGA_BYTES_PER_PIXEL, true);
+# endif
+#else
+    char cmd[256];
+    snprintf(cmd, sizeof(cmd), "nv>legend {%s} {%s} %g %g",
+             colorMapName, title.c_str(), range[0], range[1]);
+
+# ifdef USE_THREADS
+#  ifdef RENDER_TARGA
+    ResponseQueue *queue = (ResponseQueue *)clientData;
+    queueTGA(queue, cmd, imgData->GetPointer(0), width, height,
+             TARGA_BYTES_PER_PIXEL);
+#  else
+    ResponseQueue *queue = (ResponseQueue *)clientData;
+    queuePPM(queue, cmd, imgData->GetPointer(0), width, height);
+#  endif
+# else
+#  ifdef RENDER_TARGA
+    writeTGA(g_fdOut, cmd, imgData->GetPointer(0), width, height,
+             TARGA_BYTES_PER_PIXEL);
+#  else
+    writePPM(g_fdOut, cmd, imgData->GetPointer(0), width, height);
+#  endif
+# endif // USE_THREADS
+#endif // DEBUG
+    return TCL_OK;
+}
+
+static int
+LICAddOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+         Tcl_Obj *const *objv)
+{
+    if (objc == 3) {
+        const char *name = Tcl_GetString(objv[2]);
+        if (!g_renderer->addGraphicsObject<LIC>(name)) {
+            Tcl_AppendResult(interp, "Failed to create lic", (char*)NULL);
+            return TCL_ERROR;
+        }
+    } else {
+        if (!g_renderer->addGraphicsObject<LIC>("all")) {
+            Tcl_AppendResult(interp, "Failed to create lic for one or more data sets", (char*)NULL);
+            return TCL_ERROR;
+        }
+    }
+    return TCL_OK;
+}
+
+static int
+LICColorMapOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+              Tcl_Obj *const *objv)
+{
+    const char *colorMapName = Tcl_GetString(objv[2]);
+    if (objc == 4) {
+        const char *dataSetName = Tcl_GetString(objv[3]);
+        g_renderer->setGraphicsObjectColorMap<LIC>(dataSetName, colorMapName);
+    } else {
+        g_renderer->setGraphicsObjectColorMap<LIC>("all", colorMapName);
+    }
+    return TCL_OK;
+}
+
+static int
+LICDeleteOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+            Tcl_Obj *const *objv)
+{
+    if (objc == 3) {
+        const char *name = Tcl_GetString(objv[2]);
+        g_renderer->deleteGraphicsObject<LIC>(name);
+    } else {
+        g_renderer->deleteGraphicsObject<LIC>("all");
+    }
+    return TCL_OK;
+}
+
+static int
+LICEdgeVisibilityOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                    Tcl_Obj *const *objv)
+{
+    bool state;
+    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 4) {
+        const char *name = Tcl_GetString(objv[3]);
+        g_renderer->setGraphicsObjectEdgeVisibility<LIC>(name, state);
+    } else {
+        g_renderer->setGraphicsObjectEdgeVisibility<LIC>("all", state);
+    }
+    return TCL_OK;
+}
+
+static int
+LICLightingOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+              Tcl_Obj *const *objv)
+{
+    bool state;
+    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 4) {
+        const char *name = Tcl_GetString(objv[3]);
+        g_renderer->setGraphicsObjectLighting<LIC>(name, state);
+    } else {
+        g_renderer->setGraphicsObjectLighting<LIC>("all", state);
+    }
+    return TCL_OK;
+}
+
+static int
+LICLineColorOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+               Tcl_Obj *const *objv)
+{
+    float color[3];
+    if (GetFloatFromObj(interp, objv[2], &color[0]) != TCL_OK ||
+        GetFloatFromObj(interp, objv[3], &color[1]) != TCL_OK ||
+        GetFloatFromObj(interp, objv[4], &color[2]) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 6) {
+        const char *name = Tcl_GetString(objv[5]);
+        g_renderer->setGraphicsObjectEdgeColor<LIC>(name, color);
+    } else {
+        g_renderer->setGraphicsObjectEdgeColor<LIC>("all", color);
+    }
+    return TCL_OK;
+}
+
+static int
+LICLineWidthOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+               Tcl_Obj *const *objv)
+{
+    float width;
+    if (GetFloatFromObj(interp, objv[2], &width) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 4) {
+        const char *name = Tcl_GetString(objv[3]);
+        g_renderer->setGraphicsObjectEdgeWidth<LIC>(name, width);
+    } else {
+        g_renderer->setGraphicsObjectEdgeWidth<LIC>("all", width);
+    }
+    return TCL_OK;
+}
+
+static int
+LICOpacityOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+             Tcl_Obj *const *objv)
+{
+    double opacity;
+    if (Tcl_GetDoubleFromObj(interp, objv[2], &opacity) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 4) {
+        const char *name = Tcl_GetString(objv[3]);
+        g_renderer->setGraphicsObjectOpacity<LIC>(name, opacity);
+    } else {
+        g_renderer->setGraphicsObjectOpacity<LIC>("all", opacity);
+    }
+    return TCL_OK;
+}
+
+static int
+LICOrientOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+            Tcl_Obj *const *objv)
+{
+    double quat[4];
+    if (Tcl_GetDoubleFromObj(interp, objv[2], &quat[0]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[3], &quat[1]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[4], &quat[2]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[5], &quat[3]) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 7) {
+        const char *name = Tcl_GetString(objv[6]);
+        g_renderer->setGraphicsObjectOrientation<LIC>(name, quat);
+    } else {
+        g_renderer->setGraphicsObjectOrientation<LIC>("all", quat);
+    }
+    return TCL_OK;
+}
+
+static int
+LICPositionOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+              Tcl_Obj *const *objv)
+{
+    double pos[3];
+    if (Tcl_GetDoubleFromObj(interp, objv[2], &pos[0]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[3], &pos[1]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[4], &pos[2]) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 6) {
+        const char *name = Tcl_GetString(objv[5]);
+        g_renderer->setGraphicsObjectPosition<LIC>(name, pos);
+    } else {
+        g_renderer->setGraphicsObjectPosition<LIC>("all", pos);
+    }
+    return TCL_OK;
+}
+
+static int
+LICPreInterpOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+               Tcl_Obj *const *objv)
+{
+    bool state;
+    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 4) {
+        const char *name = Tcl_GetString(objv[3]);
+        g_renderer->setGraphicsObjectInterpolateBeforeMapping<LIC>(name, state);
+    } else {
+        g_renderer->setGraphicsObjectInterpolateBeforeMapping<LIC>("all", state);
+    }
+    return TCL_OK;
+}
+
+static int
+LICScaleOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+           Tcl_Obj *const *objv)
+{
+    double scale[3];
+    if (Tcl_GetDoubleFromObj(interp, objv[2], &scale[0]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[3], &scale[1]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[4], &scale[2]) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 6) {
+        const char *name = Tcl_GetString(objv[5]);
+        g_renderer->setGraphicsObjectScale<LIC>(name, scale);
+    } else {
+        g_renderer->setGraphicsObjectScale<LIC>("all", scale);
+    }
+    return TCL_OK;
+}
+
+static int
+LICVisibleOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+             Tcl_Obj *const *objv)
+{
+    bool state;
+    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 4) {
+        const char *name = Tcl_GetString(objv[3]);
+        g_renderer->setGraphicsObjectVisibility<LIC>(name, state);
+    } else {
+        g_renderer->setGraphicsObjectVisibility<LIC>("all", state);
+    }
+    return TCL_OK;
+}
+
+static int
+LICVolumeSliceOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                 Tcl_Obj *const *objv)
+{
+    double ratio;
+    if (Tcl_GetDoubleFromObj(interp, objv[3], &ratio) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    const char *string = Tcl_GetString(objv[2]);
+    char c = string[0];
+    Axis axis;
+    if ((c == 'x') && (strcmp(string, "x") == 0)) {
+        axis = X_AXIS;
+    } else if ((c == 'y') && (strcmp(string, "y") == 0)) {
+        axis = Y_AXIS;
+    } else if ((c == 'z') && (strcmp(string, "z") == 0)) {
+        axis = Z_AXIS;
+    } else {
+        Tcl_AppendResult(interp, "bad axis option \"", string,
+                         "\": should be axisName ratio", (char*)NULL);
+        return TCL_ERROR;
+    }
+    if (objc == 5) {
+        const char *name = Tcl_GetString(objv[4]);
+        g_renderer->setGraphicsObjectVolumeSlice<LIC>(name, axis, ratio);
+    } else {
+        g_renderer->setGraphicsObjectVolumeSlice<LIC>("all", axis, ratio);
+    }
+    return TCL_OK;
+}
+
+static Rappture::CmdSpec licOps[] = {
+    {"add",          1, LICAddOp, 2, 3, "?dataSetName?"},
+    {"colormap",     1, LICColorMapOp, 3, 4, "colorMapName ?dataSetName?"},
+    {"delete",       1, LICDeleteOp, 2, 3, "?dataSetName?"},
+    {"edges",        1, LICEdgeVisibilityOp, 3, 4, "bool ?dataSetName?"},
+    {"lighting",     3, LICLightingOp, 3, 4, "bool ?dataSetName?"},
+    {"linecolor",    5, LICLineColorOp, 5, 6, "r g b ?dataSetName?"},
+    {"linewidth",    5, LICLineWidthOp, 3, 4, "width ?dataSetName?"},
+    {"opacity",      2, LICOpacityOp, 3, 4, "value ?dataSetName?"},
+    {"orient",       2, LICOrientOp, 6, 7, "qw qx qy qz ?dataSetName?"},
+    {"pos",          2, LICPositionOp, 5, 6, "x y z ?dataSetName?"},
+    {"preinterp",    2, LICPreInterpOp, 3, 4, "bool ?dataSetName?"},
+    {"scale",        2, LICScaleOp, 5, 6, "sx sy sz ?dataSetName?"},
+    {"slice",        2, LICVolumeSliceOp, 4, 5, "axis ratio ?dataSetName?"},
+    {"visible",      1, LICVisibleOp, 3, 4, "bool ?dataSetName?"}
+};
+static int nLICOps = NumCmdSpecs(licOps);
+
+static int
+LICCmd(ClientData clientData, Tcl_Interp *interp, int objc, 
+       Tcl_Obj *const *objv)
+{
+    Tcl_ObjCmdProc *proc;
+
+    proc = Rappture::GetOpFromObj(interp, nLICOps, licOps,
+                                  Rappture::CMDSPEC_ARG1, objc, objv, 0);
+    if (proc == NULL) {
+        return TCL_ERROR;
+    }
+    return (*proc) (clientData, interp, objc, objv);
+}
+
+static int
+LineAddOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+          Tcl_Obj *const *objv)
+{
+    double pt1[3];
+    double pt2[3];
+    if (Tcl_GetDoubleFromObj(interp, objv[2], &pt1[0]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[3], &pt1[1]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[4], &pt1[2]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[5], &pt2[0]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[6], &pt2[1]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[7], &pt2[2]) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    const char *name = Tcl_GetString(objv[8]);
+    if (!g_renderer->addLine(name, pt1, pt2)) {
+        Tcl_AppendResult(interp, "Failed to create line", (char*)NULL);
+        return TCL_ERROR;
+    }
+    return TCL_OK;
+}
+
+static int
+LineDeleteOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+             Tcl_Obj *const *objv)
+{
+    if (objc == 3) {
+        const char *name = Tcl_GetString(objv[2]);
+        g_renderer->deleteGraphicsObject<Line>(name);
+    } else {
+        g_renderer->deleteGraphicsObject<Line>("all");
+    }
+    return TCL_OK;
+}
+
+static int
+LineColorOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+            Tcl_Obj *const *objv)
+{
+    float color[3];
+    if (GetFloatFromObj(interp, objv[2], &color[0]) != TCL_OK ||
+        GetFloatFromObj(interp, objv[3], &color[1]) != TCL_OK ||
+        GetFloatFromObj(interp, objv[4], &color[2]) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 6) {
+        const char *name = Tcl_GetString(objv[5]);
+        g_renderer->setGraphicsObjectColor<Line>(name, color);
+    } else {
+        g_renderer->setGraphicsObjectColor<Line>("all", color);
+    }
+    return TCL_OK;
+}
+
+static int
+LineLineWidthOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                Tcl_Obj *const *objv)
+{
+    float width;
+    if (GetFloatFromObj(interp, objv[2], &width) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 4) {
+        const char *name = Tcl_GetString(objv[3]);
+        g_renderer->setGraphicsObjectEdgeWidth<Line>(name, width);
+    } else {
+        g_renderer->setGraphicsObjectEdgeWidth<Line>("all", width);
+    }
+    return TCL_OK;
+}
+
+static int
+LineOpacityOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+              Tcl_Obj *const *objv)
+{
+    double opacity;
+    if (Tcl_GetDoubleFromObj(interp, objv[2], &opacity) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 4) {
+        const char *name = Tcl_GetString(objv[3]);
+        g_renderer->setGraphicsObjectOpacity<Line>(name, opacity);
+    } else {
+        g_renderer->setGraphicsObjectOpacity<Line>("all", opacity);
+    }
+    return TCL_OK;
+}
+
+static int
+LineOrientOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+             Tcl_Obj *const *objv)
+{
+    double quat[4];
+    if (Tcl_GetDoubleFromObj(interp, objv[2], &quat[0]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[3], &quat[1]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[4], &quat[2]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[5], &quat[3]) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 7) {
+        const char *name = Tcl_GetString(objv[6]);
+        g_renderer->setGraphicsObjectOrientation<Line>(name, quat);
+    } else {
+        g_renderer->setGraphicsObjectOrientation<Line>("all", quat);
+    }
+    return TCL_OK;
+}
+
+static int
+LinePositionOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+               Tcl_Obj *const *objv)
+{
+    double pos[3];
+    if (Tcl_GetDoubleFromObj(interp, objv[2], &pos[0]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[3], &pos[1]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[4], &pos[2]) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 6) {
+        const char *name = Tcl_GetString(objv[5]);
+        g_renderer->setGraphicsObjectPosition<Line>(name, pos);
+    } else {
+        g_renderer->setGraphicsObjectPosition<Line>("all", pos);
+    }
+    return TCL_OK;
+}
+
+static int
+LineScaleOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+            Tcl_Obj *const *objv)
+{
+    double scale[3];
+    if (Tcl_GetDoubleFromObj(interp, objv[2], &scale[0]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[3], &scale[1]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[4], &scale[2]) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 6) {
+        const char *name = Tcl_GetString(objv[5]);
+        g_renderer->setGraphicsObjectScale<Line>(name, scale);
+    } else {
+        g_renderer->setGraphicsObjectScale<Line>("all", scale);
+    }
+    return TCL_OK;
+}
+
+static int
+LineVisibleOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+              Tcl_Obj *const *objv)
+{
+    bool state;
+    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 4) {
+        const char *name = Tcl_GetString(objv[3]);
+        g_renderer->setGraphicsObjectVisibility<Line>(name, state);
+    } else {
+        g_renderer->setGraphicsObjectVisibility<Line>("all", state);
+    }
+    return TCL_OK;
+}
+
+static Rappture::CmdSpec lineOps[] = {
+    {"add",       1, LineAddOp, 9, 9, "x1 y1 z1 x2 y2 z2 name"},
+    {"color",     1, LineColorOp, 5, 6, "r g b ?name?"},
+    {"delete",    1, LineDeleteOp, 2, 3, "?name?"},
+    {"linecolor", 5, LineColorOp, 5, 6, "r g b ?name?"},
+    {"linewidth", 5, LineLineWidthOp, 3, 4, "width ?name?"},
+    {"opacity",   2, LineOpacityOp, 3, 4, "value ?name?"},
+    {"orient",    2, LineOrientOp, 6, 7, "qw qx qy qz ?name?"},
+    {"pos",       2, LinePositionOp, 5, 6, "x y z ?name?"},
+    {"scale",     2, LineScaleOp, 5, 6, "sx sy sz ?name?"},
+    {"visible",   1, LineVisibleOp, 3, 4, "bool ?name?"}
+};
+static int nLineOps = NumCmdSpecs(lineOps);
+
+static int
+LineCmd(ClientData clientData, Tcl_Interp *interp, int objc, 
+       Tcl_Obj *const *objv)
+{
+    Tcl_ObjCmdProc *proc;
+
+    proc = Rappture::GetOpFromObj(interp, nLineOps, lineOps,
+                                  Rappture::CMDSPEC_ARG1, objc, objv, 0);
+    if (proc == NULL) {
+        return TCL_ERROR;
+    }
+    return (*proc) (clientData, interp, objc, objv);
+}
+
+static int
+MoleculeAddOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+              Tcl_Obj *const *objv)
+{
+    if (objc == 3) {
+        const char *name = Tcl_GetString(objv[2]);
+        if (!g_renderer->addGraphicsObject<Molecule>(name)) {
+            Tcl_AppendResult(interp, "Failed to create molecule", (char*)NULL);
+            return TCL_ERROR;
+        }
+    } else {
+        if (!g_renderer->addGraphicsObject<Molecule>("all")) {
+            Tcl_AppendResult(interp, "Failed to create molecule for one or more data sets", (char*)NULL);
+            return TCL_ERROR;
+        }
+    }
+    return TCL_OK;
+}
+
+static int
+MoleculeAtomVisibilityOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                         Tcl_Obj *const *objv)
+{
+    bool state;
+    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 4) {
+        const char *name = Tcl_GetString(objv[3]);
+        g_renderer->setMoleculeAtomVisibility(name, state);
+    } else {
+        g_renderer->setMoleculeAtomVisibility("all", state);
+    }
+    return TCL_OK;
+}
+
+static int
+MoleculeAtomLabelVisibilityOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                              Tcl_Obj *const *objv)
+{
+    bool state;
+    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 4) {
+        const char *name = Tcl_GetString(objv[3]);
+        g_renderer->setMoleculeAtomLabelVisibility(name, state);
+    } else {
+        g_renderer->setMoleculeAtomLabelVisibility("all", state);
+    }
+    return TCL_OK;
+}
+
+static int
+MoleculeAtomScaleFactorOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                          Tcl_Obj *const *objv)
+{
+    double scale;
+    if (Tcl_GetDoubleFromObj(interp, objv[2], &scale) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 4) {
+        const char *name = Tcl_GetString(objv[3]);
+        g_renderer->setMoleculeAtomRadiusScale(name, scale);
+    } else {
+        g_renderer->setMoleculeAtomRadiusScale("all", scale);
+    }
+    return TCL_OK;
+}
+
+static int
+MoleculeAtomScalingOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                      Tcl_Obj *const *objv)
+{
+    Molecule::AtomScaling scaling;
+    const char *scalingOpt = Tcl_GetString(objv[2]);
+    if (scalingOpt[0] == 'v' && strcmp(scalingOpt, "van_der_waals") == 0) {
+        scaling = Molecule::VAN_DER_WAALS_RADIUS;
+    } else if (scalingOpt[0] == 'c' && strcmp(scalingOpt, "covalent") == 0) {
+        scaling = Molecule::COVALENT_RADIUS;
+    } else if (scalingOpt[0] == 'a' && strcmp(scalingOpt, "atomic") == 0) {
+        scaling = Molecule::ATOMIC_RADIUS;
+    } else if (scalingOpt[0] == 'n' && strcmp(scalingOpt, "none") == 0) {
+        scaling = Molecule::NO_ATOM_SCALING;
+    } else {
+        Tcl_AppendResult(interp, "bad atomscale option \"", scalingOpt,
+                         "\": should be van_der_waals, covalent, atomic, or none", (char*)NULL);
+        return TCL_ERROR;
+    }
+    if (objc == 4) {
+        const char *name = Tcl_GetString(objv[3]);
+        g_renderer->setMoleculeAtomScaling(name, scaling);
+    } else {
+        g_renderer->setMoleculeAtomScaling("all", scaling);
+    }
+    return TCL_OK;
+}
+
+static int
+MoleculeBondColorModeOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                        Tcl_Obj *const *objv)
+{
+    Molecule::BondColorMode mode;
+    const char *colorMode = Tcl_GetString(objv[2]);
+    if (colorMode[0] == 'c' && strcmp(colorMode, "constant") == 0) {
+        mode = Molecule::BOND_COLOR_CONSTANT;
+    } else if (colorMode[0] == 'b' && strcmp(colorMode, "by_elements") == 0) {
+        mode = Molecule::BOND_COLOR_BY_ELEMENTS;
+    } else {
+        Tcl_AppendResult(interp, "bad bcmode option \"", colorMode,
+                         "\": should be constant or by_elements", (char*)NULL);
+        return TCL_ERROR;
+    }
+    if (objc == 4) {
+        const char *name = Tcl_GetString(objv[3]);
+        g_renderer->setMoleculeBondColorMode(name, mode);
+    } else {
+        g_renderer->setMoleculeBondColorMode("all", mode);
+    }
+    return TCL_OK;
+}
+
+static int
+MoleculeBondColorOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                    Tcl_Obj *const *objv)
+{
+    float color[3];
+    if (GetFloatFromObj(interp, objv[2], &color[0]) != TCL_OK ||
+        GetFloatFromObj(interp, objv[3], &color[1]) != TCL_OK ||
+        GetFloatFromObj(interp, objv[4], &color[2]) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 6) {
+        const char *name = Tcl_GetString(objv[5]);
+        g_renderer->setMoleculeBondColor(name, color);
+    } else {
+        g_renderer->setMoleculeBondColor("all", color);
+    }
+    return TCL_OK;
+}
+
+static int
+MoleculeBondScaleFactorOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                          Tcl_Obj *const *objv)
+{
+    double scale;
+    if (Tcl_GetDoubleFromObj(interp, objv[2], &scale) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 4) {
+        const char *name = Tcl_GetString(objv[3]);
+        g_renderer->setMoleculeBondRadiusScale(name, scale);
+    } else {
+        g_renderer->setMoleculeBondRadiusScale("all", scale);
+    }
+    return TCL_OK;
+}
+
+static int
+MoleculeBondStyleOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                    Tcl_Obj *const *objv)
+{
+    Molecule::BondStyle style;
+    const char *styleStr = Tcl_GetString(objv[2]);
+    if (styleStr[0] == 'c' && strcmp(styleStr, "cylinder") == 0) {
+        style = Molecule::BOND_STYLE_CYLINDER;
+    } else if (styleStr[0] == 'l' && strcmp(styleStr, "line") == 0) {
+        style = Molecule::BOND_STYLE_LINE;
+    } else {
+        Tcl_AppendResult(interp, "bad bstyle option \"", styleStr,
+                         "\": should be cylinder or line", (char*)NULL);
+        return TCL_ERROR;
+    }
+    if (objc == 4) {
+        const char *name = Tcl_GetString(objv[3]);
+        g_renderer->setMoleculeBondStyle(name, style);
+    } else {
+        g_renderer->setMoleculeBondStyle("all", style);
+    }
+    return TCL_OK;
+}
+
+static int
+MoleculeBondVisibilityOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                         Tcl_Obj *const *objv)
+{
+    bool state;
+    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 4) {
+        const char *name = Tcl_GetString(objv[3]);
+        g_renderer->setMoleculeBondVisibility(name, state);
+    } else {
+        g_renderer->setMoleculeBondVisibility("all", state);
+    }
+    return TCL_OK;
+}
+
+static int
+MoleculeColorOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                Tcl_Obj *const *objv)
+{
+    float color[3];
+    if (GetFloatFromObj(interp, objv[2], &color[0]) != TCL_OK ||
+        GetFloatFromObj(interp, objv[3], &color[1]) != TCL_OK ||
+        GetFloatFromObj(interp, objv[4], &color[2]) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 6) {
+        const char *name = Tcl_GetString(objv[5]);
+        g_renderer->setGraphicsObjectColor<Molecule>(name, color);
+    } else {
+        g_renderer->setGraphicsObjectColor<Molecule>("all", color);
+    }
+    return TCL_OK;
+}
+
+static int
+MoleculeColorMapOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                   Tcl_Obj *const *objv)
+{
+    const char *colorMapName = Tcl_GetString(objv[2]);
+    if (objc == 4) {
+        const char *dataSetName = Tcl_GetString(objv[3]);
+        g_renderer->setGraphicsObjectColorMap<Molecule>(dataSetName, colorMapName);
+    } else {
+        g_renderer->setGraphicsObjectColorMap<Molecule>("all", colorMapName);
+    }
+    return TCL_OK;
+}
+
+static int
+MoleculeColorModeOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                    Tcl_Obj *const *objv)
+{
+    Molecule::ColorMode mode;
+    const char *str = Tcl_GetString(objv[2]);
+    if (str[0] == 'b' && strcmp(str, "by_elements") == 0) {
+        mode = Molecule::COLOR_BY_ELEMENTS;
+    } else if (str[0] == 'c' && strcmp(str, "ccolor") == 0) {
+        mode = Molecule::COLOR_CONSTANT;
+    } else if (str[0] == 's' && strcmp(str, "scalar") == 0) {
+        mode = Molecule::COLOR_BY_SCALAR;
+    } else if (str[0] == 'v' && strcmp(str, "vmag") == 0) {
+        mode = Molecule::COLOR_BY_VECTOR_MAGNITUDE;
+    } else if (str[0] == 'v' && strcmp(str, "vx") == 0) {
+        mode = Molecule::COLOR_BY_VECTOR_X;
+    } else if (str[0] == 'v' && strcmp(str, "vy") == 0) {
+        mode = Molecule::COLOR_BY_VECTOR_Y;
+    } else if (str[0] == 'v' && strcmp(str, "vz") == 0) {
+        mode = Molecule::COLOR_BY_VECTOR_Z;
+    } else {
+        Tcl_AppendResult(interp, "bad color mode option \"", str,
+                         "\": should be one of: 'by_elements', 'scalar', 'vmag', 'vx', 'vy', 'vz', 'ccolor'", (char*)NULL);
+        return TCL_ERROR;
+    }
+    const char *fieldName = Tcl_GetString(objv[3]);
+    if (mode == Molecule::COLOR_CONSTANT) {
+        fieldName = NULL;
+    }
+#if 0
+    else if (mode == Molecule::COLOR_BY_ELEMENTS) {
+        fieldName = "element";
+    }
+#endif
+    if (objc == 5) {
+        const char *name = Tcl_GetString(objv[4]);
+        g_renderer->setMoleculeColorMode(name, mode, fieldName);
+    } else {
+        g_renderer->setMoleculeColorMode("all", mode, fieldName);
+    }
+    return TCL_OK;
+}
+
+static int
+MoleculeDeleteOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                 Tcl_Obj *const *objv)
+{
+    if (objc == 3) {
+        const char *name = Tcl_GetString(objv[2]);
+        g_renderer->deleteGraphicsObject<Molecule>(name);
+    } else {
+        g_renderer->deleteGraphicsObject<Molecule>("all");
+    }
+    return TCL_OK;
+}
+
+static int
+MoleculeEdgeVisibilityOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                         Tcl_Obj *const *objv)
+{
+    bool state;
+    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 4) {
+        const char *name = Tcl_GetString(objv[3]);
+        g_renderer->setGraphicsObjectEdgeVisibility<Molecule>(name, state);
+    } else {
+        g_renderer->setGraphicsObjectEdgeVisibility<Molecule>("all", state);
+    }
+    return TCL_OK;
+}
+
+static int
+MoleculeLightingOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                   Tcl_Obj *const *objv)
+{
+    bool state;
+    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 4) {
+        const char *name = Tcl_GetString(objv[3]);
+        g_renderer->setGraphicsObjectLighting<Molecule>(name, state);
+    } else {
+        g_renderer->setGraphicsObjectLighting<Molecule>("all", state);
+    }
+    return TCL_OK;
+}
+
+static int
+MoleculeLineColorOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                    Tcl_Obj *const *objv)
+{
+    float color[3];
+    if (GetFloatFromObj(interp, objv[2], &color[0]) != TCL_OK ||
+        GetFloatFromObj(interp, objv[3], &color[1]) != TCL_OK ||
+        GetFloatFromObj(interp, objv[4], &color[2]) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 6) {
+        const char *name = Tcl_GetString(objv[5]);
+        g_renderer->setGraphicsObjectEdgeColor<Molecule>(name, color);
+    } else {
+        g_renderer->setGraphicsObjectEdgeColor<Molecule>("all", color);
+    }
+    return TCL_OK;
+}
+
+static int
+MoleculeLineWidthOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                    Tcl_Obj *const *objv)
+{
+    float width;
+    if (GetFloatFromObj(interp, objv[2], &width) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 4) {
+        const char *name = Tcl_GetString(objv[3]);
+        g_renderer->setGraphicsObjectEdgeWidth<Molecule>(name, width);
+    } else {
+        g_renderer->setGraphicsObjectEdgeWidth<Molecule>("all", width);
+    }
+    return TCL_OK;
+}
+
+static int
+MoleculeOpacityOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                  Tcl_Obj *const *objv)
+{
+    double opacity;
+    if (Tcl_GetDoubleFromObj(interp, objv[2], &opacity) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 4) {
+        const char *name = Tcl_GetString(objv[3]);
+        g_renderer->setGraphicsObjectOpacity<Molecule>(name, opacity);
+    } else {
+        g_renderer->setGraphicsObjectOpacity<Molecule>("all", opacity);
+    }
+    return TCL_OK;
+}
+
+static int
+MoleculeOrientOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                 Tcl_Obj *const *objv)
+{
+    double quat[4];
+    if (Tcl_GetDoubleFromObj(interp, objv[2], &quat[0]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[3], &quat[1]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[4], &quat[2]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[5], &quat[3]) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 7) {
+        const char *name = Tcl_GetString(objv[6]);
+        g_renderer->setGraphicsObjectOrientation<Molecule>(name, quat);
+    } else {
+        g_renderer->setGraphicsObjectOrientation<Molecule>("all", quat);
+    }
+    return TCL_OK;
+}
+
+static int
+MoleculePositionOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                   Tcl_Obj *const *objv)
+{
+    double pos[3];
+    if (Tcl_GetDoubleFromObj(interp, objv[2], &pos[0]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[3], &pos[1]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[4], &pos[2]) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 6) {
+        const char *name = Tcl_GetString(objv[5]);
+        g_renderer->setGraphicsObjectPosition<Molecule>(name, pos);
+    } else {
+        g_renderer->setGraphicsObjectPosition<Molecule>("all", pos);
+    }
+    return TCL_OK;
+}
+
+static int
+MoleculeScaleOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                Tcl_Obj *const *objv)
+{
+    double scale[3];
+    if (Tcl_GetDoubleFromObj(interp, objv[2], &scale[0]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[3], &scale[1]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[4], &scale[2]) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 6) {
+        const char *name = Tcl_GetString(objv[5]);
+        g_renderer->setGraphicsObjectScale<Molecule>(name, scale);
+    } else {
+        g_renderer->setGraphicsObjectScale<Molecule>("all", scale);
+    }
+    return TCL_OK;
+}
+
+static int
+MoleculeVisibleOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                  Tcl_Obj *const *objv)
+{
+    bool state;
+    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 4) {
+        const char *name = Tcl_GetString(objv[3]);
+        g_renderer->setGraphicsObjectVisibility<Molecule>(name, state);
+    } else {
+        g_renderer->setGraphicsObjectVisibility<Molecule>("all", state);
+    }
+    return TCL_OK;
+}
+
+static int
+MoleculeWireframeOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                    Tcl_Obj *const *objv)
+{
+    bool state;
+    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 4) {
+        const char *name = Tcl_GetString(objv[3]);
+        g_renderer->setGraphicsObjectWireframe<Molecule>(name, state);
+    } else {
+        g_renderer->setGraphicsObjectWireframe<Molecule>("all", state);
+    }
+    return TCL_OK;
+}
+
+static Rappture::CmdSpec moleculeOps[] = {
+    {"add",          2, MoleculeAddOp, 2, 3, "?dataSetName?"},
+    {"ascale",       2, MoleculeAtomScaleFactorOp, 3, 4, "value ?dataSetName?"},
+    {"atoms",        2, MoleculeAtomVisibilityOp, 3, 4, "bool ?dataSetName?"},
+    {"bcmode",       3, MoleculeBondColorModeOp, 3, 4, "mode ?dataSetName?"},
+    {"bcolor",       3, MoleculeBondColorOp, 5, 6, "r g b ?dataSetName?"},
+    {"bonds",        2, MoleculeBondVisibilityOp, 3, 4, "bool ?dataSetName?"},
+    {"bscale",       3, MoleculeBondScaleFactorOp, 3, 4, "value ?dataSetName?"},
+    {"bstyle",       3, MoleculeBondStyleOp, 3, 4, "value ?dataSetName?"},
+    {"ccolor",       2, MoleculeColorOp, 5, 6, "r g b ?dataSetName?"},
+    {"colormap",     7, MoleculeColorMapOp, 3, 4, "colorMapName ?dataSetName?"},
+    {"colormode",    7, MoleculeColorModeOp, 4, 5, "mode fieldName ?dataSetName?"},
+    {"delete",       1, MoleculeDeleteOp, 2, 3, "?dataSetName?"},
+    {"edges",        1, MoleculeEdgeVisibilityOp, 3, 4, "bool ?dataSetName?"},
+    {"labels",       2, MoleculeAtomLabelVisibilityOp, 3, 4, "bool ?dataSetName?"},
+    {"lighting",     3, MoleculeLightingOp, 3, 4, "bool ?dataSetName?"},
+    {"linecolor",    5, MoleculeLineColorOp, 5, 6, "r g b ?dataSetName?"},
+    {"linewidth",    5, MoleculeLineWidthOp, 3, 4, "width ?dataSetName?"},
+    {"opacity",      2, MoleculeOpacityOp, 3, 4, "value ?dataSetName?"},
+    {"orient",       2, MoleculeOrientOp, 6, 7, "qw qx qy qz ?dataSetName?"},
+    {"pos",          1, MoleculePositionOp, 5, 6, "x y z ?dataSetName?"},
+    {"rscale",       1, MoleculeAtomScalingOp, 3, 4, "scaling ?dataSetName?"},
+    {"scale",        1, MoleculeScaleOp, 5, 6, "sx sy sz ?dataSetName?"},
+    {"visible",      1, MoleculeVisibleOp, 3, 4, "bool ?dataSetName?"},
+    {"wireframe",    1, MoleculeWireframeOp, 3, 4, "bool ?dataSetName?"}
+};
+static int nMoleculeOps = NumCmdSpecs(moleculeOps);
+
+static int
+MoleculeCmd(ClientData clientData, Tcl_Interp *interp, int objc, 
+            Tcl_Obj *const *objv)
+{
+    Tcl_ObjCmdProc *proc;
+
+    proc = Rappture::GetOpFromObj(interp, nMoleculeOps, moleculeOps,
+                                  Rappture::CMDSPEC_ARG1, objc, objv, 0);
+    if (proc == NULL) {
+        return TCL_ERROR;
+    }
+    return (*proc) (clientData, interp, objc, objv);
+}
+
+static int
+OutlineAddOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+             Tcl_Obj *const *objv)
+{
+    if (objc == 3) {
+        const char *name = Tcl_GetString(objv[2]);
+        if (!g_renderer->addGraphicsObject<Outline>(name)) {
+            Tcl_AppendResult(interp, "Failed to create Outline", (char*)NULL);
+            return TCL_ERROR;
+        }
+    } else {
+        if (!g_renderer->addGraphicsObject<Outline>("all")) {
+            Tcl_AppendResult(interp, "Failed to create Outline for one or more data sets", (char*)NULL);
+            return TCL_ERROR;
+        }
+    }
+    return TCL_OK;
+}
+
+static int
+OutlineDeleteOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                Tcl_Obj *const *objv)
+{
+    if (objc == 3) {
+        const char *name = Tcl_GetString(objv[2]);
+        g_renderer->deleteGraphicsObject<Outline>(name);
+    } else {
+        g_renderer->deleteGraphicsObject<Outline>("all");
+    }
+    return TCL_OK;
+}
+
+static int
+OutlineColorOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+               Tcl_Obj *const *objv)
+{
+    float color[3];
+    if (GetFloatFromObj(interp, objv[2], &color[0]) != TCL_OK ||
+        GetFloatFromObj(interp, objv[3], &color[1]) != TCL_OK ||
+        GetFloatFromObj(interp, objv[4], &color[2]) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 6) {
+        const char *name = Tcl_GetString(objv[5]);
+        g_renderer->setGraphicsObjectColor<Outline>(name, color);
+    } else {
+        g_renderer->setGraphicsObjectColor<Outline>("all", color);
+    }
+    return TCL_OK;
+}
+
+static int
+OutlineLineWidthOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                   Tcl_Obj *const *objv)
+{
+    float width;
+    if (GetFloatFromObj(interp, objv[2], &width) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 4) {
+        const char *name = Tcl_GetString(objv[3]);
+        g_renderer->setGraphicsObjectEdgeWidth<Outline>(name, width);
+    } else {
+        g_renderer->setGraphicsObjectEdgeWidth<Outline>("all", width);
+    }
+    return TCL_OK;
+}
+
+static int
+OutlineOpacityOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                 Tcl_Obj *const *objv)
+{
+    double opacity;
+    if (Tcl_GetDoubleFromObj(interp, objv[2], &opacity) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 4) {
+        const char *name = Tcl_GetString(objv[3]);
+        g_renderer->setGraphicsObjectOpacity<Outline>(name, opacity);
+    } else {
+        g_renderer->setGraphicsObjectOpacity<Outline>("all", opacity);
+    }
+    return TCL_OK;
+}
+
+static int
+OutlineOrientOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                Tcl_Obj *const *objv)
+{
+    double quat[4];
+    if (Tcl_GetDoubleFromObj(interp, objv[2], &quat[0]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[3], &quat[1]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[4], &quat[2]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[5], &quat[3]) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 7) {
+        const char *name = Tcl_GetString(objv[6]);
+        g_renderer->setGraphicsObjectOrientation<Outline>(name, quat);
+    } else {
+        g_renderer->setGraphicsObjectOrientation<Outline>("all", quat);
+    }
+    return TCL_OK;
+}
+
+static int
+OutlinePositionOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                  Tcl_Obj *const *objv)
+{
+    double pos[3];
+    if (Tcl_GetDoubleFromObj(interp, objv[2], &pos[0]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[3], &pos[1]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[4], &pos[2]) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 6) {
+        const char *name = Tcl_GetString(objv[5]);
+        g_renderer->setGraphicsObjectPosition<Outline>(name, pos);
+    } else {
+        g_renderer->setGraphicsObjectPosition<Outline>("all", pos);
+    }
+    return TCL_OK;
+}
+
+static int
+OutlineScaleOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+               Tcl_Obj *const *objv)
+{
+    double scale[3];
+    if (Tcl_GetDoubleFromObj(interp, objv[2], &scale[0]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[3], &scale[1]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[4], &scale[2]) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 6) {
+        const char *name = Tcl_GetString(objv[5]);
+        g_renderer->setGraphicsObjectScale<Outline>(name, scale);
+    } else {
+        g_renderer->setGraphicsObjectScale<Outline>("all", scale);
+    }
+    return TCL_OK;
+}
+
+static int
+OutlineVisibleOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                 Tcl_Obj *const *objv)
+{
+    bool state;
+    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 4) {
+        const char *name = Tcl_GetString(objv[3]);
+        g_renderer->setGraphicsObjectVisibility<Outline>(name, state);
+    } else {
+        g_renderer->setGraphicsObjectVisibility<Outline>("all", state);
+    }
+    return TCL_OK;
+}
+
+static Rappture::CmdSpec outlineOps[] = {
+    {"add",       1, OutlineAddOp, 2, 3, "?dataSetName?"},
+    {"color",     1, OutlineColorOp, 5, 6, "r g b ?dataSetName?"},
+    {"delete",    1, OutlineDeleteOp, 2, 3, "?dataSetName?"},
+    {"linecolor", 5, OutlineColorOp, 5, 6, "r g b ?dataSetName?"},
+    {"linewidth", 5, OutlineLineWidthOp, 3, 4, "width ?dataSetName?"},
+    {"opacity",   2, OutlineOpacityOp, 3, 4, "value ?dataSetName?"},
+    {"orient",    2, OutlineOrientOp, 6, 7, "qw qx qy qz ?dataSetName?"},
+    {"pos",       2, OutlinePositionOp, 5, 6, "x y z ?dataSetName?"},
+    {"scale",     2, OutlineScaleOp, 5, 6, "sx sy sz ?dataSetName?"},
+    {"visible",   1, OutlineVisibleOp, 3, 4, "bool ?dataSetName?"}
+};
+static int nOutlineOps = NumCmdSpecs(outlineOps);
+
+static int
+OutlineCmd(ClientData clientData, Tcl_Interp *interp, int objc, 
+           Tcl_Obj *const *objv)
+{
+    Tcl_ObjCmdProc *proc;
+
+    proc = Rappture::GetOpFromObj(interp, nOutlineOps, outlineOps,
+                                  Rappture::CMDSPEC_ARG1, objc, objv, 0);
+    if (proc == NULL) {
+        return TCL_ERROR;
+    }
+    return (*proc) (clientData, interp, objc, objv);
+}
+
+static int
+PolyDataAddOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+              Tcl_Obj *const *objv)
+{
+    if (objc == 3) {
+        const char *name = Tcl_GetString(objv[2]);
+        if (!g_renderer->addGraphicsObject<PolyData>(name)) {
+            Tcl_AppendResult(interp, "Failed to create polydata", (char*)NULL);
+            return TCL_ERROR;
+        }
+    } else {
+        if (!g_renderer->addGraphicsObject<PolyData>("all")) {
+            Tcl_AppendResult(interp, "Failed to create polydata for one or more data sets", (char*)NULL);
+            return TCL_ERROR;
+        }
+    }
+    return TCL_OK;
+}
+
+static int
+PolyDataDeleteOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                 Tcl_Obj *const *objv)
+{
+    if (objc == 3) {
+        const char *name = Tcl_GetString(objv[2]);
+        g_renderer->deleteGraphicsObject<PolyData>(name);
+    } else {
+        g_renderer->deleteGraphicsObject<PolyData>("all");
+    }
+    return TCL_OK;
+}
+
+static int
+PolyDataColorOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                Tcl_Obj *const *objv)
+{
+    float color[3];
+    if (GetFloatFromObj(interp, objv[2], &color[0]) != TCL_OK ||
+        GetFloatFromObj(interp, objv[3], &color[1]) != TCL_OK ||
+        GetFloatFromObj(interp, objv[4], &color[2]) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 6) {
+        const char *name = Tcl_GetString(objv[5]);
+        g_renderer->setGraphicsObjectColor<PolyData>(name, color);
+    } else {
+        g_renderer->setGraphicsObjectColor<PolyData>("all", color);
+    }
+    return TCL_OK;
+}
+
+static int
+PolyDataEdgeVisibilityOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                         Tcl_Obj *const *objv)
+{
+    bool state;
+    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 4) {
+        const char *name = Tcl_GetString(objv[3]);
+        g_renderer->setGraphicsObjectEdgeVisibility<PolyData>(name, state);
+    } else {
+        g_renderer->setGraphicsObjectEdgeVisibility<PolyData>("all", state);
+    }
+    return TCL_OK;
+}
+
+static int
+PolyDataLightingOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                   Tcl_Obj *const *objv)
+{
+    bool state;
+    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 4) {
+        const char *name = Tcl_GetString(objv[3]);
+        g_renderer->setGraphicsObjectLighting<PolyData>(name, state);
+    } else {
+        g_renderer->setGraphicsObjectLighting<PolyData>("all", state);
+    }
+    return TCL_OK;
+}
+
+static int
+PolyDataLineColorOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                    Tcl_Obj *const *objv)
+{
+    float color[3];
+    if (GetFloatFromObj(interp, objv[2], &color[0]) != TCL_OK ||
+        GetFloatFromObj(interp, objv[3], &color[1]) != TCL_OK ||
+        GetFloatFromObj(interp, objv[4], &color[2]) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 6) {
+        const char *name = Tcl_GetString(objv[5]);
+        g_renderer->setGraphicsObjectEdgeColor<PolyData>(name, color);
+    } else {
+        g_renderer->setGraphicsObjectEdgeColor<PolyData>("all", color);
+    }
+    return TCL_OK;
+}
+
+static int
+PolyDataLineWidthOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                    Tcl_Obj *const *objv)
+{
+    float width;
+    if (GetFloatFromObj(interp, objv[2], &width) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 4) {
+        const char *name = Tcl_GetString(objv[3]);
+        g_renderer->setGraphicsObjectEdgeWidth<PolyData>(name, width);
+    } else {
+        g_renderer->setGraphicsObjectEdgeWidth<PolyData>("all", width);
+    }
+    return TCL_OK;
+}
+
+static int
+PolyDataMaterialOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                   Tcl_Obj *const *objv)
+{
+    double ambient, diffuse, specCoeff, specPower;
+    if (Tcl_GetDoubleFromObj(interp, objv[2], &ambient) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[3], &diffuse) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[4], &specCoeff) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[5], &specPower) != TCL_OK) {
+        return TCL_ERROR;
+    }
+
+    if (objc == 7) {
+        const char *name = Tcl_GetString(objv[6]);
+        g_renderer->setGraphicsObjectAmbient<PolyData>(name, ambient);
+        g_renderer->setGraphicsObjectDiffuse<PolyData>(name, diffuse);
+        g_renderer->setGraphicsObjectSpecular<PolyData>(name, specCoeff, specPower);
+    } else {
+        g_renderer->setGraphicsObjectAmbient<PolyData>("all", ambient);
+        g_renderer->setGraphicsObjectDiffuse<PolyData>("all", diffuse);
+        g_renderer->setGraphicsObjectSpecular<PolyData>("all", specCoeff, specPower);
+    }
+    return TCL_OK;
+}
+
+static int
+PolyDataOpacityOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                  Tcl_Obj *const *objv)
+{
+    double opacity;
+    if (Tcl_GetDoubleFromObj(interp, objv[2], &opacity) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 4) {
+        const char *name = Tcl_GetString(objv[3]);
+        g_renderer->setGraphicsObjectOpacity<PolyData>(name, opacity);
+    } else {
+        g_renderer->setGraphicsObjectOpacity<PolyData>("all", opacity);
+    }
+    return TCL_OK;
+}
+
+static int
+PolyDataOrientOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                 Tcl_Obj *const *objv)
+{
+    double quat[4];
+    if (Tcl_GetDoubleFromObj(interp, objv[2], &quat[0]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[3], &quat[1]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[4], &quat[2]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[5], &quat[3]) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 7) {
+        const char *name = Tcl_GetString(objv[6]);
+        g_renderer->setGraphicsObjectOrientation<PolyData>(name, quat);
+    } else {
+        g_renderer->setGraphicsObjectOrientation<PolyData>("all", quat);
+    }
+    return TCL_OK;
+}
+
+static int
+PolyDataPointSizeOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                    Tcl_Obj *const *objv)
+{
+    float size;
+    if (GetFloatFromObj(interp, objv[2], &size) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 4) {
+        const char *name = Tcl_GetString(objv[3]);
+        g_renderer->setGraphicsObjectPointSize<PolyData>(name, size);
+    } else {
+        g_renderer->setGraphicsObjectPointSize<PolyData>("all", size);
+    }
+    return TCL_OK;
+}
+
+static int
+PolyDataPositionOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                   Tcl_Obj *const *objv)
+{
+    double pos[3];
+    if (Tcl_GetDoubleFromObj(interp, objv[2], &pos[0]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[3], &pos[1]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[4], &pos[2]) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 6) {
+        const char *name = Tcl_GetString(objv[5]);
+        g_renderer->setGraphicsObjectPosition<PolyData>(name, pos);
+    } else {
+        g_renderer->setGraphicsObjectPosition<PolyData>("all", pos);
+    }
+    return TCL_OK;
+}
+
+static int
+PolyDataScaleOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                Tcl_Obj *const *objv)
+{
+    double scale[3];
+    if (Tcl_GetDoubleFromObj(interp, objv[2], &scale[0]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[3], &scale[1]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[4], &scale[2]) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 6) {
+        const char *name = Tcl_GetString(objv[5]);
+        g_renderer->setGraphicsObjectScale<PolyData>(name, scale);
+    } else {
+        g_renderer->setGraphicsObjectScale<PolyData>("all", scale);
+    }
+    return TCL_OK;
+}
+
+static int
+PolyDataVisibleOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                  Tcl_Obj *const *objv)
+{
+    bool state;
+    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 4) {
+        const char *name = Tcl_GetString(objv[3]);
+        g_renderer->setGraphicsObjectVisibility<PolyData>(name, state);
+    } else {
+        g_renderer->setGraphicsObjectVisibility<PolyData>("all", state);
+    }
+    return TCL_OK;
+}
+
+static int
+PolyDataWireframeOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                    Tcl_Obj *const *objv)
+{
+    bool state;
+    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 4) {
+        const char *name = Tcl_GetString(objv[3]);
+        g_renderer->setGraphicsObjectWireframe<PolyData>(name, state);
+    } else {
+        g_renderer->setGraphicsObjectWireframe<PolyData>("all", state);
+    }
+    return TCL_OK;
+}
+
+static Rappture::CmdSpec polyDataOps[] = {
+    {"add",       1, PolyDataAddOp, 2, 3, "?dataSetName?"},
+    {"color",     1, PolyDataColorOp, 5, 6, "r g b ?dataSetName?"},
+    {"delete",    1, PolyDataDeleteOp, 2, 3, "?dataSetName?"},
+    {"edges",     1, PolyDataEdgeVisibilityOp, 3, 4, "bool ?dataSetName?"},
+    {"lighting",  3, PolyDataLightingOp, 3, 4, "bool ?dataSetName?"},
+    {"linecolor", 5, PolyDataLineColorOp, 5, 6, "r g b ?dataSetName?"},
+    {"linewidth", 5, PolyDataLineWidthOp, 3, 4, "width ?dataSetName?"},
+    {"material",  1, PolyDataMaterialOp, 6, 7, "ambientCoeff diffuseCoeff specularCoeff specularPower ?dataSetName?"},
+    {"opacity",   2, PolyDataOpacityOp, 3, 4, "value ?dataSetName?"},
+    {"orient",    2, PolyDataOrientOp, 6, 7, "qw qx qy qz ?dataSetName?"},
+    {"pos",       2, PolyDataPositionOp, 5, 6, "x y z ?dataSetName?"},
+    {"ptsize",    2, PolyDataPointSizeOp, 3, 4, "size ?dataSetName?"},
+    {"scale",     1, PolyDataScaleOp, 5, 6, "sx sy sz ?dataSetName?"},
+    {"visible",   1, PolyDataVisibleOp, 3, 4, "bool ?dataSetName?"},
+    {"wireframe", 1, PolyDataWireframeOp, 3, 4, "bool ?dataSetName?"}
+};
+static int nPolyDataOps = NumCmdSpecs(polyDataOps);
+
+static int
+PolyDataCmd(ClientData clientData, Tcl_Interp *interp, int objc, 
+            Tcl_Obj *const *objv)
+{
+    Tcl_ObjCmdProc *proc;
+
+    proc = Rappture::GetOpFromObj(interp, nPolyDataOps, polyDataOps,
+                                  Rappture::CMDSPEC_ARG1, objc, objv, 0);
+    if (proc == NULL) {
+        return TCL_ERROR;
+    }
+    return (*proc) (clientData, interp, objc, objv);
+}
+
+static int
+PolygonAddOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+             Tcl_Obj *const *objv)
+{
+    int numSides;
+    if (Tcl_GetIntFromObj(interp, objv[2], &numSides) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    const char *name = Tcl_GetString(objv[3]);
+    if (!g_renderer->addPolygon(name, numSides)) {
+        Tcl_AppendResult(interp, "Failed to create polygon", (char*)NULL);
+        return TCL_ERROR;
+    }
+    return TCL_OK;
+}
+
+static int
+PolygonDeleteOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                Tcl_Obj *const *objv)
+{
+    if (objc == 3) {
+        const char *name = Tcl_GetString(objv[2]);
+        g_renderer->deleteGraphicsObject<Polygon>(name);
+    } else {
+        g_renderer->deleteGraphicsObject<Polygon>("all");
+    }
+    return TCL_OK;
+}
+
+static int
+PolygonColorOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+               Tcl_Obj *const *objv)
+{
+    float color[3];
+    if (GetFloatFromObj(interp, objv[2], &color[0]) != TCL_OK ||
+        GetFloatFromObj(interp, objv[3], &color[1]) != TCL_OK ||
+        GetFloatFromObj(interp, objv[4], &color[2]) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 6) {
+        const char *name = Tcl_GetString(objv[5]);
+        g_renderer->setGraphicsObjectColor<Polygon>(name, color);
+    } else {
+        g_renderer->setGraphicsObjectColor<Polygon>("all", color);
+    }
+    return TCL_OK;
+}
+
+static int
+PolygonEdgeVisibilityOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                        Tcl_Obj *const *objv)
+{
+    bool state;
+    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 4) {
+        const char *name = Tcl_GetString(objv[3]);
+        g_renderer->setGraphicsObjectEdgeVisibility<Polygon>(name, state);
+    } else {
+        g_renderer->setGraphicsObjectEdgeVisibility<Polygon>("all", state);
+    }
+    return TCL_OK;
+}
+
+static int
+PolygonLightingOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                  Tcl_Obj *const *objv)
+{
+    bool state;
+    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 4) {
+        const char *name = Tcl_GetString(objv[3]);
+        g_renderer->setGraphicsObjectLighting<Polygon>(name, state);
+    } else {
+        g_renderer->setGraphicsObjectLighting<Polygon>("all", state);
+    }
+    return TCL_OK;
+}
+
+static int
+PolygonLineColorOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                   Tcl_Obj *const *objv)
+{
+    float color[3];
+    if (GetFloatFromObj(interp, objv[2], &color[0]) != TCL_OK ||
+        GetFloatFromObj(interp, objv[3], &color[1]) != TCL_OK ||
+        GetFloatFromObj(interp, objv[4], &color[2]) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 6) {
+        const char *name = Tcl_GetString(objv[5]);
+        g_renderer->setGraphicsObjectEdgeColor<Polygon>(name, color);
+    } else {
+        g_renderer->setGraphicsObjectEdgeColor<Polygon>("all", color);
+    }
+    return TCL_OK;
+}
+
+static int
+PolygonLineWidthOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                   Tcl_Obj *const *objv)
+{
+    float width;
+    if (GetFloatFromObj(interp, objv[2], &width) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 4) {
+        const char *name = Tcl_GetString(objv[3]);
+        g_renderer->setGraphicsObjectEdgeWidth<Polygon>(name, width);
+    } else {
+        g_renderer->setGraphicsObjectEdgeWidth<Polygon>("all", width);
+    }
+    return TCL_OK;
+}
+
+static int
+PolygonMaterialOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                  Tcl_Obj *const *objv)
+{
+    double ambient, diffuse, specCoeff, specPower;
+    if (Tcl_GetDoubleFromObj(interp, objv[2], &ambient) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[3], &diffuse) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[4], &specCoeff) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[5], &specPower) != TCL_OK) {
+        return TCL_ERROR;
+    }
+
+    if (objc == 7) {
+        const char *name = Tcl_GetString(objv[6]);
+        g_renderer->setGraphicsObjectAmbient<Polygon>(name, ambient);
+        g_renderer->setGraphicsObjectDiffuse<Polygon>(name, diffuse);
+        g_renderer->setGraphicsObjectSpecular<Polygon>(name, specCoeff, specPower);
+    } else {
+        g_renderer->setGraphicsObjectAmbient<Polygon>("all", ambient);
+        g_renderer->setGraphicsObjectDiffuse<Polygon>("all", diffuse);
+        g_renderer->setGraphicsObjectSpecular<Polygon>("all", specCoeff, specPower);
+    }
+    return TCL_OK;
+}
+
+static int
+PolygonOpacityOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                 Tcl_Obj *const *objv)
+{
+    double opacity;
+    if (Tcl_GetDoubleFromObj(interp, objv[2], &opacity) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 4) {
+        const char *name = Tcl_GetString(objv[3]);
+        g_renderer->setGraphicsObjectOpacity<Polygon>(name, opacity);
+    } else {
+        g_renderer->setGraphicsObjectOpacity<Polygon>("all", opacity);
+    }
+    return TCL_OK;
+}
+
+static int
+PolygonOrientOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                Tcl_Obj *const *objv)
+{
+    double quat[4];
+    if (Tcl_GetDoubleFromObj(interp, objv[2], &quat[0]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[3], &quat[1]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[4], &quat[2]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[5], &quat[3]) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 7) {
+        const char *name = Tcl_GetString(objv[6]);
+        g_renderer->setGraphicsObjectOrientation<Polygon>(name, quat);
+    } else {
+        g_renderer->setGraphicsObjectOrientation<Polygon>("all", quat);
+    }
+    return TCL_OK;
+}
+
+static int
+PolygonPositionOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                  Tcl_Obj *const *objv)
+{
+    double pos[3];
+    if (Tcl_GetDoubleFromObj(interp, objv[2], &pos[0]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[3], &pos[1]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[4], &pos[2]) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 6) {
+        const char *name = Tcl_GetString(objv[5]);
+        g_renderer->setGraphicsObjectPosition<Polygon>(name, pos);
+    } else {
+        g_renderer->setGraphicsObjectPosition<Polygon>("all", pos);
+    }
+    return TCL_OK;
+}
+
+static int
+PolygonScaleOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+               Tcl_Obj *const *objv)
+{
+    double scale[3];
+    if (Tcl_GetDoubleFromObj(interp, objv[2], &scale[0]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[3], &scale[1]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[4], &scale[2]) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 6) {
+        const char *name = Tcl_GetString(objv[5]);
+        g_renderer->setGraphicsObjectScale<Polygon>(name, scale);
+    } else {
+        g_renderer->setGraphicsObjectScale<Polygon>("all", scale);
+    }
+    return TCL_OK;
+}
+
+static int
+PolygonVisibleOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                 Tcl_Obj *const *objv)
+{
+    bool state;
+    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 4) {
+        const char *name = Tcl_GetString(objv[3]);
+        g_renderer->setGraphicsObjectVisibility<Polygon>(name, state);
+    } else {
+        g_renderer->setGraphicsObjectVisibility<Polygon>("all", state);
+    }
+    return TCL_OK;
+}
+
+static int
+PolygonWireframeOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                   Tcl_Obj *const *objv)
+{
+    bool state;
+    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 4) {
+        const char *name = Tcl_GetString(objv[3]);
+        g_renderer->setGraphicsObjectWireframe<Polygon>(name, state);
+    } else {
+        g_renderer->setGraphicsObjectWireframe<Polygon>("all", state);
+    }
+    return TCL_OK;
+}
+
+static Rappture::CmdSpec polygonOps[] = {
+    {"add",       1, PolygonAddOp, 4, 4, "numSides name"},
+    {"color",     1, PolygonColorOp, 5, 6, "r g b ?name?"},
+    {"delete",    1, PolygonDeleteOp, 2, 3, "?name?"},
+    {"edges",     1, PolygonEdgeVisibilityOp, 3, 4, "bool ?name?"},
+    {"lighting",  3, PolygonLightingOp, 3, 4, "bool ?name?"},
+    {"linecolor", 5, PolygonLineColorOp, 5, 6, "r g b ?name?"},
+    {"linewidth", 5, PolygonLineWidthOp, 3, 4, "width ?name?"},
+    {"material",  1, PolygonMaterialOp, 6, 7, "ambientCoeff diffuseCoeff specularCoeff specularPower ?name?"},
+    {"opacity",   2, PolygonOpacityOp, 3, 4, "value ?name?"},
+    {"orient",    2, PolygonOrientOp, 6, 7, "qw qx qy qz ?name?"},
+    {"pos",       2, PolygonPositionOp, 5, 6, "x y z ?name?"},
+    {"scale",     1, PolygonScaleOp, 5, 6, "sx sy sz ?name?"},
+    {"visible",   1, PolygonVisibleOp, 3, 4, "bool ?name?"},
+    {"wireframe", 1, PolygonWireframeOp, 3, 4, "bool ?name?"}
+};
+static int nPolygonOps = NumCmdSpecs(polygonOps);
+
+static int
+PolygonCmd(ClientData clientData, Tcl_Interp *interp, int objc, 
+           Tcl_Obj *const *objv)
+{
+    Tcl_ObjCmdProc *proc;
+
+    proc = Rappture::GetOpFromObj(interp, nPolygonOps, polygonOps,
+                                  Rappture::CMDSPEC_ARG1, objc, objv, 0);
+    if (proc == NULL) {
+        return TCL_ERROR;
+    }
+    return (*proc) (clientData, interp, objc, objv);
+}
+
+static int
+PseudoColorAddOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+               Tcl_Obj *const *objv)
+{
+    if (objc == 3) {
+        const char *name = Tcl_GetString(objv[2]);
+        if (!g_renderer->addGraphicsObject<PseudoColor>(name)) {
+            Tcl_AppendResult(interp, "Failed to create pseudocolor", (char*)NULL);
+            return TCL_ERROR;
+        }
+    } else {
+        if (!g_renderer->addGraphicsObject<PseudoColor>("all")) {
+            Tcl_AppendResult(interp, "Failed to create pseudocolor for one or more data sets", (char*)NULL);
+            return TCL_ERROR;
+        }
+    }
+    return TCL_OK;
+}
+
+static int
+PseudoColorColorOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                   Tcl_Obj *const *objv)
+{
+    float color[3];
+    if (GetFloatFromObj(interp, objv[2], &color[0]) != TCL_OK ||
+        GetFloatFromObj(interp, objv[3], &color[1]) != TCL_OK ||
+        GetFloatFromObj(interp, objv[4], &color[2]) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 6) {
+        const char *name = Tcl_GetString(objv[5]);
+        g_renderer->setGraphicsObjectColor<PseudoColor>(name, color);
+    } else {
+        g_renderer->setGraphicsObjectColor<PseudoColor>("all", color);
+    }
+    return TCL_OK;
+}
+
+static int
+PseudoColorColorMapOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                      Tcl_Obj *const *objv)
+{
+    const char *colorMapName = Tcl_GetString(objv[2]);
+    if (objc == 4) {
+        const char *dataSetName = Tcl_GetString(objv[3]);
+        g_renderer->setGraphicsObjectColorMap<PseudoColor>(dataSetName, colorMapName);
+    } else {
+        g_renderer->setGraphicsObjectColorMap<PseudoColor>("all", colorMapName);
+    }
+    return TCL_OK;
+}
+
+static int
+PseudoColorColorModeOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                       Tcl_Obj *const *objv)
+{
+    PseudoColor::ColorMode mode;
+    const char *str = Tcl_GetString(objv[2]);
+    if (str[0] == 'c' && strcmp(str, "ccolor") == 0) {
+        mode = PseudoColor::COLOR_CONSTANT;
+    } else if (str[0] == 's' && strcmp(str, "scalar") == 0) {
+        mode = PseudoColor::COLOR_BY_SCALAR;
+    } else if (str[0] == 'v' && strcmp(str, "vmag") == 0) {
+        mode = PseudoColor::COLOR_BY_VECTOR_MAGNITUDE;
+    } else if (str[0] == 'v' && strcmp(str, "vx") == 0) {
+        mode = PseudoColor::COLOR_BY_VECTOR_X;
+    } else if (str[0] == 'v' && strcmp(str, "vy") == 0) {
+        mode = PseudoColor::COLOR_BY_VECTOR_Y;
+    } else if (str[0] == 'v' && strcmp(str, "vz") == 0) {
+        mode = PseudoColor::COLOR_BY_VECTOR_Z;
+    } else {
+        Tcl_AppendResult(interp, "bad color mode option \"", str,
+                         "\": should be one of: 'scalar', 'vmag', 'vx', 'vy', 'vz', 'ccolor'", (char*)NULL);
+        return TCL_ERROR;
+    }
+    const char *fieldName = Tcl_GetString(objv[3]);
+    if (mode == PseudoColor::COLOR_CONSTANT) {
+        fieldName = NULL;
+    }
+    if (objc == 5) {
+        const char *name = Tcl_GetString(objv[4]);
+        g_renderer->setPseudoColorColorMode(name, mode, fieldName);
+    } else {
+        g_renderer->setPseudoColorColorMode("all", mode, fieldName);
+    }
+    return TCL_OK;
+}
+
+static int
+PseudoColorDeleteOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                  Tcl_Obj *const *objv)
+{
+    if (objc == 3) {
+        const char *name = Tcl_GetString(objv[2]);
+        g_renderer->deleteGraphicsObject<PseudoColor>(name);
+    } else {
+        g_renderer->deleteGraphicsObject<PseudoColor>("all");
+    }
+    return TCL_OK;
+}
+
+static int
+PseudoColorEdgeVisibilityOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                            Tcl_Obj *const *objv)
+{
+    bool state;
+    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 4) {
+        const char *name = Tcl_GetString(objv[3]);
+        g_renderer->setGraphicsObjectEdgeVisibility<PseudoColor>(name, state);
+    } else {
+        g_renderer->setGraphicsObjectEdgeVisibility<PseudoColor>("all", state);
+    }
+    return TCL_OK;
+}
+
+static int
+PseudoColorLightingOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                      Tcl_Obj *const *objv)
+{
+    bool state;
+    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 4) {
+        const char *name = Tcl_GetString(objv[3]);
+        g_renderer->setGraphicsObjectLighting<PseudoColor>(name, state);
+    } else {
+        g_renderer->setGraphicsObjectLighting<PseudoColor>("all", state);
+    }
+    return TCL_OK;
+}
+
+static int
+PseudoColorLineColorOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                       Tcl_Obj *const *objv)
+{
+    float color[3];
+    if (GetFloatFromObj(interp, objv[2], &color[0]) != TCL_OK ||
+        GetFloatFromObj(interp, objv[3], &color[1]) != TCL_OK ||
+        GetFloatFromObj(interp, objv[4], &color[2]) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 6) {
+        const char *name = Tcl_GetString(objv[5]);
+        g_renderer->setGraphicsObjectEdgeColor<PseudoColor>(name, color);
+    } else {
+        g_renderer->setGraphicsObjectEdgeColor<PseudoColor>("all", color);
+    }
+    return TCL_OK;
+}
+
+static int
+PseudoColorLineWidthOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                       Tcl_Obj *const *objv)
+{
+    float width;
+    if (GetFloatFromObj(interp, objv[2], &width) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 4) {
+        const char *name = Tcl_GetString(objv[3]);
+        g_renderer->setGraphicsObjectEdgeWidth<PseudoColor>(name, width);
+    } else {
+        g_renderer->setGraphicsObjectEdgeWidth<PseudoColor>("all", width);
+    }
+    return TCL_OK;
+}
+
+static int
+PseudoColorOpacityOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                     Tcl_Obj *const *objv)
+{
+    double opacity;
+    if (Tcl_GetDoubleFromObj(interp, objv[2], &opacity) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 4) {
+        const char *name = Tcl_GetString(objv[3]);
+        g_renderer->setGraphicsObjectOpacity<PseudoColor>(name, opacity);
+    } else {
+        g_renderer->setGraphicsObjectOpacity<PseudoColor>("all", opacity);
+    }
+    return TCL_OK;
+}
+
+static int
+PseudoColorOrientOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                    Tcl_Obj *const *objv)
+{
+    double quat[4];
+    if (Tcl_GetDoubleFromObj(interp, objv[2], &quat[0]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[3], &quat[1]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[4], &quat[2]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[5], &quat[3]) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 7) {
+        const char *name = Tcl_GetString(objv[6]);
+        g_renderer->setGraphicsObjectOrientation<PseudoColor>(name, quat);
+    } else {
+        g_renderer->setGraphicsObjectOrientation<PseudoColor>("all", quat);
+    }
+    return TCL_OK;
+}
+
+static int
+PseudoColorPositionOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                      Tcl_Obj *const *objv)
+{
+    double pos[3];
+    if (Tcl_GetDoubleFromObj(interp, objv[2], &pos[0]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[3], &pos[1]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[4], &pos[2]) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 6) {
+        const char *name = Tcl_GetString(objv[5]);
+        g_renderer->setGraphicsObjectPosition<PseudoColor>(name, pos);
+    } else {
+        g_renderer->setGraphicsObjectPosition<PseudoColor>("all", pos);
+    }
+    return TCL_OK;
+}
+
+static int
+PseudoColorPreInterpOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                       Tcl_Obj *const *objv)
+{
+    bool state;
+    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 4) {
+        const char *name = Tcl_GetString(objv[3]);
+        g_renderer->setGraphicsObjectInterpolateBeforeMapping<PseudoColor>(name, state);
+    } else {
+        g_renderer->setGraphicsObjectInterpolateBeforeMapping<PseudoColor>("all", state);
+    }
+    return TCL_OK;
+}
+
+static int
+PseudoColorScaleOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                   Tcl_Obj *const *objv)
+{
+    double scale[3];
+    if (Tcl_GetDoubleFromObj(interp, objv[2], &scale[0]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[3], &scale[1]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[4], &scale[2]) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 6) {
+        const char *name = Tcl_GetString(objv[5]);
+        g_renderer->setGraphicsObjectScale<PseudoColor>(name, scale);
+    } else {
+        g_renderer->setGraphicsObjectScale<PseudoColor>("all", scale);
+    }
+    return TCL_OK;
+}
+
+static int
+PseudoColorVisibleOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                     Tcl_Obj *const *objv)
+{
+    bool state;
+    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 4) {
+        const char *name = Tcl_GetString(objv[3]);
+        g_renderer->setGraphicsObjectVisibility<PseudoColor>(name, state);
+    } else {
+        g_renderer->setGraphicsObjectVisibility<PseudoColor>("all", state);
+    }
+    return TCL_OK;
+}
+
+static int
+PseudoColorWireframeOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                       Tcl_Obj *const *objv)
+{
+    bool state;
+    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 4) {
+        const char *name = Tcl_GetString(objv[3]);
+        g_renderer->setGraphicsObjectWireframe<PseudoColor>(name, state);
+    } else {
+        g_renderer->setGraphicsObjectWireframe<PseudoColor>("all", state);
+    }
+    return TCL_OK;
+}
+
+static Rappture::CmdSpec pseudoColorOps[] = {
+    {"add",          1, PseudoColorAddOp, 2, 3, "?dataSetName?"},
+    {"ccolor",       2, PseudoColorColorOp, 5, 6, "r g b ?dataSetName?"},
+    {"colormap",     7, PseudoColorColorMapOp, 3, 4, "colorMapName ?dataSetName?"},
+    {"colormode",    7, PseudoColorColorModeOp, 4, 5, "mode fieldName ?dataSetName?"},
+    {"delete",       1, PseudoColorDeleteOp, 2, 3, "?dataSetName?"},
+    {"edges",        1, PseudoColorEdgeVisibilityOp, 3, 4, "bool ?dataSetName?"},
+    {"lighting",     3, PseudoColorLightingOp, 3, 4, "bool ?dataSetName?"},
+    {"linecolor",    5, PseudoColorLineColorOp, 5, 6, "r g b ?dataSetName?"},
+    {"linewidth",    5, PseudoColorLineWidthOp, 3, 4, "width ?dataSetName?"},
+    {"opacity",      2, PseudoColorOpacityOp, 3, 4, "value ?dataSetName?"},
+    {"orient",       2, PseudoColorOrientOp, 6, 7, "qw qx qy qz ?dataSetName?"},
+    {"pos",          2, PseudoColorPositionOp, 5, 6, "x y z ?dataSetName?"},
+    {"preinterp",    2, PseudoColorPreInterpOp, 3, 4, "bool ?dataSetName?"},
+    {"scale",        1, PseudoColorScaleOp, 5, 6, "sx sy sz ?dataSetName?"},
+    {"visible",      1, PseudoColorVisibleOp, 3, 4, "bool ?dataSetName?"},
+    {"wireframe",    1, PseudoColorWireframeOp, 3, 4, "bool ?dataSetName?"}
+};
+static int nPseudoColorOps = NumCmdSpecs(pseudoColorOps);
+
+static int
+PseudoColorCmd(ClientData clientData, Tcl_Interp *interp, int objc, 
+               Tcl_Obj *const *objv)
+{
+    Tcl_ObjCmdProc *proc;
+
+    proc = Rappture::GetOpFromObj(interp, nPseudoColorOps, pseudoColorOps,
+                                  Rappture::CMDSPEC_ARG1, objc, objv, 0);
+    if (proc == NULL) {
+        return TCL_ERROR;
+    }
+    return (*proc) (clientData, interp, objc, objv);
+}
+
+static int
+RendererClipPlaneOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                    Tcl_Obj *const *objv)
+{
+    const char *string = Tcl_GetString(objv[2]);
+    char c = string[0];
+    Axis axis;
+    if ((c == 'x') && (strcmp(string, "x") == 0)) {
+        axis = X_AXIS;
+    } else if ((c == 'y') && (strcmp(string, "y") == 0)) {
+        axis = Y_AXIS;
+    } else if ((c == 'z') && (strcmp(string, "z") == 0)) {
+        axis = Z_AXIS;
+    } else {
+        Tcl_AppendResult(interp, "bad clipplane option \"", string,
+                         "\": should be axisName ratio direction", (char*)NULL);
+        return TCL_ERROR;
+    }
+    double ratio;
+    if (Tcl_GetDoubleFromObj(interp, objv[3], &ratio) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    int direction;
+    if (Tcl_GetIntFromObj(interp, objv[4], &direction) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    g_renderer->setClipPlane(axis, ratio, direction);
+    return TCL_OK;
+}
+
+static int
+RendererDepthPeelingOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                       Tcl_Obj *const *objv)
+{
+    bool state;
+    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    g_renderer->setUseDepthPeeling(state);
+    return TCL_OK;
+}
+
+static int
+RendererTwoSidedLightingOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                           Tcl_Obj *const *objv)
+{
+    bool state;
+    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    g_renderer->setUseTwoSidedLighting(state);
+    return TCL_OK;
+}
+
+static int
+RendererRenderOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                 Tcl_Obj *const *objv)
+{
+    g_renderer->eventuallyRender();
+    return TCL_OK;
+}
+
+static Rappture::CmdSpec rendererOps[] = {
+    {"clipplane",  1, RendererClipPlaneOp, 5, 5, "axis ratio direction"},
+    {"depthpeel",  1, RendererDepthPeelingOp, 3, 3, "bool"},
+    {"light2side", 1, RendererTwoSidedLightingOp, 3, 3, "bool"},
+    {"render",     1, RendererRenderOp, 2, 2, ""}
+};
+static int nRendererOps = NumCmdSpecs(rendererOps);
+
+static int
+RendererCmd(ClientData clientData, Tcl_Interp *interp, int objc, 
+            Tcl_Obj *const *objv)
+{
+    Tcl_ObjCmdProc *proc;
+
+    proc = Rappture::GetOpFromObj(interp, nRendererOps, rendererOps,
+                                  Rappture::CMDSPEC_ARG1, objc, objv, 0);
+    if (proc == NULL) {
+        return TCL_ERROR;
+    }
+    return (*proc) (clientData, interp, objc, objv);
+}
+
+static int
+ScreenBgColorOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                Tcl_Obj *const *objv)
+{
+    float color[3];
+
+    if (GetFloatFromObj(interp, objv[2], &color[0]) != TCL_OK ||
+        GetFloatFromObj(interp, objv[3], &color[1]) != TCL_OK ||
+        GetFloatFromObj(interp, objv[4], &color[2]) != TCL_OK) {
+        return TCL_ERROR;
+    }
+
+    g_renderer->setBackgroundColor(color);
+    return TCL_OK;
+}
+
+static int
+ScreenSizeOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+             Tcl_Obj *const *objv)
+{
+    int width, height;
+
+    if (Tcl_GetIntFromObj(interp, objv[2], &width) != TCL_OK ||
+        Tcl_GetIntFromObj(interp, objv[3], &height) != TCL_OK) {
+        return TCL_ERROR;
+    }
+
+    g_renderer->setWindowSize(width, height);
+    return TCL_OK;
+}
+
+static Rappture::CmdSpec screenOps[] = {
+    {"bgcolor", 1, ScreenBgColorOp, 5, 5, "r g b"},
+    {"size", 1, ScreenSizeOp, 4, 4, "width height"}
+};
+static int nScreenOps = NumCmdSpecs(screenOps);
+
+static int
+ScreenCmd(ClientData clientData, Tcl_Interp *interp, int objc, 
+          Tcl_Obj *const *objv)
+{
+    Tcl_ObjCmdProc *proc;
+
+    proc = Rappture::GetOpFromObj(interp, nScreenOps, screenOps,
+                                  Rappture::CMDSPEC_ARG1, objc, objv, 0);
+    if (proc == NULL) {
+        return TCL_ERROR;
+    }
+    return (*proc) (clientData, interp, objc, objv);
+}
+
+static int
+SphereAddOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+            Tcl_Obj *const *objv)
+{
+    const char *name = Tcl_GetString(objv[2]);
+    if (!g_renderer->addGraphicsObject<Sphere>(name)) {
+        Tcl_AppendResult(interp, "Failed to create sphere", (char*)NULL);
+        return TCL_ERROR;
+    }
+    return TCL_OK;
+}
+
+static int
+SphereDeleteOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+               Tcl_Obj *const *objv)
+{
+    if (objc == 3) {
+        const char *name = Tcl_GetString(objv[2]);
+        g_renderer->deleteGraphicsObject<Sphere>(name);
+    } else {
+        g_renderer->deleteGraphicsObject<Sphere>("all");
+    }
+    return TCL_OK;
+}
+
+static int
+SphereColorOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+              Tcl_Obj *const *objv)
+{
+    float color[3];
+    if (GetFloatFromObj(interp, objv[2], &color[0]) != TCL_OK ||
+        GetFloatFromObj(interp, objv[3], &color[1]) != TCL_OK ||
+        GetFloatFromObj(interp, objv[4], &color[2]) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 6) {
+        const char *name = Tcl_GetString(objv[5]);
+        g_renderer->setGraphicsObjectColor<Sphere>(name, color);
+    } else {
+        g_renderer->setGraphicsObjectColor<Sphere>("all", color);
+    }
+    return TCL_OK;
+}
+
+static int
+SphereEdgeVisibilityOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                       Tcl_Obj *const *objv)
+{
+    bool state;
+    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 4) {
+        const char *name = Tcl_GetString(objv[3]);
+        g_renderer->setGraphicsObjectEdgeVisibility<Sphere>(name, state);
+    } else {
+        g_renderer->setGraphicsObjectEdgeVisibility<Sphere>("all", state);
+    }
+    return TCL_OK;
+}
+
+static int
+SphereLightingOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                 Tcl_Obj *const *objv)
+{
+    bool state;
+    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 4) {
+        const char *name = Tcl_GetString(objv[3]);
+        g_renderer->setGraphicsObjectLighting<Sphere>(name, state);
+    } else {
+        g_renderer->setGraphicsObjectLighting<Sphere>("all", state);
+    }
+    return TCL_OK;
+}
+
+static int
+SphereLineColorOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                  Tcl_Obj *const *objv)
+{
+    float color[3];
+    if (GetFloatFromObj(interp, objv[2], &color[0]) != TCL_OK ||
+        GetFloatFromObj(interp, objv[3], &color[1]) != TCL_OK ||
+        GetFloatFromObj(interp, objv[4], &color[2]) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 6) {
+        const char *name = Tcl_GetString(objv[5]);
+        g_renderer->setGraphicsObjectEdgeColor<Sphere>(name, color);
+    } else {
+        g_renderer->setGraphicsObjectEdgeColor<Sphere>("all", color);
+    }
+    return TCL_OK;
+}
+
+static int
+SphereLineWidthOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                  Tcl_Obj *const *objv)
+{
+    float width;
+    if (GetFloatFromObj(interp, objv[2], &width) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 4) {
+        const char *name = Tcl_GetString(objv[3]);
+        g_renderer->setGraphicsObjectEdgeWidth<Sphere>(name, width);
+    } else {
+        g_renderer->setGraphicsObjectEdgeWidth<Sphere>("all", width);
+    }
+    return TCL_OK;
+}
+
+static int
+SphereMaterialOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                 Tcl_Obj *const *objv)
+{
+    double ambient, diffuse, specCoeff, specPower;
+    if (Tcl_GetDoubleFromObj(interp, objv[2], &ambient) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[3], &diffuse) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[4], &specCoeff) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[5], &specPower) != TCL_OK) {
+        return TCL_ERROR;
+    }
+
+    if (objc == 7) {
+        const char *name = Tcl_GetString(objv[6]);
+        g_renderer->setGraphicsObjectAmbient<Sphere>(name, ambient);
+        g_renderer->setGraphicsObjectDiffuse<Sphere>(name, diffuse);
+        g_renderer->setGraphicsObjectSpecular<Sphere>(name, specCoeff, specPower);
+    } else {
+        g_renderer->setGraphicsObjectAmbient<Sphere>("all", ambient);
+        g_renderer->setGraphicsObjectDiffuse<Sphere>("all", diffuse);
+        g_renderer->setGraphicsObjectSpecular<Sphere>("all", specCoeff, specPower);
+    }
+    return TCL_OK;
+}
+
+static int
+SphereOpacityOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                Tcl_Obj *const *objv)
+{
+    double opacity;
+    if (Tcl_GetDoubleFromObj(interp, objv[2], &opacity) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 4) {
+        const char *name = Tcl_GetString(objv[3]);
+        g_renderer->setGraphicsObjectOpacity<Sphere>(name, opacity);
+    } else {
+        g_renderer->setGraphicsObjectOpacity<Sphere>("all", opacity);
+    }
+    return TCL_OK;
+}
+
+static int
+SphereOrientOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+               Tcl_Obj *const *objv)
+{
+    double quat[4];
+    if (Tcl_GetDoubleFromObj(interp, objv[2], &quat[0]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[3], &quat[1]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[4], &quat[2]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[5], &quat[3]) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 7) {
+        const char *name = Tcl_GetString(objv[6]);
+        g_renderer->setGraphicsObjectOrientation<Sphere>(name, quat);
+    } else {
+        g_renderer->setGraphicsObjectOrientation<Sphere>("all", quat);
+    }
+    return TCL_OK;
+}
+
+static int
+SpherePositionOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                 Tcl_Obj *const *objv)
+{
+    double pos[3];
+    if (Tcl_GetDoubleFromObj(interp, objv[2], &pos[0]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[3], &pos[1]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[4], &pos[2]) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 6) {
+        const char *name = Tcl_GetString(objv[5]);
+        g_renderer->setGraphicsObjectPosition<Sphere>(name, pos);
+    } else {
+        g_renderer->setGraphicsObjectPosition<Sphere>("all", pos);
+    }
+    return TCL_OK;
+}
+
+static int
+SphereResolutionOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                   Tcl_Obj *const *objv)
+{
+    int theta, phi;
+    if (Tcl_GetIntFromObj(interp, objv[2], &theta) != TCL_OK ||
+        Tcl_GetIntFromObj(interp, objv[3], &phi) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 5) {
+        const char *name = Tcl_GetString(objv[4]);
+        g_renderer->setSphereResolution(name, theta, phi);
+    } else {
+        g_renderer->setSphereResolution("all", theta, phi);
+    }
+    return TCL_OK;
+}
+
+static int
+SphereScaleOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+              Tcl_Obj *const *objv)
+{
+    double scale[3];
+    if (Tcl_GetDoubleFromObj(interp, objv[2], &scale[0]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[3], &scale[1]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[4], &scale[2]) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 6) {
+        const char *name = Tcl_GetString(objv[5]);
+        g_renderer->setGraphicsObjectScale<Sphere>(name, scale);
+    } else {
+        g_renderer->setGraphicsObjectScale<Sphere>("all", scale);
+    }
+    return TCL_OK;
+}
+
+static int
+SphereSectionOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                Tcl_Obj *const *objv)
+{
+    double thetaStart, thetaEnd, phiStart, phiEnd;
+    if (Tcl_GetDoubleFromObj(interp, objv[2], &thetaStart) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[3], &thetaEnd) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[4], &phiStart) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[5], &phiEnd) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 7) {
+        const char *name = Tcl_GetString(objv[6]);
+        g_renderer->setSphereSection(name, thetaStart, thetaEnd, phiStart, phiEnd);
+    } else {
+        g_renderer->setSphereSection("all", thetaStart, thetaEnd, phiStart, phiEnd);
+    }
+    return TCL_OK;
+}
+
+static int
+SphereVisibleOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                Tcl_Obj *const *objv)
+{
+    bool state;
+    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 4) {
+        const char *name = Tcl_GetString(objv[3]);
+        g_renderer->setGraphicsObjectVisibility<Sphere>(name, state);
+    } else {
+        g_renderer->setGraphicsObjectVisibility<Sphere>("all", state);
+    }
+    return TCL_OK;
+}
+
+static int
+SphereWireframeOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                  Tcl_Obj *const *objv)
+{
+    bool state;
+    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 4) {
+        const char *name = Tcl_GetString(objv[3]);
+        g_renderer->setGraphicsObjectWireframe<Sphere>(name, state);
+    } else {
+        g_renderer->setGraphicsObjectWireframe<Sphere>("all", state);
+    }
+    return TCL_OK;
+}
+
+static Rappture::CmdSpec sphereOps[] = {
+    {"add",       1, SphereAddOp, 3, 3, "name"},
+    {"color",     1, SphereColorOp, 5, 6, "r g b ?name?"},
+    {"delete",    1, SphereDeleteOp, 2, 3, "?name?"},
+    {"edges",     1, SphereEdgeVisibilityOp, 3, 4, "bool ?name?"},
+    {"lighting",  3, SphereLightingOp, 3, 4, "bool ?name?"},
+    {"linecolor", 5, SphereLineColorOp, 5, 6, "r g b ?name?"},
+    {"linewidth", 5, SphereLineWidthOp, 3, 4, "width ?name?"},
+    {"material",  1, SphereMaterialOp, 6, 7, "ambientCoeff diffuseCoeff specularCoeff specularPower ?name?"},
+    {"opacity",   2, SphereOpacityOp, 3, 4, "value ?name?"},
+    {"orient",    2, SphereOrientOp, 6, 7, "qw qx qy qz ?name?"},
+    {"pos",       2, SpherePositionOp, 5, 6, "x y z ?name?"},
+    {"resolution",1, SphereResolutionOp, 4, 5, "thetaRes phiRes ?name?"},
+    {"scale",     2, SphereScaleOp, 5, 6, "sx sy sz ?name?"},
+    {"section",   2, SphereSectionOp, 6, 7, "thetaStart thetaEnd phiStart phiEnd ?name?"},
+    {"visible",   1, SphereVisibleOp, 3, 4, "bool ?name?"},
+    {"wireframe", 1, SphereWireframeOp, 3, 4, "bool ?name?"}
+};
+static int nSphereOps = NumCmdSpecs(sphereOps);
+
+static int
+SphereCmd(ClientData clientData, Tcl_Interp *interp, int objc, 
+       Tcl_Obj *const *objv)
+{
+    Tcl_ObjCmdProc *proc;
+
+    proc = Rappture::GetOpFromObj(interp, nSphereOps, sphereOps,
+                                  Rappture::CMDSPEC_ARG1, objc, objv, 0);
+    if (proc == NULL) {
+        return TCL_ERROR;
+    }
+    return (*proc) (clientData, interp, objc, objv);
+}
+
+static int
+StreamlinesAddOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                 Tcl_Obj *const *objv)
+{
+    if (objc == 3) {
+        const char *name = Tcl_GetString(objv[2]);
+        if (!g_renderer->addGraphicsObject<Streamlines>(name)) {
+            Tcl_AppendResult(interp, "Failed to create streamlines", (char*)NULL);
+            return TCL_ERROR;
+        }
+    } else {
+        if (!g_renderer->addGraphicsObject<Streamlines>("all")) {
+            Tcl_AppendResult(interp, "Failed to create streamlines for one or more data sets", (char*)NULL);
+            return TCL_ERROR;
+        }
+    }
+    return TCL_OK;
+}
+
+static int
+StreamlinesColorOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                   Tcl_Obj *const *objv)
+{
+    float color[3];
+    if (GetFloatFromObj(interp, objv[2], &color[0]) != TCL_OK ||
+        GetFloatFromObj(interp, objv[3], &color[1]) != TCL_OK ||
+        GetFloatFromObj(interp, objv[4], &color[2]) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 6) {
+        const char *name = Tcl_GetString(objv[5]);
+        g_renderer->setGraphicsObjectColor<Streamlines>(name, color);
+    } else {
+        g_renderer->setGraphicsObjectColor<Streamlines>("all", color);
+    }
+    return TCL_OK;
+}
+
+static int
+StreamlinesColorMapOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                      Tcl_Obj *const *objv)
+{
+    const char *colorMapName = Tcl_GetString(objv[2]);
+    if (objc == 4) {
+        const char *dataSetName = Tcl_GetString(objv[3]);
+        g_renderer->setGraphicsObjectColorMap<Streamlines>(dataSetName, colorMapName);
+    } else {
+        g_renderer->setGraphicsObjectColorMap<Streamlines>("all", colorMapName);
+    }
+    return TCL_OK;
+}
+
+static int
+StreamlinesColorModeOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                       Tcl_Obj *const *objv)
+{
+    Streamlines::ColorMode mode;
+    const char *str = Tcl_GetString(objv[2]);
+    if (str[0] == 's' && strcmp(str, "scalar") == 0) {
+        mode = Streamlines::COLOR_BY_SCALAR;
+    } else if (str[0] == 'v' && strcmp(str, "vmag") == 0) {
+        mode = Streamlines::COLOR_BY_VECTOR_MAGNITUDE;
+    } else if (str[0] == 'v' && strcmp(str, "vx") == 0) {
+        mode = Streamlines::COLOR_BY_VECTOR_X;
+    } else if (str[0] == 'v' && strcmp(str, "vy") == 0) {
+        mode = Streamlines::COLOR_BY_VECTOR_Y;
+    } else if (str[0] == 'v' && strcmp(str, "vz") == 0) {
+        mode = Streamlines::COLOR_BY_VECTOR_Z;
+    } else if (str[0] == 'c' && strcmp(str, "ccolor") == 0) {
+        mode = Streamlines::COLOR_CONSTANT;
+    } else {
+        Tcl_AppendResult(interp, "bad color mode option \"", str,
+                         "\": should be one of: 'scalar', 'vmag', 'vx', 'vy', 'vz', 'ccolor'", (char*)NULL);
+        return TCL_ERROR;
+    }
+    const char *fieldName = Tcl_GetString(objv[3]);
+    if (mode == Streamlines::COLOR_CONSTANT) {
+        fieldName = NULL;
+    }
+    if (objc == 5) {
+        const char *dataSetName = Tcl_GetString(objv[4]);
+        g_renderer->setStreamlinesColorMode(dataSetName, mode, fieldName);
+    } else {
+        g_renderer->setStreamlinesColorMode("all", mode, fieldName);
+    }
+    return TCL_OK;
+}
+
+static int
+StreamlinesDeleteOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                    Tcl_Obj *const *objv)
+{
+    if (objc == 3) {
+        const char *name = Tcl_GetString(objv[2]);
+        g_renderer->deleteGraphicsObject<Streamlines>(name);
+    } else {
+        g_renderer->deleteGraphicsObject<Streamlines>("all");
+    }
+    return TCL_OK;
+}
+
+static int
+StreamlinesEdgeVisibilityOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                            Tcl_Obj *const *objv)
+{
+    bool state;
+    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 4) {
+        const char *name = Tcl_GetString(objv[3]);
+        g_renderer->setGraphicsObjectEdgeVisibility<Streamlines>(name, state);
+    } else {
+        g_renderer->setGraphicsObjectEdgeVisibility<Streamlines>("all", state);
+    }
+    return TCL_OK;
+}
+
+static int
+StreamlinesLengthOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                    Tcl_Obj *const *objv)
+{
+    double length;
+    if (Tcl_GetDoubleFromObj(interp, objv[2], &length) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 4) {
+        const char *name = Tcl_GetString(objv[3]);
+        g_renderer->setStreamlinesLength(name, length);
+    } else {
+        g_renderer->setStreamlinesLength("all", length);
+    }
+    return TCL_OK;
+}
+
+static int
+StreamlinesLightingOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                      Tcl_Obj *const *objv)
+{
+    bool state;
+    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 4) {
+        const char *name = Tcl_GetString(objv[3]);
+        g_renderer->setGraphicsObjectLighting<Streamlines>(name, state);
+    } else {
+        g_renderer->setGraphicsObjectLighting<Streamlines>("all", state);
+    }
+    return TCL_OK;
+}
+
+static int
+StreamlinesLineColorOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                       Tcl_Obj *const *objv)
+{
+    float color[3];
+    if (GetFloatFromObj(interp, objv[2], &color[0]) != TCL_OK ||
+        GetFloatFromObj(interp, objv[3], &color[1]) != TCL_OK ||
+        GetFloatFromObj(interp, objv[4], &color[2]) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 6) {
+        const char *name = Tcl_GetString(objv[5]);
+        g_renderer->setGraphicsObjectEdgeColor<Streamlines>(name, color);
+    } else {
+        g_renderer->setGraphicsObjectEdgeColor<Streamlines>("all", color);
+    }
+    return TCL_OK;
+}
+
+static int
+StreamlinesLinesOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                   Tcl_Obj *const *objv)
+{
+    if (objc == 3) {
+        const char *name = Tcl_GetString(objv[2]);
+        g_renderer->setStreamlinesTypeToLines(name);
+    } else {
+        g_renderer->setStreamlinesTypeToLines("all");
+    }
+    return TCL_OK;
+}
+
+static int
+StreamlinesLineWidthOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                       Tcl_Obj *const *objv)
+{
+    float width;
+    if (GetFloatFromObj(interp, objv[2], &width) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 4) {
+        const char *name = Tcl_GetString(objv[3]);
+        g_renderer->setGraphicsObjectEdgeWidth<Streamlines>(name, width);
+    } else {
+        g_renderer->setGraphicsObjectEdgeWidth<Streamlines>("all", width);
+    }
+    return TCL_OK;
+}
+
+static int
+StreamlinesOpacityOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                     Tcl_Obj *const *objv)
+{
+    double opacity;
+    if (Tcl_GetDoubleFromObj(interp, objv[2], &opacity) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 4) {
+        const char *name = Tcl_GetString(objv[3]);
+        g_renderer->setGraphicsObjectOpacity<Streamlines>(name, opacity);
+    } else {
+        g_renderer->setGraphicsObjectOpacity<Streamlines>("all", opacity);
+    }
+    return TCL_OK;
+}
+
+static int
+StreamlinesOrientOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                    Tcl_Obj *const *objv)
+{
+    double quat[4];
+    if (Tcl_GetDoubleFromObj(interp, objv[2], &quat[0]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[3], &quat[1]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[4], &quat[2]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[5], &quat[3]) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 7) {
+        const char *name = Tcl_GetString(objv[6]);
+        g_renderer->setGraphicsObjectOrientation<Streamlines>(name, quat);
+    } else {
+        g_renderer->setGraphicsObjectOrientation<Streamlines>("all", quat);
+    }
+    return TCL_OK;
+}
+
+static int
+StreamlinesPositionOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                      Tcl_Obj *const *objv)
+{
+    double pos[3];
+    if (Tcl_GetDoubleFromObj(interp, objv[2], &pos[0]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[3], &pos[1]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[4], &pos[2]) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 6) {
+        const char *name = Tcl_GetString(objv[5]);
+        g_renderer->setGraphicsObjectPosition<Streamlines>(name, pos);
+    } else {
+        g_renderer->setGraphicsObjectPosition<Streamlines>("all", pos);
+    }
+    return TCL_OK;
+}
+
+static int
+StreamlinesScaleOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                   Tcl_Obj *const *objv)
+{
+    double scale[3];
+    if (Tcl_GetDoubleFromObj(interp, objv[2], &scale[0]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[3], &scale[1]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[4], &scale[2]) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 6) {
+        const char *name = Tcl_GetString(objv[5]);
+        g_renderer->setGraphicsObjectScale<Streamlines>(name, scale);
+    } else {
+        g_renderer->setGraphicsObjectScale<Streamlines>("all", scale);
+    }
+    return TCL_OK;
+}
+
+static int
+StreamlinesRibbonsOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                     Tcl_Obj *const *objv)
+{
+    double width, angle;
+    if (Tcl_GetDoubleFromObj(interp, objv[2], &width) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (Tcl_GetDoubleFromObj(interp, objv[3], &angle) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 5) {
+        const char *name = Tcl_GetString(objv[4]);
+        g_renderer->setStreamlinesTypeToRibbons(name, width, angle);
+    } else {
+        g_renderer->setStreamlinesTypeToRibbons("all", width, angle);
+    }
+    return TCL_OK;
+}
+
+static int
+StreamlinesSeedColorOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                       Tcl_Obj *const *objv)
+{
+    float color[3];
+    if (GetFloatFromObj(interp, objv[3], &color[0]) != TCL_OK ||
+        GetFloatFromObj(interp, objv[4], &color[1]) != TCL_OK ||
+        GetFloatFromObj(interp, objv[5], &color[2]) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 7) {
+        const char *name = Tcl_GetString(objv[6]);
+        g_renderer->setStreamlinesSeedColor(name, color);
+    } else {
+        g_renderer->setStreamlinesSeedColor("all", color);
+    }
+    return TCL_OK;
+}
+
+static int
+StreamlinesSeedDiskOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                      Tcl_Obj *const *objv)
+{
+    double center[3], normal[3], radius, innerRadius;
+    int numPoints;
+    for (int i = 0; i < 3; i++) {
+        if (Tcl_GetDoubleFromObj(interp, objv[3+i], &center[i]) != TCL_OK) {
+            return TCL_ERROR;
+        }
+        if (Tcl_GetDoubleFromObj(interp, objv[6+i], &normal[i]) != TCL_OK) {
+            return TCL_ERROR;
+        }
+    }
+    if (Tcl_GetDoubleFromObj(interp, objv[9], &radius) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (Tcl_GetDoubleFromObj(interp, objv[10], &innerRadius) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (Tcl_GetIntFromObj(interp, objv[11], &numPoints) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 13) {
+        const char *name = Tcl_GetString(objv[12]);
+        g_renderer->setStreamlinesSeedToDisk(name, center, normal, radius, innerRadius, numPoints);
+    } else {
+        g_renderer->setStreamlinesSeedToDisk("all", center, normal, radius, innerRadius, numPoints);
+    }
+    return TCL_OK;
+}
+
+static int
+StreamlinesSeedFilledMeshOp(ClientData clientData, Tcl_Interp *interp,
+                            int objc, Tcl_Obj *const *objv)
+{
+    int numPoints = 0;
+    if (Tcl_GetIntFromObj(interp, objv[3], &numPoints) != TCL_OK ||
+        numPoints < 1) {
+        return TCL_ERROR;
+    }
+    const char *string = Tcl_GetString(objv[4]);
+    char c = string[0];
+    if ((c != 'd') || (strcmp(string, "data") != 0)) {
+        Tcl_AppendResult(interp, "bad streamlines seed fmesh option \"",
+                         string, "\": should be data", (char*)NULL);
+        return TCL_ERROR;
+    }
+    string = Tcl_GetString(objv[5]);
+    c = string[0];
+    if ((c != 'f') || (strcmp(string, "follows") != 0)) {
+        Tcl_AppendResult(interp, "bad streamlines seed fmesh option \"",
+                         string, "\": should be follows", (char*)NULL);
+        return TCL_ERROR;
+    }
+    int nbytes = 0;
+    if (Tcl_GetIntFromObj(interp, objv[6], &nbytes) != TCL_OK ||
+        nbytes < 0) {
+        return TCL_ERROR;
+    }
+    char *data = (char *)malloc(nbytes);
+    if (!SocketRead(data, nbytes)) {
+        free(data);
+        return TCL_ERROR;
+    }
+    if (objc == 8) {
+        const char *name = Tcl_GetString(objv[7]);
+        if (!g_renderer->setStreamlinesSeedToFilledMesh(name, data, nbytes,
+                                                        numPoints)) {
+            free(data);
+            Tcl_AppendResult(interp, "Couldn't read mesh data or streamlines not found", (char*)NULL);
+            return TCL_ERROR;
+        }
+    } else {
+        if (!g_renderer->setStreamlinesSeedToFilledMesh("all", data, nbytes,
+                                                        numPoints)) {
+            free(data);
+            Tcl_AppendResult(interp, "Couldn't read mesh data or streamlines not found", (char*)NULL);
+            return TCL_ERROR;
+        }
+    }
+    free(data);
+    return TCL_OK;
+}
+
+static int
+StreamlinesSeedMeshPointsOp(ClientData clientData, Tcl_Interp *interp,
+                            int objc, Tcl_Obj *const *objv)
+{
+    const char *string = Tcl_GetString(objv[3]);
+    char c = string[0];
+    if ((c != 'd') || (strcmp(string, "data") != 0)) {
+        Tcl_AppendResult(interp, "bad streamlines seed fmesh option \"",
+                         string, "\": should be data", (char*)NULL);
+        return TCL_ERROR;
+    }
+    string = Tcl_GetString(objv[4]);
+    c = string[0];
+    if ((c != 'f') || (strcmp(string, "follows") != 0)) {
+        Tcl_AppendResult(interp, "bad streamlines seed fmesh option \"",
+                         string, "\": should be follows", (char*)NULL);
+        return TCL_ERROR;
+    }
+    int nbytes = 0;
+    if (Tcl_GetIntFromObj(interp, objv[5], &nbytes) != TCL_OK ||
+        nbytes < 0) {
+        return TCL_ERROR;
+    }
+    char *data = (char *)malloc(nbytes);
+    if (!SocketRead(data, nbytes)) {
+        free(data);
+        return TCL_ERROR;
+    }
+    if (objc == 7) {
+        const char *name = Tcl_GetString(objv[6]);
+        if (!g_renderer->setStreamlinesSeedToMeshPoints(name, data, nbytes)) {
+            free(data);
+            Tcl_AppendResult(interp, "Couldn't read mesh data or streamlines not found", (char*)NULL);
+            return TCL_ERROR;
+        }
+    } else {
+        if (!g_renderer->setStreamlinesSeedToMeshPoints("all", data, nbytes)) {
+            free(data);
+            Tcl_AppendResult(interp, "Couldn't read mesh data or streamlines not found", (char*)NULL);
+            return TCL_ERROR;
+        }
+    }
+    free(data);
+    return TCL_OK;
+}
+
+static int
+StreamlinesSeedNumPointsOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                           Tcl_Obj *const *objv)
+{
+    int numPoints;
+    if (Tcl_GetIntFromObj(interp, objv[3], &numPoints) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 5) {
+        const char *name = Tcl_GetString(objv[4]);
+        g_renderer->setStreamlinesNumberOfSeedPoints(name, numPoints);
+    } else {
+        g_renderer->setStreamlinesNumberOfSeedPoints("all", numPoints);
+    }
+    return TCL_OK;
+}
+
+static int
+StreamlinesSeedPointsOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                        Tcl_Obj *const *objv)
+{
+    if (objc == 4) {
+        const char *name = Tcl_GetString(objv[3]);
+        g_renderer->setStreamlinesSeedToMeshPoints(name);
+    } else {
+        g_renderer->setStreamlinesSeedToMeshPoints("all");
+    }
+    return TCL_OK;
+}
+
+static int
+StreamlinesSeedPolygonOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                         Tcl_Obj *const *objv)
+{
+    double center[3], normal[3], angle, radius;
+    int numSides;
+    for (int i = 0; i < 3; i++) {
+        if (Tcl_GetDoubleFromObj(interp, objv[3+i], &center[i]) != TCL_OK) {
+            return TCL_ERROR;
+        }
+        if (Tcl_GetDoubleFromObj(interp, objv[6+i], &normal[i]) != TCL_OK) {
+            return TCL_ERROR;
+        }
+    }
+    if (Tcl_GetDoubleFromObj(interp, objv[9], &angle) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (Tcl_GetDoubleFromObj(interp, objv[10], &radius) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (Tcl_GetIntFromObj(interp, objv[11], &numSides) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (numSides < 3) {
+        Tcl_AppendResult(interp, "numSides must be 3 or greater", (char*)NULL);
+        return TCL_ERROR;
+    }
+    if (objc == 13) {
+        const char *name = Tcl_GetString(objv[12]);
+        g_renderer->setStreamlinesSeedToPolygon(name, center, normal, angle, radius, numSides);
+    } else {
+        g_renderer->setStreamlinesSeedToPolygon("all", center, normal, angle, radius, numSides);
+    }
+    return TCL_OK;
+}
+
+static int
+StreamlinesSeedFilledPolygonOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                               Tcl_Obj *const *objv)
+{
+    double center[3], normal[3], angle, radius;
+    int numSides, numPoints;
+    for (int i = 0; i < 3; i++) {
+        if (Tcl_GetDoubleFromObj(interp, objv[3+i], &center[i]) != TCL_OK) {
+            return TCL_ERROR;
+        }
+        if (Tcl_GetDoubleFromObj(interp, objv[6+i], &normal[i]) != TCL_OK) {
+            return TCL_ERROR;
+        }
+    }
+    if (Tcl_GetDoubleFromObj(interp, objv[9], &angle) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (Tcl_GetDoubleFromObj(interp, objv[10], &radius) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (Tcl_GetIntFromObj(interp, objv[11], &numSides) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (numSides < 3) {
+        Tcl_AppendResult(interp, "numSides must be 3 or greater", (char*)NULL);
+        return TCL_ERROR;
+    }
+    if (Tcl_GetIntFromObj(interp, objv[12], &numPoints) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 14) {
+        const char *name = Tcl_GetString(objv[13]);
+        g_renderer->setStreamlinesSeedToFilledPolygon(name, center, normal, angle,
+                                                      radius, numSides, numPoints);
+    } else {
+        g_renderer->setStreamlinesSeedToFilledPolygon("all", center, normal, angle,
+                                                      radius, numSides, numPoints);
+    }
+    return TCL_OK;
+}
+
+static int
+StreamlinesSeedRakeOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                      Tcl_Obj *const *objv)
+{
+    double start[3], end[3];
+    int numPoints;
+    for (int i = 0; i < 3; i++) {
+        if (Tcl_GetDoubleFromObj(interp, objv[3+i], &start[i]) != TCL_OK) {
+            return TCL_ERROR;
+        }
+        if (Tcl_GetDoubleFromObj(interp, objv[6+i], &end[i]) != TCL_OK) {
+            return TCL_ERROR;
+        }
+    }
+    if (Tcl_GetIntFromObj(interp, objv[9], &numPoints) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 11) {
+        const char *name = Tcl_GetString(objv[10]);
+        g_renderer->setStreamlinesSeedToRake(name, start, end, numPoints);
+    } else {
+        g_renderer->setStreamlinesSeedToRake("all", start, end, numPoints);
+    }
+    return TCL_OK;
+}
+
+static int
+StreamlinesSeedRandomOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                        Tcl_Obj *const *objv)
+{
+    int numPoints;
+    if (Tcl_GetIntFromObj(interp, objv[3], &numPoints) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 5) {
+        const char *name = Tcl_GetString(objv[4]);
+        g_renderer->setStreamlinesSeedToFilledMesh(name, numPoints);
+    } else {
+        g_renderer->setStreamlinesSeedToFilledMesh("all", numPoints);
+    }
+    return TCL_OK;
+}
+
+static int
+StreamlinesSeedVisibleOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                         Tcl_Obj *const *objv)
+{
+    bool state;
+    if (GetBooleanFromObj(interp, objv[3], &state) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 5) {
+        const char *name = Tcl_GetString(objv[4]);
+        g_renderer->setStreamlinesSeedVisibility(name, state);
+    } else {
+        g_renderer->setStreamlinesSeedVisibility("all", state);
+    }
+    return TCL_OK;
+}
+
+static Rappture::CmdSpec streamlinesSeedOps[] = {
+    {"color",   1, StreamlinesSeedColorOp,         6, 7, "r g b ?dataSetName?"},
+    {"disk",    1, StreamlinesSeedDiskOp,          12, 13, "centerX centerY centerZ normalX normalY normalZ radius innerRadius numPoints ?dataSetName?"},
+    {"fmesh",   2, StreamlinesSeedFilledMeshOp,    7, 8, "numPoints data follows nbytes ?dataSetName?"},
+    {"fpoly",   2, StreamlinesSeedFilledPolygonOp, 13, 14, "centerX centerY centerZ normalX normalY normalZ angle radius numSides numPoints ?dataSetName?"},
+    {"mesh",    1, StreamlinesSeedMeshPointsOp,    6, 7, "data follows nbytes ?dataSetName?"},
+    {"numpts",  1, StreamlinesSeedNumPointsOp,     4, 5, "numPoints ?dataSetName?"},
+    {"points",  3, StreamlinesSeedPointsOp,        3, 4, "?dataSetName?"},
+    {"polygon", 3, StreamlinesSeedPolygonOp,       12, 13, "centerX centerY centerZ normalX normalY normalZ angle radius numSides ?dataSetName?"},
+    {"rake",    3, StreamlinesSeedRakeOp,          10, 11, "startX startY startZ endX endY endZ numPoints ?dataSetName?"},
+    {"random",  3, StreamlinesSeedRandomOp,        4, 5, "numPoints ?dataSetName?"},
+    {"visible", 1, StreamlinesSeedVisibleOp,       4, 5, "bool ?dataSetName?"}
+};
+static int nStreamlinesSeedOps = NumCmdSpecs(streamlinesSeedOps);
+
+static int
+StreamlinesSeedOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                  Tcl_Obj *const *objv)
+{
+    Tcl_ObjCmdProc *proc;
+
+    proc = Rappture::GetOpFromObj(interp, nStreamlinesSeedOps, streamlinesSeedOps,
+                                  Rappture::CMDSPEC_ARG2, objc, objv, 0);
+    if (proc == NULL) {
+        return TCL_ERROR;
+    }
+    return (*proc) (clientData, interp, objc, objv);
+}
+
+static int
+StreamlinesTubesOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                   Tcl_Obj *const *objv)
+{
+    int numSides;
+    double radius;
+    if (Tcl_GetIntFromObj(interp, objv[2], &numSides) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (Tcl_GetDoubleFromObj(interp, objv[3], &radius) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 5) {
+        const char *name = Tcl_GetString(objv[4]);
+        g_renderer->setStreamlinesTypeToTubes(name, numSides, radius);
+    } else {
+        g_renderer->setStreamlinesTypeToTubes("all", numSides, radius);
+    }
+    return TCL_OK;
+}
+
+static int
+StreamlinesVisibleOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                     Tcl_Obj *const *objv)
+{
+    bool state;
+    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 4) {
+        const char *name = Tcl_GetString(objv[3]);
+        g_renderer->setGraphicsObjectVisibility<Streamlines>(name, state);
+    } else {
+        g_renderer->setGraphicsObjectVisibility<Streamlines>("all", state);
+    }
+    return TCL_OK;
+}
+
+static Rappture::CmdSpec streamlinesOps[] = {
+    {"add",          1, StreamlinesAddOp,            2, 3, "?dataSetName?"},
+    {"ccolor",       1, StreamlinesColorOp,          5, 6, "r g b ?dataSetName?"},
+    {"colormap",     7, StreamlinesColorMapOp,       3, 4, "colorMapName ?dataSetName?"},
+    {"colormode",    7, StreamlinesColorModeOp,      4, 5, "mode fieldName ?dataSetName?"},
+    {"delete",       1, StreamlinesDeleteOp,         2, 3, "?dataSetName?"},
+    {"edges",        1, StreamlinesEdgeVisibilityOp, 3, 4, "bool ?dataSetName?"},
+    {"length",       2, StreamlinesLengthOp,         3, 4, "length ?dataSetName?"},
+    {"lighting",     3, StreamlinesLightingOp,       3, 4, "bool ?dataSetName?"},
+    {"linecolor",    5, StreamlinesLineColorOp,      5, 6, "r g b ?dataSetName?"},
+    {"lines",        5, StreamlinesLinesOp,          2, 3, "?dataSetName?"},
+    {"linewidth",    5, StreamlinesLineWidthOp,      3, 4, "width ?dataSetName?"},
+    {"opacity",      2, StreamlinesOpacityOp,        3, 4, "val ?dataSetName?"},
+    {"orient",       2, StreamlinesOrientOp,         6, 7, "qw qx qy qz ?dataSetName?"},
+    {"pos",          1, StreamlinesPositionOp,       5, 6, "x y z ?dataSetName?"},
+    {"ribbons",      1, StreamlinesRibbonsOp,        4, 5, "width angle ?dataSetName?"},
+    {"scale",        2, StreamlinesScaleOp,          5, 6, "sx sy sz ?dataSetName?"},
+    {"seed",         2, StreamlinesSeedOp,           3, 14, "op params... ?dataSetName?"},
+    {"tubes",        1, StreamlinesTubesOp,          4, 5, "numSides radius ?dataSetName?"},
+    {"visible",      1, StreamlinesVisibleOp,        3, 4, "bool ?dataSetName?"}
+};
+static int nStreamlinesOps = NumCmdSpecs(streamlinesOps);
+
+static int
+StreamlinesCmd(ClientData clientData, Tcl_Interp *interp, int objc, 
+               Tcl_Obj *const *objv)
+{
+    Tcl_ObjCmdProc *proc;
+
+    proc = Rappture::GetOpFromObj(interp, nStreamlinesOps, streamlinesOps,
+                                  Rappture::CMDSPEC_ARG1, objc, objv, 0);
+    if (proc == NULL) {
+        return TCL_ERROR;
+    }
+    return (*proc) (clientData, interp, objc, objv);
+}
+
+static int
+VolumeAddOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+            Tcl_Obj *const *objv)
+{
+    if (objc == 3) {
+        const char *name = Tcl_GetString(objv[2]);
+        if (!g_renderer->addGraphicsObject<Volume>(name)) {
+            Tcl_AppendResult(interp, "Failed to create volume", (char*)NULL);
+            return TCL_ERROR;
+        }
+    } else {
+        if (!g_renderer->addGraphicsObject<Volume>("all")) {
+            Tcl_AppendResult(interp, "Failed to create volume for one or more data sets", (char*)NULL);
+            return TCL_ERROR;
+        }
+    }
+    return TCL_OK;
+}
+
+static int
+VolumeColorMapOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                 Tcl_Obj *const *objv)
+{
+    const char *colorMapName = Tcl_GetString(objv[2]);
+    if (objc == 4) {
+        const char *dataSetName = Tcl_GetString(objv[3]);
+        g_renderer->setGraphicsObjectColorMap<Volume>(dataSetName, colorMapName);
+    } else {
+        g_renderer->setGraphicsObjectColorMap<Volume>("all", colorMapName);
+    }
+    return TCL_OK;
+}
+
+static int
+VolumeDeleteOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+               Tcl_Obj *const *objv)
+{
+    if (objc == 3) {
+        const char *name = Tcl_GetString(objv[2]);
+        g_renderer->deleteGraphicsObject<Volume>(name);
+    } else {
+        g_renderer->deleteGraphicsObject<Volume>("all");
+    }
+    return TCL_OK;
+}
+
+static int
+VolumeLightingOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                 Tcl_Obj *const *objv)
+{
+    bool state;
+    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 4) {
+        const char *name = Tcl_GetString(objv[3]);
+        g_renderer->setGraphicsObjectLighting<Volume>(name, state);
+    } else {
+        g_renderer->setGraphicsObjectLighting<Volume>("all", state);
+    }
+    return TCL_OK;
+}
+
+static int
+VolumeOpacityOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                Tcl_Obj *const *objv)
+{
+    double opacity;
+    if (Tcl_GetDoubleFromObj(interp, objv[2], &opacity) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 4) {
+        const char *name = Tcl_GetString(objv[3]);
+        g_renderer->setGraphicsObjectOpacity<Volume>(name, opacity);
+    } else {
+        g_renderer->setGraphicsObjectOpacity<Volume>("all", opacity);
+    }
+    return TCL_OK;
+}
+
+static int
+VolumeOrientOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+               Tcl_Obj *const *objv)
+{
+    double quat[4];
+    if (Tcl_GetDoubleFromObj(interp, objv[2], &quat[0]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[3], &quat[1]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[4], &quat[2]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[5], &quat[3]) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 7) {
+        const char *name = Tcl_GetString(objv[6]);
+        g_renderer->setGraphicsObjectOrientation<Volume>(name, quat);
+    } else {
+        g_renderer->setGraphicsObjectOrientation<Volume>("all", quat);
+    }
+    return TCL_OK;
+}
+
+static int
+VolumePositionOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                 Tcl_Obj *const *objv)
+{
+    double pos[3];
+    if (Tcl_GetDoubleFromObj(interp, objv[2], &pos[0]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[3], &pos[1]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[4], &pos[2]) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 6) {
+        const char *name = Tcl_GetString(objv[5]);
+        g_renderer->setGraphicsObjectPosition<Volume>(name, pos);
+    } else {
+        g_renderer->setGraphicsObjectPosition<Volume>("all", pos);
+    }
+    return TCL_OK;
+}
+
+static int
+VolumeSampleRateOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                   Tcl_Obj *const *objv)
+{
+    double quality;
+    if (Tcl_GetDoubleFromObj(interp, objv[2], &quality) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (quality < 0.0 || quality > 1.0) {
+        Tcl_AppendResult(interp, "bad volume quality value \"",
+                         Tcl_GetString(objv[2]),
+                         "\": should be in the range [0,1]", (char*)NULL);
+        return TCL_ERROR;
+    }
+    double distance;
+    double maxFactor = 4.0;
+    if (quality >= 0.5) {
+        distance = 1.0 / ((quality - 0.5) * (maxFactor - 1.0) * 2.0 + 1.0);
+    } else {
+        distance = ((0.5 - quality) * (maxFactor - 1.0) * 2.0 + 1.0);
+    }
+    if (objc == 4) {
+        const char *name = Tcl_GetString(objv[3]);
+        g_renderer->setVolumeSampleDistance(name, distance);
+    } else {
+        g_renderer->setVolumeSampleDistance("all", distance);
+    }
+    return TCL_OK;
+}
+
+static int
+VolumeScaleOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+              Tcl_Obj *const *objv)
+{
+    double scale[3];
+    if (Tcl_GetDoubleFromObj(interp, objv[2], &scale[0]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[3], &scale[1]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[4], &scale[2]) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 6) {
+        const char *name = Tcl_GetString(objv[5]);
+        g_renderer->setGraphicsObjectScale<Volume>(name, scale);
+    } else {
+        g_renderer->setGraphicsObjectScale<Volume>("all", scale);
+    }
+    return TCL_OK;
+}
+
+static int
+VolumeShadingAmbientOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                       Tcl_Obj *const *objv)
+{
+    double coeff;
+    if (Tcl_GetDoubleFromObj(interp, objv[3], &coeff) != TCL_OK) {
+        return TCL_ERROR;
+    }
+
+    if (objc == 5) {
+        const char *name = Tcl_GetString(objv[4]);
+        g_renderer->setGraphicsObjectAmbient<Volume>(name, coeff);
+    } else {
+        g_renderer->setGraphicsObjectAmbient<Volume>("all", coeff);
+    }
+    return TCL_OK;
+}
+
+static int
+VolumeShadingDiffuseOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                       Tcl_Obj *const *objv)
+{
+    double coeff;
+    if (Tcl_GetDoubleFromObj(interp, objv[3], &coeff) != TCL_OK) {
+        return TCL_ERROR;
+    }
+
+    if (objc == 5) {
+        const char *name = Tcl_GetString(objv[4]);
+        g_renderer->setGraphicsObjectDiffuse<Volume>(name, coeff);
+    } else {
+        g_renderer->setGraphicsObjectDiffuse<Volume>("all", coeff);
+    }
+    return TCL_OK;
+}
+
+static int
+VolumeShadingSpecularOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                        Tcl_Obj *const *objv)
+{
+    double coeff, power;
+    if (Tcl_GetDoubleFromObj(interp, objv[3], &coeff) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[4], &power) != TCL_OK) {
+        return TCL_ERROR;
+    }
+
+    if (objc == 6) {
+        const char *name = Tcl_GetString(objv[5]);
+        g_renderer->setGraphicsObjectSpecular<Volume>(name, coeff, power);
+    } else {
+        g_renderer->setGraphicsObjectSpecular<Volume>("all", coeff, power);
+    }
+    return TCL_OK;
+}
+
+static Rappture::CmdSpec volumeShadingOps[] = {
+    {"ambient",  1, VolumeShadingAmbientOp,  4, 5, "coeff ?dataSetName?"},
+    {"diffuse",  1, VolumeShadingDiffuseOp,  4, 5, "coeff ?dataSetName?"},
+    {"specular", 1, VolumeShadingSpecularOp, 5, 6, "coeff power ?dataSetName?"}
+};
+static int nVolumeShadingOps = NumCmdSpecs(volumeShadingOps);
+
+static int
+VolumeShadingOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                Tcl_Obj *const *objv)
+{
+    Tcl_ObjCmdProc *proc;
+
+    proc = Rappture::GetOpFromObj(interp, nVolumeShadingOps, volumeShadingOps,
+                                  Rappture::CMDSPEC_ARG2, objc, objv, 0);
+    if (proc == NULL) {
+        return TCL_ERROR;
+    }
+    return (*proc) (clientData, interp, objc, objv);
+}
+
+static int
+VolumeVisibleOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                Tcl_Obj *const *objv)
+{
+    bool state;
+    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 4) {
+        const char *name = Tcl_GetString(objv[3]);
+        g_renderer->setGraphicsObjectVisibility<Volume>(name, state);
+    } else {
+        g_renderer->setGraphicsObjectVisibility<Volume>("all", state);
+    }
+    return TCL_OK;
+}
+
+static Rappture::CmdSpec volumeOps[] = {
+    {"add",          1, VolumeAddOp,        2, 3, "?dataSetName?"},
+    {"colormap",     1, VolumeColorMapOp,   3, 4, "colorMapName ?dataSetName?"},
+    {"delete",       1, VolumeDeleteOp,     2, 3, "?dataSetName?"},
+    {"lighting",     1, VolumeLightingOp,   3, 4, "bool ?dataSetName?"},
+    {"opacity",      2, VolumeOpacityOp,    3, 4, "val ?dataSetName?"},
+    {"orient",       2, VolumeOrientOp,     6, 7, "qw qx qy qz ?dataSetName?"},
+    {"pos",          1, VolumePositionOp,   5, 6, "x y z ?dataSetName?"},
+    {"quality",      1, VolumeSampleRateOp, 3, 4, "val ?dataSetName?"},
+    {"scale",        2, VolumeScaleOp,      5, 6, "sx sy sz ?dataSetName?"},
+    {"shading",      2, VolumeShadingOp,    4, 6, "oper val ?dataSetName?"},
+    {"visible",      1, VolumeVisibleOp,    3, 4, "bool ?dataSetName?"}
+};
+static int nVolumeOps = NumCmdSpecs(volumeOps);
+
+static int
+VolumeCmd(ClientData clientData, Tcl_Interp *interp, int objc, 
+          Tcl_Obj *const *objv)
+{
+    Tcl_ObjCmdProc *proc;
+
+    proc = Rappture::GetOpFromObj(interp, nVolumeOps, volumeOps,
+                                  Rappture::CMDSPEC_ARG1, objc, objv, 0);
+    if (proc == NULL) {
+        return TCL_ERROR;
+    }
+    return (*proc) (clientData, interp, objc, objv);
+}
+
+static int
+WarpAddOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+          Tcl_Obj *const *objv)
+{
+    if (objc == 3) {
+        const char *name = Tcl_GetString(objv[2]);
+        if (!g_renderer->addGraphicsObject<Warp>(name)) {
+            Tcl_AppendResult(interp, "Failed to create warp", (char*)NULL);
+            return TCL_ERROR;
+        }
+    } else {
+        if (!g_renderer->addGraphicsObject<Warp>("all")) {
+            Tcl_AppendResult(interp, "Failed to create warp for one or more data sets", (char*)NULL);
+            return TCL_ERROR;
+        }
+    }
+    return TCL_OK;
+}
+
+static int
+WarpColorOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+            Tcl_Obj *const *objv)
+{
+    float color[3];
+    if (GetFloatFromObj(interp, objv[2], &color[0]) != TCL_OK ||
+        GetFloatFromObj(interp, objv[3], &color[1]) != TCL_OK ||
+        GetFloatFromObj(interp, objv[4], &color[2]) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 6) {
+        const char *name = Tcl_GetString(objv[5]);
+        g_renderer->setGraphicsObjectColor<Warp>(name, color);
+    } else {
+        g_renderer->setGraphicsObjectColor<Warp>("all", color);
+    }
+    return TCL_OK;
+}
+
+static int
+WarpColorMapOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+               Tcl_Obj *const *objv)
+{
+    const char *colorMapName = Tcl_GetString(objv[2]);
+    if (objc == 4) {
+        const char *dataSetName = Tcl_GetString(objv[3]);
+        g_renderer->setGraphicsObjectColorMap<Warp>(dataSetName, colorMapName);
+    } else {
+        g_renderer->setGraphicsObjectColorMap<Warp>("all", colorMapName);
+    }
+    return TCL_OK;
+}
+
+static int
+WarpColorModeOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                Tcl_Obj *const *objv)
+{
+    Warp::ColorMode mode;
+    const char *str = Tcl_GetString(objv[2]);
+    if (str[0] == 'c' && strcmp(str, "ccolor") == 0) {
+        mode = Warp::COLOR_CONSTANT;
+    } else if (str[0] == 's' && strcmp(str, "scalar") == 0) {
+        mode = Warp::COLOR_BY_SCALAR;
+    } else if (str[0] == 'v' && strcmp(str, "vmag") == 0) {
+        mode = Warp::COLOR_BY_VECTOR_MAGNITUDE;
+    } else if (str[0] == 'v' && strcmp(str, "vx") == 0) {
+        mode = Warp::COLOR_BY_VECTOR_X;
+    } else if (str[0] == 'v' && strcmp(str, "vy") == 0) {
+        mode = Warp::COLOR_BY_VECTOR_Y;
+    } else if (str[0] == 'v' && strcmp(str, "vz") == 0) {
+        mode = Warp::COLOR_BY_VECTOR_Z;
+    } else {
+        Tcl_AppendResult(interp, "bad color mode option \"", str,
+                         "\": should be one of: 'scalar', 'vmag', 'vx', 'vy', 'vz', 'ccolor'", (char*)NULL);
+        return TCL_ERROR;
+    }
+    const char *fieldName = Tcl_GetString(objv[3]);
+    if (mode == Warp::COLOR_CONSTANT) {
+        fieldName = NULL;
+    }
+    if (objc == 5) {
+        const char *name = Tcl_GetString(objv[4]);
+        g_renderer->setWarpColorMode(name, mode, fieldName);
+    } else {
+        g_renderer->setWarpColorMode("all", mode, fieldName);
+    }
+    return TCL_OK;
+}
+
+static int
+WarpDeleteOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+             Tcl_Obj *const *objv)
+{
+    if (objc == 3) {
+        const char *name = Tcl_GetString(objv[2]);
+        g_renderer->deleteGraphicsObject<Warp>(name);
+    } else {
+        g_renderer->deleteGraphicsObject<Warp>("all");
+    }
+    return TCL_OK;
+}
+
+static int
+WarpEdgeVisibilityOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                     Tcl_Obj *const *objv)
+{
+    bool state;
+    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 4) {
+        const char *name = Tcl_GetString(objv[3]);
+        g_renderer->setGraphicsObjectEdgeVisibility<Warp>(name, state);
+    } else {
+        g_renderer->setGraphicsObjectEdgeVisibility<Warp>("all", state);
+    }
+    return TCL_OK;
+}
+
+static int
+WarpLightingOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+               Tcl_Obj *const *objv)
+{
+    bool state;
+    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 4) {
+        const char *name = Tcl_GetString(objv[3]);
+        g_renderer->setGraphicsObjectLighting<Warp>(name, state);
+    } else {
+        g_renderer->setGraphicsObjectLighting<Warp>("all", state);
+    }
+    return TCL_OK;
+}
+
+static int
+WarpLineColorOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                Tcl_Obj *const *objv)
+{
+    float color[3];
+    if (GetFloatFromObj(interp, objv[2], &color[0]) != TCL_OK ||
+        GetFloatFromObj(interp, objv[3], &color[1]) != TCL_OK ||
+        GetFloatFromObj(interp, objv[4], &color[2]) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 6) {
+        const char *name = Tcl_GetString(objv[5]);
+        g_renderer->setGraphicsObjectEdgeColor<Warp>(name, color);
+    } else {
+        g_renderer->setGraphicsObjectEdgeColor<Warp>("all", color);
+    }
+    return TCL_OK;
+}
+
+static int
+WarpLineWidthOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                Tcl_Obj *const *objv)
+{
+    float width;
+    if (GetFloatFromObj(interp, objv[2], &width) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 4) {
+        const char *name = Tcl_GetString(objv[3]);
+        g_renderer->setGraphicsObjectEdgeWidth<Warp>(name, width);
+    } else {
+        g_renderer->setGraphicsObjectEdgeWidth<Warp>("all", width);
+    }
+    return TCL_OK;
+}
+
+static int
+WarpOpacityOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                   Tcl_Obj *const *objv)
+{
+    double opacity;
+    if (Tcl_GetDoubleFromObj(interp, objv[2], &opacity) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 4) {
+        const char *name = Tcl_GetString(objv[3]);
+        g_renderer->setGraphicsObjectOpacity<Warp>(name, opacity);
+    } else {
+        g_renderer->setGraphicsObjectOpacity<Warp>("all", opacity);
+    }
+    return TCL_OK;
+}
+
+static int
+WarpOrientOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+             Tcl_Obj *const *objv)
+{
+    double quat[4];
+    if (Tcl_GetDoubleFromObj(interp, objv[2], &quat[0]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[3], &quat[1]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[4], &quat[2]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[5], &quat[3]) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 7) {
+        const char *name = Tcl_GetString(objv[6]);
+        g_renderer->setGraphicsObjectOrientation<Warp>(name, quat);
+    } else {
+        g_renderer->setGraphicsObjectOrientation<Warp>("all", quat);
+    }
+    return TCL_OK;
+}
+
+static int
+WarpPositionOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+               Tcl_Obj *const *objv)
+{
+    double pos[3];
+    if (Tcl_GetDoubleFromObj(interp, objv[2], &pos[0]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[3], &pos[1]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[4], &pos[2]) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 6) {
+        const char *name = Tcl_GetString(objv[5]);
+        g_renderer->setGraphicsObjectPosition<Warp>(name, pos);
+    } else {
+        g_renderer->setGraphicsObjectPosition<Warp>("all", pos);
+    }
+    return TCL_OK;
+}
+
+static int
+WarpPreInterpOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                Tcl_Obj *const *objv)
+{
+    bool state;
+    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 4) {
+        const char *name = Tcl_GetString(objv[3]);
+        g_renderer->setGraphicsObjectInterpolateBeforeMapping<Warp>(name, state);
+    } else {
+        g_renderer->setGraphicsObjectInterpolateBeforeMapping<Warp>("all", state);
+    }
+    return TCL_OK;
+}
+
+static int
+WarpScaleOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+            Tcl_Obj *const *objv)
+{
+    double scale[3];
+    if (Tcl_GetDoubleFromObj(interp, objv[2], &scale[0]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[3], &scale[1]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[4], &scale[2]) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 6) {
+        const char *name = Tcl_GetString(objv[5]);
+        g_renderer->setGraphicsObjectScale<Warp>(name, scale);
+    } else {
+        g_renderer->setGraphicsObjectScale<Warp>("all", scale);
+    }
+    return TCL_OK;
+}
+
+static int
+WarpVisibleOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+              Tcl_Obj *const *objv)
+{
+    bool state;
+    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 4) {
+        const char *name = Tcl_GetString(objv[3]);
+        g_renderer->setGraphicsObjectVisibility<Warp>(name, state);
+    } else {
+        g_renderer->setGraphicsObjectVisibility<Warp>("all", state);
+    }
+    return TCL_OK;
+}
+
+static int
+WarpWarpScaleOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                Tcl_Obj *const *objv)
+{
+    double scale;
+    if (Tcl_GetDoubleFromObj(interp, objv[2], &scale) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 4) {
+        const char *name = Tcl_GetString(objv[3]);
+        g_renderer->setWarpWarpScale(name, scale);
+    } else {
+        g_renderer->setWarpWarpScale("all", scale);
+    }
+    return TCL_OK;
+}
+
+static int
+WarpWireframeOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                Tcl_Obj *const *objv)
+{
+    bool state;
+    if (GetBooleanFromObj(interp, objv[2], &state) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 4) {
+        const char *name = Tcl_GetString(objv[3]);
+        g_renderer->setGraphicsObjectWireframe<Warp>(name, state);
+    } else {
+        g_renderer->setGraphicsObjectWireframe<Warp>("all", state);
+    }
+    return TCL_OK;
+}
+
+static Rappture::CmdSpec warpOps[] = {
+    {"add",          1, WarpAddOp, 2, 3, "?dataSetName?"},
+    {"ccolor",       2, WarpColorOp, 5, 6, "r g b ?dataSetName?"},
+    {"colormap",     7, WarpColorMapOp, 3, 4, "colorMapName ?dataSetName?"},
+    {"colormode",    7, WarpColorModeOp, 4, 5, "mode fieldName ?dataSetName?"},
+    {"delete",       1, WarpDeleteOp, 2, 3, "?dataSetName?"},
+    {"edges",        1, WarpEdgeVisibilityOp, 3, 4, "bool ?dataSetName?"},
+    {"lighting",     3, WarpLightingOp, 3, 4, "bool ?dataSetName?"},
+    {"linecolor",    5, WarpLineColorOp, 5, 6, "r g b ?dataSetName?"},
+    {"linewidth",    5, WarpLineWidthOp, 3, 4, "width ?dataSetName?"},
+    {"opacity",      2, WarpOpacityOp, 3, 4, "value ?dataSetName?"},
+    {"orient",       2, WarpOrientOp, 6, 7, "qw qx qy qz ?dataSetName?"},
+    {"pos",          2, WarpPositionOp, 5, 6, "x y z ?dataSetName?"},
+    {"preinterp",    2, WarpPreInterpOp, 3, 4, "bool ?dataSetName?"},
+    {"scale",        2, WarpScaleOp, 5, 6, "sx sy sz ?dataSetName?"},
+    {"visible",      1, WarpVisibleOp, 3, 4, "bool ?dataSetName?"},
+    {"warpscale",    2, WarpWarpScaleOp, 3, 4, "value ?dataSetName?"},
+    {"wireframe",    2, WarpWireframeOp, 3, 4, "bool ?dataSetName?"}
+};
+static int nWarpOps = NumCmdSpecs(warpOps);
+
+static int
+WarpCmd(ClientData clientData, Tcl_Interp *interp, int objc, 
+             Tcl_Obj *const *objv)
+{
+    Tcl_ObjCmdProc *proc;
+
+    proc = Rappture::GetOpFromObj(interp, nWarpOps, warpOps,
+                                  Rappture::CMDSPEC_ARG1, objc, objv, 0);
+    if (proc == NULL) {
+        return TCL_ERROR;
+    }
+    return (*proc) (clientData, interp, objc, objv);
+}
+
+/**
+ * \brief Execute commands from client in Tcl interpreter
+ * 
+ * In this threaded model, the select call is for event compression.  We
+ * want to execute render server commands as long as they keep coming.  
+ * This lets us execute a stream of many commands but render once.  This 
+ * benefits camera movements, screen resizing, and opacity changes 
+ * (using a slider on the client).  The down side is you don't render
+ * until there's a lull in the command stream.  If the client needs an
+ * image, it can issue an "imgflush" command.  That breaks us out of the
+ * read loop.
+ */
+int
+VtkVis::processCommands(Tcl_Interp *interp,
+                        ClientData clientData,
+                        ReadBuffer *inBufPtr, 
+                        int fdOut)
+{
+    int ret = 1;
+    int status = TCL_OK;
+
+    Tcl_DString command;
+    Tcl_DStringInit(&command);
+    fd_set readFds;
+    struct timeval tv, *tvPtr;
+
+    FD_ZERO(&readFds);
+    FD_SET(inBufPtr->file(), &readFds);
+    tvPtr = NULL;                       /* Wait for the first read. This is so
+                                         * that we don't spin when no data is
+                                         * available. */
+    while (inBufPtr->isLineAvailable() || 
+           (select(1, &readFds, NULL, NULL, tvPtr) > 0)) {
+        size_t numBytes;
+        unsigned char *buffer;
+
+        /* A short read is treated as an error here because we assume that we
+         * will always get commands line by line. */
+        if (inBufPtr->getLine(&numBytes, &buffer) != ReadBuffer::OK) {
+            /* Terminate the server if we can't communicate with the client
+             * anymore. */
+            if (inBufPtr->status() == ReadBuffer::ENDFILE) {
+                TRACE("Exiting server on EOF from client");
+                return -1;
+            } else {
+                ERROR("Exiting server, failed to read from client: %s",
+                      strerror(errno));
+                return -1;
+            }
+        }
+        Tcl_DStringAppend(&command, (char *)buffer, numBytes);
+        if (Tcl_CommandComplete(Tcl_DStringValue(&command))) {
+            struct timeval start, finish;
+            gettimeofday(&start, NULL);
+            status = ExecuteCommand(interp, &command);
+            gettimeofday(&finish, NULL);
+            g_stats.cmdTime += (MSECS_ELAPSED(start, finish) / 1.0e+3);
+            g_stats.nCommands++;
+            if (status == TCL_BREAK) {
+                return 1;               /* This was caused by a "imgflush"
+                                         * command. Break out of the read loop
+                                         * and allow a new image to be
+                                         * rendered. */
+            } else { //if (status != TCL_OK) {
+                ret = 0;
+                if (handleError(interp, clientData, status, fdOut) < 0) {
+                    return -1;
+                }
+            }
+        }
+
+        tv.tv_sec = tv.tv_usec = 0L;    /* On successive reads, we break out
+                                         * if no data is available. */
+        FD_SET(inBufPtr->file(), &readFds);
+        tvPtr = &tv;
+    }
+
+    return ret;
+}
+
+/**
+ * \brief Send error message to client socket
+ */
+int
+VtkVis::handleError(Tcl_Interp *interp,
+                    ClientData clientData,
+                    int status, int fdOut)
+{
+    const char *string;
+    int nBytes;
+
+    if (status != TCL_OK) {
+        string = Tcl_GetVar(interp, "errorInfo", TCL_GLOBAL_ONLY);
+        nBytes = strlen(string);
+        if (nBytes > 0) {
+            TRACE("status=%d errorInfo=(%s)", status, string);
+
+            std::ostringstream oss;
+            oss << "nv>viserror -type internal_error -token " << g_stats.nCommands << " -bytes " << nBytes << "\n" << string;
+            nBytes = oss.str().length();
+
+#ifdef USE_THREADS
+            queueResponse(clientData, oss.str().c_str(), nBytes, Response::VOLATILE, Response::ERROR);
+#else
+            if (write(fdOut, oss.str().c_str(), nBytes) < 0) {
+                ERROR("write failed: %s", strerror(errno));
+                return -1;
+            }
+#endif
+        }
+    }
+
+    string = getUserMessages();
+    nBytes = strlen(string);
+    if (nBytes > 0) {
+        TRACE("userError=(%s)", string);
+
+        std::ostringstream oss;
+        oss << "nv>viserror -type error -token " << g_stats.nCommands << " -bytes " << nBytes << "\n" << string;
+        nBytes = oss.str().length();
+
+#ifdef USE_THREADS
+        queueResponse(clientData, oss.str().c_str(), nBytes, Response::VOLATILE, Response::ERROR);
+#else
+        if (write(fdOut, oss.str().c_str(), nBytes) < 0) {
+            ERROR("write failed: %s", strerror(errno));
+            return -1;
+        }
+#endif
+        clearUserMessages();
+    }
+
+    return 0;
+}
+
+/**
+ * \brief Create Tcl interpreter and add commands
+ *
+ * \return The initialized Tcl interpreter
+ */
+void
+VtkVis::initTcl(Tcl_Interp *interp, ClientData clientData)
+{
+    Tcl_MakeSafe(interp);
+    Tcl_CreateObjCommand(interp, "arc",         ArcCmd,         clientData, NULL);
+    Tcl_CreateObjCommand(interp, "arrow",       ArrowCmd,       clientData, NULL);
+    Tcl_CreateObjCommand(interp, "axis",        AxisCmd,        clientData, NULL);
+    Tcl_CreateObjCommand(interp, "box",         BoxCmd,         clientData, NULL);
+    Tcl_CreateObjCommand(interp, "camera",      CameraCmd,      clientData, NULL);
+    Tcl_CreateObjCommand(interp, "clientinfo",  ClientInfoCmd,  clientData, NULL);
+    Tcl_CreateObjCommand(interp, "colormap",    ColorMapCmd,    clientData, NULL);
+    Tcl_CreateObjCommand(interp, "cone",        ConeCmd,        clientData, NULL);
+    Tcl_CreateObjCommand(interp, "contour2d",   Contour2DCmd,   clientData, NULL);
+    Tcl_CreateObjCommand(interp, "contour3d",   Contour3DCmd,   clientData, NULL);
+    Tcl_CreateObjCommand(interp, "cutplane",    CutplaneCmd,    clientData, NULL);
+    Tcl_CreateObjCommand(interp, "cylinder",    CylinderCmd,    clientData, NULL);
+    Tcl_CreateObjCommand(interp, "dataset",     DataSetCmd,     clientData, NULL);
+    Tcl_CreateObjCommand(interp, "disk",        DiskCmd,        clientData, NULL);
+    Tcl_CreateObjCommand(interp, "glyphs",      GlyphsCmd,      clientData, NULL);
+    Tcl_CreateObjCommand(interp, "heightmap",   HeightMapCmd,   clientData, NULL);
+    Tcl_CreateObjCommand(interp, "imgflush",    ImageFlushCmd,  clientData, NULL);
+    Tcl_CreateObjCommand(interp, "legend",      LegendCmd,      clientData, NULL);
+    Tcl_CreateObjCommand(interp, "lic",         LICCmd,         clientData, NULL);
+    Tcl_CreateObjCommand(interp, "line",        LineCmd,        clientData, NULL);
+    Tcl_CreateObjCommand(interp, "molecule",    MoleculeCmd,    clientData, NULL);
+    Tcl_CreateObjCommand(interp, "outline",     OutlineCmd,     clientData, NULL);
+    Tcl_CreateObjCommand(interp, "polydata",    PolyDataCmd,    clientData, NULL);
+    Tcl_CreateObjCommand(interp, "polygon",     PolygonCmd,     clientData, NULL);
+    Tcl_CreateObjCommand(interp, "pseudocolor", PseudoColorCmd, clientData, NULL);
+    Tcl_CreateObjCommand(interp, "renderer",    RendererCmd,    clientData, NULL);
+    Tcl_CreateObjCommand(interp, "screen",      ScreenCmd,      clientData, NULL);
+    Tcl_CreateObjCommand(interp, "sphere",      SphereCmd,      clientData, NULL);
+    Tcl_CreateObjCommand(interp, "streamlines", StreamlinesCmd, clientData, NULL);
+    Tcl_CreateObjCommand(interp, "volume",      VolumeCmd,      clientData, NULL);
+    Tcl_CreateObjCommand(interp, "warp",        WarpCmd,        clientData, NULL);
+}
+
+/**
+ * \brief Delete Tcl commands and interpreter
+ */
+void VtkVis::exitTcl(Tcl_Interp *interp)
+{
+    Tcl_DeleteCommand(interp, "arc");
+    Tcl_DeleteCommand(interp, "arrow");
+    Tcl_DeleteCommand(interp, "axis");
+    Tcl_DeleteCommand(interp, "box");
+    Tcl_DeleteCommand(interp, "camera");
+    Tcl_DeleteCommand(interp, "clientinfo");
+    Tcl_DeleteCommand(interp, "colormap");
+    Tcl_DeleteCommand(interp, "cone");
+    Tcl_DeleteCommand(interp, "contour2d");
+    Tcl_DeleteCommand(interp, "contour3d");
+    Tcl_DeleteCommand(interp, "cutplane");
+    Tcl_DeleteCommand(interp, "cylinder");
+    Tcl_DeleteCommand(interp, "dataset");
+    Tcl_DeleteCommand(interp, "disk");
+    Tcl_DeleteCommand(interp, "glyphs");
+    Tcl_DeleteCommand(interp, "heightmap");
+    Tcl_DeleteCommand(interp, "imgflush");
+    Tcl_DeleteCommand(interp, "legend");
+    Tcl_DeleteCommand(interp, "lic");
+    Tcl_DeleteCommand(interp, "line");
+    Tcl_DeleteCommand(interp, "molecule");
+    Tcl_DeleteCommand(interp, "outline");
+    Tcl_DeleteCommand(interp, "polydata");
+    Tcl_DeleteCommand(interp, "polygon");
+    Tcl_DeleteCommand(interp, "pseudocolor");
+    Tcl_DeleteCommand(interp, "renderer");
+    Tcl_DeleteCommand(interp, "screen");
+    Tcl_DeleteCommand(interp, "sphere");
+    Tcl_DeleteCommand(interp, "streamlines");
+    Tcl_DeleteCommand(interp, "volume");
+    Tcl_DeleteCommand(interp, "warp");
+
+    Tcl_DeleteInterp(interp);
+}
Index: /trunk/packages/vizservers/vtkvis/VtkRendererCmd.h
===================================================================
--- /trunk/packages/vizservers/vtkvis/VtkRendererCmd.h	(revision 3616)
+++ /trunk/packages/vizservers/vtkvis/VtkRendererCmd.h	(revision 3616)
@@ -0,0 +1,44 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (C) 2004-2012  HUBzero Foundation, LLC
+ *
+ * Author: Leif Delgass <ldelgass@purdue.edu>
+ */
+
+#ifndef VTKVIS_RENDERERCMD_H
+#define VTKVIS_RENDERERCMD_H
+
+#include <cstdio>
+#include <tcl.h>
+
+#include "ReadBuffer.h"
+#ifdef USE_THREADS
+#include "ResponseQueue.h"
+#endif
+
+namespace VtkVis {
+
+#ifdef USE_THREADS
+extern void queueResponse(ClientData clientData, const void *bytes, size_t len, 
+                          Response::AllocationType allocType,
+                          Response::ResponseType type = Response::DATA);
+#endif
+
+extern int processCommands(Tcl_Interp *interp,
+                           ClientData clientData,
+                           ReadBuffer *inBufPtr,
+                           int fdOut);
+
+extern int handleError(Tcl_Interp *interp,
+                       ClientData clientData,
+                       int status,
+                       int fdOut);
+
+extern void initTcl(Tcl_Interp *interp,
+                    ClientData clientData);
+
+extern void exitTcl(Tcl_Interp *interp);
+
+}
+
+#endif
Index: /trunk/packages/vizservers/vtkvis/VtkRendererGraphicsObjs.cpp
===================================================================
--- /trunk/packages/vizservers/vtkvis/VtkRendererGraphicsObjs.cpp	(revision 3616)
+++ /trunk/packages/vizservers/vtkvis/VtkRendererGraphicsObjs.cpp	(revision 3616)
@@ -0,0 +1,3057 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (C) 2004-2012  HUBzero Foundation, LLC
+ *
+ * Author: Leif Delgass <ldelgass@purdue.edu>
+ */
+
+#include <cstring>
+#include <typeinfo>
+
+#include <vtkVersion.h>
+#include <vtkSmartPointer.h>
+#include <vtkDataSet.h>
+#include <vtkCharArray.h>
+#include <vtkDataSetReader.h>
+
+#include "VtkRendererGraphicsObjs.h"
+#include "VtkRenderer.h"
+#include "VtkDataSet.h"
+#include "Box.h"
+#include "Contour2D.h"
+#include "Contour3D.h"
+#include "Cutplane.h"
+#include "Glyphs.h"
+#include "HeightMap.h"
+#include "LIC.h"
+#include "Line.h"
+#include "Molecule.h"
+#include "PolyData.h"
+#include "PseudoColor.h"
+#include "Sphere.h"
+#include "Streamlines.h"
+#include "Volume.h"
+#include "ColorMap.h"
+#include "Trace.h"
+
+// Template specializations
+namespace VtkVis {
+
+template<>
+Renderer::ArcHashmap &
+Renderer::getGraphicsObjectHashmap<Arc>()
+{ return _arcs; }
+
+template<>
+Renderer::ArrowHashmap &
+Renderer::getGraphicsObjectHashmap<Arrow>()
+{ return _arrows; }
+
+template<>
+Renderer::BoxHashmap &
+Renderer::getGraphicsObjectHashmap<Box>()
+{ return _boxes; }
+
+template<>
+Renderer::ConeHashmap &
+Renderer::getGraphicsObjectHashmap<Cone>()
+{ return _cones; }
+
+template<>
+Renderer::Contour2DHashmap &
+Renderer::getGraphicsObjectHashmap<Contour2D>()
+{ return _contour2Ds; }
+
+template<>
+Renderer::Contour3DHashmap &
+Renderer::getGraphicsObjectHashmap<Contour3D>()
+{ return _contour3Ds; }
+
+template<>
+Renderer::CutplaneHashmap &
+Renderer::getGraphicsObjectHashmap<Cutplane>()
+{ return _cutplanes; }
+
+template<>
+Renderer::CylinderHashmap &
+Renderer::getGraphicsObjectHashmap<Cylinder>()
+{ return _cylinders; }
+
+template<>
+Renderer::DiskHashmap &
+Renderer::getGraphicsObjectHashmap<Disk>()
+{ return _disks; }
+
+template<>
+Renderer::GlyphsHashmap &
+Renderer::getGraphicsObjectHashmap<Glyphs>()
+{ return _glyphs; }
+
+template<>
+Renderer::GroupHashmap &
+Renderer::getGraphicsObjectHashmap<Group>()
+{ return _groups; }
+
+template<>
+Renderer::HeightMapHashmap &
+Renderer::getGraphicsObjectHashmap<HeightMap>()
+{ return _heightMaps; }
+
+template<>
+Renderer::LICHashmap &
+Renderer::getGraphicsObjectHashmap<LIC>()
+{ return _lics; }
+
+template<>
+Renderer::LineHashmap &
+Renderer::getGraphicsObjectHashmap<Line>()
+{ return _lines; }
+
+template<>
+Renderer::MoleculeHashmap &
+Renderer::getGraphicsObjectHashmap<Molecule>()
+{ return _molecules; }
+
+template<>
+Renderer::OutlineHashmap &
+Renderer::getGraphicsObjectHashmap<Outline>()
+{ return _outlines; }
+
+template<>
+Renderer::PolyDataHashmap &
+Renderer::getGraphicsObjectHashmap<PolyData>()
+{ return _polyDatas; }
+
+template<>
+Renderer::PolygonHashmap &
+Renderer::getGraphicsObjectHashmap<Polygon>()
+{ return _polygons; }
+
+template<>
+Renderer::PseudoColorHashmap &
+Renderer::getGraphicsObjectHashmap<PseudoColor>()
+{ return _pseudoColors; }
+
+template<>
+Renderer::SphereHashmap &
+Renderer::getGraphicsObjectHashmap<Sphere>()
+{ return _spheres; }
+
+template<>
+Renderer::StreamlinesHashmap &
+Renderer::getGraphicsObjectHashmap<Streamlines>()
+{ return _streamlines; }
+
+template<>
+Renderer::VolumeHashmap &
+Renderer::getGraphicsObjectHashmap<Volume>()
+{ return _volumes; }
+
+template<>
+Renderer::WarpHashmap &
+Renderer::getGraphicsObjectHashmap<Warp>()
+{ return _warps; }
+
+template Arc *Renderer::getGraphicsObject(const DataSetId&);
+template Arrow *Renderer::getGraphicsObject(const DataSetId&);
+template Box *Renderer::getGraphicsObject(const DataSetId&);
+template Cone *Renderer::getGraphicsObject(const DataSetId&);
+template Cylinder *Renderer::getGraphicsObject(const DataSetId&);
+template Disk *Renderer::getGraphicsObject(const DataSetId&);
+template Group *Renderer::getGraphicsObject(const DataSetId&);
+template Line *Renderer::getGraphicsObject(const DataSetId&);
+template Polygon *Renderer::getGraphicsObject(const DataSetId&);
+template Sphere *Renderer::getGraphicsObject(const DataSetId&);
+
+template <>
+bool Renderer::addGraphicsObject<Box>(const DataSetId& id)
+{
+    Box *gobj;
+    if ((gobj = getGraphicsObject<Box>(id)) != NULL) {
+        WARN("Replacing existing %s %s", gobj->getClassName(), id.c_str());
+        deleteGraphicsObject<Box>(id);
+    }
+
+    gobj = new Box();
+ 
+    gobj->setDataSet(NULL, this);
+
+    if (gobj->getProp() == NULL &&
+        gobj->getOverlayProp() == NULL) {
+        delete gobj;
+        return false;
+    } else {
+        if (gobj->getProp())
+            _renderer->AddViewProp(gobj->getProp());
+        if (gobj->getOverlayProp())
+            _renderer->AddViewProp(gobj->getOverlayProp());
+    }
+
+    getGraphicsObjectHashmap<Box>()[id] = gobj;
+
+    sceneBoundsChanged();
+    _needsRedraw = true;
+    return true;
+}
+
+template <>
+bool Renderer::addGraphicsObject<Sphere>(const DataSetId& id)
+{
+    Sphere *gobj;
+    if ((gobj = getGraphicsObject<Sphere>(id)) != NULL) {
+        WARN("Replacing existing %s %s", gobj->getClassName(), id.c_str());
+        deleteGraphicsObject<Sphere>(id);
+    }
+
+    gobj = new Sphere();
+ 
+    gobj->setDataSet(NULL, this);
+
+    if (gobj->getProp() == NULL &&
+        gobj->getOverlayProp() == NULL) {
+        delete gobj;
+        return false;
+    } else {
+        if (gobj->getProp())
+            _renderer->AddViewProp(gobj->getProp());
+        if (gobj->getOverlayProp())
+            _renderer->AddViewProp(gobj->getOverlayProp());
+    }
+
+    getGraphicsObjectHashmap<Sphere>()[id] = gobj;
+
+    sceneBoundsChanged();
+    _needsRedraw = true;
+    return true;
+}
+
+/**
+ * \brief Set the volume slice used for mapping volumetric data
+ */
+template <>
+void Renderer::setGraphicsObjectVolumeSlice<HeightMap>(const DataSetId& id, Axis axis, double ratio)
+{
+    HeightMapHashmap::iterator itr;
+
+    bool doAll = false;
+
+    if (id.compare("all") == 0) {
+        itr = _heightMaps.begin();
+        if (itr == _heightMaps.end())
+            return;
+        doAll = true;
+    } else {
+        itr = _heightMaps.find(id);
+    }
+
+    if (itr == _heightMaps.end()) {
+        ERROR("HeightMap not found: %s", id.c_str());
+        return;
+    }
+
+    do {
+        itr->second->selectVolumeSlice(axis, ratio);
+     } while (doAll && ++itr != _heightMaps.end());
+
+    sceneBoundsChanged();
+    _needsRedraw = true;
+}
+
+}
+
+using namespace VtkVis;
+
+/**
+ * \brief Create a new Arc and associate it with an ID
+ */
+bool Renderer::addArc(const DataSetId& id, double pt1[3], double pt2[3])
+{
+    Arc *gobj;
+    if ((gobj = getGraphicsObject<Arc>(id)) != NULL) {
+        WARN("Replacing existing %s %s", gobj->getClassName(), id.c_str());
+        deleteGraphicsObject<Arc>(id);
+    }
+
+    gobj = new Arc();
+ 
+    gobj->setDataSet(NULL, this);
+
+    if (gobj->getProp() == NULL &&
+        gobj->getOverlayProp() == NULL) {
+        delete gobj;
+        return false;
+    } else {
+        if (gobj->getProp())
+            _renderer->AddViewProp(gobj->getProp());
+        if (gobj->getOverlayProp())
+            _renderer->AddViewProp(gobj->getOverlayProp());
+    }
+
+    gobj->setEndPoints(pt1, pt2);
+
+    getGraphicsObjectHashmap<Arc>()[id] = gobj;
+
+    sceneBoundsChanged();
+    _needsRedraw = true;
+    return true;
+}
+
+/**
+ * \brief Set Arc resolution
+ */
+void Renderer::setArcResolution(const DataSetId& id, int res)
+{
+    ArcHashmap::iterator itr;
+
+    bool doAll = false;
+
+    if (id.compare("all") == 0) {
+        itr = _arcs.begin();
+        if (itr == _arcs.end())
+            return;
+        doAll = true;
+    } else {
+        itr = _arcs.find(id);
+    }
+    if (itr == _arcs.end()) {
+        ERROR("Arc not found: %s", id.c_str());
+        return;
+    }
+
+    do {
+        itr->second->setResolution(res);
+    } while (doAll && ++itr != _arcs.end());
+
+    sceneBoundsChanged();
+    _needsRedraw = true;
+}
+
+/**
+ * \brief Create a new Arrow and associate it with an ID
+ */
+bool Renderer::addArrow(const DataSetId& id, double tipRadius, double shaftRadius, double tipLength)
+{
+    Arrow *gobj;
+    if ((gobj = getGraphicsObject<Arrow>(id)) != NULL) {
+        WARN("Replacing existing %s %s", gobj->getClassName(), id.c_str());
+        deleteGraphicsObject<Arrow>(id);
+    }
+
+    gobj = new Arrow();
+ 
+    gobj->setDataSet(NULL, this);
+
+    if (gobj->getProp() == NULL &&
+        gobj->getOverlayProp() == NULL) {
+        delete gobj;
+        return false;
+    } else {
+        if (gobj->getProp())
+            _renderer->AddViewProp(gobj->getProp());
+        if (gobj->getOverlayProp())
+            _renderer->AddViewProp(gobj->getOverlayProp());
+    }
+
+    gobj->setRadii(tipRadius, shaftRadius);
+    gobj->setTipLength(tipLength);
+
+    getGraphicsObjectHashmap<Arrow>()[id] = gobj;
+
+    sceneBoundsChanged();
+    _needsRedraw = true;
+    return true;
+}
+
+/**
+ * \brief Set Arrow resolution
+ */
+void Renderer::setArrowResolution(const DataSetId& id, int tipRes, int shaftRes)
+{
+    ArrowHashmap::iterator itr;
+
+    bool doAll = false;
+
+    if (id.compare("all") == 0) {
+        itr = _arrows.begin();
+        if (itr == _arrows.end())
+            return;
+        doAll = true;
+    } else {
+        itr = _arrows.find(id);
+    }
+    if (itr == _arrows.end()) {
+        ERROR("Arrow not found: %s", id.c_str());
+        return;
+    }
+
+    do {
+        itr->second->setResolution(tipRes, shaftRes);
+    } while (doAll && ++itr != _arrows.end());
+
+    sceneBoundsChanged();
+    _needsRedraw = true;
+}
+
+/**
+ * \brief Create a new Cone and associate it with an ID
+ */
+bool Renderer::addCone(const DataSetId& id, double radius, double height, bool cap)
+{
+    Cone *gobj;
+    if ((gobj = getGraphicsObject<Cone>(id)) != NULL) {
+        WARN("Replacing existing %s %s", gobj->getClassName(), id.c_str());
+        deleteGraphicsObject<Cone>(id);
+    }
+
+    gobj = new Cone();
+ 
+    gobj->setDataSet(NULL, this);
+
+    if (gobj->getProp() == NULL &&
+        gobj->getOverlayProp() == NULL) {
+        delete gobj;
+        return false;
+    } else {
+        if (gobj->getProp())
+            _renderer->AddViewProp(gobj->getProp());
+        if (gobj->getOverlayProp())
+            _renderer->AddViewProp(gobj->getOverlayProp());
+    }
+
+    gobj->setRadius(radius);
+    gobj->setHeight(height);
+    gobj->setCapping(cap);
+
+    getGraphicsObjectHashmap<Cone>()[id] = gobj;
+
+    sceneBoundsChanged();
+    _needsRedraw = true;
+    return true;
+}
+
+/**
+ * \brief Set Cone resolution
+ */
+void Renderer::setConeResolution(const DataSetId& id, int res)
+{
+    ConeHashmap::iterator itr;
+
+    bool doAll = false;
+
+    if (id.compare("all") == 0) {
+        itr = _cones.begin();
+        if (itr == _cones.end())
+            return;
+        doAll = true;
+    } else {
+        itr = _cones.find(id);
+    }
+    if (itr == _cones.end()) {
+        ERROR("Cone not found: %s", id.c_str());
+        return;
+    }
+
+    do {
+        itr->second->setResolution(res);
+    } while (doAll && ++itr != _cones.end());
+
+    sceneBoundsChanged();
+    _needsRedraw = true;
+}
+
+/**
+ * \brief Create a new Contour2D and associate it with the named DataSet
+ */
+bool Renderer::addContour2D(const DataSetId& id, int numContours)
+{
+    DataSetHashmap::iterator itr;
+
+    bool doAll = false;
+
+    if (id.compare("all") == 0) {
+        itr = _dataSets.begin();
+    } else {
+        itr = _dataSets.find(id);
+    }
+    if (itr == _dataSets.end()) {
+        ERROR("Unknown dataset %s", id.c_str());
+        return false;
+    }
+
+    do {
+        DataSet *ds = itr->second;
+        const DataSetId& dsID = ds->getName();
+
+        if (getGraphicsObject<Contour2D>(dsID)) {
+            WARN("Replacing existing Contour2D %s", dsID.c_str());
+            deleteGraphicsObject<Contour2D>(dsID);
+        }
+
+        Contour2D *contour = new Contour2D(numContours);
+ 
+        contour->setDataSet(ds, this);
+
+        if (contour->getProp() == NULL) {
+            delete contour;
+            return false;
+        } else {
+            _renderer->AddViewProp(contour->getProp());
+        }
+
+        _contour2Ds[dsID] = contour;
+    } while (doAll && ++itr != _dataSets.end());
+
+    sceneBoundsChanged();
+    _needsRedraw = true;
+    return true;
+}
+
+/**
+ * \brief Create a new Contour2D and associate it with the named DataSet
+ */
+bool Renderer::addContour2D(const DataSetId& id, const std::vector<double>& contours)
+{
+    DataSetHashmap::iterator itr;
+
+    bool doAll = false;
+
+    if (id.compare("all") == 0) {
+        itr = _dataSets.begin();
+    } else {
+        itr = _dataSets.find(id);
+    }
+    if (itr == _dataSets.end()) {
+        ERROR("Unknown dataset %s", id.c_str());
+        return false;
+    }
+
+    do {
+        DataSet *ds = itr->second;
+        const DataSetId& dsID = ds->getName();
+
+        if (getGraphicsObject<Contour2D>(dsID)) {
+            WARN("Replacing existing Contour2D %s", dsID.c_str());
+            deleteGraphicsObject<Contour2D>(dsID);
+        }
+
+        Contour2D *contour = new Contour2D(contours);
+
+        contour->setDataSet(ds, this);
+
+        if (contour->getProp() == NULL) {
+            delete contour;
+            return false;
+        } else {
+            _renderer->AddViewProp(contour->getProp());
+        }
+
+        _contour2Ds[dsID] = contour;
+    } while (doAll && ++itr != _dataSets.end());
+
+    sceneBoundsChanged();
+    _needsRedraw = true;
+    return true;
+}
+
+/**
+ * \brief Set the number of equally spaced contour isolines for the given DataSet
+ */
+void Renderer::setContour2DNumContours(const DataSetId& id, int numContours)
+{
+    Contour2DHashmap::iterator itr;
+
+    bool doAll = false;
+
+    if (id.compare("all") == 0) {
+        itr = _contour2Ds.begin();
+        doAll = true;
+    } else {
+        itr = _contour2Ds.find(id);
+    }
+    if (itr == _contour2Ds.end()) {
+        ERROR("Contour2D not found: %s", id.c_str());
+        return;
+    }
+
+    do {
+        itr->second->setNumContours(numContours);
+    } while (doAll && ++itr != _contour2Ds.end());
+
+    sceneBoundsChanged();
+    _needsRedraw = true;
+}
+
+/**
+ * \brief Set the number of equally spaced isosurfaces for the given DataSet
+ */
+void Renderer::setContour2DContourField(const DataSetId& id, const char *fieldName)
+{
+    Contour2DHashmap::iterator itr;
+
+    bool doAll = false;
+
+    if (id.compare("all") == 0) {
+        itr = _contour2Ds.begin();
+        doAll = true;
+    } else {
+        itr = _contour2Ds.find(id);
+    }
+    if (itr == _contour2Ds.end()) {
+        ERROR("Contour2D not found: %s", id.c_str());
+        return;
+    }
+
+    do {
+        itr->second->setContourField(fieldName);
+     } while (doAll && ++itr != _contour2Ds.end());
+
+    sceneBoundsChanged();
+    _needsRedraw = true;
+}
+
+/**
+ * \brief Set a list of isovalues for the given DataSet
+ */
+void Renderer::setContour2DContourList(const DataSetId& id, const std::vector<double>& contours)
+{
+    Contour2DHashmap::iterator itr;
+
+    bool doAll = false;
+
+    if (id.compare("all") == 0) {
+        itr = _contour2Ds.begin();
+        doAll = true;
+    } else {
+        itr = _contour2Ds.find(id);
+    }
+    if (itr == _contour2Ds.end()) {
+        ERROR("Contour2D not found: %s", id.c_str());
+        return;
+    }
+
+    do {
+        itr->second->setContourList(contours);
+    } while (doAll && ++itr != _contour2Ds.end());
+
+    sceneBoundsChanged();
+     _needsRedraw = true;
+}
+
+/**
+ * \brief Set the color mode for the specified DataSet
+ */
+void Renderer::setContour2DColorMode(const DataSetId& id,
+                                     Contour2D::ColorMode mode,
+                                     DataSet::DataAttributeType type,
+                                     const char *name, double range[2])
+{
+    Contour2DHashmap::iterator itr;
+
+    bool doAll = false;
+
+    if (id.compare("all") == 0) {
+        itr = _contour2Ds.begin();
+        if (itr == _contour2Ds.end())
+            return;
+        doAll = true;
+    } else {
+        itr = _contour2Ds.find(id);
+    }
+    if (itr == _contour2Ds.end()) {
+        ERROR("Contour2D not found: %s", id.c_str());
+        return;
+    }
+
+    do {
+        itr->second->setColorMode(mode, type, name, range);
+    } while (doAll && ++itr != _contour2Ds.end());
+
+    _needsRedraw = true;
+}
+
+/**
+ * \brief Set the color mode for the specified DataSet
+ */
+void Renderer::setContour2DColorMode(const DataSetId& id,
+                                     Contour2D::ColorMode mode,
+                                     const char *name, double range[2])
+{
+    Contour2DHashmap::iterator itr;
+
+    bool doAll = false;
+
+    if (id.compare("all") == 0) {
+        itr = _contour2Ds.begin();
+        if (itr == _contour2Ds.end())
+            return;
+        doAll = true;
+    } else {
+        itr = _contour2Ds.find(id);
+    }
+    if (itr == _contour2Ds.end()) {
+        ERROR("Contour2D not found: %s", id.c_str());
+        return;
+    }
+
+    do {
+        itr->second->setColorMode(mode, name, range);
+    } while (doAll && ++itr != _contour2Ds.end());
+
+    _needsRedraw = true;
+}
+
+/**
+ * \brief Create a new Contour3D and associate it with the named DataSet
+ */
+bool Renderer::addContour3D(const DataSetId& id, int numContours)
+{
+    DataSetHashmap::iterator itr;
+
+    bool doAll = false;
+
+    if (id.compare("all") == 0) {
+        itr = _dataSets.begin();
+    } else {
+        itr = _dataSets.find(id);
+    }
+    if (itr == _dataSets.end()) {
+        ERROR("Unknown dataset %s", id.c_str());
+        return false;
+    }
+
+    do {
+        DataSet *ds = itr->second;
+        const DataSetId& dsID = ds->getName();
+
+        if (getGraphicsObject<Contour3D>(dsID)) {
+            WARN("Replacing existing Contour3D %s", dsID.c_str());
+            deleteGraphicsObject<Contour3D>(dsID);
+        }
+
+        Contour3D *contour = new Contour3D(numContours);
+
+        contour->setDataSet(ds, this);
+
+        if (contour->getProp() == NULL) {
+            delete contour;
+            return false;
+        } else {
+            _renderer->AddViewProp(contour->getProp());
+        }
+
+        _contour3Ds[dsID] = contour;
+    } while (doAll && ++itr != _dataSets.end());
+
+    sceneBoundsChanged();
+    _needsRedraw = true;
+    return true;
+}
+
+/**
+ * \brief Create a new Contour3D and associate it with the named DataSet
+ */
+bool Renderer::addContour3D(const DataSetId& id,const std::vector<double>& contours)
+{
+    DataSetHashmap::iterator itr;
+
+    bool doAll = false;
+
+    if (id.compare("all") == 0) {
+        itr = _dataSets.begin();
+    } else {
+        itr = _dataSets.find(id);
+    }
+    if (itr == _dataSets.end()) {
+        ERROR("Unknown dataset %s", id.c_str());
+        return false;
+    }
+
+    do {
+        DataSet *ds = itr->second;
+        const DataSetId& dsID = ds->getName();
+
+        if (getGraphicsObject<Contour3D>(dsID)) {
+            WARN("Replacing existing Contour3D %s", dsID.c_str());
+            deleteGraphicsObject<Contour3D>(dsID);
+        }
+
+        Contour3D *contour = new Contour3D(contours);
+
+        contour->setDataSet(ds, this);
+
+        if (contour->getProp() == NULL) {
+            delete contour;
+            return false;
+        } else {
+            _renderer->AddViewProp(contour->getProp());
+        }
+
+        _contour3Ds[dsID] = contour;
+    } while (doAll && ++itr != _dataSets.end());
+
+    sceneBoundsChanged();
+    _needsRedraw = true;
+    return true;
+}
+
+/**
+ * \brief Set the number of equally spaced isosurfaces for the given DataSet
+ */
+void Renderer::setContour3DContourField(const DataSetId& id, const char *fieldName)
+{
+    Contour3DHashmap::iterator itr;
+
+    bool doAll = false;
+
+    if (id.compare("all") == 0) {
+        itr = _contour3Ds.begin();
+        doAll = true;
+    } else {
+        itr = _contour3Ds.find(id);
+    }
+    if (itr == _contour3Ds.end()) {
+        ERROR("Contour3D not found: %s", id.c_str());
+        return;
+    }
+
+    do {
+        itr->second->setContourField(fieldName);
+     } while (doAll && ++itr != _contour3Ds.end());
+
+    sceneBoundsChanged();
+    _needsRedraw = true;
+}
+
+/**
+ * \brief Set the number of equally spaced isosurfaces for the given DataSet
+ */
+void Renderer::setContour3DNumContours(const DataSetId& id, int numContours)
+{
+    Contour3DHashmap::iterator itr;
+
+    bool doAll = false;
+
+    if (id.compare("all") == 0) {
+        itr = _contour3Ds.begin();
+        doAll = true;
+    } else {
+        itr = _contour3Ds.find(id);
+    }
+    if (itr == _contour3Ds.end()) {
+        ERROR("Contour3D not found: %s", id.c_str());
+        return;
+    }
+
+    do {
+        itr->second->setNumContours(numContours);
+     } while (doAll && ++itr != _contour3Ds.end());
+
+    sceneBoundsChanged();
+    _needsRedraw = true;
+}
+
+/**
+ * \brief Set a list of isovalues for the given DataSet
+ */
+void Renderer::setContour3DContourList(const DataSetId& id, const std::vector<double>& contours)
+{
+    Contour3DHashmap::iterator itr;
+
+    bool doAll = false;
+
+    if (id.compare("all") == 0) {
+        itr = _contour3Ds.begin();
+        doAll = true;
+    } else {
+        itr = _contour3Ds.find(id);
+    }
+    if (itr == _contour3Ds.end()) {
+        ERROR("Contour3D not found: %s", id.c_str());
+        return;
+    }
+
+    do {
+        itr->second->setContourList(contours);
+    } while (doAll && ++itr != _contour3Ds.end());
+
+    sceneBoundsChanged();
+    _needsRedraw = true;
+}
+
+/**
+ * \brief Set the color mode for the specified DataSet
+ */
+void Renderer::setContour3DColorMode(const DataSetId& id,
+                                     Contour3D::ColorMode mode,
+                                     DataSet::DataAttributeType type,
+                                     const char *name, double range[2])
+{
+    Contour3DHashmap::iterator itr;
+
+    bool doAll = false;
+
+    if (id.compare("all") == 0) {
+        itr = _contour3Ds.begin();
+        if (itr == _contour3Ds.end())
+            return;
+        doAll = true;
+    } else {
+        itr = _contour3Ds.find(id);
+    }
+    if (itr == _contour3Ds.end()) {
+        ERROR("Contour3D not found: %s", id.c_str());
+        return;
+    }
+
+    do {
+        itr->second->setColorMode(mode, type, name, range);
+    } while (doAll && ++itr != _contour3Ds.end());
+
+    _needsRedraw = true;
+}
+
+/**
+ * \brief Set the color mode for the specified DataSet
+ */
+void Renderer::setContour3DColorMode(const DataSetId& id,
+                                     Contour3D::ColorMode mode,
+                                     const char *name, double range[2])
+{
+    Contour3DHashmap::iterator itr;
+
+    bool doAll = false;
+
+    if (id.compare("all") == 0) {
+        itr = _contour3Ds.begin();
+        if (itr == _contour3Ds.end())
+            return;
+        doAll = true;
+    } else {
+        itr = _contour3Ds.find(id);
+    }
+    if (itr == _contour3Ds.end()) {
+        ERROR("Contour3D not found: %s", id.c_str());
+        return;
+    }
+
+    do {
+        itr->second->setColorMode(mode, name, range);
+    } while (doAll && ++itr != _contour3Ds.end());
+
+    _needsRedraw = true;
+}
+
+/**
+ * \brief Set the visibility of cutplane outlines
+ */
+void Renderer::setCutplaneOutlineVisibility(const DataSetId& id, bool state)
+{
+    CutplaneHashmap::iterator itr;
+
+    bool doAll = false;
+
+    if (id.compare("all") == 0) {
+        itr = _cutplanes.begin();
+        if (itr == _cutplanes.end())
+            return;
+        doAll = true;
+    } else {
+        itr = _cutplanes.find(id);
+    }
+
+    if (itr == _cutplanes.end()) {
+        ERROR("Cutplane not found: %s", id.c_str());
+        return;
+    }
+
+    do {
+        itr->second->setOutlineVisibility(state);
+     } while (doAll && ++itr != _cutplanes.end());
+
+    sceneBoundsChanged();
+    _needsRedraw = true;
+}
+
+/**
+ * \brief Set the visibility of slices in one of the three axes
+ */
+void Renderer::setCutplaneSliceVisibility(const DataSetId& id, Axis axis, bool state)
+{
+    CutplaneHashmap::iterator itr;
+
+    bool doAll = false;
+
+    if (id.compare("all") == 0) {
+        itr = _cutplanes.begin();
+        if (itr == _cutplanes.end())
+            return;
+        doAll = true;
+    } else {
+        itr = _cutplanes.find(id);
+    }
+
+    if (itr == _cutplanes.end()) {
+        ERROR("Cutplane not found: %s", id.c_str());
+        return;
+    }
+
+    do {
+        itr->second->setSliceVisibility(axis, state);
+     } while (doAll && ++itr != _cutplanes.end());
+
+    sceneBoundsChanged();
+    _needsRedraw = true;
+}
+
+/**
+ * \brief Set the color mode for the specified DataSet
+ */
+void Renderer::setCutplaneColorMode(const DataSetId& id,
+                                    Cutplane::ColorMode mode,
+                                    DataSet::DataAttributeType type,
+                                    const char *name, double range[2])
+{
+    CutplaneHashmap::iterator itr;
+
+    bool doAll = false;
+
+    if (id.compare("all") == 0) {
+        itr = _cutplanes.begin();
+        if (itr == _cutplanes.end())
+            return;
+        doAll = true;
+    } else {
+        itr = _cutplanes.find(id);
+    }
+    if (itr == _cutplanes.end()) {
+        ERROR("Cutplane not found: %s", id.c_str());
+        return;
+    }
+
+    do {
+        itr->second->setColorMode(mode, type, name, range);
+    } while (doAll && ++itr != _cutplanes.end());
+
+    _needsRedraw = true;
+}
+
+/**
+ * \brief Set the color mode for the specified DataSet
+ */
+void Renderer::setCutplaneColorMode(const DataSetId& id,
+                                    Cutplane::ColorMode mode,
+                                    const char *name, double range[2])
+{
+    CutplaneHashmap::iterator itr;
+
+    bool doAll = false;
+
+    if (id.compare("all") == 0) {
+        itr = _cutplanes.begin();
+        if (itr == _cutplanes.end())
+            return;
+        doAll = true;
+    } else {
+        itr = _cutplanes.find(id);
+    }
+    if (itr == _cutplanes.end()) {
+        ERROR("Cutplane not found: %s", id.c_str());
+        return;
+    }
+
+    do {
+        itr->second->setColorMode(mode, name, range);
+    } while (doAll && ++itr != _cutplanes.end());
+
+    _needsRedraw = true;
+}
+
+/**
+ * \brief Create a new Cylinder and associate it with an ID
+ */
+bool Renderer::addCylinder(const DataSetId& id, double radius, double height, bool cap)
+{
+    Cylinder *gobj;
+    if ((gobj = getGraphicsObject<Cylinder>(id)) != NULL) {
+        WARN("Replacing existing %s %s", gobj->getClassName(), id.c_str());
+        deleteGraphicsObject<Cylinder>(id);
+    }
+
+    gobj = new Cylinder();
+ 
+    gobj->setDataSet(NULL, this);
+
+    if (gobj->getProp() == NULL &&
+        gobj->getOverlayProp() == NULL) {
+        delete gobj;
+        return false;
+    } else {
+        if (gobj->getProp())
+            _renderer->AddViewProp(gobj->getProp());
+        if (gobj->getOverlayProp())
+            _renderer->AddViewProp(gobj->getOverlayProp());
+    }
+
+    gobj->setRadius(radius);
+    gobj->setHeight(height);
+    gobj->setCapping(cap);
+
+    getGraphicsObjectHashmap<Cylinder>()[id] = gobj;
+
+    sceneBoundsChanged();
+    _needsRedraw = true;
+    return true;
+}
+
+/**
+ * \brief Set Cylinder resolution
+ */
+void Renderer::setCylinderResolution(const DataSetId& id, int res)
+{
+    CylinderHashmap::iterator itr;
+
+    bool doAll = false;
+
+    if (id.compare("all") == 0) {
+        itr = _cylinders.begin();
+        if (itr == _cylinders.end())
+            return;
+        doAll = true;
+    } else {
+        itr = _cylinders.find(id);
+    }
+    if (itr == _cylinders.end()) {
+        ERROR("Cylinder not found: %s", id.c_str());
+        return;
+    }
+
+    do {
+        itr->second->setResolution(res);
+    } while (doAll && ++itr != _cylinders.end());
+
+    sceneBoundsChanged();
+    _needsRedraw = true;
+}
+
+/**
+ * \brief Create a new Disk and associate it with an ID
+ */
+bool Renderer::addDisk(const DataSetId& id, double innerRadius, double outerRadius)
+{
+    Disk *gobj;
+    if ((gobj = getGraphicsObject<Disk>(id)) != NULL) {
+        WARN("Replacing existing %s %s", gobj->getClassName(), id.c_str());
+        deleteGraphicsObject<Disk>(id);
+    }
+
+    gobj = new Disk();
+ 
+    gobj->setDataSet(NULL, this);
+
+    if (gobj->getProp() == NULL &&
+        gobj->getOverlayProp() == NULL) {
+        delete gobj;
+        return false;
+    } else {
+        if (gobj->getProp())
+            _renderer->AddViewProp(gobj->getProp());
+        if (gobj->getOverlayProp())
+            _renderer->AddViewProp(gobj->getOverlayProp());
+    }
+
+    gobj->setRadii(innerRadius, outerRadius);
+
+    getGraphicsObjectHashmap<Disk>()[id] = gobj;
+
+    sceneBoundsChanged();
+    _needsRedraw = true;
+    return true;
+}
+
+/**
+ * \brief Set Disk resolution
+ */
+void Renderer::setDiskResolution(const DataSetId& id, int resRadial, int resCircum)
+{
+    DiskHashmap::iterator itr;
+
+    bool doAll = false;
+
+    if (id.compare("all") == 0) {
+        itr = _disks.begin();
+        if (itr == _disks.end())
+            return;
+        doAll = true;
+    } else {
+        itr = _disks.find(id);
+    }
+    if (itr == _disks.end()) {
+        ERROR("Disk not found: %s", id.c_str());
+        return;
+    }
+
+    do {
+        itr->second->setResolution(resRadial, resCircum);
+    } while (doAll && ++itr != _disks.end());
+
+    sceneBoundsChanged();
+    _needsRedraw = true;
+}
+
+/**
+ * \brief Create a new Glyphs and associate it with the named DataSet
+ */
+bool Renderer::addGlyphs(const DataSetId& id, Glyphs::GlyphShape shape)
+{
+    DataSetHashmap::iterator itr;
+
+    bool doAll = false;
+
+    if (id.compare("all") == 0) {
+        itr = _dataSets.begin();
+    } else {
+        itr = _dataSets.find(id);
+    }
+    if (itr == _dataSets.end()) {
+        ERROR("Unknown dataset %s", id.c_str());
+        return false;
+    }
+
+    do {
+        DataSet *ds = itr->second;
+        const DataSetId& dsID = ds->getName();
+
+        if (getGraphicsObject<Glyphs>(dsID)) {
+            WARN("Replacing existing Glyphs %s", dsID.c_str());
+            deleteGraphicsObject<Glyphs>(dsID);
+        }
+
+        Glyphs *glyphs = new Glyphs(shape);
+
+        glyphs->setDataSet(ds, this);
+
+        if (glyphs->getProp() == NULL) {
+            delete glyphs;
+            return false;
+        } else {
+            _renderer->AddViewProp(glyphs->getProp());
+        }
+
+        _glyphs[dsID] = glyphs;
+    } while (doAll && ++itr != _dataSets.end());
+
+    sceneBoundsChanged();
+    _needsRedraw = true;
+    return true;
+}
+
+/**
+ * \brief Set the color mode for the specified DataSet
+ */
+void Renderer::setGlyphsColorMode(const DataSetId& id,
+                                  Glyphs::ColorMode mode,
+                                  const char *name, double range[2])
+{
+    GlyphsHashmap::iterator itr;
+
+    bool doAll = false;
+
+    if (id.compare("all") == 0) {
+        itr = _glyphs.begin();
+        if (itr == _glyphs.end())
+            return;
+        doAll = true;
+    } else {
+        itr = _glyphs.find(id);
+    }
+    if (itr == _glyphs.end()) {
+        ERROR("Glyphs not found: %s", id.c_str());
+        return;
+    }
+
+    do {
+        itr->second->setColorMode(mode, name, range);
+    } while (doAll && ++itr != _glyphs.end());
+
+    _needsRedraw = true;
+}
+
+/**
+ * \brief Controls the array used to scale glyphs for the given DataSet
+ */
+void Renderer::setGlyphsScalingMode(const DataSetId& id,
+                                    Glyphs::ScalingMode mode,
+                                    const char *name, double range[2])
+{
+    GlyphsHashmap::iterator itr;
+
+    bool doAll = false;
+
+    if (id.compare("all") == 0) {
+        itr = _glyphs.begin();
+        if (itr == _glyphs.end())
+            return;
+        doAll = true;
+    } else {
+        itr = _glyphs.find(id);
+    }
+    if (itr == _glyphs.end()) {
+        ERROR("Glyphs not found: %s", id.c_str());
+        return;
+    }
+
+    do {
+        itr->second->setScalingMode(mode, name, range);
+    } while (doAll && ++itr != _glyphs.end());
+
+    sceneBoundsChanged();
+    _needsRedraw = true;
+}
+
+/**
+ * \brief Controls if field data range is normalized to [0,1] before
+ * applying scale factor for the given DataSet
+ */
+void Renderer::setGlyphsNormalizeScale(const DataSetId& id, bool normalize)
+{
+    GlyphsHashmap::iterator itr;
+
+    bool doAll = false;
+
+    if (id.compare("all") == 0) {
+        itr = _glyphs.begin();
+        if (itr == _glyphs.end())
+            return;
+        doAll = true;
+    } else {
+        itr = _glyphs.find(id);
+    }
+    if (itr == _glyphs.end()) {
+        ERROR("Glyphs not found: %s", id.c_str());
+        return;
+    }
+
+    do {
+        itr->second->setNormalizeScale(normalize);
+    } while (doAll && ++itr != _glyphs.end());
+
+    sceneBoundsChanged();
+    _needsRedraw = true;
+}
+
+/**
+ * \brief Controls if glyphs are oriented from a vector field for the 
+ * given DataSet
+ */
+void Renderer::setGlyphsOrientMode(const DataSetId& id, bool state,
+                                   const char *name)
+{
+    GlyphsHashmap::iterator itr;
+
+    bool doAll = false;
+
+    if (id.compare("all") == 0) {
+        itr = _glyphs.begin();
+        if (itr == _glyphs.end())
+            return;
+        doAll = true;
+    } else {
+        itr = _glyphs.find(id);
+    }
+    if (itr == _glyphs.end()) {
+        ERROR("Glyphs not found: %s", id.c_str());
+        return;
+    }
+
+    do {
+        itr->second->setOrientMode(state, name);
+    } while (doAll && ++itr != _glyphs.end());
+
+    sceneBoundsChanged();
+    _needsRedraw = true;
+}
+
+/**
+ * \brief Set the shape of Glyphs for the given DataSet
+ */
+void Renderer::setGlyphsShape(const DataSetId& id, Glyphs::GlyphShape shape)
+{
+    GlyphsHashmap::iterator itr;
+
+    bool doAll = false;
+
+    if (id.compare("all") == 0) {
+        itr = _glyphs.begin();
+        if (itr == _glyphs.end())
+            return;
+        doAll = true;
+    } else {
+        itr = _glyphs.find(id);
+    }
+    if (itr == _glyphs.end()) {
+        ERROR("Glyphs not found: %s", id.c_str());
+        return;
+    }
+
+    do {
+        itr->second->setGlyphShape(shape);
+    } while (doAll && ++itr != _glyphs.end());
+
+    sceneBoundsChanged();
+    _needsRedraw = true;
+}
+
+/**
+ * \brief Set the glyph scaling factor for the given DataSet
+ */
+void Renderer::setGlyphsScaleFactor(const DataSetId& id, double scale)
+{
+    GlyphsHashmap::iterator itr;
+
+    bool doAll = false;
+
+    if (id.compare("all") == 0) {
+        itr = _glyphs.begin();
+        if (itr == _glyphs.end())
+            return;
+        doAll = true;
+    } else {
+        itr = _glyphs.find(id);
+    }
+    if (itr == _glyphs.end()) {
+        ERROR("Glyphs not found: %s", id.c_str());
+        return;
+    }
+
+    do {
+        itr->second->setScaleFactor(scale);
+    } while (doAll && ++itr != _glyphs.end());
+
+    sceneBoundsChanged();
+    _needsRedraw = true;
+}
+
+/**
+ * \brief Create a new HeightMap and associate it with the named DataSet
+ */
+bool Renderer::addHeightMap(const DataSetId& id, int numContours, double heightScale)
+{
+    DataSetHashmap::iterator itr;
+
+    bool doAll = false;
+
+    if (id.compare("all") == 0) {
+        itr = _dataSets.begin();
+    } else {
+        itr = _dataSets.find(id);
+    }
+    if (itr == _dataSets.end()) {
+        ERROR("Unknown dataset %s", id.c_str());
+        return false;
+    }
+
+    do {
+        DataSet *ds = itr->second;
+        const DataSetId& dsID = ds->getName();
+
+        if (getGraphicsObject<HeightMap>(dsID)) {
+            WARN("Replacing existing HeightMap %s", dsID.c_str());
+            deleteGraphicsObject<HeightMap>(dsID);
+        }
+
+        HeightMap *hmap = new HeightMap(numContours, heightScale);
+
+        hmap->setDataSet(ds, this);
+
+        if (hmap->getProp() == NULL) {
+            delete hmap;
+            return false;
+        } else {
+            _renderer->AddViewProp(hmap->getProp());
+        }
+
+        _heightMaps[dsID] = hmap;
+    } while (doAll && ++itr != _dataSets.end());
+
+    sceneBoundsChanged();
+    _needsRedraw = true;
+    return true;
+}
+
+/**
+ * \brief Create a new HeightMap and associate it with the named DataSet
+ */
+bool Renderer::addHeightMap(const DataSetId& id, const std::vector<double>& contours, double heightScale)
+{
+    DataSetHashmap::iterator itr;
+
+    bool doAll = false;
+
+    if (id.compare("all") == 0) {
+        itr = _dataSets.begin();
+    } else {
+        itr = _dataSets.find(id);
+    }
+    if (itr == _dataSets.end()) {
+        ERROR("Unknown dataset %s", id.c_str());
+        return false;
+    }
+
+    do {
+        DataSet *ds = itr->second;
+        const DataSetId& dsID = ds->getName();
+
+        if (getGraphicsObject<HeightMap>(dsID)) {
+            WARN("Replacing existing HeightMap %s", dsID.c_str());
+            deleteGraphicsObject<HeightMap>(dsID);
+        }
+
+        HeightMap *hmap = new HeightMap(contours, heightScale);
+
+        hmap->setDataSet(ds, this);
+
+        if (hmap->getProp() == NULL) {
+            delete hmap;
+            return false;
+        } else {
+            _renderer->AddViewProp(hmap->getProp());
+        }
+
+        _heightMaps[dsID] = hmap;
+    } while (doAll && ++itr != _dataSets.end());
+
+    sceneBoundsChanged();
+    _needsRedraw = true;
+    return true;
+}
+
+/**
+ * \brief Set amount to scale scalar values when creating elevations
+ * in the height map
+ */
+void Renderer::setHeightMapHeightScale(const DataSetId& id, double scale)
+{
+    HeightMapHashmap::iterator itr;
+
+    bool doAll = false;
+
+    if (id.compare("all") == 0) {
+        itr = _heightMaps.begin();
+        if (itr == _heightMaps.end())
+            return;
+        doAll = true;
+    } else {
+        itr = _heightMaps.find(id);
+    }
+
+    if (itr == _heightMaps.end()) {
+        ERROR("HeightMap not found: %s", id.c_str());
+        return;
+    }
+
+    do {
+        itr->second->setHeightScale(scale);
+     } while (doAll && ++itr != _heightMaps.end());
+
+    sceneBoundsChanged();
+    _needsRedraw = true;
+}
+
+/**
+ * \brief Set the number of equally spaced contour isolines for the given DataSet
+ */
+void Renderer::setHeightMapNumContours(const DataSetId& id, int numContours)
+{
+    HeightMapHashmap::iterator itr;
+
+    bool doAll = false;
+
+    if (id.compare("all") == 0) {
+        itr = _heightMaps.begin();
+        doAll = true;
+    } else {
+        itr = _heightMaps.find(id);
+    }
+    if (itr == _heightMaps.end()) {
+        ERROR("HeightMap not found: %s", id.c_str());
+        return;
+    }
+
+    do {
+        itr->second->setNumContours(numContours);
+    } while (doAll && ++itr != _heightMaps.end());
+
+    sceneBoundsChanged();
+    _needsRedraw = true;
+}
+
+/**
+ * \brief Set a list of height map contour isovalues for the given DataSet
+ */
+void Renderer::setHeightMapContourList(const DataSetId& id, const std::vector<double>& contours)
+{
+    HeightMapHashmap::iterator itr;
+
+    bool doAll = false;
+
+    if (id.compare("all") == 0) {
+        itr = _heightMaps.begin();
+        doAll = true;
+    } else {
+        itr = _heightMaps.find(id);
+    }
+    if (itr == _heightMaps.end()) {
+        ERROR("HeightMap not found: %s", id.c_str());
+        return;
+    }
+
+    do {
+        itr->second->setContourList(contours);
+    } while (doAll && ++itr != _heightMaps.end());
+
+    sceneBoundsChanged();
+     _needsRedraw = true;
+}
+
+/**
+ * \brief Turn on/off rendering height map contour lines for the given DataSet
+ */
+void Renderer::setHeightMapContourLineVisibility(const DataSetId& id, bool state)
+{
+    HeightMapHashmap::iterator itr;
+
+    bool doAll = false;
+
+    if (id.compare("all") == 0) {
+        itr = _heightMaps.begin();
+        if (itr == _heightMaps.end())
+            return;
+        doAll = true;
+    } else {
+        itr = _heightMaps.find(id);
+    }
+    if (itr == _heightMaps.end()) {
+        ERROR("HeightMap not found: %s", id.c_str());
+        return;
+    }
+
+    do {
+        itr->second->setContourLineVisibility(state);
+    } while (doAll && ++itr != _heightMaps.end());
+
+    sceneBoundsChanged();
+    _needsRedraw = true;
+}
+
+/**
+ * \brief Turn on/off rendering height map colormap surface for the given DataSet
+ */
+void Renderer::setHeightMapContourSurfaceVisibility(const DataSetId& id, bool state)
+{
+    HeightMapHashmap::iterator itr;
+
+    bool doAll = false;
+
+    if (id.compare("all") == 0) {
+        itr = _heightMaps.begin();
+        if (itr == _heightMaps.end())
+            return;
+        doAll = true;
+    } else {
+        itr = _heightMaps.find(id);
+    }
+    if (itr == _heightMaps.end()) {
+        ERROR("HeightMap not found: %s", id.c_str());
+        return;
+    }
+
+    do {
+        itr->second->setContourSurfaceVisibility(state);
+    } while (doAll && ++itr != _heightMaps.end());
+
+    sceneBoundsChanged();
+    _needsRedraw = true;
+}
+
+/**
+ * \brief Set the RGB height map isoline color for the specified DataSet
+ */
+void Renderer::setHeightMapContourEdgeColor(const DataSetId& id, float color[3])
+{
+    HeightMapHashmap::iterator itr;
+
+    bool doAll = false;
+
+    if (id.compare("all") == 0) {
+        itr = _heightMaps.begin();
+        if (itr == _heightMaps.end())
+            return;
+        doAll = true;
+    } else {
+        itr = _heightMaps.find(id);
+    }
+    if (itr == _heightMaps.end()) {
+        ERROR("HeightMap not found: %s", id.c_str());
+        return;
+    }
+
+    do {
+        itr->second->setContourEdgeColor(color);
+    } while (doAll && ++itr != _heightMaps.end());
+
+    _needsRedraw = true;
+}
+
+/**
+ * \brief Set the height map isoline width for the specified DataSet (may be a no-op)
+ *
+ * If the OpenGL implementation/hardware does not support wide lines, 
+ * this function may not have an effect.
+ */
+void Renderer::setHeightMapContourEdgeWidth(const DataSetId& id, float edgeWidth)
+{
+    HeightMapHashmap::iterator itr;
+
+    bool doAll = false;
+
+    if (id.compare("all") == 0) {
+        itr = _heightMaps.begin();
+        if (itr == _heightMaps.end())
+            return;
+        doAll = true;
+    } else {
+        itr = _heightMaps.find(id);
+    }
+    if (itr == _heightMaps.end()) {
+        ERROR("HeightMap not found: %s", id.c_str());
+        return;
+    }
+
+    do {
+        itr->second->setContourEdgeWidth(edgeWidth);
+    } while (doAll && ++itr != _heightMaps.end());
+
+    sceneBoundsChanged();
+    _needsRedraw = true;
+}
+
+/**
+ * \brief Toggle colormapping of contour lines
+ */
+void Renderer::setHeightMapContourLineColorMapEnabled(const DataSetId& id, bool mode)
+{
+    HeightMapHashmap::iterator itr;
+
+    bool doAll = false;
+
+    if (id.compare("all") == 0) {
+        itr = _heightMaps.begin();
+        if (itr == _heightMaps.end())
+            return;
+        doAll = true;
+    } else {
+        itr = _heightMaps.find(id);
+    }
+    if (itr == _heightMaps.end()) {
+        ERROR("HeightMap not found: %s", id.c_str());
+        return;
+    }
+
+    do {
+        itr->second->setContourLineColorMapEnabled(mode);
+    } while (doAll && ++itr != _heightMaps.end());
+
+    _needsRedraw = true;    
+}
+
+/**
+ * \brief Set the color mode for the specified DataSet
+ */
+void Renderer::setHeightMapColorMode(const DataSetId& id,
+                                     HeightMap::ColorMode mode,
+                                     DataSet::DataAttributeType type,
+                                     const char *name, double range[2])
+{
+    HeightMapHashmap::iterator itr;
+
+    bool doAll = false;
+
+    if (id.compare("all") == 0) {
+        itr = _heightMaps.begin();
+        if (itr == _heightMaps.end())
+            return;
+        doAll = true;
+    } else {
+        itr = _heightMaps.find(id);
+    }
+    if (itr == _heightMaps.end()) {
+        ERROR("HeightMap not found: %s", id.c_str());
+        return;
+    }
+
+    do {
+        itr->second->setColorMode(mode, type, name, range);
+    } while (doAll && ++itr != _heightMaps.end());
+
+    _needsRedraw = true;
+}
+
+/**
+ * \brief Set the color mode for the specified DataSet
+ */
+void Renderer::setHeightMapColorMode(const DataSetId& id,
+                                     HeightMap::ColorMode mode,
+                                     const char *name, double range[2])
+{
+    HeightMapHashmap::iterator itr;
+
+    bool doAll = false;
+
+    if (id.compare("all") == 0) {
+        itr = _heightMaps.begin();
+        if (itr == _heightMaps.end())
+            return;
+        doAll = true;
+    } else {
+        itr = _heightMaps.find(id);
+    }
+    if (itr == _heightMaps.end()) {
+        ERROR("HeightMap not found: %s", id.c_str());
+        return;
+    }
+
+    do {
+        itr->second->setColorMode(mode, name, range);
+    } while (doAll && ++itr != _heightMaps.end());
+
+    _needsRedraw = true;
+}
+
+/**
+ * \brief Create a new Line and associate it with an ID
+ */
+bool Renderer::addLine(const DataSetId& id, double pt1[3], double pt2[3])
+{
+    Line *gobj;
+    if ((gobj = getGraphicsObject<Line>(id)) != NULL) {
+        WARN("Replacing existing %s %s", gobj->getClassName(), id.c_str());
+        deleteGraphicsObject<Line>(id);
+    }
+
+    gobj = new Line();
+ 
+    gobj->setDataSet(NULL, this);
+
+    if (gobj->getProp() == NULL &&
+        gobj->getOverlayProp() == NULL) {
+        delete gobj;
+        return false;
+    } else {
+        if (gobj->getProp())
+            _renderer->AddViewProp(gobj->getProp());
+        if (gobj->getOverlayProp())
+            _renderer->AddViewProp(gobj->getOverlayProp());
+    }
+
+    gobj->setEndPoints(pt1, pt2);
+
+    getGraphicsObjectHashmap<Line>()[id] = gobj;
+
+    sceneBoundsChanged();
+    _needsRedraw = true;
+    return true;
+}
+
+/**
+ * \brief Set radius scale factor for atoms
+ */
+void Renderer::setMoleculeAtomRadiusScale(const DataSetId& id, double scale)
+{
+    MoleculeHashmap::iterator itr;
+
+    bool doAll = false;
+
+    if (id.compare("all") == 0) {
+        itr = _molecules.begin();
+        if (itr == _molecules.end())
+            return;
+        doAll = true;
+    } else {
+        itr = _molecules.find(id);
+    }
+    if (itr == _molecules.end()) {
+        ERROR("Molecule not found: %s", id.c_str());
+        return;
+    }
+
+    do {
+        itr->second->setAtomRadiusScale(scale);
+    } while (doAll && ++itr != _molecules.end());
+
+    sceneBoundsChanged();
+    _needsRedraw = true;
+}
+
+/**
+ * \brief Set radius standard for scaling atoms
+ */
+void Renderer::setMoleculeAtomScaling(const DataSetId& id, Molecule::AtomScaling scaling)
+{
+    MoleculeHashmap::iterator itr;
+
+    bool doAll = false;
+
+    if (id.compare("all") == 0) {
+        itr = _molecules.begin();
+        if (itr == _molecules.end())
+            return;
+        doAll = true;
+    } else {
+        itr = _molecules.find(id);
+    }
+    if (itr == _molecules.end()) {
+        ERROR("Molecule not found: %s", id.c_str());
+        return;
+    }
+
+    do {
+        itr->second->setAtomScaling(scaling);
+    } while (doAll && ++itr != _molecules.end());
+
+    sceneBoundsChanged();
+    _needsRedraw = true;
+}
+
+/**
+ * \brief Turn on/off rendering of the Molecule atoms for the given DataSet
+ */
+void Renderer::setMoleculeAtomVisibility(const DataSetId& id, bool state)
+{
+    MoleculeHashmap::iterator itr;
+
+    bool doAll = false;
+
+    if (id.compare("all") == 0) {
+        itr = _molecules.begin();
+        if (itr == _molecules.end())
+            return;
+        doAll = true;
+    } else {
+        itr = _molecules.find(id);
+    }
+    if (itr == _molecules.end()) {
+        ERROR("Molecule not found: %s", id.c_str());
+        return;
+    }
+
+    do {
+        itr->second->setAtomVisibility(state);
+    } while (doAll && ++itr != _molecules.end());
+
+    sceneBoundsChanged();
+    _needsRedraw = true;
+}
+
+/**
+ * \brief Turn on/off rendering of the Molecule atom labels for the given DataSet
+ */
+void Renderer::setMoleculeAtomLabelVisibility(const DataSetId& id, bool state)
+{
+    MoleculeHashmap::iterator itr;
+
+    bool doAll = false;
+
+    if (id.compare("all") == 0) {
+        itr = _molecules.begin();
+        if (itr == _molecules.end())
+            return;
+        doAll = true;
+    } else {
+        itr = _molecules.find(id);
+    }
+    if (itr == _molecules.end()) {
+        ERROR("Molecule not found: %s", id.c_str());
+        return;
+    }
+
+    do {
+        itr->second->setAtomLabelVisibility(state);
+    } while (doAll && ++itr != _molecules.end());
+
+    sceneBoundsChanged();
+    _needsRedraw = true;
+}
+
+/**
+ * \brief Set radius scale factor for atoms
+ */
+void Renderer::setMoleculeBondRadiusScale(const DataSetId& id, double scale)
+{
+    MoleculeHashmap::iterator itr;
+
+    bool doAll = false;
+
+    if (id.compare("all") == 0) {
+        itr = _molecules.begin();
+        if (itr == _molecules.end())
+            return;
+        doAll = true;
+    } else {
+        itr = _molecules.find(id);
+    }
+    if (itr == _molecules.end()) {
+        ERROR("Molecule not found: %s", id.c_str());
+        return;
+    }
+
+    do {
+        itr->second->setBondRadiusScale(scale);
+    } while (doAll && ++itr != _molecules.end());
+
+    sceneBoundsChanged();
+    _needsRedraw = true;
+}
+
+/**
+ * \brief Turn on/off rendering of the Molecule bonds for the given DataSet
+ */
+void Renderer::setMoleculeBondVisibility(const DataSetId& id, bool state)
+{
+    MoleculeHashmap::iterator itr;
+
+    bool doAll = false;
+
+    if (id.compare("all") == 0) {
+        itr = _molecules.begin();
+        if (itr == _molecules.end())
+            return;
+        doAll = true;
+    } else {
+        itr = _molecules.find(id);
+    }
+    if (itr == _molecules.end()) {
+        ERROR("Molecule not found: %s", id.c_str());
+        return;
+    }
+
+    do {
+        itr->second->setBondVisibility(state);
+    } while (doAll && ++itr != _molecules.end());
+
+    sceneBoundsChanged();
+    _needsRedraw = true;
+}
+
+/**
+ * \brief Set render style of the Molecule bonds for the given DataSet
+ */
+void Renderer::setMoleculeBondStyle(const DataSetId& id, Molecule::BondStyle style)
+{
+    MoleculeHashmap::iterator itr;
+
+    bool doAll = false;
+
+    if (id.compare("all") == 0) {
+        itr = _molecules.begin();
+        if (itr == _molecules.end())
+            return;
+        doAll = true;
+    } else {
+        itr = _molecules.find(id);
+    }
+    if (itr == _molecules.end()) {
+        ERROR("Molecule not found: %s", id.c_str());
+        return;
+    }
+
+    do {
+        itr->second->setBondStyle(style);
+    } while (doAll && ++itr != _molecules.end());
+
+    sceneBoundsChanged();
+    _needsRedraw = true;
+}
+
+/**
+ * \brief Set coloring mode of the Molecule bonds for the given DataSet
+ */
+void Renderer::setMoleculeBondColorMode(const DataSetId& id, Molecule::BondColorMode mode)
+{
+    MoleculeHashmap::iterator itr;
+
+    bool doAll = false;
+
+    if (id.compare("all") == 0) {
+        itr = _molecules.begin();
+        if (itr == _molecules.end())
+            return;
+        doAll = true;
+    } else {
+        itr = _molecules.find(id);
+    }
+    if (itr == _molecules.end()) {
+        ERROR("Molecule not found: %s", id.c_str());
+        return;
+    }
+
+    do {
+        itr->second->setBondColorMode(mode);
+    } while (doAll && ++itr != _molecules.end());
+
+    _needsRedraw = true;
+}
+
+/**
+ * \brief Set constant color of the Molecule bonds for the given DataSet
+ */
+void Renderer::setMoleculeBondColor(const DataSetId& id, float color[3])
+{
+    MoleculeHashmap::iterator itr;
+
+    bool doAll = false;
+
+    if (id.compare("all") == 0) {
+        itr = _molecules.begin();
+        if (itr == _molecules.end())
+            return;
+        doAll = true;
+    } else {
+        itr = _molecules.find(id);
+    }
+    if (itr == _molecules.end()) {
+        ERROR("Molecule not found: %s", id.c_str());
+        return;
+    }
+
+    do {
+        itr->second->setBondColor(color);
+    } while (doAll && ++itr != _molecules.end());
+
+    _needsRedraw = true;
+}
+
+/**
+ * \brief Set the color mode for the specified DataSet
+ */
+void Renderer::setMoleculeColorMode(const DataSetId& id,
+                                    Molecule::ColorMode mode,
+                                    DataSet::DataAttributeType type,
+                                    const char *name, double range[2])
+{
+    MoleculeHashmap::iterator itr;
+
+    bool doAll = false;
+
+    if (id.compare("all") == 0) {
+        itr = _molecules.begin();
+        if (itr == _molecules.end())
+            return;
+        doAll = true;
+    } else {
+        itr = _molecules.find(id);
+    }
+    if (itr == _molecules.end()) {
+        ERROR("Molecule not found: %s", id.c_str());
+        return;
+    }
+
+    do {
+        itr->second->setColorMode(mode, type, name, range);
+    } while (doAll && ++itr != _molecules.end());
+
+    _needsRedraw = true;
+}
+
+/**
+ * \brief Set the color mode for the specified DataSet
+ */
+void Renderer::setMoleculeColorMode(const DataSetId& id,
+                                    Molecule::ColorMode mode,
+                                    const char *name, double range[2])
+{
+    MoleculeHashmap::iterator itr;
+
+    bool doAll = false;
+
+    if (id.compare("all") == 0) {
+        itr = _molecules.begin();
+        if (itr == _molecules.end())
+            return;
+        doAll = true;
+    } else {
+        itr = _molecules.find(id);
+    }
+    if (itr == _molecules.end()) {
+        ERROR("Molecule not found: %s", id.c_str());
+        return;
+    }
+
+    do {
+        itr->second->setColorMode(mode, name, range);
+    } while (doAll && ++itr != _molecules.end());
+
+    _needsRedraw = true;
+}
+
+/**
+ * \brief Create a new n-sided regular Polygon and associate it with an ID
+ */
+bool Renderer::addPolygon(const DataSetId& id, int numSides)
+{
+    Polygon *gobj;
+    if ((gobj = getGraphicsObject<Polygon>(id)) != NULL) {
+        WARN("Replacing existing %s %s", gobj->getClassName(), id.c_str());
+        deleteGraphicsObject<Polygon>(id);
+    }
+
+    gobj = new Polygon();
+ 
+    gobj->setDataSet(NULL, this);
+
+    if (gobj->getProp() == NULL &&
+        gobj->getOverlayProp() == NULL) {
+        delete gobj;
+        return false;
+    } else {
+        if (gobj->getProp())
+            _renderer->AddViewProp(gobj->getProp());
+        if (gobj->getOverlayProp())
+            _renderer->AddViewProp(gobj->getOverlayProp());
+    }
+
+    gobj->setNumberOfSides(numSides);
+
+    getGraphicsObjectHashmap<Polygon>()[id] = gobj;
+
+    sceneBoundsChanged();
+    _needsRedraw = true;
+    return true;
+}
+
+/**
+ * \brief Set the color mode for the specified DataSet
+ */
+void Renderer::setPseudoColorColorMode(const DataSetId& id,
+                                       PseudoColor::ColorMode mode,
+                                       DataSet::DataAttributeType type,
+                                       const char *name, double range[2])
+{
+    PseudoColorHashmap::iterator itr;
+
+    bool doAll = false;
+
+    if (id.compare("all") == 0) {
+        itr = _pseudoColors.begin();
+        if (itr == _pseudoColors.end())
+            return;
+        doAll = true;
+    } else {
+        itr = _pseudoColors.find(id);
+    }
+    if (itr == _pseudoColors.end()) {
+        ERROR("PseudoColor not found: %s", id.c_str());
+        return;
+    }
+
+    do {
+        itr->second->setColorMode(mode, type, name, range);
+    } while (doAll && ++itr != _pseudoColors.end());
+
+    _needsRedraw = true;
+}
+
+/**
+ * \brief Set the color mode for the specified DataSet
+ */
+void Renderer::setPseudoColorColorMode(const DataSetId& id,
+                                       PseudoColor::ColorMode mode,
+                                       const char *name, double range[2])
+{
+    PseudoColorHashmap::iterator itr;
+
+    bool doAll = false;
+
+    if (id.compare("all") == 0) {
+        itr = _pseudoColors.begin();
+        if (itr == _pseudoColors.end())
+            return;
+        doAll = true;
+    } else {
+        itr = _pseudoColors.find(id);
+    }
+    if (itr == _pseudoColors.end()) {
+        ERROR("PseudoColor not found: %s", id.c_str());
+        return;
+    }
+
+    do {
+        itr->second->setColorMode(mode, name, range);
+    } while (doAll && ++itr != _pseudoColors.end());
+
+    _needsRedraw = true;
+}
+
+/**
+ * \brief Set Sphere resolution
+ */
+void Renderer::setSphereResolution(const DataSetId& id, int thetaRes, int phiRes)
+{
+    SphereHashmap::iterator itr;
+
+    bool doAll = false;
+
+    if (id.compare("all") == 0) {
+        itr = _spheres.begin();
+        if (itr == _spheres.end())
+            return;
+        doAll = true;
+    } else {
+        itr = _spheres.find(id);
+    }
+    if (itr == _spheres.end()) {
+        ERROR("Sphere not found: %s", id.c_str());
+        return;
+    }
+
+    do {
+        itr->second->setThetaResolution(thetaRes);
+        itr->second->setPhiResolution(phiRes);
+    } while (doAll && ++itr != _spheres.end());
+
+    sceneBoundsChanged();
+    _needsRedraw = true;
+}
+
+/**
+ * \brief Set Sphere section
+ */
+void Renderer::setSphereSection(const DataSetId& id, double thetaStart, double thetaEnd,
+                                double phiStart, double phiEnd)
+{
+    SphereHashmap::iterator itr;
+
+    bool doAll = false;
+
+    if (id.compare("all") == 0) {
+        itr = _spheres.begin();
+        if (itr == _spheres.end())
+            return;
+        doAll = true;
+    } else {
+        itr = _spheres.find(id);
+    }
+    if (itr == _spheres.end()) {
+        ERROR("Sphere not found: %s", id.c_str());
+        return;
+    }
+
+    do {
+        itr->second->setStartTheta(thetaStart);
+        itr->second->setEndTheta(thetaEnd);
+        itr->second->setStartPhi(phiStart);
+        itr->second->setEndPhi(phiEnd);
+    } while (doAll && ++itr != _spheres.end());
+
+    sceneBoundsChanged();
+    _needsRedraw = true;
+}
+
+/**
+ * \brief Set the streamlines seed to points of the streamlines DataSet
+ */
+void Renderer::setStreamlinesNumberOfSeedPoints(const DataSetId& id, int numPoints)
+{
+    StreamlinesHashmap::iterator itr;
+
+    bool doAll = false;
+
+    if (id.compare("all") == 0) {
+        itr = _streamlines.begin();
+        if (itr == _streamlines.end())
+            return;
+        doAll = true;
+    } else {
+        itr = _streamlines.find(id);
+    }
+    if (itr == _streamlines.end()) {
+        ERROR("Streamlines not found: %s", id.c_str());
+        return;
+    }
+
+    do {
+        itr->second->setNumberOfSeedPoints(numPoints);
+    } while (doAll && ++itr != _streamlines.end());
+
+    sceneBoundsChanged();
+    _needsRedraw = true;
+}
+
+/**
+ * \brief Set the streamlines seed to points of the streamlines DataSet
+ */
+void Renderer::setStreamlinesSeedToMeshPoints(const DataSetId& id)
+{
+    StreamlinesHashmap::iterator itr;
+
+    bool doAll = false;
+
+    if (id.compare("all") == 0) {
+        itr = _streamlines.begin();
+        if (itr == _streamlines.end())
+            return;
+        doAll = true;
+    } else {
+        itr = _streamlines.find(id);
+    }
+    if (itr == _streamlines.end()) {
+        ERROR("Streamlines not found: %s", id.c_str());
+        return;
+    }
+
+    do {
+        itr->second->setSeedToMeshPoints();
+    } while (doAll && ++itr != _streamlines.end());
+
+    sceneBoundsChanged();
+    _needsRedraw = true;
+}
+
+/**
+ * \brief Set the streamlines seed to points distributed randomly inside
+ * cells of the streamlines DataSet
+ */
+void Renderer::setStreamlinesSeedToFilledMesh(const DataSetId& id, int numPoints)
+{
+    StreamlinesHashmap::iterator itr;
+
+    bool doAll = false;
+
+    if (id.compare("all") == 0) {
+        itr = _streamlines.begin();
+        if (itr == _streamlines.end())
+            return;
+        doAll = true;
+    } else {
+        itr = _streamlines.find(id);
+    }
+    if (itr == _streamlines.end()) {
+        ERROR("Streamlines not found: %s", id.c_str());
+        return;
+    }
+
+    do {
+        itr->second->setSeedToFilledMesh(numPoints);
+    } while (doAll && ++itr != _streamlines.end());
+
+    sceneBoundsChanged();
+    _needsRedraw = true;
+}
+
+/**
+ * \brief Set the streamlines seed to points of a DataSet
+ *
+ * \param[in] id DataSet identifier
+ * \param[in] data Bytes of VTK DataSet file
+ * \param[in] nbytes Length of data array
+ *
+ * \return boolean indicating success or failure
+ */
+bool Renderer::setStreamlinesSeedToMeshPoints(const DataSetId& id,
+                                              char *data, size_t nbytes)
+{
+    vtkSmartPointer<vtkDataSetReader> reader = vtkSmartPointer<vtkDataSetReader>::New();
+    vtkSmartPointer<vtkCharArray> dataSetString = vtkSmartPointer<vtkCharArray>::New();
+
+    dataSetString->SetArray(data, nbytes, 1);
+    reader->SetInputArray(dataSetString);
+    reader->ReadFromInputStringOn();
+    reader->Update();
+
+    vtkSmartPointer<vtkDataSet> dataSet = reader->GetOutput();
+    if (dataSet == NULL) {
+        return false;
+    }
+#ifndef USE_VTK6
+    dataSet->SetPipelineInformation(NULL);
+#endif
+    StreamlinesHashmap::iterator itr;
+
+    bool doAll = false;
+
+    if (id.compare("all") == 0) {
+        itr = _streamlines.begin();
+        doAll = true;
+    } else {
+        itr = _streamlines.find(id);
+    }
+    if (itr == _streamlines.end()) {
+        ERROR("Streamlines not found: %s", id.c_str());
+        return false;
+    }
+
+    do {
+        itr->second->setSeedToMeshPoints(dataSet);
+    } while (doAll && ++itr != _streamlines.end());
+
+    sceneBoundsChanged();
+    _needsRedraw = true;
+    return true;
+}
+
+/**
+ * \brief Set the streamlines seed to points distributed randomly inside
+ * cells of DataSet
+ *
+ * \param[in] id DataSet identifier
+ * \param[in] data Bytes of VTK DataSet file
+ * \param[in] nbytes Length of data array
+ * \param[in] numPoints Number of random seed points to generate
+ *
+ * \return boolean indicating success or failure
+ */
+bool Renderer::setStreamlinesSeedToFilledMesh(const DataSetId& id,
+                                              char *data, size_t nbytes,
+                                              int numPoints)
+{
+    vtkSmartPointer<vtkDataSetReader> reader = vtkSmartPointer<vtkDataSetReader>::New();
+    vtkSmartPointer<vtkCharArray> dataSetString = vtkSmartPointer<vtkCharArray>::New();
+
+    dataSetString->SetArray(data, nbytes, 1);
+    reader->SetInputArray(dataSetString);
+    reader->ReadFromInputStringOn();
+    reader->Update();
+
+    vtkSmartPointer<vtkDataSet> dataSet = reader->GetOutput();
+    if (dataSet == NULL) {
+        return false;
+    }
+#ifndef USE_VTK6
+    dataSet->SetPipelineInformation(NULL);
+#endif
+    StreamlinesHashmap::iterator itr;
+
+    bool doAll = false;
+
+    if (id.compare("all") == 0) {
+        itr = _streamlines.begin();
+        doAll = true;
+    } else {
+        itr = _streamlines.find(id);
+    }
+    if (itr == _streamlines.end()) {
+        ERROR("Streamlines not found: %s", id.c_str());
+        return false;
+    }
+
+    do {
+        itr->second->setSeedToFilledMesh(dataSet, numPoints);
+    } while (doAll && ++itr != _streamlines.end());
+
+    sceneBoundsChanged();
+    _needsRedraw = true;
+    return true;
+}
+
+/**
+ * \brief Set the streamlines seed to points along a line
+ */
+void Renderer::setStreamlinesSeedToRake(const DataSetId& id,
+                                        double start[3], double end[3],
+                                        int numPoints)
+{
+    StreamlinesHashmap::iterator itr;
+
+    bool doAll = false;
+
+    if (id.compare("all") == 0) {
+        itr = _streamlines.begin();
+        if (itr == _streamlines.end())
+            return;
+        doAll = true;
+    } else {
+        itr = _streamlines.find(id);
+    }
+    if (itr == _streamlines.end()) {
+        ERROR("Streamlines not found: %s", id.c_str());
+        return;
+    }
+
+    do {
+        itr->second->setSeedToRake(start, end, numPoints);
+    } while (doAll && ++itr != _streamlines.end());
+
+    sceneBoundsChanged();
+    _needsRedraw = true;
+}
+
+/**
+ * \brief Set the streamlines seed to points inside a disk, with optional
+ * hole
+ */
+void Renderer::setStreamlinesSeedToDisk(const DataSetId& id,
+                                        double center[3], double normal[3],
+                                        double radius, double innerRadius,
+                                        int numPoints)
+{
+    StreamlinesHashmap::iterator itr;
+
+    bool doAll = false;
+
+    if (id.compare("all") == 0) {
+        itr = _streamlines.begin();
+        if (itr == _streamlines.end())
+            return;
+        doAll = true;
+    } else {
+        itr = _streamlines.find(id);
+    }
+    if (itr == _streamlines.end()) {
+        ERROR("Streamlines not found: %s", id.c_str());
+        return;
+    }
+
+    do {
+        itr->second->setSeedToDisk(center, normal, radius, innerRadius, numPoints);
+    } while (doAll && ++itr != _streamlines.end());
+
+    sceneBoundsChanged();
+    _needsRedraw = true;
+}
+
+/**
+ * \brief Set the streamlines seed to vertices of an n-sided polygon
+ */
+void Renderer::setStreamlinesSeedToPolygon(const DataSetId& id,
+                                           double center[3], double normal[3],
+                                           double angle, double radius,
+                                           int numSides)
+{
+    StreamlinesHashmap::iterator itr;
+
+    bool doAll = false;
+
+    if (id.compare("all") == 0) {
+        itr = _streamlines.begin();
+        if (itr == _streamlines.end())
+            return;
+        doAll = true;
+    } else {
+        itr = _streamlines.find(id);
+    }
+    if (itr == _streamlines.end()) {
+        ERROR("Streamlines not found: %s", id.c_str());
+        return;
+    }
+
+    do {
+        itr->second->setSeedToPolygon(center, normal, angle, radius, numSides);
+    } while (doAll && ++itr != _streamlines.end());
+
+    sceneBoundsChanged();
+    _needsRedraw = true;
+}
+
+/**
+ * \brief Set the streamlines seed to vertices of an n-sided polygon
+ */
+void Renderer::setStreamlinesSeedToFilledPolygon(const DataSetId& id,
+                                                 double center[3],
+                                                 double normal[3],
+                                                 double angle, double radius,
+                                                 int numSides, int numPoints)
+{
+    StreamlinesHashmap::iterator itr;
+
+    bool doAll = false;
+
+    if (id.compare("all") == 0) {
+        itr = _streamlines.begin();
+        if (itr == _streamlines.end())
+            return;
+        doAll = true;
+    } else {
+        itr = _streamlines.find(id);
+    }
+    if (itr == _streamlines.end()) {
+        ERROR("Streamlines not found: %s", id.c_str());
+        return;
+    }
+
+    do {
+        itr->second->setSeedToFilledPolygon(center, normal, angle,
+                                            radius, numSides, numPoints);
+    } while (doAll && ++itr != _streamlines.end());
+
+    sceneBoundsChanged();
+    _needsRedraw = true;
+}
+
+/**
+ * \brief Set Streamlines rendering to polylines for the specified DataSet
+ */
+void Renderer::setStreamlinesTypeToLines(const DataSetId& id)
+{
+    StreamlinesHashmap::iterator itr;
+
+    bool doAll = false;
+
+    if (id.compare("all") == 0) {
+        itr = _streamlines.begin();
+        if (itr == _streamlines.end())
+            return;
+        doAll = true;
+    } else {
+        itr = _streamlines.find(id);
+    }
+    if (itr == _streamlines.end()) {
+        ERROR("Streamlines not found: %s", id.c_str());
+        return;
+    }
+
+    do {
+        itr->second->setLineTypeToLines();
+    } while (doAll && ++itr != _streamlines.end());
+
+    sceneBoundsChanged();
+    _needsRedraw = true;
+}
+
+/**
+ * \brief Set Streamlines rendering to tubes for the specified DataSet
+ */
+void Renderer::setStreamlinesTypeToTubes(const DataSetId& id, int numSides, double radius)
+{
+    StreamlinesHashmap::iterator itr;
+
+    bool doAll = false;
+
+    if (id.compare("all") == 0) {
+        itr = _streamlines.begin();
+        if (itr == _streamlines.end())
+            return;
+        doAll = true;
+    } else {
+        itr = _streamlines.find(id);
+    }
+    if (itr == _streamlines.end()) {
+        ERROR("Streamlines not found: %s", id.c_str());
+        return;
+    }
+
+    do {
+        itr->second->setLineTypeToTubes(numSides, radius);
+    } while (doAll && ++itr != _streamlines.end());
+
+    sceneBoundsChanged();
+    _needsRedraw = true;
+}
+
+/**
+ * \brief Set Streamlines rendering to ribbons for the specified DataSet
+ */
+void Renderer::setStreamlinesTypeToRibbons(const DataSetId& id, double width, double angle)
+{
+    StreamlinesHashmap::iterator itr;
+
+    bool doAll = false;
+
+    if (id.compare("all") == 0) {
+        itr = _streamlines.begin();
+        if (itr == _streamlines.end())
+            return;
+        doAll = true;
+    } else {
+        itr = _streamlines.find(id);
+    }
+    if (itr == _streamlines.end()) {
+        ERROR("Streamlines not found: %s", id.c_str());
+        return;
+    }
+
+    do {
+        itr->second->setLineTypeToRibbons(width, angle);
+    } while (doAll && ++itr != _streamlines.end());
+
+    sceneBoundsChanged();
+    _needsRedraw = true;
+}
+
+/**
+ * \brief Set Streamlines maximum length for the specified DataSet
+ */
+void Renderer::setStreamlinesLength(const DataSetId& id, double length)
+{
+    StreamlinesHashmap::iterator itr;
+
+    bool doAll = false;
+
+    if (id.compare("all") == 0) {
+        itr = _streamlines.begin();
+        if (itr == _streamlines.end())
+            return;
+        doAll = true;
+    } else {
+        itr = _streamlines.find(id);
+    }
+    if (itr == _streamlines.end()) {
+        ERROR("Streamlines not found: %s", id.c_str());
+        return;
+    }
+
+    do {
+        itr->second->setMaxPropagation(length);
+    } while (doAll && ++itr != _streamlines.end());
+
+    sceneBoundsChanged();
+    _needsRedraw = true;
+}
+
+/**
+ * \brief Turn on/off rendering of the Streamlines seed geometry for the given DataSet
+ */
+void Renderer::setStreamlinesSeedVisibility(const DataSetId& id, bool state)
+{
+    StreamlinesHashmap::iterator itr;
+
+    bool doAll = false;
+
+    if (id.compare("all") == 0) {
+        itr = _streamlines.begin();
+        if (itr == _streamlines.end())
+            return;
+        doAll = true;
+    } else {
+        itr = _streamlines.find(id);
+    }
+    if (itr == _streamlines.end()) {
+        ERROR("Streamlines not found: %s", id.c_str());
+        return;
+    }
+
+    do {
+        itr->second->setSeedVisibility(state);
+    } while (doAll && ++itr != _streamlines.end());
+
+    sceneBoundsChanged();
+    _needsRedraw = true;
+}
+
+/**
+ * \brief Set the color mode for the specified DataSet
+ */
+void Renderer::setStreamlinesColorMode(const DataSetId& id,
+                                       Streamlines::ColorMode mode,
+                                       DataSet::DataAttributeType type,
+                                       const char *name, double range[2])
+{
+    StreamlinesHashmap::iterator itr;
+
+    bool doAll = false;
+
+    if (id.compare("all") == 0) {
+        itr = _streamlines.begin();
+        if (itr == _streamlines.end())
+            return;
+        doAll = true;
+    } else {
+        itr = _streamlines.find(id);
+    }
+    if (itr == _streamlines.end()) {
+        ERROR("Streamlines not found: %s", id.c_str());
+        return;
+    }
+
+    do {
+        itr->second->setColorMode(mode, type, name, range);
+    } while (doAll && ++itr != _streamlines.end());
+
+    _needsRedraw = true;
+}
+
+/**
+ * \brief Set the color mode for the specified DataSet
+ */
+void Renderer::setStreamlinesColorMode(const DataSetId& id,
+                                       Streamlines::ColorMode mode,
+                                       const char *name, double range[2])
+{
+    StreamlinesHashmap::iterator itr;
+
+    bool doAll = false;
+
+    if (id.compare("all") == 0) {
+        itr = _streamlines.begin();
+        if (itr == _streamlines.end())
+            return;
+        doAll = true;
+    } else {
+        itr = _streamlines.find(id);
+    }
+    if (itr == _streamlines.end()) {
+        ERROR("Streamlines not found: %s", id.c_str());
+        return;
+    }
+
+    do {
+        itr->second->setColorMode(mode, name, range);
+    } while (doAll && ++itr != _streamlines.end());
+
+    _needsRedraw = true;
+}
+
+/**
+ * \brief Set the RGB line/edge color for the specified DataSet
+ */
+void Renderer::setStreamlinesSeedColor(const DataSetId& id, float color[3])
+{
+    StreamlinesHashmap::iterator itr;
+
+    bool doAll = false;
+
+    if (id.compare("all") == 0) {
+        itr = _streamlines.begin();
+        if (itr == _streamlines.end())
+            return;
+        doAll = true;
+    } else {
+        itr = _streamlines.find(id);
+    }
+    if (itr == _streamlines.end()) {
+        ERROR("Streamlines not found: %s", id.c_str());
+        return;
+    }
+
+    do {
+        itr->second->setSeedColor(color);
+    } while (doAll && ++itr != _streamlines.end());
+
+    _needsRedraw = true;
+}
+
+/**
+ * \brief Set the sample rate for the volume shader
+ *
+ * Smaller values will give better rendering at the cost
+ * of slower rendering
+ */
+void Renderer::setVolumeSampleDistance(const DataSetId& id, double distance)
+{
+    VolumeHashmap::iterator itr;
+
+    bool doAll = false;
+
+    if (id.compare("all") == 0) {
+        itr = _volumes.begin();
+        if (itr == _volumes.end())
+            return;
+        doAll = true;
+    } else {
+        itr = _volumes.find(id);
+    }
+    if (itr == _volumes.end()) {
+        ERROR("Volume not found: %s", id.c_str());
+        return;
+    }
+
+    do {
+        distance *= itr->second->getAverageSpacing();
+        itr->second->setSampleDistance((float)distance);
+    } while (doAll && ++itr != _volumes.end());
+
+    _needsRedraw = true;
+}
+
+/**
+ * \brief Set the color mode for the specified DataSet
+ */
+void Renderer::setWarpColorMode(const DataSetId& id,
+                                Warp::ColorMode mode,
+                                DataSet::DataAttributeType type,
+                                const char *name, double range[2])
+{
+    WarpHashmap::iterator itr;
+
+    bool doAll = false;
+
+    if (id.compare("all") == 0) {
+        itr = _warps.begin();
+        if (itr == _warps.end())
+            return;
+        doAll = true;
+    } else {
+        itr = _warps.find(id);
+    }
+    if (itr == _warps.end()) {
+        ERROR("Warp not found: %s", id.c_str());
+        return;
+    }
+
+    do {
+        itr->second->setColorMode(mode, type, name, range);
+    } while (doAll && ++itr != _warps.end());
+
+    _needsRedraw = true;
+}
+
+/**
+ * \brief Set the color mode for the specified DataSet
+ */
+void Renderer::setWarpColorMode(const DataSetId& id,
+                                Warp::ColorMode mode,
+                                const char *name, double range[2])
+{
+    WarpHashmap::iterator itr;
+
+    bool doAll = false;
+
+    if (id.compare("all") == 0) {
+        itr = _warps.begin();
+        if (itr == _warps.end())
+            return;
+        doAll = true;
+    } else {
+        itr = _warps.find(id);
+    }
+    if (itr == _warps.end()) {
+        ERROR("Warp not found: %s", id.c_str());
+        return;
+    }
+
+    do {
+        itr->second->setColorMode(mode, name, range);
+    } while (doAll && ++itr != _warps.end());
+
+    _needsRedraw = true;
+}
+
+/**
+ * \brief Set amount to scale vector magnitudes when warping
+ * a mesh
+ */
+void Renderer::setWarpWarpScale(const DataSetId& id, double scale)
+{
+    WarpHashmap::iterator itr;
+
+    bool doAll = false;
+
+    if (id.compare("all") == 0) {
+        itr = _warps.begin();
+        if (itr == _warps.end())
+            return;
+        doAll = true;
+    } else {
+        itr = _warps.find(id);
+    }
+
+    if (itr == _warps.end()) {
+        ERROR("Warp not found: %s", id.c_str());
+        return;
+    }
+
+    do {
+        itr->second->setWarpScale(scale);
+     } while (doAll && ++itr != _warps.end());
+
+    sceneBoundsChanged();
+    _needsRedraw = true;
+}
Index: /trunk/packages/vizservers/vtkvis/VtkRendererGraphicsObjs.h
===================================================================
--- /trunk/packages/vizservers/vtkvis/VtkRendererGraphicsObjs.h	(revision 3616)
+++ /trunk/packages/vizservers/vtkvis/VtkRendererGraphicsObjs.h	(revision 3616)
@@ -0,0 +1,1027 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (C) 2004-2012  HUBzero Foundation, LLC
+ *
+ * Author: Leif Delgass <ldelgass@purdue.edu>
+ */
+
+#ifndef VTKVIS_RENDERER_GRAPHICS_OBJS_H
+#define VTKVIS_RENDERER_GRAPHICS_OBJS_H
+
+#include <tr1/unordered_map>
+#include <typeinfo>
+
+// Use GCC/G++ specific name demangling
+#define DEMANGLE
+
+#ifdef DEMANGLE
+#include <cstdlib>
+#include <cxxabi.h>
+#define GO_TRACE(go, format, ...)                                            \
+do {                                                                         \
+    int status;                                                              \
+    char * typeName = abi::__cxa_demangle(typeid(go).name(), 0, 0, &status); \
+    TRACE("%s " format, typeName, __VA_ARGS__);                              \
+    free(typeName);                                                          \
+} while (0)
+
+#define GO_ERROR(go, format, ...)                                            \
+do {                                                                         \
+    int status;                                                              \
+    char * typeName = abi::__cxa_demangle(typeid(go).name(), 0, 0, &status); \
+    ERROR("%s " format, typeName, __VA_ARGS__);                              \
+    free(typeName);                                                          \
+} while (0)
+#else
+#define GO_TRACE(go, format, ...) TRACE("%s " format, typeid(go).name(), __VA_ARGS__);
+#define GO_ERROR(go, format, ...) ERROR("%s " format, typeid(go).name(), __VA_ARGS__);
+#endif
+
+#include "VtkRenderer.h"
+
+namespace VtkVis {
+
+/**
+ * \brief Look up graphics object by name
+ */
+template<class GraphicsObject>
+GraphicsObject *Renderer::getGraphicsObject(const DataSetId& id)
+{
+    std::tr1::unordered_map<DataSetId, GraphicsObject *>& hashmap =
+        getGraphicsObjectHashmap<GraphicsObject>();
+    typename std::tr1::unordered_map<DataSetId, GraphicsObject *>::iterator
+        itr = hashmap.find(id);
+
+    if (itr == hashmap.end()) {
+#ifdef DEBUG
+        GO_TRACE(GraphicsObject, "not found: %s", id.c_str());
+#endif
+        return NULL;
+    } else
+        return itr->second;
+}
+
+/**
+ * \brief Delete graphics object by name
+ */
+template<class GraphicsObject>
+void Renderer::deleteGraphicsObject(const DataSetId& id)
+{
+    std::tr1::unordered_map<DataSetId, GraphicsObject *>& hashmap =
+        getGraphicsObjectHashmap<GraphicsObject>();
+    typename std::tr1::unordered_map<DataSetId, GraphicsObject *>::iterator itr;
+
+    bool doAll = false;
+
+    if (id.compare("all") == 0) {
+        itr = hashmap.begin();
+        doAll = true;
+    } else {
+        itr = hashmap.find(id);
+    }
+    if (itr == hashmap.end()) {
+        GO_ERROR(GraphicsObject, "not found: %s", id.c_str());
+        return;
+    }
+
+    TRACE("Deleting %s for %s", itr->second->getClassName(), id.c_str());
+
+    do {
+        GraphicsObject *gobj = itr->second;
+        if (gobj->getProp())
+            _renderer->RemoveViewProp(gobj->getProp());
+        if (gobj->getOverlayProp())
+            _renderer->RemoveViewProp(gobj->getOverlayProp());
+        delete gobj;
+
+        itr = hashmap.erase(itr);
+    } while (doAll && itr != hashmap.end());
+
+    sceneBoundsChanged();
+    _needsRedraw = true;
+}
+
+/**
+ * \brief Delete all graphics objects from renderer
+ */
+template<class GraphicsObject>
+void Renderer::deleteAllGraphicsObjects()
+{
+    std::tr1::unordered_map<DataSetId, GraphicsObject *>& hashmap =
+        getGraphicsObjectHashmap<GraphicsObject>();
+    typename std::tr1::unordered_map<DataSetId, GraphicsObject *>::iterator itr;
+
+    itr = hashmap.begin();
+    if (itr == hashmap.end())
+        return;
+
+    TRACE("Deleting all %s objects", itr->second->getClassName());
+
+    for (; itr != hashmap.end(); ++itr) {
+        delete itr->second;
+    }
+    hashmap.clear();
+}
+
+/**
+ * \brief Add a graphics objects to the renderer's scene
+ */
+template<class GraphicsObject>
+bool Renderer::addGraphicsObject(const DataSetId& id)
+{
+    DataSetHashmap::iterator itr;
+
+    bool doAll = false;
+
+    if (id.compare("all") == 0) {
+        itr = _dataSets.begin();
+    } else {
+        itr = _dataSets.find(id);
+    }
+    if (itr == _dataSets.end()) {
+        ERROR("Unknown dataset %s", id.c_str());
+        return false;
+    }
+
+    do {
+        DataSet *ds = itr->second;
+        const DataSetId& dsID = ds->getName();
+
+        GraphicsObject *gobj;
+        if ((gobj = getGraphicsObject<GraphicsObject>(dsID)) != NULL) {
+            WARN("Replacing existing %s %s", gobj->getClassName(), dsID.c_str());
+            deleteGraphicsObject<GraphicsObject>(dsID);
+        }
+
+        gobj = new GraphicsObject();
+ 
+        gobj->setDataSet(ds, this);
+
+        if (gobj->getProp() == NULL &&
+            gobj->getOverlayProp() == NULL) {
+            delete gobj;
+            return false;
+        } else {
+            if (gobj->getProp())
+                _renderer->AddViewProp(gobj->getProp());
+            if (gobj->getOverlayProp())
+                _renderer->AddViewProp(gobj->getOverlayProp());
+        }
+
+        getGraphicsObjectHashmap<GraphicsObject>()[dsID] = gobj;
+    } while (doAll && ++itr != _dataSets.end());
+
+    sceneBoundsChanged();
+    _needsRedraw = true;
+    return true;
+}
+
+/**
+ * \brief Set the prop orientation with a quaternion
+ */
+template<class GraphicsObject>
+void Renderer::setGraphicsObjectTransform(const DataSetId& id, vtkMatrix4x4 *trans)
+{
+    std::tr1::unordered_map<DataSetId, GraphicsObject *>& hashmap = 
+        getGraphicsObjectHashmap<GraphicsObject>();
+    typename std::tr1::unordered_map<DataSetId, GraphicsObject *>::iterator itr;
+
+    bool doAll = false;
+
+    if (id.compare("all") == 0) {
+        itr = hashmap.begin();
+        if (itr == hashmap.end())
+            return;
+        doAll = true;
+    } else {
+        itr = hashmap.find(id);
+    }
+    if (itr == hashmap.end()) {
+        GO_ERROR(GraphicsObject, "not found: %s", id.c_str());
+        return;
+    }
+
+    do {
+        itr->second->setTransform(trans);
+    } while (doAll && ++itr != hashmap.end());
+
+    sceneBoundsChanged();
+    _needsRedraw = true;
+}
+
+/**
+ * \brief Set the prop orientation with a quaternion
+ */
+template<class GraphicsObject>
+void Renderer::setGraphicsObjectOrientation(const DataSetId& id, double quat[4])
+{
+    std::tr1::unordered_map<DataSetId, GraphicsObject *>& hashmap = 
+        getGraphicsObjectHashmap<GraphicsObject>();
+    typename std::tr1::unordered_map<DataSetId, GraphicsObject *>::iterator itr;
+
+    bool doAll = false;
+
+    if (id.compare("all") == 0) {
+        itr = hashmap.begin();
+        if (itr == hashmap.end())
+            return;
+        doAll = true;
+    } else {
+        itr = hashmap.find(id);
+    }
+    if (itr == hashmap.end()) {
+        GO_ERROR(GraphicsObject, "not found: %s", id.c_str());
+        return;
+    }
+
+    do {
+        itr->second->setOrientation(quat);
+    } while (doAll && ++itr != hashmap.end());
+
+    sceneBoundsChanged();
+    _needsRedraw = true;
+}
+
+/**
+ * \brief Set the prop orientation with a rotation about an axis
+ */
+template<class GraphicsObject>
+void Renderer::setGraphicsObjectOrientation(const DataSetId& id, double angle, double axis[3])
+{
+    std::tr1::unordered_map<DataSetId, GraphicsObject *>& hashmap = 
+        getGraphicsObjectHashmap<GraphicsObject>();
+    typename std::tr1::unordered_map<DataSetId, GraphicsObject *>::iterator itr;
+
+    bool doAll = false;
+
+    if (id.compare("all") == 0) {
+        itr = hashmap.begin();
+        if (itr == hashmap.end())
+            return;
+        doAll = true;
+    } else {
+        itr = hashmap.find(id);
+    }
+    if (itr == hashmap.end()) {
+        GO_ERROR(GraphicsObject, "not found: %s", id.c_str());
+        return;
+    }
+
+    do {
+        itr->second->setOrientation(angle, axis);
+    } while (doAll && ++itr != hashmap.end());
+
+    sceneBoundsChanged();
+    _needsRedraw = true;
+}
+
+/**
+ * \brief Set the prop position in world coords
+ */
+template<class GraphicsObject>
+void Renderer::setGraphicsObjectPosition(const DataSetId& id, double pos[3])
+{
+    std::tr1::unordered_map<DataSetId, GraphicsObject *>& hashmap = 
+        getGraphicsObjectHashmap<GraphicsObject>();
+    typename std::tr1::unordered_map<DataSetId, GraphicsObject *>::iterator itr;
+
+    bool doAll = false;
+
+    if (id.compare("all") == 0) {
+        itr = hashmap.begin();
+        if (itr == hashmap.end())
+            return;
+        doAll = true;
+    } else {
+        itr = hashmap.find(id);
+    }
+    if (itr == hashmap.end()) {
+        GO_ERROR(GraphicsObject, "not found: %s", id.c_str());
+        return;
+    }
+
+    do {
+        itr->second->setPosition(pos);
+    } while (doAll && ++itr != hashmap.end());
+
+    sceneBoundsChanged();
+    _needsRedraw = true;
+}
+
+/**
+ * \brief Set the prop scaling based on a 2D aspect ratio
+ *
+ * \param id The name of the DataSet
+ * \param aspect The aspect ratio (width/height), zero means native aspect
+ */
+template<class GraphicsObject>
+void Renderer::setGraphicsObjectAspect(const DataSetId& id, double aspect)
+{
+    std::tr1::unordered_map<DataSetId, GraphicsObject *>& hashmap = 
+        getGraphicsObjectHashmap<GraphicsObject>();
+    typename std::tr1::unordered_map<DataSetId, GraphicsObject *>::iterator itr;
+
+    bool doAll = false;
+
+    if (id.compare("all") == 0) {
+        itr = hashmap.begin();
+        if (itr == hashmap.end())
+            return;
+        doAll = true;
+    } else {
+        itr = hashmap.find(id);
+    }
+    if (itr == hashmap.end()) {
+        GO_ERROR(GraphicsObject, "not found: %s", id.c_str());
+        return;
+    }
+
+    do {
+        itr->second->setAspect(aspect);
+    } while (doAll && ++itr != hashmap.end());
+
+    sceneBoundsChanged();
+    _needsRedraw = true;
+}
+
+/**
+ * \brief Set the prop scaling
+ */
+template<class GraphicsObject>
+void Renderer::setGraphicsObjectScale(const DataSetId& id, double scale[3])
+{
+    std::tr1::unordered_map<DataSetId, GraphicsObject *>& hashmap = 
+        getGraphicsObjectHashmap<GraphicsObject>();
+    typename std::tr1::unordered_map<DataSetId, GraphicsObject *>::iterator itr;
+
+    bool doAll = false;
+
+    if (id.compare("all") == 0) {
+        itr = hashmap.begin();
+        if (itr == hashmap.end())
+            return;
+        doAll = true;
+    } else {
+        itr = hashmap.find(id);
+    }
+    if (itr == hashmap.end()) {
+        GO_ERROR(GraphicsObject, "not found: %s", id.c_str());
+        return;
+    }
+
+    do {
+        itr->second->setScale(scale);
+    } while (doAll && ++itr != hashmap.end());
+
+    sceneBoundsChanged();
+    _needsRedraw = true;
+}
+
+/**
+ * \brief Set visibility of VtkGraphicsObject for the given DataSet
+ */
+template<class GraphicsObject>
+void Renderer::setGraphicsObjectVisibility(const DataSetId& id, bool state)
+{
+    std::tr1::unordered_map<DataSetId, GraphicsObject *>& hashmap =
+        getGraphicsObjectHashmap<GraphicsObject>();
+    typename std::tr1::unordered_map<DataSetId, GraphicsObject *>::iterator itr;
+
+    bool doAll = false;
+
+    if (id.compare("all") == 0) {
+        itr = hashmap.begin();
+        if (itr == hashmap.end())
+            return;
+        doAll = true;
+    } else {
+        itr = hashmap.find(id);
+    }
+    if (itr == hashmap.end()) {
+        GO_ERROR(GraphicsObject, "not found: %s", id.c_str());
+        return;
+    }
+
+    do {
+        itr->second->setVisibility(state);
+    } while (doAll && ++itr != hashmap.end());
+
+    sceneBoundsChanged();
+    _needsRedraw = true;
+}
+
+/**
+ * \brief Set the volume slice
+ */
+template<class GraphicsObject>
+void Renderer::setGraphicsObjectVolumeSlice(const DataSetId& id, Axis axis, double ratio)
+{
+    std::tr1::unordered_map<DataSetId, GraphicsObject *>& hashmap = 
+        getGraphicsObjectHashmap<GraphicsObject>();
+    typename std::tr1::unordered_map<DataSetId, GraphicsObject *>::iterator itr;
+
+    bool doAll = false;
+
+    if (id.compare("all") == 0) {
+        itr = hashmap.begin();
+        if (itr == hashmap.end())
+            return;
+        doAll = true;
+    } else {
+        itr = hashmap.find(id);
+    }
+
+    if (itr == hashmap.end()) {
+        GO_ERROR(GraphicsObject, "not found: %s", id.c_str());
+        return;
+    }
+
+    do {
+        itr->second->selectVolumeSlice(axis, ratio);
+     } while (doAll && ++itr != hashmap.end());
+
+    sceneBoundsChanged();
+    _needsRedraw = true;
+}
+
+
+/**
+ * \brief Set the RGB actor color for the specified DataSet
+ */
+template<class GraphicsObject>
+void Renderer::setGraphicsObjectColor(const DataSetId& id, float color[3])
+{
+    std::tr1::unordered_map<DataSetId, GraphicsObject *>& hashmap = 
+        getGraphicsObjectHashmap<GraphicsObject>();
+    typename std::tr1::unordered_map<DataSetId, GraphicsObject *>::iterator itr;
+
+    bool doAll = false;
+
+    if (id.compare("all") == 0) {
+        itr = hashmap.begin();
+        if (itr == hashmap.end())
+            return;
+        doAll = true;
+    } else {
+        itr = hashmap.find(id);
+    }
+    if (itr == hashmap.end()) {
+        GO_ERROR(GraphicsObject, "not found: %s", id.c_str());
+        return;
+    }
+
+    do {
+        itr->second->setColor(color);
+    } while (doAll && ++itr != hashmap.end());
+
+    _needsRedraw = true;
+}
+
+/**
+ * \brief Turn on/off edges for the given DataSet
+ */
+template<class GraphicsObject>
+void Renderer::setGraphicsObjectEdgeVisibility(const DataSetId& id, bool state)
+{
+    std::tr1::unordered_map<DataSetId, GraphicsObject *>& hashmap = 
+        getGraphicsObjectHashmap<GraphicsObject>();
+    typename std::tr1::unordered_map<DataSetId, GraphicsObject *>::iterator itr;
+
+    bool doAll = false;
+
+    if (id.compare("all") == 0) {
+        itr = hashmap.begin();
+        if (itr == hashmap.end())
+            return;
+        doAll = true;
+    } else {
+        itr = hashmap.find(id);
+    }
+    if (itr == hashmap.end()) {
+        GO_ERROR(GraphicsObject, "not found: %s", id.c_str());
+        return;
+    }
+
+    do {
+        itr->second->setEdgeVisibility(state);
+    } while (doAll && ++itr != hashmap.end());
+
+    sceneBoundsChanged();
+    _needsRedraw = true;
+}
+
+/**
+ * \brief Set the RGB isosurface edge color for the specified DataSet
+ */
+template<class GraphicsObject>
+void Renderer::setGraphicsObjectEdgeColor(const DataSetId& id, float color[3])
+{
+    std::tr1::unordered_map<DataSetId, GraphicsObject *>& hashmap = 
+        getGraphicsObjectHashmap<GraphicsObject>();
+    typename std::tr1::unordered_map<DataSetId, GraphicsObject *>::iterator itr;
+
+    bool doAll = false;
+
+    if (id.compare("all") == 0) {
+        itr = hashmap.begin();
+        if (itr == hashmap.end())
+            return;
+        doAll = true;
+    } else {
+        itr = hashmap.find(id);
+    }
+    if (itr == hashmap.end()) {
+        GO_ERROR(GraphicsObject, "not found: %s", id.c_str());
+        return;
+    }
+
+    do {
+        itr->second->setEdgeColor(color);
+    } while (doAll && ++itr != hashmap.end());
+
+    _needsRedraw = true;
+}
+
+/**
+ * \brief Set the isosurface edge width for the specified DataSet (may be a no-op)
+ *
+ * If the OpenGL implementation/hardware does not support wide lines, 
+ * this function may not have an effect.
+ */
+template<class GraphicsObject>
+void Renderer::setGraphicsObjectEdgeWidth(const DataSetId& id, float edgeWidth)
+{
+    std::tr1::unordered_map<DataSetId, GraphicsObject *>& hashmap = 
+        getGraphicsObjectHashmap<GraphicsObject>();
+    typename std::tr1::unordered_map<DataSetId, GraphicsObject *>::iterator itr;
+
+    bool doAll = false;
+
+    if (id.compare("all") == 0) {
+        itr = hashmap.begin();
+        if (itr == hashmap.end())
+            return;
+        doAll = true;
+    } else {
+        itr = hashmap.find(id);
+    }
+    if (itr == hashmap.end()) {
+        GO_ERROR(GraphicsObject, "not found: %s", id.c_str());
+        return;
+    }
+
+    do {
+        itr->second->setEdgeWidth(edgeWidth);
+    } while (doAll && ++itr != hashmap.end());
+
+    sceneBoundsChanged();
+    _needsRedraw = true;
+}
+
+/**
+ * \brief Set ambient lighting/shading coefficient for the specified DataSet
+ */
+template<class GraphicsObject>
+void Renderer::setGraphicsObjectAmbient(const DataSetId& id, double coeff)
+{
+    std::tr1::unordered_map<DataSetId, GraphicsObject *>& hashmap = 
+        getGraphicsObjectHashmap<GraphicsObject>();
+    typename std::tr1::unordered_map<DataSetId, GraphicsObject *>::iterator itr;
+
+    bool doAll = false;
+
+    if (id.compare("all") == 0) {
+        itr = hashmap.begin();
+        if (itr == hashmap.end())
+            return;
+        doAll = true;
+    } else {
+        itr = hashmap.find(id);
+    }
+    if (itr == hashmap.end()) {
+        GO_ERROR(GraphicsObject, "not found: %s", id.c_str());
+        return;
+    }
+
+    do {
+        itr->second->setAmbient(coeff);
+    } while (doAll && ++itr != hashmap.end());
+
+    _needsRedraw = true;
+}
+
+/**
+ * \brief Set diffuse lighting/shading coefficient for the specified DataSet
+ */
+template<class GraphicsObject>
+void Renderer::setGraphicsObjectDiffuse(const DataSetId& id, double coeff)
+{
+    std::tr1::unordered_map<DataSetId, GraphicsObject *>& hashmap = 
+        getGraphicsObjectHashmap<GraphicsObject>();
+    typename std::tr1::unordered_map<DataSetId, GraphicsObject *>::iterator itr;
+
+    bool doAll = false;
+
+    if (id.compare("all") == 0) {
+        itr = hashmap.begin();
+        if (itr == hashmap.end())
+            return;
+        doAll = true;
+    } else {
+        itr = hashmap.find(id);
+    }
+    if (itr == hashmap.end()) {
+        GO_ERROR(GraphicsObject, "not found: %s", id.c_str());
+        return;
+    }
+
+    do {
+        itr->second->setDiffuse(coeff);
+    } while (doAll && ++itr != hashmap.end());
+
+    _needsRedraw = true;
+}
+
+/**
+ * \brief Set specular lighting/shading coefficient and power for the specified DataSet
+ */
+template<class GraphicsObject>
+void Renderer::setGraphicsObjectSpecular(const DataSetId& id, double coeff, double power)
+{
+    std::tr1::unordered_map<DataSetId, GraphicsObject *>& hashmap = 
+        getGraphicsObjectHashmap<GraphicsObject>();
+    typename std::tr1::unordered_map<DataSetId, GraphicsObject *>::iterator itr;
+
+    bool doAll = false;
+
+    if (id.compare("all") == 0) {
+        itr = hashmap.begin();
+        if (itr == hashmap.end())
+            return;
+        doAll = true;
+    } else {
+        itr = hashmap.find(id);
+    }
+    if (itr == hashmap.end()) {
+        GO_ERROR(GraphicsObject, "not found: %s", id.c_str());
+        return;
+    }
+
+    do {
+        itr->second->setSpecular(coeff, power);
+    } while (doAll && ++itr != hashmap.end());
+
+    _needsRedraw = true;
+}
+
+/**
+ * \brief Turn actor lighting on/off for the specified DataSet
+ */
+template<class GraphicsObject>
+void Renderer::setGraphicsObjectLighting(const DataSetId& id, bool state)
+{
+    std::tr1::unordered_map<DataSetId, GraphicsObject *>& hashmap = 
+        getGraphicsObjectHashmap<GraphicsObject>();
+    typename std::tr1::unordered_map<DataSetId, GraphicsObject *>::iterator itr;
+
+    bool doAll = false;
+
+    if (id.compare("all") == 0) {
+        itr = hashmap.begin();
+        if (itr == hashmap.end())
+            return;
+        doAll = true;
+    } else {
+        itr = hashmap.find(id);
+    }
+    if (itr == hashmap.end()) {
+        GO_ERROR(GraphicsObject, "not found: %s", id.c_str());
+        return;
+    }
+
+    do {
+        itr->second->setLighting(state);
+    } while (doAll && ++itr != hashmap.end());
+
+    _needsRedraw = true;
+}
+
+/**
+ * \brief Set opacity of VtkGraphicsObject for the given DataSet
+ */
+template<class GraphicsObject>
+void Renderer::setGraphicsObjectOpacity(const DataSetId& id, double opacity)
+{
+    std::tr1::unordered_map<DataSetId, GraphicsObject *>& hashmap = 
+        getGraphicsObjectHashmap<GraphicsObject>();
+    typename std::tr1::unordered_map<DataSetId, GraphicsObject *>::iterator itr;
+
+    bool doAll = false;
+
+    if (id.compare("all") == 0) {
+        itr = hashmap.begin();
+        if (itr == hashmap.end())
+            return;
+        doAll = true;
+    } else {
+        itr = hashmap.find(id);
+    }
+    if (itr == hashmap.end()) {
+        GO_ERROR(GraphicsObject, "not found: %s", id.c_str());
+        return;
+    }
+
+    do {
+        itr->second->setOpacity(opacity);
+    } while (doAll && ++itr != hashmap.end());
+
+    _needsRedraw = true;
+}
+
+/**
+ * \brief Set the point size for the specified DataSet (may be a no-op)
+ *
+ * If the OpenGL implementation/hardware does not support wide points, 
+ * this function may not have an effect.
+ */
+template<class GraphicsObject>
+void Renderer::setGraphicsObjectPointSize(const DataSetId& id, float size)
+{
+    std::tr1::unordered_map<DataSetId, GraphicsObject *>& hashmap = 
+        getGraphicsObjectHashmap<GraphicsObject>();
+    typename std::tr1::unordered_map<DataSetId, GraphicsObject *>::iterator itr;
+
+    bool doAll = false;
+
+    if (id.compare("all") == 0) {
+        itr = hashmap.begin();
+        if (itr == hashmap.end())
+            return;
+        doAll = true;
+    } else {
+        itr = hashmap.find(id);
+    }
+    if (itr == hashmap.end()) {
+        GO_ERROR(GraphicsObject, "not found: %s", id.c_str());
+        return;
+    }
+
+    do {
+        itr->second->setPointSize(size);
+    } while (doAll && ++itr != hashmap.end());
+
+    sceneBoundsChanged();
+    _needsRedraw = true;
+}
+
+/**
+ * \brief Set wireframe actor rendering for the specified DataSet
+ */
+template<class GraphicsObject>
+void Renderer::setGraphicsObjectWireframe(const DataSetId& id, bool state)
+{
+    std::tr1::unordered_map<DataSetId, GraphicsObject *>& hashmap = 
+        getGraphicsObjectHashmap<GraphicsObject>();
+    typename std::tr1::unordered_map<DataSetId, GraphicsObject *>::iterator itr;
+
+    bool doAll = false;
+
+    if (id.compare("all") == 0) {
+        itr = hashmap.begin();
+        if (itr == hashmap.end())
+            return;
+        doAll = true;
+    } else {
+        itr = hashmap.find(id);
+    }
+    if (itr == hashmap.end()) {
+        GO_ERROR(GraphicsObject, "not found: %s", id.c_str());
+        return;
+    }
+
+    do {
+        itr->second->setWireframe(state);
+    } while (doAll && ++itr != hashmap.end());
+
+    _needsRedraw = true;
+}
+
+/**
+ * \brief Associate an existing named color map with a graphics object for the given DataSet
+ */
+template<class GraphicsObject>
+void Renderer::setGraphicsObjectInterpolateBeforeMapping(const DataSetId& id, bool state)
+{
+    std::tr1::unordered_map<DataSetId, GraphicsObject *>& hashmap = 
+        getGraphicsObjectHashmap<GraphicsObject>();
+    typename std::tr1::unordered_map<DataSetId, GraphicsObject *>::iterator itr;
+
+    bool doAll = false;
+
+    if (id.compare("all") == 0) {
+        itr = hashmap.begin();
+        if (itr == hashmap.end())
+            return;
+        doAll = true;
+    } else {
+        itr = hashmap.find(id);
+    }
+
+    if (itr == hashmap.end()) {
+        GO_ERROR(GraphicsObject, "not found: %s", id.c_str());
+        return;
+    }
+
+    do {
+        itr->second->setInterpolateBeforeMapping(state);
+    } while (doAll && ++itr != hashmap.end());
+
+    _needsRedraw = true;
+}
+
+/**
+ * \brief Associate an existing named color map with a graphics object for the given DataSet
+ */
+template<class GraphicsObject>
+void Renderer::setGraphicsObjectColorMap(const DataSetId& id, const ColorMapId& colorMapId)
+{
+    std::tr1::unordered_map<DataSetId, GraphicsObject *>& hashmap = 
+        getGraphicsObjectHashmap<GraphicsObject>();
+    typename std::tr1::unordered_map<DataSetId, GraphicsObject *>::iterator itr;
+
+    bool doAll = false;
+
+    if (id.compare("all") == 0) {
+        itr = hashmap.begin();
+        if (itr == hashmap.end())
+            return;
+        doAll = true;
+    } else {
+        itr = hashmap.find(id);
+    }
+
+    if (itr == hashmap.end()) {
+        GO_ERROR(GraphicsObject, "not found: %s", id.c_str());
+        return;
+    }
+
+    ColorMap *cmap = getColorMap(colorMapId);
+    if (cmap == NULL) {
+        ERROR("Unknown colormap: %s", colorMapId.c_str());
+        return;
+    }
+
+    do {
+        GO_TRACE(GraphicsObject, "Set color map: %s for dataset %s",
+                 colorMapId.c_str(),
+                 itr->second->getDataSet()->getName().c_str());
+
+        itr->second->setColorMap(cmap);
+    } while (doAll && ++itr != hashmap.end());
+
+    _needsRedraw = true;
+}
+
+/**
+ * \brief Notify graphics object that color map has changed
+ */
+template<class GraphicsObject>
+void Renderer::updateGraphicsObjectColorMap(ColorMap *cmap)
+{
+    std::tr1::unordered_map<DataSetId, GraphicsObject *>& hashmap = 
+        getGraphicsObjectHashmap<GraphicsObject>();
+    typename std::tr1::unordered_map<DataSetId, GraphicsObject *>::iterator itr;
+
+    for (itr = hashmap.begin(); itr != hashmap.end(); ++itr) {
+        if (itr->second->getColorMap() == cmap) {
+            itr->second->updateColorMap();
+            _needsRedraw = true;
+        }
+    }
+}
+
+/**
+ * \brief Check if a color map is in use by a graphics object
+ */
+template<class GraphicsObject>
+bool Renderer::graphicsObjectColorMapUsed(ColorMap *cmap)
+{
+    std::tr1::unordered_map<DataSetId, GraphicsObject *>& hashmap = 
+        getGraphicsObjectHashmap<GraphicsObject>();
+    typename std::tr1::unordered_map<DataSetId, GraphicsObject *>::iterator itr;
+
+    for (itr = hashmap.begin(); itr != hashmap.end(); ++itr) {
+        if (itr->second->getColorMap() == cmap)
+            return true;
+    }
+    return false;
+}
+
+/**
+ * \brief Compute union of bounds and GO's bounds
+ */
+template<class GraphicsObject>
+void Renderer::mergeGraphicsObjectBounds(double *bounds, bool onlyVisible)
+{
+    std::tr1::unordered_map<DataSetId, GraphicsObject *>& hashmap = 
+        getGraphicsObjectHashmap<GraphicsObject>();
+    typename std::tr1::unordered_map<DataSetId, GraphicsObject *>::iterator itr;
+
+    for (itr = hashmap.begin(); itr != hashmap.end(); ++itr) {
+        if ((!onlyVisible || itr->second->getVisibility()) &&
+            itr->second->getProp() != NULL)
+            mergeBounds(bounds, bounds, itr->second->getBounds());
+#ifdef DEBUG
+        double *bPtr = itr->second->getBounds();
+        assert(bPtr != NULL);
+        GO_TRACE(GraphicsObject,
+                 "%s bounds: %g %g %g %g %g %g",
+                 itr->first.c_str(),
+                 bPtr[0], bPtr[1], bPtr[2], bPtr[3], bPtr[4], bPtr[5]);
+#endif
+    }
+}
+
+/**
+ * \brief Compute union of bounds and GO's unscaled bounds
+ *
+ * Unscaled bounds are the bounds of the object before any actor scaling is
+ * applied
+ */
+template<class GraphicsObject>
+void Renderer::mergeGraphicsObjectUnscaledBounds(double *bounds, bool onlyVisible)
+{
+    std::tr1::unordered_map<DataSetId, GraphicsObject *>& hashmap = 
+        getGraphicsObjectHashmap<GraphicsObject>();
+    typename std::tr1::unordered_map<DataSetId, GraphicsObject *>::iterator itr;
+
+    for (itr = hashmap.begin(); itr != hashmap.end(); ++itr) {
+        if ((!onlyVisible || itr->second->getVisibility()) &&
+            itr->second->getProp() != NULL)
+            mergeBounds(bounds, bounds, itr->second->getUnscaledBounds());
+#ifdef DEBUG
+        double *bPtr = itr->second->getUnscaledBounds();
+        assert(bPtr != NULL);
+        GO_TRACE(GraphicsObject,
+                 "%s bounds: %g %g %g %g %g %g",
+                 itr->first.c_str(),
+                 bPtr[0], bPtr[1], bPtr[2], bPtr[3], bPtr[4], bPtr[5]);
+#endif
+    }
+}
+
+/**
+ * \brief Notify object that field value ranges have changed
+ */
+template<class GraphicsObject>
+void Renderer::updateGraphicsObjectFieldRanges()
+{
+    std::tr1::unordered_map<DataSetId, GraphicsObject *>& hashmap = 
+        getGraphicsObjectHashmap<GraphicsObject>();
+    typename std::tr1::unordered_map<DataSetId, GraphicsObject *>::iterator itr;
+
+    for (itr = hashmap.begin(); itr != hashmap.end(); ++itr) {
+        itr->second->updateRanges(this);
+    }
+}
+
+/**
+ * \brief Pass global clip planes to graphics object
+ */
+template<class GraphicsObject>
+void Renderer::setGraphicsObjectClippingPlanes(vtkPlaneCollection *planes)
+{
+    std::tr1::unordered_map<DataSetId, GraphicsObject *>& hashmap = 
+        getGraphicsObjectHashmap<GraphicsObject>();
+    typename std::tr1::unordered_map<DataSetId, GraphicsObject *>::iterator itr;
+
+    for (itr = hashmap.begin(); itr != hashmap.end(); ++itr) {
+        itr->second->setClippingPlanes(planes);
+    }
+}
+
+/**
+ * \brief Set the prop scaling based on a 2D aspect ratio
+ *
+ * This method sets the aspect on all graphics objects of a given type
+ *
+ * \param aspectRatio The aspect ratio (width/height), zero means native aspect
+ */
+template<class GraphicsObject>
+void Renderer::setGraphicsObjectAspect(double aspectRatio)
+{
+    std::tr1::unordered_map<DataSetId, GraphicsObject *>& hashmap = 
+        getGraphicsObjectHashmap<GraphicsObject>();
+    typename std::tr1::unordered_map<DataSetId, GraphicsObject *>::iterator itr;
+
+    for (itr = hashmap.begin(); itr != hashmap.end(); ++itr) {
+        itr->second->setAspect(aspectRatio);
+    }
+
+    sceneBoundsChanged();
+    _needsRedraw = true;
+}
+
+}
+
+#endif
Index: /trunk/packages/vizservers/vtkvis/Warp.cpp
===================================================================
--- /trunk/packages/vizservers/vtkvis/Warp.cpp	(revision 3616)
+++ /trunk/packages/vizservers/vtkvis/Warp.cpp	(revision 3616)
@@ -0,0 +1,616 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (C) 2004-2012  HUBzero Foundation, LLC
+ *
+ * Author: Leif Delgass <ldelgass@purdue.edu>
+ */
+
+#include <cassert>
+#include <cfloat>
+#include <cstring>
+
+#include <vtkDataSet.h>
+#include <vtkPointData.h>
+#include <vtkCellData.h>
+#include <vtkCellDataToPointData.h>
+#include <vtkDataSetMapper.h>
+#include <vtkUnstructuredGrid.h>
+#include <vtkProperty.h>
+#include <vtkImageData.h>
+#include <vtkLookupTable.h>
+#include <vtkTransform.h>
+#include <vtkDelaunay2D.h>
+#include <vtkDelaunay3D.h>
+#include <vtkGaussianSplatter.h>
+#include <vtkExtractVOI.h>
+#include <vtkDataSetSurfaceFilter.h>
+
+#include "Warp.h"
+#include "VtkRenderer.h"
+#include "Trace.h"
+
+#define MESH_POINT_CLOUDS
+
+using namespace VtkVis;
+
+Warp::Warp() :
+    VtkGraphicsObject(),
+    _warpScale(1.0),
+    _colorMap(NULL),
+    _colorMode(COLOR_BY_SCALAR),
+    _colorFieldType(DataSet::POINT_DATA),
+    _renderer(NULL)
+{
+    _colorFieldRange[0] = DBL_MAX;
+    _colorFieldRange[1] = -DBL_MAX;
+}
+
+Warp::~Warp()
+{
+#ifdef WANT_TRACE
+    if (_dataSet != NULL)
+        TRACE("Deleting Warp for %s", _dataSet->getName().c_str());
+    else
+        TRACE("Deleting Warp with NULL DataSet");
+#endif
+}
+
+void Warp::setDataSet(DataSet *dataSet,
+                      Renderer *renderer)
+{
+    if (_dataSet != dataSet) {
+        _dataSet = dataSet;
+
+        _renderer = renderer;
+
+        if (renderer->getUseCumulativeRange()) {
+            renderer->getCumulativeDataRange(_dataRange,
+                                             _dataSet->getActiveScalarsName(),
+                                             1);
+            renderer->getCumulativeDataRange(_vectorMagnitudeRange,
+                                             _dataSet->getActiveVectorsName(),
+                                             3);
+            for (int i = 0; i < 3; i++) {
+                renderer->getCumulativeDataRange(_vectorComponentRange[i],
+                                                 _dataSet->getActiveVectorsName(),
+                                                 3, i);
+            }
+        } else {
+            _dataSet->getScalarRange(_dataRange);
+            _dataSet->getVectorRange(_vectorMagnitudeRange);
+            for (int i = 0; i < 3; i++) {
+                _dataSet->getVectorRange(_vectorComponentRange[i], i);
+            }
+        }
+
+        update();
+    }
+}
+
+/**
+ * \brief Internal method to set up pipeline after a state change
+ */
+void Warp::update()
+{
+    if (_dataSet == NULL)
+        return;
+
+    vtkDataSet *ds = _dataSet->getVtkDataSet();
+
+    if (_warp == NULL) {
+        _warp = vtkSmartPointer<vtkWarpVector>::New();
+    }
+
+    // Mapper, actor to render color-mapped data set
+    if (_dsMapper == NULL) {
+        _dsMapper = vtkSmartPointer<vtkDataSetMapper>::New();
+        // Map scalars through lookup table regardless of type
+        _dsMapper->SetColorModeToMapScalars();
+    }
+
+    vtkSmartPointer<vtkCellDataToPointData> cellToPtData;
+    if (ds->GetPointData() == NULL ||
+        ds->GetPointData()->GetVectors() == NULL) {
+        TRACE("No vector point data in dataset %s", _dataSet->getName().c_str());
+        if (ds->GetCellData() != NULL &&
+            ds->GetCellData()->GetVectors() != NULL) {
+            cellToPtData = 
+                vtkSmartPointer<vtkCellDataToPointData>::New();
+#ifdef USE_VTK6
+            cellToPtData->SetInputData(ds);
+#else
+            cellToPtData->SetInput(ds);
+#endif
+            //cellToPtData->PassCellDataOn();
+            cellToPtData->Update();
+            ds = cellToPtData->GetOutput();
+        } else {
+            USER_ERROR("No vector field was found in the data set");
+            return;
+        }
+    }
+
+    vtkPolyData *pd = vtkPolyData::SafeDownCast(ds);
+    if (pd) {
+        // DataSet is a vtkPolyData
+        if (pd->GetNumberOfLines() == 0 &&
+            pd->GetNumberOfPolys() == 0 &&
+            pd->GetNumberOfStrips() == 0) {
+            // DataSet is a point cloud
+            PrincipalPlane plane;
+            double offset;
+            if (_dataSet->is2D(&plane, &offset)) {
+#ifdef MESH_POINT_CLOUDS
+                vtkSmartPointer<vtkDelaunay2D> mesher = vtkSmartPointer<vtkDelaunay2D>::New();
+                if (plane == PLANE_ZY) {
+                    vtkSmartPointer<vtkTransform> trans = vtkSmartPointer<vtkTransform>::New();
+                    trans->RotateWXYZ(90, 0, 1, 0);
+                    if (offset != 0.0) {
+                        trans->Translate(-offset, 0, 0);
+                    }
+                    mesher->SetTransform(trans);
+                } else if (plane == PLANE_XZ) {
+                    vtkSmartPointer<vtkTransform> trans = vtkSmartPointer<vtkTransform>::New();
+                    trans->RotateWXYZ(-90, 1, 0, 0);
+                    if (offset != 0.0) {
+                        trans->Translate(0, -offset, 0);
+                    }
+                    mesher->SetTransform(trans);
+                } else if (offset != 0.0) {
+                    // XY with Z offset
+                    vtkSmartPointer<vtkTransform> trans = vtkSmartPointer<vtkTransform>::New();
+                    trans->Translate(0, 0, -offset);
+                    mesher->SetTransform(trans);
+                }
+#ifdef USE_VTK6
+                mesher->SetInputData(pd);
+#else
+                mesher->SetInput(pd);
+#endif
+                vtkAlgorithmOutput *warpOutput = initWarp(mesher->GetOutputPort());
+                _dsMapper->SetInputConnection(warpOutput);
+#else
+                vtkSmartPointer<vtkGaussianSplatter> splatter = vtkSmartPointer<vtkGaussianSplatter>::New();
+                vtkSmartPointer<vtkExtractVOI> slicer = vtkSmartPointer<vtkExtractVOI>::New();
+#ifdef USE_VTK6
+                splatter->SetInputData(pd);
+#else
+                splatter->SetInput(pd);
+#endif
+                int dims[3];
+                splatter->GetSampleDimensions(dims);
+                TRACE("Sample dims: %d %d %d", dims[0], dims[1], dims[2]);
+                if (plane == PLANE_ZY) {
+                    dims[0] = 3;
+                    slicer->SetVOI(1, 1, 0, dims[1]-1, 0, dims[1]-1);
+                } else if (plane == PLANE_XZ) {
+                    dims[1] = 3;
+                    slicer->SetVOI(0, dims[0]-1, 1, 1, 0, dims[2]-1);
+                } else {
+                    dims[2] = 3;
+                    slicer->SetVOI(0, dims[0]-1, 0, dims[1]-1, 1, 1);
+                }
+                splatter->SetSampleDimensions(dims);
+                double bounds[6];
+                splatter->Update();
+                splatter->GetModelBounds(bounds);
+                TRACE("Model bounds: %g %g %g %g %g %g",
+                      bounds[0], bounds[1],
+                      bounds[2], bounds[3],
+                      bounds[4], bounds[5]);
+                slicer->SetInputConnection(splatter->GetOutputPort());
+                slicer->SetSampleRate(1, 1, 1);
+                vtkSmartPointer<vtkDataSetSurfaceFilter> gf = vtkSmartPointer<vtkDataSetSurfaceFilter>::New();
+                gf->UseStripsOn();
+                gf->SetInputConnection(slicer->GetOutputPort());
+                vtkAlgorithmOutput *warpOutput = initWarp(gf->GetOutputPort());
+                _dsMapper->SetInputConnection(warpOutput);
+#endif
+            } else {
+                // Data Set is a 3D point cloud
+                vtkSmartPointer<vtkDelaunay3D> mesher = vtkSmartPointer<vtkDelaunay3D>::New();
+#ifdef USE_VTK6
+                mesher->SetInputData(pd);
+#else
+                mesher->SetInput(pd);
+#endif
+                vtkSmartPointer<vtkDataSetSurfaceFilter> gf = vtkSmartPointer<vtkDataSetSurfaceFilter>::New();
+                gf->SetInputConnection(mesher->GetOutputPort());
+                vtkAlgorithmOutput *warpOutput = initWarp(gf->GetOutputPort());
+                _dsMapper->SetInputConnection(warpOutput);
+             }
+        } else {
+            // DataSet is a vtkPolyData with lines and/or polygons
+            vtkAlgorithmOutput *warpOutput = initWarp(pd);
+            if (warpOutput != NULL) {
+                _dsMapper->SetInputConnection(warpOutput);
+            } else {
+#ifdef USE_VTK6
+                _dsMapper->SetInputData(pd);
+#else
+                _dsMapper->SetInput(pd);
+#endif
+            }
+        }
+    } else {
+        TRACE("Generating surface for data set");
+        // DataSet is NOT a vtkPolyData
+        vtkSmartPointer<vtkDataSetSurfaceFilter> gf = vtkSmartPointer<vtkDataSetSurfaceFilter>::New();
+#ifdef USE_VTK6
+        gf->SetInputData(ds);
+#else
+        gf->SetInput(ds);
+#endif
+        vtkAlgorithmOutput *warpOutput = initWarp(gf->GetOutputPort());
+        _dsMapper->SetInputConnection(warpOutput);
+    }
+
+    setInterpolateBeforeMapping(true);
+
+    if (_lut == NULL) {
+        setColorMap(ColorMap::getDefault());
+    }
+
+    setColorMode(_colorMode);
+
+    initProp();
+    getActor()->SetMapper(_dsMapper);
+    _dsMapper->Update();
+}
+
+void Warp::setInterpolateBeforeMapping(bool state)
+{
+    if (_dsMapper != NULL) {
+        _dsMapper->SetInterpolateScalarsBeforeMapping((state ? 1 : 0));
+    }
+}
+
+vtkAlgorithmOutput *Warp::initWarp(vtkAlgorithmOutput *input)
+{
+    TRACE("Warp scale: %g", _warpScale);
+    if (_warpScale == 0.0) {
+        _warp = NULL;
+        return input;
+    } else if (input == NULL) {
+        ERROR("NULL input");
+        return input;
+    } else {
+        if (_warp == NULL)
+            _warp = vtkSmartPointer<vtkWarpVector>::New();
+        _warp->SetScaleFactor(_warpScale);
+        _warp->SetInputConnection(input);
+        return _warp->GetOutputPort();
+    }
+}
+
+vtkAlgorithmOutput *Warp::initWarp(vtkDataSet *ds)
+{
+    TRACE("Warp scale: %g", _warpScale);
+    if (_warpScale == 0.0) {
+        _warp = NULL;
+        return NULL;
+    } else if (ds == NULL) {
+        ERROR("NULL input");
+        return NULL;
+    } else {
+        if (_warp == NULL)
+            _warp = vtkSmartPointer<vtkWarpVector>::New();
+        _warp->SetScaleFactor(_warpScale);
+#ifdef USE_VTK6
+        _warp->SetInputData(ds);
+#else
+        _warp->SetInput(ds);
+#endif
+        return _warp->GetOutputPort();
+    }
+}
+
+/**
+ * \brief Controls relative scaling of deformation
+ */
+void Warp::setWarpScale(double scale)
+{
+    if (_warpScale == scale)
+        return;
+
+    _warpScale = scale;
+    if (_warp == NULL) {
+        vtkAlgorithmOutput *warpOutput = initWarp(_dsMapper->GetInputConnection(0, 0));
+        _dsMapper->SetInputConnection(warpOutput);
+    } else if (scale == 0.0) {
+        vtkAlgorithmOutput *warpInput = _warp->GetInputConnection(0, 0);
+        _dsMapper->SetInputConnection(warpInput);
+        _warp = NULL;
+    } else {
+        _warp->SetScaleFactor(_warpScale);
+    }
+
+    if (_dsMapper != NULL)
+        _dsMapper->Update();
+}
+
+void Warp::updateRanges(Renderer *renderer)
+{
+    if (_dataSet == NULL) {
+        ERROR("called before setDataSet");
+        return;
+    }
+
+    if (renderer->getUseCumulativeRange()) {
+        renderer->getCumulativeDataRange(_dataRange,
+                                         _dataSet->getActiveScalarsName(),
+                                         1);
+        renderer->getCumulativeDataRange(_vectorMagnitudeRange,
+                                         _dataSet->getActiveVectorsName(),
+                                         3);
+        for (int i = 0; i < 3; i++) {
+            renderer->getCumulativeDataRange(_vectorComponentRange[i],
+                                             _dataSet->getActiveVectorsName(),
+                                             3, i);
+        }
+    } else {
+        _dataSet->getScalarRange(_dataRange);
+        _dataSet->getVectorRange(_vectorMagnitudeRange);
+        for (int i = 0; i < 3; i++) {
+            _dataSet->getVectorRange(_vectorComponentRange[i], i);
+        }
+    }
+
+    // Need to update color map ranges
+    double *rangePtr = _colorFieldRange;
+    if (_colorFieldRange[0] > _colorFieldRange[1]) {
+        rangePtr = NULL;
+    }
+    setColorMode(_colorMode, _colorFieldType, _colorFieldName.c_str(), rangePtr);
+}
+
+void Warp::setColorMode(ColorMode mode)
+{
+    _colorMode = mode;
+    if (_dataSet == NULL)
+        return;
+
+    switch (mode) {
+    case COLOR_BY_SCALAR:
+        setColorMode(mode,
+                     _dataSet->getActiveScalarsType(),
+                     _dataSet->getActiveScalarsName(),
+                     _dataRange);
+        break;
+    case COLOR_BY_VECTOR_MAGNITUDE:
+        setColorMode(mode,
+                     _dataSet->getActiveVectorsType(),
+                     _dataSet->getActiveVectorsName(),
+                     _vectorMagnitudeRange);
+        break;
+    case COLOR_BY_VECTOR_X:
+        setColorMode(mode,
+                     _dataSet->getActiveVectorsType(),
+                     _dataSet->getActiveVectorsName(),
+                     _vectorComponentRange[0]);
+        break;
+    case COLOR_BY_VECTOR_Y:
+        setColorMode(mode,
+                     _dataSet->getActiveVectorsType(),
+                     _dataSet->getActiveVectorsName(),
+                     _vectorComponentRange[1]);
+        break;
+    case COLOR_BY_VECTOR_Z:
+        setColorMode(mode,
+                     _dataSet->getActiveVectorsType(),
+                     _dataSet->getActiveVectorsName(),
+                     _vectorComponentRange[2]);
+        break;
+    case COLOR_CONSTANT:
+    default:
+        setColorMode(mode, DataSet::POINT_DATA, NULL, NULL);
+        break;
+    }
+}
+
+void Warp::setColorMode(ColorMode mode,
+                        const char *name, double range[2])
+{
+    if (_dataSet == NULL)
+        return;
+    DataSet::DataAttributeType type = DataSet::POINT_DATA;
+    int numComponents = 1;
+    if (name != NULL && strlen(name) > 0 &&
+        !_dataSet->getFieldInfo(name, &type, &numComponents)) {
+        ERROR("Field not found: %s", name);
+        return;
+    }
+    setColorMode(mode, type, name, range);
+}
+
+void Warp::setColorMode(ColorMode mode, DataSet::DataAttributeType type,
+                        const char *name, double range[2])
+{
+    _colorMode = mode;
+    _colorFieldType = type;
+    if (name == NULL)
+        _colorFieldName.clear();
+    else
+        _colorFieldName = name;
+    if (range == NULL) {
+        _colorFieldRange[0] = DBL_MAX;
+        _colorFieldRange[1] = -DBL_MAX;
+    } else {
+        memcpy(_colorFieldRange, range, sizeof(double)*2);
+    }
+
+    if (_dataSet == NULL || _dsMapper == NULL)
+        return;
+
+    switch (type) {
+    case DataSet::POINT_DATA:
+        _dsMapper->SetScalarModeToUsePointFieldData();
+        break;
+    case DataSet::CELL_DATA:
+        _dsMapper->SetScalarModeToUseCellFieldData();
+        break;
+    default:
+        ERROR("Unsupported DataAttributeType: %d", type);
+        return;
+    }
+
+    if (name != NULL && strlen(name) > 0) {
+        _dsMapper->SelectColorArray(name);
+    } else {
+        _dsMapper->SetScalarModeToDefault();
+    }
+
+    if (_lut != NULL) {
+        if (range != NULL) {
+            _lut->SetRange(range);
+        } else if (name != NULL && strlen(name) > 0) {
+            double r[2];
+            int comp = -1;
+            if (mode == COLOR_BY_VECTOR_X)
+                comp = 0;
+            else if (mode == COLOR_BY_VECTOR_Y)
+                comp = 1;
+            else if (mode == COLOR_BY_VECTOR_Z)
+                comp = 2;
+
+            if (_renderer->getUseCumulativeRange()) {
+                int numComponents;
+                if  (!_dataSet->getFieldInfo(name, type, &numComponents)) {
+                    ERROR("Field not found: %s, type: %d", name, type);
+                    return;
+                } else if (numComponents < comp+1) {
+                    ERROR("Request for component %d in field with %d components",
+                          comp, numComponents);
+                    return;
+                }
+                _renderer->getCumulativeDataRange(r, name, type, numComponents, comp);
+            } else {
+                _dataSet->getDataRange(r, name, type, comp);
+            }
+            _lut->SetRange(r);
+        }
+    }
+
+    switch (mode) {
+    case COLOR_BY_SCALAR:
+        _dsMapper->ScalarVisibilityOn();
+        break;
+    case COLOR_BY_VECTOR_MAGNITUDE:
+        _dsMapper->ScalarVisibilityOn();
+        if (_lut != NULL) {
+            _lut->SetVectorModeToMagnitude();
+        }
+        break;
+    case COLOR_BY_VECTOR_X:
+        _dsMapper->ScalarVisibilityOn();
+        if (_lut != NULL) {
+            _lut->SetVectorModeToComponent();
+            _lut->SetVectorComponent(0);
+        }
+        break;
+    case COLOR_BY_VECTOR_Y:
+        _dsMapper->ScalarVisibilityOn();
+        if (_lut != NULL) {
+            _lut->SetVectorModeToComponent();
+            _lut->SetVectorComponent(1);
+        }
+        break;
+    case COLOR_BY_VECTOR_Z:
+        _dsMapper->ScalarVisibilityOn();
+        if (_lut != NULL) {
+            _lut->SetVectorModeToComponent();
+            _lut->SetVectorComponent(2);
+        }
+        break;
+    case COLOR_CONSTANT:
+    default:
+        _dsMapper->ScalarVisibilityOff();
+        break;
+    }
+}
+
+/**
+ * \brief Called when the color map has been edited
+ */
+void Warp::updateColorMap()
+{
+    setColorMap(_colorMap);
+}
+
+/**
+ * \brief Associate a colormap lookup table with the DataSet
+ */
+void Warp::setColorMap(ColorMap *cmap)
+{
+    if (cmap == NULL)
+        return;
+
+    _colorMap = cmap;
+ 
+    if (_lut == NULL) {
+        _lut = vtkSmartPointer<vtkLookupTable>::New();
+        if (_dsMapper != NULL) {
+            _dsMapper->UseLookupTableScalarRangeOn();
+            _dsMapper->SetLookupTable(_lut);
+        }
+        _lut->DeepCopy(cmap->getLookupTable());
+        switch (_colorMode) {
+        case COLOR_CONSTANT:
+        case COLOR_BY_SCALAR:
+            _lut->SetRange(_dataRange);
+            break;
+        case COLOR_BY_VECTOR_MAGNITUDE:
+            _lut->SetRange(_vectorMagnitudeRange);
+            break;
+        case COLOR_BY_VECTOR_X:
+            _lut->SetRange(_vectorComponentRange[0]);
+            break;
+        case COLOR_BY_VECTOR_Y:
+            _lut->SetRange(_vectorComponentRange[1]);
+            break;
+        case COLOR_BY_VECTOR_Z:
+            _lut->SetRange(_vectorComponentRange[2]);
+            break;
+        default:
+            break;
+        }
+    } else {
+        double range[2];
+        _lut->GetTableRange(range);
+        _lut->DeepCopy(cmap->getLookupTable());
+        _lut->SetRange(range);
+        _lut->Modified();
+    }
+
+    switch (_colorMode) {
+    case COLOR_BY_VECTOR_MAGNITUDE:
+        _lut->SetVectorModeToMagnitude();
+        break;
+    case COLOR_BY_VECTOR_X:
+        _lut->SetVectorModeToComponent();
+        _lut->SetVectorComponent(0);
+        break;
+    case COLOR_BY_VECTOR_Y:
+        _lut->SetVectorModeToComponent();
+        _lut->SetVectorComponent(1);
+        break;
+    case COLOR_BY_VECTOR_Z:
+        _lut->SetVectorModeToComponent();
+        _lut->SetVectorComponent(2);
+        break;
+    default:
+         break;
+    }
+}
+
+/**
+ * \brief Set a group of world coordinate planes to clip rendering
+ *
+ * Passing NULL for planes will remove all cliping planes
+ */
+void Warp::setClippingPlanes(vtkPlaneCollection *planes)
+{
+    if (_dsMapper != NULL) {
+        _dsMapper->SetClippingPlanes(planes);
+    }
+}
Index: /trunk/packages/vizservers/vtkvis/Warp.h
===================================================================
--- /trunk/packages/vizservers/vtkvis/Warp.h	(revision 3616)
+++ /trunk/packages/vizservers/vtkvis/Warp.h	(revision 3616)
@@ -0,0 +1,110 @@
+/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (C) 2004-2012  HUBzero Foundation, LLC
+ *
+ * Author: Leif Delgass <ldelgass@purdue.edu>
+ */
+
+#ifndef VTKVIS_WARP_H
+#define VTKVIS_WARP_H
+
+#include <vtkSmartPointer.h>
+#include <vtkAlgorithmOutput.h>
+#include <vtkLookupTable.h>
+#include <vtkDataSet.h>
+#include <vtkDataSetMapper.h>
+#include <vtkActor.h>
+#include <vtkPlaneCollection.h>
+#include <vtkWarpVector.h>
+
+#include "ColorMap.h"
+#include "VtkGraphicsObject.h"
+
+namespace VtkVis {
+
+/**
+ * \brief Warp a mesh based on point data vectors
+ *
+ * This class can be used to visualize mechanical deformation or 
+ * to create flow profiles/surfaces
+ */
+class Warp : public VtkGraphicsObject {
+public:
+    enum ColorMode {
+        COLOR_BY_SCALAR,
+        COLOR_BY_VECTOR_MAGNITUDE,
+        COLOR_BY_VECTOR_X,
+        COLOR_BY_VECTOR_Y,
+        COLOR_BY_VECTOR_Z,
+        COLOR_CONSTANT
+    };
+
+    Warp();
+    virtual ~Warp();
+
+    virtual const char *getClassName() const
+    {
+        return "Warp";
+    }
+
+    virtual void setDataSet(DataSet *dataSet,
+                            Renderer *renderer);
+
+    virtual void setClippingPlanes(vtkPlaneCollection *planes);
+
+    void setWarpScale(double scale);
+
+    double getWarpScale()
+    {
+        return _warpScale;
+    }
+
+    void setInterpolateBeforeMapping(bool state);
+
+    void setColorMode(ColorMode mode, DataSet::DataAttributeType type,
+                      const char *name, double range[2] = NULL);
+
+    void setColorMode(ColorMode mode,
+                      const char *name, double range[2] = NULL);
+
+    void setColorMode(ColorMode mode);
+
+    void setColorMap(ColorMap *colorMap);
+
+    /**
+     * \brief Return the ColorMap in use
+     */
+    ColorMap *getColorMap()
+    {
+        return _colorMap;
+    }
+
+    void updateColorMap();
+
+    virtual void updateRanges(Renderer *renderer);
+
+private:
+    virtual void update();
+
+    vtkAlgorithmOutput *initWarp(vtkAlgorithmOutput *input);
+    vtkAlgorithmOutput *initWarp(vtkDataSet *input);
+
+    double _warpScale;
+
+    ColorMap *_colorMap;
+    ColorMode _colorMode;
+    std::string _colorFieldName;
+    DataSet::DataAttributeType _colorFieldType;
+    double _colorFieldRange[2];
+    double _vectorMagnitudeRange[2];
+    double _vectorComponentRange[3][2];
+    Renderer *_renderer;
+
+    vtkSmartPointer<vtkLookupTable> _lut;
+    vtkSmartPointer<vtkWarpVector> _warp;
+    vtkSmartPointer<vtkDataSetMapper> _dsMapper;
+};
+
+}
+
+#endif
