Index: trunk/psLib/src/image/psImageManip.c
===================================================================
--- trunk/psLib/src/image/psImageManip.c	(revision 1216)
+++ trunk/psLib/src/image/psImageManip.c	(revision 1226)
@@ -10,6 +10,6 @@
  *  @author Ross Harman, MHPCC
  *
- *  @version $Revision: 1.2 $ $Name: not supported by cvs2svn $
- *  @date $Date: 2004-07-14 23:22:49 $
+ *  @version $Revision: 1.3 $ $Name: not supported by cvs2svn $
+ *  @date $Date: 2004-07-15 19:58:37 $
  *
  *  Copyright 2004 Maui High Performance Computing Center, University of Hawaii
@@ -18,4 +18,5 @@
 #include <stdlib.h>
 #include <stdbool.h>
+#include <string.h>                    // for memcpy, etc.
 
 #include "psError.h"
@@ -50,21 +51,19 @@
             if (vmin < PS_MIN_##type || vmin > PS_MAX_##type) { \
                 psError(__func__, "Specified vmin (%g) is outside of image's " \
-                        typename " pixel range", \
-                        vmin); \
+                        typename " pixel range (%g to %g)", \
+                        vmin,(psF64)PS_MIN_##type,(psF64)PS_MAX_##type); \
             } \
             if (vmax > PS_MAX_##type || vmax < PS_MIN_##type) { \
                 psError(__func__, "Specified vmax (%g) is outside of image's " \
-                        typename " pixel range", \
-                        vmax); \
-            } \
-            ps##type minimum = (ps##type) min; \
-            ps##type maximum = (ps##type) max; \
+                        typename " pixel range (%g to %g)", \
+                        vmax,(psF64)PS_MIN_##type,(psF64)PS_MAX_##type); \
+            } \
             for (unsigned int row = 0;row<numRows;row++) { \
                 ps##type* inputRow = input->data.type[row]; \
                 for (unsigned int col = 0; col < numCols; col++) { \
-                    if (inputRow[col] < minimum) { \
+                    if ((psF64)inputRow[col] < min) { \
                         inputRow[col] = (ps##type)vmin; \
                         numClipped++; \
-                    } else if (inputRow[col] > maximum) { \
+                    } else if ((psF64)inputRow[col] > max) { \
                         inputRow[col] = (ps##type)vmax; \
                         numClipped++; \
@@ -341,5 +340,5 @@
 
     switch (stats->options &
-            ! (PS_STAT_USE_RANGE | PS_STAT_USE_BINSIZE | PS_STAT_ROBUST_FOR_SAMPLE)) {
+            ~ (PS_STAT_USE_RANGE | PS_STAT_USE_BINSIZE | PS_STAT_ROBUST_FOR_SAMPLE)) {
     case PS_STAT_SAMPLE_MEAN:
         *value = stats->sampleMean;
@@ -484,2 +483,46 @@
     return out;
 }
+
+psImage* psImageRoll(psImage* out, const psImage* in, int dx, int dy)
+{
+    int outRows;
+    int outCols;
+    int elementSize;
+
+    if (in == NULL) {
+        psError(__func__,"Input image can not be NULL.");
+        return NULL;
+    }
+
+    // create an output image of the same size and type
+    outRows = in->numRows;
+    outCols = in->numCols;
+    elementSize = PSELEMTYPE_SIZEOF(in->type.type);
+    out = psImageRecycle(out,outCols, outRows, in->type.type);
+
+    // make dx and dy between 0 and outCols or outRows, respectively
+    dx = dx % outCols;
+    dy = dy % outRows;
+    if (dx < 0) {
+        dx += outCols;
+    }
+    if (dy < 0) {
+        dy += outRows;
+    }
+
+    int segment1Size = elementSize*(outCols-dx);
+    int segment2Size = elementSize*dx;
+
+    for (int row=0;row<outRows;row++) {
+        int inRowNumber = row+dy;
+        if (inRowNumber >= outRows) {
+            inRowNumber -= outRows;
+        }
+        psU8* inRow = in->data.U8[inRowNumber]; // to allow byte arithmetic, but for all types
+        psU8* outRow = out->data.U8[row];
+        memcpy(outRow,inRow+segment2Size,segment1Size);
+        memcpy(outRow+segment1Size,inRow,segment2Size);
+    }
+
+    return out;
+}
