Index: trunk/psLib/src/image/psImage.c
===================================================================
--- trunk/psLib/src/image/psImage.c	(revision 2294)
+++ trunk/psLib/src/image/psImage.c	(revision 2375)
@@ -9,6 +9,6 @@
  *  @author Ross Harman, MHPCC
  *
- *  @version $Revision: 1.53 $ $Name: not supported by cvs2svn $
- *  @date $Date: 2004-11-06 00:44:56 $
+ *  @version $Revision: 1.54 $ $Name: not supported by cvs2svn $
+ *  @date $Date: 2004-11-16 20:00:21 $
  *
  *  Copyright 2004 Maui High Performance Computing Center, University of Hawaii
@@ -26,5 +26,34 @@
 #include "psImageErrors.h"
 
-static void imageFree(psImage* image);
+static void imageFree(psImage* image)
+{
+    if (image == NULL) {
+        return;
+    }
+
+    if (image->type.type == PS_TYPE_PTR) {
+        // 2-D array of pointers -- must dereference elements
+        psU32 oldNumRows = image->numRows;
+        psU32 oldNumCols = image->numCols;
+        psPtr* rowPtr;
+
+        for (psU32 row = 0; row < oldNumRows; row++) {
+            rowPtr = image->data.PTR[row];
+            for (psU32 col = 0; col < oldNumCols; col++) {
+                psMemDecrRefCounter(rowPtr[col]);
+            }
+        }
+    }
+
+    if (image->parent != NULL) {
+        psArrayRemove(image->parent->children,image);
+        image->parent = NULL;
+    }
+
+    psImageFreeChildren(image);
+
+    psFree(image->rawDataBuffer);
+    psFree(image->data.V);
+}
 
 psImage* psImageAlloc(psU32 numCols,
@@ -71,34 +100,52 @@
 }
 
-static void imageFree(psImage* image)
+psRegion* psRegionAlloc(double x0,
+                        double x1,
+                        double y0,
+                        double y1)
 {
-    if (image == NULL) {
-        return;
-    }
-
-    if (image->type.type == PS_TYPE_PTR) {
-        // 2-D array of pointers -- must dereference elements
-        psU32 oldNumRows = image->numRows;
-        psU32 oldNumCols = image->numCols;
-        psPtr* rowPtr;
-
-        for (psU32 row = 0; row < oldNumRows; row++) {
-            rowPtr = image->data.PTR[row];
-            for (psU32 col = 0; col < oldNumCols; col++) {
-                psMemDecrRefCounter(rowPtr[col]);
-            }
-        }
-    }
-
-    if (image->parent != NULL) {
-        psArrayRemove(image->parent->children,image);
-        image->parent = NULL;
-    }
-
-    psImageFreeChildren(image);
-
-    psFree(image->rawDataBuffer);
-    psFree(image->data.V);
-}
+    psRegion* out = psAlloc(sizeof(psRegion));
+
+    out->x0 = x0;
+    out->y0 = y0;
+    out->x1 = x1;
+    out->y1 = y1;
+
+    return out;
+}
+
+
+
+psRegion* psRegionFromString(char* region)
+{
+    psS32 col0;
+    psS32 col1;
+    psS32 row0;
+    psS32 row1;
+
+    // section should be of the form '[col0:col1,row0:row1]'
+    if (region == NULL) {
+        psError(PS_ERR_BAD_PARAMETER_NULL, true,
+                PS_ERRORTEXT_psImage_SUBSECTION_NULL);
+        return NULL;
+    }
+
+    if (sscanf(region,"[%d:%d,%d:%d]",&col0,&col1,&row0,&row1) < 4) {
+        psError(PS_ERR_BAD_PARAMETER_NULL, true,
+                PS_ERRORTEXT_psImage_SUBSECTION_INVALID,
+                region);
+        return NULL;
+    }
+
+    if (col0 > col1 || row0 > row1) {
+        psError(PS_ERR_BAD_PARAMETER_VALUE, true,
+                PS_ERRORTEXT_psImage_SUBSET_RANGE_MALFORMED,
+                col0,col1,row0,row1);
+        return NULL;
+    }
+
+    return psRegionAlloc(col0,col1,row0,row1);
+}
+
 
 psImage* psImageRecycle(psImage* old,
Index: trunk/psLib/src/image/psImage.h
===================================================================
--- trunk/psLib/src/image/psImage.h	(revision 2294)
+++ trunk/psLib/src/image/psImage.h	(revision 2375)
@@ -11,6 +11,6 @@
  *  @author Ross Harman, MHPCC
  *
- *  @version $Revision: 1.42 $ $Name: not supported by cvs2svn $
- *  @date $Date: 2004-10-27 00:57:31 $
+ *  @version $Revision: 1.43 $ $Name: not supported by cvs2svn $
+ *  @date $Date: 2004-11-16 20:00:21 $
  *
  *  Copyright 2004 Maui High Performance Computing Center, University of Hawaii
@@ -75,4 +75,18 @@
 psImage;
 
+/** Basic image region structure.
+ *
+ * Struct for specifying a rectangular area in an image.
+ *
+ */
+typedef struct
+{
+    double x0;                         ///< the first column of the region.
+    double x1;                         ///< the last column of the region.
+    double y0;                         ///< the first row of the region.
+    double y1;                         ///< the last row of the region.
+}
+psRegion;
+
 /** Create an image of the specified size and type.
  *
@@ -84,7 +98,26 @@
  */
 psImage* psImageAlloc(
-    psU32 numCols,              ///< Number of rows in image.
-    psU32 numRows,              ///< Number of columns in image.
+    psU32 numCols,                     ///< Number of rows in image.
+    psU32 numRows,                     ///< Number of columns in image.
     const psElemType type              ///< Type of data for image.
+);
+
+/** Create an image of the specified size and type.
+ *
+ * Uses psLib memory allocation functions to create an image struct of the
+ * specified size and type.
+ *
+ * @return psImage* : Pointer to psImage.
+ *
+ */
+psRegion* psRegionAlloc(
+    double x0,                         ///< the first column of the region.
+    double x1,                         ///< the last column of the region.
+    double y0,                         ///< the first row of the region.
+    double y1                          ///< the last row of the region.
+);
+
+psRegion* psRegionFromString(
+    char* region                       ///< image rectangular region in the form '[x0:x1,y0:y1]'
 );
 
@@ -96,6 +129,6 @@
 psImage* psImageRecycle(
     psImage* old,                      ///< the psImage to recycle by resizing image buffer
-    psU32 numCols,              ///< the desired number of columns in image
-    psU32 numRows,              ///< the desired number of rows in image
+    psU32 numCols,                     ///< the desired number of columns in image
+    psU32 numRows,                     ///< the desired number of rows in image
     const psElemType type              ///< the desired datatype of the image
 );
Index: trunk/psLib/src/image/psImageConvolve.c
===================================================================
--- trunk/psLib/src/image/psImageConvolve.c	(revision 2294)
+++ trunk/psLib/src/image/psImageConvolve.c	(revision 2375)
@@ -5,6 +5,6 @@
  *  @author Robert DeSonia, MHPCC
  *
- *  @version $Revision: 1.8 $ $Name: not supported by cvs2svn $
- *  @date $Date: 2004-11-04 01:05:00 $
+ *  @version $Revision: 1.9 $ $Name: not supported by cvs2svn $
+ *  @date $Date: 2004-11-16 20:00:21 $
  *
  *  Copyright 2004 Maui High Performance Computing Center, University of Hawaii
@@ -93,8 +93,10 @@
                            psBool relative)
 {
-    psS32 x = 0;
-    psS32 y = 0;
-    psS32 t = 0;
-    psS32 deltaT;
+    psS32 lastX;
+    psS32 lastY;
+    psS32 lastT;
+    psS32 x;
+    psS32 y;
+    psS32 t;
     psS32 oldX;
     psS32 oldY;
@@ -148,17 +150,11 @@
         ps##TYPE *xShiftData = xShifts->data.TYPE; \
         ps##TYPE *yShiftData = yShifts->data.TYPE; \
-        x = 0; \
-        y = 0; \
-        t = 0; \
-        for (psS32 lcv = 0; lcv < length; lcv++) { \
-            if (relative) { \
-                x += xShiftData[lcv]; \
-                y += yShiftData[lcv]; \
-                t += tShiftData[lcv]; \
-            } else { \
-                x = xShiftData[lcv]; \
-                y = yShiftData[lcv]; \
-                t = tShiftData[lcv]; \
-            } \
+        lastX =  xShiftData[length-1]; \
+        lastY =  yShiftData[length-1]; \
+        \
+        for (int lcv = 0; lcv < length; lcv++) { \
+            x = lastX - xShiftData[lcv]; \
+            y = lastY - yShiftData[lcv]; \
+            \
             if (x < xMin) { \
                 xMin = x; \
@@ -172,51 +168,108 @@
             } \
         } \
+        \
+        normalizeTime = 1.0 / (psKernelType)(lastT - tShiftData[0]); \
         result = psKernelAlloc(xMin,xMax,yMin,yMax); \
         kernel = result->kernel; \
         \
-        normalizeTime = 1.0 / (psKernelType)(t); \
+        lastT = 0; \
+        for (int i = 0; i < length; i++) { \
+            t = tShiftData[i] - lastT; \
+            x = lastX - xShiftData[i]; \
+            y = lastY - yShiftData[i]; \
+            \
+            kernel[y][x] += (psKernelType)t * normalizeTime; \
+            lastT = t; \
+        } \
+        break; \
+    }
+
+    #define RELATIVE_KERNEL_GENERATE_CASE(TYPE) \
+case PS_TYPE_##TYPE: { \
+        ps##TYPE *tShiftData = tShifts->data.TYPE; \
+        ps##TYPE *xShiftData = xShifts->data.TYPE; \
+        ps##TYPE *yShiftData = yShifts->data.TYPE; \
+        \
         x = 0; \
         y = 0; \
         t = 0; \
-        for (psS32 i = 0; i < length; i++) { \
-            deltaT = t; \
-            oldX = x; \
-            oldY = y; \
-            if (relative) { \
-                t += tShiftData[i]; \
-                x += xShiftData[i]; \
-                y += yShiftData[i]; \
-            } else { \
-                t = tShiftData[i]; \
-                x = xShiftData[i]; \
-                y = yShiftData[i]; \
+        \
+        for (int lcv = length-1; lcv >= 0; lcv--) { \
+            t += tShiftData[lcv]; \
+            \
+            if (x < xMin) { \
+                xMin = x; \
+            } else if (x > xMax) { \
+                xMax = x; \
             } \
-            deltaT = t - deltaT; \
+            if (y < yMin) { \
+                yMin = y; \
+            } else if (y > yMax) { \
+                yMax = y; \
+            } \
+            x += xShiftData[lcv]; \
+            y += yShiftData[lcv]; \
             \
-            kernel[oldY][oldX] += deltaT * normalizeTime; \
+        } \
+        result = psKernelAlloc(xMin,xMax,yMin,yMax); \
+        kernel = result->kernel; \
+        \
+        normalizeTime = 1.0 / (psKernelType)t; \
+        x = 0; \
+        y = 0; \
+        for (psS32 i = length-1; i >= 0; i--) { \
+            kernel[y][x] += (psKernelType)(tShiftData[i]) * normalizeTime; \
+            x += xShiftData[i]; \
+            y += yShiftData[i]; \
+            \
         } \
         break; \
     }
 
-    switch (xShifts->type.type) {
-        KERNEL_GENERATE_CASE(U8);
-        KERNEL_GENERATE_CASE(U16);
-        KERNEL_GENERATE_CASE(U32);
-        KERNEL_GENERATE_CASE(U64);
-        KERNEL_GENERATE_CASE(S8);
-        KERNEL_GENERATE_CASE(S16);
-        KERNEL_GENERATE_CASE(S32);
-        KERNEL_GENERATE_CASE(S64);
-        KERNEL_GENERATE_CASE(F32);
-        KERNEL_GENERATE_CASE(F64);
-        KERNEL_GENERATE_CASE(C32);
-        KERNEL_GENERATE_CASE(C64);
-
-    default: {
-            char* typeStr;
-            PS_TYPE_NAME(typeStr,xShifts->type.type);
-            psError(PS_ERR_BAD_PARAMETER_TYPE, true,
-                    PS_ERRORTEXT_psImage_IMAGE_TYPE_UNSUPPORTED,
-                    typeStr);
+    if (relative) {
+        switch (xShifts->type.type) {
+            RELATIVE_KERNEL_GENERATE_CASE(U8);
+            RELATIVE_KERNEL_GENERATE_CASE(U16);
+            RELATIVE_KERNEL_GENERATE_CASE(U32);
+            RELATIVE_KERNEL_GENERATE_CASE(U64);
+            RELATIVE_KERNEL_GENERATE_CASE(S8);
+            RELATIVE_KERNEL_GENERATE_CASE(S16);
+            RELATIVE_KERNEL_GENERATE_CASE(S32);
+            RELATIVE_KERNEL_GENERATE_CASE(S64);
+            RELATIVE_KERNEL_GENERATE_CASE(F32);
+            RELATIVE_KERNEL_GENERATE_CASE(F64);
+            RELATIVE_KERNEL_GENERATE_CASE(C32);
+            RELATIVE_KERNEL_GENERATE_CASE(C64);
+
+        default: {
+                char* typeStr;
+                PS_TYPE_NAME(typeStr,xShifts->type.type);
+                psError(PS_ERR_BAD_PARAMETER_TYPE, true,
+                        PS_ERRORTEXT_psImage_IMAGE_TYPE_UNSUPPORTED,
+                        typeStr);
+            }
+        }
+    } else {
+        switch (xShifts->type.type) {
+            KERNEL_GENERATE_CASE(U8);
+            KERNEL_GENERATE_CASE(U16);
+            KERNEL_GENERATE_CASE(U32);
+            KERNEL_GENERATE_CASE(U64);
+            KERNEL_GENERATE_CASE(S8);
+            KERNEL_GENERATE_CASE(S16);
+            KERNEL_GENERATE_CASE(S32);
+            KERNEL_GENERATE_CASE(S64);
+            KERNEL_GENERATE_CASE(F32);
+            KERNEL_GENERATE_CASE(F64);
+            KERNEL_GENERATE_CASE(C32);
+            KERNEL_GENERATE_CASE(C64);
+
+        default: {
+                char* typeStr;
+                PS_TYPE_NAME(typeStr,xShifts->type.type);
+                psError(PS_ERR_BAD_PARAMETER_TYPE, true,
+                        PS_ERRORTEXT_psImage_IMAGE_TYPE_UNSUPPORTED,
+                        typeStr);
+            }
         }
     }
Index: trunk/psLib/src/image/psImageErrors.h
===================================================================
--- trunk/psLib/src/image/psImageErrors.h	(revision 2294)
+++ trunk/psLib/src/image/psImageErrors.h	(revision 2375)
@@ -7,6 +7,6 @@
  *  @author Robert DeSonia, MHPCC
  *
- *  @version $Revision: 1.10 $ $Name: not supported by cvs2svn $
- *  @date $Date: 2004-10-13 23:34:57 $
+ *  @version $Revision: 1.11 $ $Name: not supported by cvs2svn $
+ *  @date $Date: 2004-11-16 20:00:21 $
  *
  *  Copyright 2004 Maui High Performance Computing Center, University of Hawaii
Index: trunk/psLib/src/image/psImageManip.h
===================================================================
--- trunk/psLib/src/image/psImageManip.h	(revision 2294)
+++ trunk/psLib/src/image/psImageManip.h	(revision 2375)
@@ -11,6 +11,6 @@
  *  @author Ross Harman, MHPCC
  *
- *  @version $Revision: 1.14 $ $Name: not supported by cvs2svn $
- *  @date $Date: 2004-10-27 00:57:31 $
+ *  @version $Revision: 1.15 $ $Name: not supported by cvs2svn $
+ *  @date $Date: 2004-11-16 20:00:21 $
  *
  *  Copyright 2004 Maui High Performance Computing Center, University of Hawaii
@@ -83,6 +83,6 @@
     psImage* image,                    ///< target image
     const psImage* overlay,            ///< the overlay image
-    psS32 col0,                          ///< the column to start overlay
-    psS32 row0,                          ///< the row to start overlay
+    psS32 col0,                        ///< the column to start overlay
+    psS32 row0,                        ///< the row to start overlay
     const char *op                     ///< the operation to perform for overlay
 );
@@ -103,5 +103,5 @@
     const psImage* restrict mask,      ///< mask for input image.  If NULL, no masking is done.
     psMaskType maskVal,                ///< the bits to check in mask.
-    psU32 scale,                ///< the scale to rebin for each dimension
+    psU32 scale,                       ///< the scale to rebin for each dimension
     const psStats* stats
     ///< the statistic to perform when rebinning.  Only one method should be set.
@@ -121,5 +121,5 @@
     psImage* out,                      ///< an psImage to recycle.  If NULL, a new image is created
     const psImage* in,                 ///< input image
-    psS32 scale,                         ///< resample scaling factor
+    psS32 scale,                       ///< resample scaling factor
     psImageInterpolateMode mode        ///< the interpolation mode used in resampling
 );
@@ -176,6 +176,6 @@
     psImage* out,                      ///< an psImage to recycle.  If NULL, a new image is created
     const psImage* in,                 ///< input image
-    psS32 dx,                            ///< number of pixels to roll in the x-dimension
-    psS32 dy                             ///< number of pixels to roll in the y-dimension
+    psS32 dx,                          ///< number of pixels to roll in the x-dimension
+    psS32 dy                           ///< number of pixels to roll in the y-dimension
 );
 
