Index: /vtkvis/branches/1.7/ColorMap.cpp
===================================================================
--- /vtkvis/branches/1.7/ColorMap.cpp	(revision 4782)
+++ /vtkvis/branches/1.7/ColorMap.cpp	(revision 4783)
@@ -145,21 +145,21 @@
     // Clamp value to [0,1]
     if (cp.value < 0.0)
-	cp.value = 0.0;
+        cp.value = 0.0;
     if (cp.value > 1.0)
-	cp.value = 1.0;
+        cp.value = 1.0;
 
 #ifdef DEBUG
     TRACE("New control point: %g = %g %g %g",
-	  cp.value, cp.color[0], cp.color[1], cp.color[2]);
+          cp.value, cp.color[0], cp.color[1], cp.color[2]);
 #endif
     for (std::list<ControlPoint>::iterator itr = _controlPoints.begin();
-	 itr != _controlPoints.end(); ++itr) {
-	if (itr->value == cp.value) {
-	    *itr = cp;
-	    return;
-	} else if (itr->value > cp.value) {
-	    _controlPoints.insert(itr, cp);
-	    return;
-	}
+         itr != _controlPoints.end(); ++itr) {
+        if (itr->value == cp.value) {
+            *itr = cp;
+            return;
+        } else if (itr->value > cp.value) {
+            _controlPoints.insert(itr, cp);
+            return;
+        }
     }
     // If we reach here, our control point goes at the end
@@ -176,21 +176,21 @@
     // Clamp value to [0,1]
     if (cp.value < 0.0)
-	cp.value = 0.0;
+        cp.value = 0.0;
     if (cp.value > 1.0)
-	cp.value = 1.0;
+        cp.value = 1.0;
 
 #ifdef DEBUG
     TRACE("New opacity control point: %g = %g",
-	  cp.value, cp.alpha);
+          cp.value, cp.alpha);
 #endif
     for (std::list<OpacityControlPoint>::iterator itr = _opacityControlPoints.begin();
-	 itr != _opacityControlPoints.end(); ++itr) {
-	if (itr->value == cp.value) {
-	    *itr = cp;
-	    return;
-	} else if (itr->value > cp.value) {
-	    _opacityControlPoints.insert(itr, cp);
-	    return;
-	}
+         itr != _opacityControlPoints.end(); ++itr) {
+        if (itr->value == cp.value) {
+            *itr = cp;
+            return;
+        } else if (itr->value > cp.value) {
+            _opacityControlPoints.insert(itr, cp);
+            return;
+        }
     }
     // If we reach here, our control point goes at the end
@@ -209,9 +209,9 @@
 {
     if (numEntries != _numTableEntries) {
-	_needsBuild = true;
-	_numTableEntries = numEntries;
-	if (_lookupTable != NULL) {
-	    build();
-	}
+        _needsBuild = true;
+        _numTableEntries = numEntries;
+        if (_lookupTable != NULL) {
+            build();
+        }
     }
 }
@@ -236,10 +236,10 @@
 {
     if (!_needsBuild)
-	return;
+        return;
 
     TRACE("%s", _name.c_str());
 
     if (_lookupTable == NULL) {
-	_lookupTable = vtkSmartPointer<vtkLookupTable>::New();
+        _lookupTable = vtkSmartPointer<vtkLookupTable>::New();
     }
 
@@ -252,12 +252,12 @@
     // constant range up to first specified cp
     if (itr->value > 0.0) {
-	ControlPoint cp = *itr;
-	cp.value = 0.0;
-	itr = _controlPoints.insert(itr, cp);
+        ControlPoint cp = *itr;
+        cp.value = 0.0;
+        itr = _controlPoints.insert(itr, cp);
     }
     if (oitr->value > 0.0) {
-	OpacityControlPoint ocp = *oitr;
-	ocp.value = 0.0;
-	oitr = _opacityControlPoints.insert(oitr, ocp);
+        OpacityControlPoint ocp = *oitr;
+        ocp.value = 0.0;
+        oitr = _opacityControlPoints.insert(oitr, ocp);
     }
 
@@ -268,44 +268,44 @@
 
     for (int i = 0; i < _numTableEntries; i++) {
-	double value = _numTableEntries < 2 ? 0.0 : ((double)i)/(_numTableEntries-1);
+        double value = _numTableEntries < 2 ? 0.0 : ((double)i)/(_numTableEntries-1);
         double color[4];
-	while (itr2 != _controlPoints.end() && value > itr2->value) {
-	    itr = itr2;
-	    itr2++;
-	}
-	while (oitr2 != _opacityControlPoints.end() && value > oitr2->value) {
-	    oitr = oitr2;
-	    oitr2++;
-	}
-	if (itr2 == _controlPoints.end()) {
+        while (itr2 != _controlPoints.end() && value > itr2->value) {
+            itr = itr2;
+            itr2++;
+        }
+        while (oitr2 != _opacityControlPoints.end() && value > oitr2->value) {
+            oitr = oitr2;
+            oitr2++;
+        }
+        if (itr2 == _controlPoints.end()) {
 #ifdef DEBUG
-	    TRACE("val: %g Range: %g - 1 Color: %g %g %g", value, itr->value,
-		  itr->color[0], itr->color[1], itr->color[2]);
+            TRACE("val: %g Range: %g - 1 Color: %g %g %g", value, itr->value,
+                  itr->color[0], itr->color[1], itr->color[2]);
 #endif
             memcpy(color, itr->color, sizeof(double)*3);
-	} else {
-	    assert(itr->value < itr2->value);
-	    assert(value >= itr->value && value <= itr2->value);
-	    lerp(color, *itr, *itr2, value);
+        } else {
+            assert(itr->value < itr2->value);
+            assert(value >= itr->value && value <= itr2->value);
+            lerp(color, *itr, *itr2, value);
 #ifdef DEBUG
-	    TRACE("val: %g Range: %g - %g Color: %g %g %g", value, itr->value, itr2->value,
-		  color[0], color[1], color[2]);
+            TRACE("val: %g Range: %g - %g Color: %g %g %g", value, itr->value, itr2->value,
+                  color[0], color[1], color[2]);
 #endif
-	}
-	if (oitr2 == _opacityControlPoints.end()) {
+        }
+        if (oitr2 == _opacityControlPoints.end()) {
 #ifdef DEBUG
-	    TRACE("val: %g Range: %g - 1 Alpha %g", value, oitr->value,
-		  oitr->alpha);
+            TRACE("val: %g Range: %g - 1 Alpha %g", value, oitr->value,
+                  oitr->alpha);
 #endif
             color[3] = oitr->alpha;
-	} else {
-	    assert(oitr->value < oitr2->value);
-	    assert(value >= oitr->value && value <= oitr2->value);
-	    lerp(&color[3], *oitr, *oitr2, value);
+        } else {
+            assert(oitr->value < oitr2->value);
+            assert(value >= oitr->value && value <= oitr2->value);
+            lerp(&color[3], *oitr, *oitr2, value);
 #ifdef DEBUG
-	    TRACE("val: %g Range: %g - %g Alpha: %g", value, oitr->value, oitr2->value,
-		  color[3]);
+            TRACE("val: %g Range: %g - %g Alpha: %g", value, oitr->value, oitr2->value,
+                  color[3]);
 #endif
-	}
+        }
         _lookupTable->SetTableValue(i, color);
     }
@@ -324,5 +324,5 @@
     double factor = (value - cp1.value) / (cp2.value - cp1.value);
     for (int i = 0; i < 3; i++) {
-	result[i] = cp1.color[i] * (1.0 - factor) + cp2.color[i] * factor;
+        result[i] = cp1.color[i] * (1.0 - factor) + cp2.color[i] * factor;
     }
 }
@@ -384,5 +384,5 @@
     cp[4].color[2] = 0.0;
     for (int i = 0; i < 5; i++) {
-	_default->addControlPoint(cp[i]);
+        _default->addControlPoint(cp[i]);
     }
     OpacityControlPoint ocp[2];
@@ -462,5 +462,5 @@
     cp[4].color[2] = 0.0;
     for (int i = 0; i < 5; i++) {
-	_volumeDefault->addControlPoint(cp[i]);
+        _volumeDefault->addControlPoint(cp[i]);
     }
     OpacityControlPoint ocp[2];
Index: /vtkvis/branches/1.7/GraphicsObject.h
===================================================================
--- /vtkvis/branches/1.7/GraphicsObject.h	(revision 4782)
+++ /vtkvis/branches/1.7/GraphicsObject.h	(revision 4783)
@@ -287,5 +287,5 @@
         PrincipalPlane plane;
         if (!_dataSet->is2D(&plane)) {
-            TRACE("Not setting aspect for 3D object");
+            TRACE("Not setting aspect for 3D object %s", getClassName());
             return;
         }
Index: /vtkvis/branches/1.7/Image.cpp
===================================================================
--- /vtkvis/branches/1.7/Image.cpp	(revision 4782)
+++ /vtkvis/branches/1.7/Image.cpp	(revision 4783)
@@ -76,4 +76,5 @@
         TRACE("Creating mapper");
         vtkSmartPointer<vtkImageResliceMapper> newMapper = vtkSmartPointer<vtkImageResliceMapper>::New();
+        newMapper->AutoAdjustImageQualityOff();
         getImageSlice()->SetMapper(newMapper);
         mapper = getImageMapper();
Index: /vtkvis/branches/1.7/Image.h
===================================================================
--- /vtkvis/branches/1.7/Image.h	(revision 4782)
+++ /vtkvis/branches/1.7/Image.h	(revision 4783)
@@ -66,4 +66,36 @@
     }
 
+    void setSlicePlane(double normal[3], double origin[3])
+    {
+        setSliceFollowsCamera(false);
+
+        vtkImageMapper3D *mapper = getImageMapper();
+        vtkImageResliceMapper *resliceMapper = vtkImageResliceMapper::SafeDownCast(mapper);
+        if (resliceMapper != NULL) {
+            vtkSmartPointer<vtkPlane> plane = vtkSmartPointer<vtkPlane>::New();
+            plane->SetNormal(normal);
+            plane->SetOrigin(origin);
+            resliceMapper->SetSlicePlane(plane);
+        }
+    }
+
+    void setSliceFollowsCamera(bool state)
+    {
+        vtkImageMapper3D *mapper = getImageMapper();
+        if (mapper != NULL) {
+            mapper->SetSliceFacesCamera(state ? 1 : 0);
+            mapper->SetSliceAtFocalPoint(state ? 1 : 0);
+        }
+    }
+
+    void setJumpToNearestSlice(bool state)
+    {
+        vtkImageMapper3D *mapper = getImageMapper();
+        vtkImageResliceMapper *resliceMapper = vtkImageResliceMapper::SafeDownCast(mapper);
+        if (resliceMapper != NULL) {
+            resliceMapper->SetJumpToNearestSlice(state ? 1 : 0);
+        }
+    }
+
     void setExtents(int extent[6])
     {
Index: /vtkvis/branches/1.7/Renderer.h
===================================================================
--- /vtkvis/branches/1.7/Renderer.h	(revision 4782)
+++ /vtkvis/branches/1.7/Renderer.h	(revision 4783)
@@ -512,5 +512,5 @@
     void setGraphicsObjectVolumeSlice(const DataSetId& id, Axis axis, double ratio);
 
-    //   Prop/Prop3D properties
+    // Prop/Prop3D properties
 
     template<class T>
@@ -538,5 +538,5 @@
     void setGraphicsObjectVisibility(const DataSetId& id, bool state);
 
-    //   Actor properties
+    // Actor properties
 
     template<class T>
@@ -765,4 +765,5 @@
     void setImageBorder(const DataSetId& id, bool state);
 
+    // For ImageActor/ImageSliceMapper only
     void setImageExtents(const DataSetId& id, int extents[6]);
 
@@ -771,4 +772,9 @@
     void setImageWindow(const DataSetId& id, double window);
 
+    void setImageSlicePlane(const DataSetId& id, double normal[3], double origin[3]);
+
+    void setImageSliceFollowsCamera(const DataSetId& id, bool state);
+
+    // For ImageActor/ImageSliceMapper only
     void setImageZSlice(const DataSetId& id, int z);
 
Index: /vtkvis/branches/1.7/RendererCmd.cpp
===================================================================
--- /vtkvis/branches/1.7/RendererCmd.cpp	(revision 4782)
+++ /vtkvis/branches/1.7/RendererCmd.cpp	(revision 4783)
@@ -2077,9 +2077,9 @@
     Renderer::Aspect aspect;
     const char *string = Tcl_GetString(objv[2]);
-    if ((strcmp(string, "native") == 0)) {
+    if (string[0] == 'n' && (strcmp(string, "native") == 0)) {
         aspect = Renderer::ASPECT_NATIVE;
-    } else if ((strcmp(string, "square") == 0)) {
+    } else if (string[0] == 's' && (strcmp(string, "square") == 0)) {
         aspect = Renderer::ASPECT_SQUARE;
-    } else if ((strcmp(string, "window") == 0)) {
+    } else if (string[0] == 'w' && (strcmp(string, "window") == 0)) {
         aspect = Renderer::ASPECT_WINDOW;
     } else {
@@ -2098,9 +2098,9 @@
     Renderer::CameraMode mode;
     const char *string = Tcl_GetString(objv[2]);
-    if ((strcmp(string, "persp") == 0)) {
+    if (string[0] == 'p' && (strcmp(string, "persp") == 0)) {
         mode = Renderer::PERSPECTIVE;
-    } else if ((strcmp(string, "ortho") == 0)) {
+    } else if (string[0] == 'o' && (strcmp(string, "ortho") == 0)) {
         mode = Renderer::ORTHO;
-    } else if ((strcmp(string, "image") == 0)) {
+    } else if (string[0] == 'i' && (strcmp(string, "image") == 0)) {
         mode = Renderer::IMAGE;
     } else {
@@ -2283,14 +2283,14 @@
 
 static 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"}
+    {"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",   3, 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);
@@ -2485,5 +2485,5 @@
     if (Tcl_GetIntFromObj(interp, objv[2], &numEntries) != TCL_OK) {
         const char *str = Tcl_GetString(objv[2]);
-        if (strcmp(str, "default") == 0) {
+        if (str[0] == 'd' && strcmp(str, "default") == 0) {
             numEntries = -1;
         } else {
@@ -4831,7 +4831,7 @@
 {
     const char *value = Tcl_GetString(objv[2]);
-    if (strcmp(value, "all") == 0) {
+    if (value[0] == 'a' && strcmp(value, "all") == 0) {
         g_renderer->setUseCumulativeDataRange(true);
-    } else if (strcmp(value, "explicit") == 0) {
+    } else if (value[0] == 'e' && strcmp(value, "explicit") == 0) {
         if (objc < 6 || objc > 9) {
             Tcl_AppendResult(interp, "wrong number of arguments for explicit maprange", (char*)NULL);
@@ -4850,9 +4850,9 @@
         if (objc > 6) {
             const char *fieldType = Tcl_GetString(objv[6]);
-            if (strcmp(fieldType, "point_data") == 0) {
+            if (fieldType[0] == 'p' && strcmp(fieldType, "point_data") == 0) {
                 type = DataSet::POINT_DATA;
-            } else if (strcmp(fieldType, "cell_data") == 0) {
+            } else if (fieldType[0] == 'c' && strcmp(fieldType, "cell_data") == 0) {
                 type = DataSet::CELL_DATA;
-            } else if (strcmp(fieldType, "field_data") == 0) {
+            } else if (fieldType[0] == 'f' && strcmp(fieldType, "field_data") == 0) {
                 type = DataSet::FIELD_DATA;
             } else {
@@ -4873,7 +4873,7 @@
         }
         g_renderer->setCumulativeDataRange(range, fieldName, type, numComponents, component);
-    } else if (strcmp(value, "separate") == 0) {
+    } else if (value[0] == 's' && strcmp(value, "separate") == 0) {
         g_renderer->setUseCumulativeDataRange(false);
-    } else if (strcmp(value, "visible") == 0) {
+    } else if (value[0] == 'v' && strcmp(value, "visible") == 0) {
         g_renderer->setUseCumulativeDataRange(true, true);
     } else {
@@ -6937,4 +6937,21 @@
 
 static int
+ImageFollowCameraOp(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->setImageSliceFollowsCamera(name, state);
+    } else {
+        g_renderer->setImageSliceFollowsCamera("all", state);
+    }
+    return TCL_OK;
+}
+
+static int
 ImageLevelOp(ClientData clientData, Tcl_Interp *interp, int objc, 
              Tcl_Obj *const *objv)
@@ -7024,4 +7041,26 @@
     } else {
         g_renderer->setGraphicsObjectScale<Image>("all", scale);
+    }
+    return TCL_OK;
+}
+
+static int
+ImageSlicePlaneOp(ClientData clientData, Tcl_Interp *interp, int objc, 
+                  Tcl_Obj *const *objv)
+{
+    double normal[3], origin[3];
+    if (Tcl_GetDoubleFromObj(interp, objv[2], &normal[0]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[3], &normal[1]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[4], &normal[2]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[5], &origin[0]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[6], &origin[1]) != TCL_OK ||
+        Tcl_GetDoubleFromObj(interp, objv[7], &origin[2]) != TCL_OK) {
+        return TCL_ERROR;
+    }
+    if (objc == 4) {
+        const char *name = Tcl_GetString(objv[8]);
+        g_renderer->setImageSlicePlane(name, normal, origin);
+    } else {
+        g_renderer->setImageSlicePlane("all", normal, origin);
     }
     return TCL_OK;
@@ -7088,9 +7127,11 @@
     {"delete",       1, ImageDeleteOp, 2, 3, "?dataSetName?"},
     {"extents",      1, ImageExtentsOp, 8, 9, "xmin xmax ymin ymax zmin zmax ?dataSetName?"},
+    {"follow",       1, ImageFollowCameraOp, 3, 4, "bool ?dataSetName?"},
     {"level",        1, ImageLevelOp, 3, 4, "val ?dataSetName?"},
     {"opacity",      2, ImageOpacityOp, 3, 4, "value ?dataSetName?"},
     {"orient",       2, ImageOrientOp, 6, 7, "qw qx qy qz ?dataSetName?"},
     {"pos",          1, ImagePositionOp, 5, 6, "x y z ?dataSetName?"},
-    {"scale",        1, ImageScaleOp, 5, 6, "sx sy sz ?dataSetName?"},
+    {"scale",        2, ImageScaleOp, 5, 6, "sx sy sz ?dataSetName?"},
+    {"slice",        2, ImageSlicePlaneOp, 8, 9, "nx ny nz ox oy oz ?dataSetName?"},
     {"visible",      1, ImageVisibleOp, 3, 4, "bool ?dataSetName?"},
     {"window",       1, ImageWindowOp, 3, 4, "val ?dataSetName?"},
Index: /vtkvis/branches/1.7/RendererGraphicsObjs.cpp
===================================================================
--- /vtkvis/branches/1.7/RendererGraphicsObjs.cpp	(revision 4782)
+++ /vtkvis/branches/1.7/RendererGraphicsObjs.cpp	(revision 4783)
@@ -2400,4 +2400,56 @@
 }
 
+void Renderer::setImageSlicePlane(const DataSetId& id, double normal[3], double origin[3])
+{
+    ImageHashmap::iterator itr;
+
+    bool doAll = false;
+
+    if (id.compare("all") == 0) {
+        itr = _images.begin();
+        if (itr == _images.end())
+            return;
+        doAll = true;
+    } else {
+        itr = _images.find(id);
+    }
+    if (itr == _images.end()) {
+        ERROR("Image not found: %s", id.c_str());
+        return;
+    }
+
+    do {
+        itr->second->setSlicePlane(normal, origin);
+    } while (doAll && ++itr != _images.end());
+
+    _needsRedraw = true;
+}
+
+void Renderer::setImageSliceFollowsCamera(const DataSetId& id, bool state)
+{
+    ImageHashmap::iterator itr;
+
+    bool doAll = false;
+
+    if (id.compare("all") == 0) {
+        itr = _images.begin();
+        if (itr == _images.end())
+            return;
+        doAll = true;
+    } else {
+        itr = _images.find(id);
+    }
+    if (itr == _images.end()) {
+        ERROR("Image not found: %s", id.c_str());
+        return;
+    }
+
+    do {
+        itr->second->setSliceFollowsCamera(state);
+    } while (doAll && ++itr != _images.end());
+
+    _needsRedraw = true;
+}
+
 void Renderer::setImageZSlice(const DataSetId& id, int z)
 {
Index: /vtkvis/branches/1.7/protocol.txt
===================================================================
--- /vtkvis/branches/1.7/protocol.txt	(revision 4782)
+++ /vtkvis/branches/1.7/protocol.txt	(revision 4783)
@@ -603,4 +603,8 @@
 image delete <?dataSetName?>
 image extents <xmin> <xmax> <ymin> <ymax> <zmin> <zmax> <?dataSetName?>
+      Deprecated
+image follow <bool> <?dataSetName?>
+      Toggle camera following.  When on, slice plane will face the camera and
+      camera focal point determines slice offset
 image level <level> <?dataSetName?>
 image opacity <opacity> <?dataSetName?>
@@ -608,7 +612,11 @@
 image pos <x> <y> <z> <?dataSetName?>
 image scale <sx> <sy> <sz> <?dataSetName?>
+image slice <nx> <ny> <nz> <ox> <oy> <oz> <?dataSetName?>
+      Disable camera follow and set slice plane by plane normal (nx,ny,nz) and 
+      origin (ox,oy,oz)
 image visible <bool> <?dataSetName?>
 image window <windowWidth> <?dataSetName?>
 image zslice <sliceNum> <?dataSetName?>
+      Deprecated
 
 lic add <?datasetName?>
