Index: trunk/psLib/src/imageops/psImageGeomManip.c
===================================================================
--- trunk/psLib/src/imageops/psImageGeomManip.c	(revision 16873)
+++ trunk/psLib/src/imageops/psImageGeomManip.c	(revision 16910)
@@ -10,6 +10,6 @@
  *  @author Ross Harman, MHPCC
  *
- *  @version $Revision: 1.41 $ $Name: not supported by cvs2svn $
- *  @date $Date: 2007-04-12 18:55:10 $
+ *  @version $Revision: 1.42 $ $Name: not supported by cvs2svn $
+ *  @date $Date: 2008-03-11 00:41:30 $
  *
  *  Copyright 2004-2005 Maui High Performance Computing Center, University of Hawaii
@@ -659,4 +659,93 @@
 }
 
+bool psImageShiftMask(psImage **out, psImage **outMask, const psImage* in, const psImage *inMask,
+                      psMaskType maskVal, float dx, float dy, double exposed, psMaskType blank,
+                      psImageInterpolateMode mode)
+{
+    PS_ASSERT(out, false);
+    PS_ASSERT_IMAGE_NON_NULL(in, false);
+    if (inMask) {
+        PS_ASSERT_IMAGE_NON_NULL(inMask, false);
+        PS_ASSERT_IMAGES_SIZE_EQUAL(in, inMask, false);
+        PS_ASSERT_IMAGE_TYPE(inMask, PS_TYPE_MASK, false);
+    }
+
+    int numRows = in->numRows, numCols = in->numCols; // Size of image
+    psElemType type = in->type.type;    // Type of image
+
+    *out = psImageRecycle(*out, numCols, numRows, type);
+    if (outMask) {
+        *outMask = psImageRecycle(*outMask, numCols, numRows, PS_TYPE_MASK);
+    }
+
+    psImageInterpolateOptions *interp = psImageInterpolateOptionsAlloc(PS_INTERPOLATE_BICUBE, in, NULL,
+                                                                       inMask, maskVal, exposed, NAN, blank,
+                                                                       blank, 0.0);
+
+    #define PSIMAGE_SHIFT_MASK_CASE(TYPE) \
+case PS_TYPE_##TYPE: \
+    if (exposed < PS_MIN_##TYPE || \
+            exposed > PS_MAX_##TYPE || \
+            exposed < PS_MIN_##TYPE || \
+            exposed > PS_MAX_##TYPE) { \
+        psError(PS_ERR_BAD_PARAMETER_VALUE, true, \
+                _("Specified exposed value, %g%+gi, is not the the range of input image's " \
+                  "valid pixel values (%s), i.e. [%g:%g]."), \
+                exposed, exposed, \
+                PS_TYPE_##TYPE##_NAME,  \
+                (double)PS_MIN_##TYPE,(double)PS_MAX_##TYPE); \
+        psFree(out); \
+        out = NULL; \
+        break; \
+    } \
+    /* note: output(i,j) = input(i+0.5-dx,j+0.5-dy) */ \
+    /* positive dx,dy moves pixel i-dx,j-dy to i,y */ \
+    /* also: pixel center is 0.5,0.5 */ \
+    for (int row = 0; row < numRows; row++) { \
+        ps##TYPE* outRow = (*out)->data.TYPE[row]; \
+        psMaskType *outMaskRow = (outMask ? (*outMask)->data.PS_TYPE_MASK_DATA[row] : NULL); \
+        float y = row + 0.5 - dy; \
+        for (int col = 0; col < numCols; col++) { \
+            float x = col + 0.5 - dx; \
+            double value; \
+            psMaskType valueMask; \
+            if (!psImageInterpolate(&value, NULL, &valueMask, x, y, interp)) { \
+                psError(PS_ERR_UNKNOWN, false, "Unable to interpolate image."); \
+                psFree(interp); \
+                return false; \
+            } \
+            outRow[col] = value; \
+            if (outMask) { \
+                outMaskRow[col] = valueMask; \
+            } \
+        } \
+    } \
+    break;
+
+    switch (type) {
+        PSIMAGE_SHIFT_MASK_CASE(U8);
+        PSIMAGE_SHIFT_MASK_CASE(U16);
+        PSIMAGE_SHIFT_MASK_CASE(U32);
+        PSIMAGE_SHIFT_MASK_CASE(U64);
+        PSIMAGE_SHIFT_MASK_CASE(S8);
+        PSIMAGE_SHIFT_MASK_CASE(S16);
+        PSIMAGE_SHIFT_MASK_CASE(S32);
+        PSIMAGE_SHIFT_MASK_CASE(S64);
+        PSIMAGE_SHIFT_MASK_CASE(F32);
+        PSIMAGE_SHIFT_MASK_CASE(F64);
+      default: {
+          char* typeStr;
+          PS_TYPE_NAME(typeStr,type);
+          psError(PS_ERR_BAD_PARAMETER_TYPE, true, _("Specified psImage type, %s, is not supported."),
+                  typeStr);
+          psFree(interp);
+          return false;
+        }
+    }
+
+    psFree(interp);
+    return true;
+}
+
 psImage* psImageTransform(psImage *output,
                           psPixels** blankPixels,
@@ -745,6 +834,6 @@
         // create the output image.
         output = psImageRecycle(output, numCols, numRows, input->type.type);
-	P_PSIMAGE_SET_COL0(output, region.x0);
-	P_PSIMAGE_SET_ROW0(output, region.y0);
+        P_PSIMAGE_SET_COL0(output, region.x0);
+        P_PSIMAGE_SET_ROW0(output, region.y0);
     } else { // size of output is determined by output parameter
         numRows = output->numRows;
Index: trunk/psLib/src/imageops/psImageGeomManip.h
===================================================================
--- trunk/psLib/src/imageops/psImageGeomManip.h	(revision 16873)
+++ trunk/psLib/src/imageops/psImageGeomManip.h	(revision 16910)
@@ -6,6 +6,6 @@
  * @author Robert DeSonia, MHPCC
  *
- * @version $Revision: 1.21 $ $Name: not supported by cvs2svn $
- * @date $Date: 2007-04-05 00:17:29 $
+ * @version $Revision: 1.22 $ $Name: not supported by cvs2svn $
+ * @date $Date: 2008-03-11 00:41:30 $
  * Copyright 2004-2005 Maui High Performance Computing Center, University of Hawaii
  */
@@ -98,4 +98,19 @@
 );
 
+/// Apply a translation to an image
+///
+/// This function is very much like psImageShift, except that it applies the same shifts to the mask
+bool psImageShiftMask(
+    psImage **out,                      ///< Output shifted image
+    psImage **outMask,                  ///< Output shifted mask, or NULL
+    const psImage* in,                  ///< Input image
+    const psImage *inMask,              ///< Input mask, or NULL
+    psMaskType maskVal,                 ///< Value to mask
+    float dx, float dy,                 ///< Shift to apply
+    double exposed,                     ///< Value to give exposed pixels
+    psMaskType blank,                   ///< Mask value for exposed pixels
+    psImageInterpolateMode mode         ///< Interpolation mode
+    );
+
 /** Roll image by an integer number of pixels in either direction.
  *
