Index: /trunk/psLib/src/image/psImageConvolve.c
===================================================================
--- /trunk/psLib/src/image/psImageConvolve.c	(revision 1862)
+++ /trunk/psLib/src/image/psImageConvolve.c	(revision 1863)
@@ -5,12 +5,15 @@
  *  @author Robert DeSonia, MHPCC
  *
- *  @version $Revision: 1.2 $ $Name: not supported by cvs2svn $
- *  @date $Date: 2004-09-21 22:30:19 $
+ *  @version $Revision: 1.3 $ $Name: not supported by cvs2svn $
+ *  @date $Date: 2004-09-23 18:30:57 $
  *
  *  Copyright 2004 Maui High Performance Computing Center, University of Hawaii
  */
 
+#include <string.h>
+
 #include "psImageConvolve.h"
 #include "psImageFFT.h"
+#include "psMatrixVectorArithmetic.h"
 #include "psMemory.h"
 #include "psLogMsg.h"
@@ -27,4 +30,5 @@
     int numCols;
 
+    // following is explicitly spelled out in the SDRS as a requirement
     if (yMin > yMax) {
         int temp = yMin;
@@ -37,4 +41,5 @@
     }
 
+    // following is explicitly spelled out in the SDRS as a requirement
     if (xMin > xMax) {
         int temp = xMin;
@@ -55,9 +60,9 @@
     result->yMin = yMin;
     result->yMax = yMax;
-    result->p_data = psImageAlloc(numCols,numRows,PS_TYPE_F32);
-    result->p_kernelRows = psAlloc(sizeof(psF32*)*numRows);
-
-    psF32** kernelRows = result->p_kernelRows;
-    psF32** imageRows = result->p_data->data.F32;
+    result->image = psImageAlloc(numCols,numRows,PS_TYPE_KERNEL);
+    result->p_kernelRows = psAlloc(sizeof(psKernelType*)*numRows);
+
+    psKernelType** kernelRows = result->p_kernelRows;
+    psKernelType** imageRows = result->image->data.PS_TYPE_KERNEL_DATA;
     for (int i = 0; i < numRows; i++) {
         kernelRows[i] = imageRows[i] - xMin;
@@ -73,13 +78,18 @@
 {
     if (ptr != NULL) {
-        psFree(ptr->p_data);
+        psFree(ptr->image);
         psFree(ptr->p_kernelRows);
     }
 }
 
-psKernel* psKernelGenerate(const psVector* xShifts, const psVector* yShifts)
+psKernel* psKernelGenerate(const psVector* tShifts,
+                           const psVector* xShifts,
+                           const psVector* yShifts,
+                           bool relative)
 {
     int x = 0;
     int y = 0;
+    int t = 0;
+    int deltaT = 0;
     int xMin = 0;
     int xMax = 0;
@@ -87,7 +97,7 @@
     int yMax = 0;
     int length = 0;
-    psF32 relativeTime = 1.0f;            // fraction of total time for each shift clock
+    psKernelType normalizeTime = 1.0;  // fraction of total time for each shift clock
     psKernel* result = NULL;
-    psF32** kernel = NULL;
+    psKernelType** kernel = NULL;
 
     // got non-NULL vectors?
@@ -100,36 +110,45 @@
 
     // types match?
-    if (xShifts->type.type != yShifts->type.type) {
+    if (xShifts->type.type != yShifts->type.type ||
+            tShifts->type.type != xShifts->type.type) {
         char* typeXStr;
         char* typeYStr;
+        char* typeTStr;
         PS_TYPE_NAME(typeXStr,xShifts->type.type);
         PS_TYPE_NAME(typeYStr,yShifts->type.type);
+        PS_TYPE_NAME(typeTStr,tShifts->type.type);
         psErrorMsg(PS_ERRORNAME_DOMAIN "psKernelGenerate",
                    PS_ERR_BAD_PARAMETER_TYPE, true,
                    PS_ERRORTEXT_psImageConvolve_SHIFT_TYPE_MISMATCH,
-                   typeXStr, typeYStr);
+                   typeTStr, typeXStr, typeYStr);
         return NULL;
     }
 
     // determine the usable length of the shift vector
-    if (xShifts->n != yShifts->n) {
+    length = xShifts->n;
+    if (length != yShifts->n ||
+            length != tShifts->n) {
         psLogMsg(__func__,PS_LOG_WARN,"Shift vectors found to be different sizes.");
-        length = xShifts->n;
         if (yShifts->n < length) {
             length = yShifts->n;
         }
-    } else {
-        length = xShifts->n;
-    }
-    relativeTime = 1 / (1+length); // 1+length 'cause we count origin before shift
-    // e.g., 1 time unit at origin + a time unit for each shift clock
+        if (tShifts->n < length) {
+            length = tShifts->n;
+        }
+    }
 
     #define 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; \
         for (int lcv = 0; lcv < length; lcv++) { \
-            x += xShiftData[lcv]; \
-            y += yShiftData[lcv]; \
+            if (relative) { \
+                x += xShiftData[lcv]; \
+                y += yShiftData[lcv]; \
+            } else { \
+                x = xShiftData[lcv]; \
+                y = yShiftData[lcv]; \
+            } \
             if (x < xMin) { \
                 xMin = x; \
@@ -146,12 +165,22 @@
         kernel = result->kernel; \
         \
-        kernel[0][0]+=relativeTime;    /* mark the original point as one exposure. */ \
-        \
-        x = 0; \
-        y = 0; \
-        for (int i = 0; i < length; i++) { \
-            x += xShiftData[i]; \
-            y += yShiftData[i]; \
-            kernel[y][x]+=relativeTime; \
+        x = xShiftData[0]; \
+        y = yShiftData[0]; \
+        t = tShiftData[0]; \
+        normalizeTime = 1.0 / (psKernelType)(tShiftData[length-1]-t); \
+        for (int i = 1; i < length; i++) { \
+            deltaT = t; \
+            if (relative) { \
+                t += tShiftData[i]; \
+                x += xShiftData[i]; \
+                y += yShiftData[i]; \
+            } else { \
+                t = tShiftData[i]; \
+                x = xShiftData[i]; \
+                y = yShiftData[i]; \
+            } \
+            deltaT = t - deltaT; \
+            \
+            kernel[y][x] += deltaT * normalizeTime; \
         } \
     }
@@ -186,6 +215,154 @@
 psImage* psImageConvolve(psImage* out, const psImage* in, const psKernel* kernel, bool direct)
 {
-
-
-    return NULL;
+    if (in == NULL) {
+        psFree(out);
+        return NULL;
+    }
+
+    if (kernel == NULL) {
+        psErrorMsg(PS_ERRORNAME_DOMAIN "psImageConvolve",
+                   PS_ERR_BAD_PARAMETER_NULL, true,
+                   PS_ERRORTEXT_psImageConvolve_KERNEL_NULL);
+        psFree(out);
+        return NULL;
+    }
+    int xMin = kernel->xMin;
+    int xMax = kernel->xMax;
+    int yMin = kernel->yMin;
+    int yMax = kernel->yMax;
+    psKernelType** kData = kernel->kernel;
+
+    // make the output image to the proper size and type
+    int numRows = in->numRows;
+    int numCols = in->numCols;
+
+
+
+    if (direct) {
+        // spatial convolution
+
+        #define SPATIAL_CONVOLVE_CASE(TYPE) \
+    case PS_TYPE_##TYPE: { \
+            ps##TYPE** inData = in->data.TYPE; \
+            out = psImageRecycle(out, numCols, numRows, PS_TYPE_##TYPE); \
+            for (int row=0;row<numRows;row++) { \
+                ps##TYPE* outRow = out->data.TYPE[row]; \
+                for (int col=0;col<numCols;col++) { \
+                    ps##TYPE pixel = 0.0; \
+                    for (int kRow = yMin; kRow < yMax; kRow++) { \
+                        if (row-kRow >= 0 && row-kRow < numRows) { \
+                            for (int kCol = xMin; kCol < xMax; kCol++) { \
+                                if (col-kCol >= 0 && col-kCol < numCols) { \
+                                    pixel += kData[kRow][kCol] * inData[row-kRow][col-kCol]; \
+                                } \
+                            } \
+                        } \
+                    } \
+                    outRow[col] = pixel; \
+                } \
+            } \
+        } \
+        break;
+
+        switch (in->type.type) {
+            SPATIAL_CONVOLVE_CASE(U8)
+            SPATIAL_CONVOLVE_CASE(U16)
+            SPATIAL_CONVOLVE_CASE(U32)
+            SPATIAL_CONVOLVE_CASE(U64)
+            SPATIAL_CONVOLVE_CASE(S8)
+            SPATIAL_CONVOLVE_CASE(S16)
+            SPATIAL_CONVOLVE_CASE(S32)
+            SPATIAL_CONVOLVE_CASE(S64)
+            SPATIAL_CONVOLVE_CASE(F32)
+            SPATIAL_CONVOLVE_CASE(F64)
+            SPATIAL_CONVOLVE_CASE(C32)
+            SPATIAL_CONVOLVE_CASE(C64)
+
+        default: {
+                char* typeStr;
+                PS_TYPE_NAME(typeStr,in->type.type);
+                psErrorMsg(PS_ERRORNAME_DOMAIN "psImageConvolve",
+                           PS_ERR_BAD_PARAMETER_TYPE, true,
+                           PS_ERRORTEXT_psImage_IMAGE_TYPE_UNSUPPORTED,
+                           typeStr);
+                psFree(out);
+                return NULL;
+
+            }
+        }
+
+
+    } else {
+        // fourier convolution
+        int kRows = kernel->image->numRows;
+        int kCols = kernel->image->numCols;
+        int x0 = (numCols - kCols) / 2;
+        int y0 = (numRows - kRows) / 2;
+        psImage* paddedKernel;
+
+        // check to see if kernel is smaller, otherwise padding it up will fail.
+        if (x0 < 0 || y0 < 0) {
+            psErrorMsg(PS_ERRORNAME_DOMAIN "psImageConvolve",
+                       PS_ERR_BAD_PARAMETER_SIZE, true,
+                       PS_ERRORTEXT_psImageConvolve_KERNEL_TOO_LARGE,
+                       kernel->image->numCols,kernel->image->numRows,
+                       numCols, numRows);
+            psFree(out);
+            return NULL;
+        }
+
+        // pad the kernel to the same size of image
+        paddedKernel = psImageAlloc(numCols,numRows,PS_TYPE_KERNEL);
+        memset(paddedKernel->data.V,0,sizeof(psKernelType)*numCols*numRows); // zeroize image
+        for (int row=0;row<kRows;row++) {
+            psKernelType* padRow = paddedKernel->data.PS_TYPE_KERNEL_DATA[row+y0];
+            psKernelType* kernelRow = kernel->image->data.PS_TYPE_KERNEL_DATA[row];
+            for (int col=0;col<kCols;col++) {
+                padRow[col+x0] = kernelRow[col];
+            }
+        }
+
+        psImage* kernelFourier = psImageFFT(NULL, paddedKernel, PS_FFT_FORWARD);
+        if (kernelFourier == NULL) {
+            psErrorMsg(PS_ERRORNAME_DOMAIN "psImageConvolve",
+                       PS_ERR_UNKNOWN, false,
+                       PS_ERRORTEXT_psImageConvolve_KERNEL_FFT_FAILED);
+            psFree(out);
+            return NULL;
+        }
+
+
+        psImage* inFourier = psImageFFT(NULL, in, PS_FFT_FORWARD);
+        if (inFourier == NULL) {
+            psErrorMsg(PS_ERRORNAME_DOMAIN "psImageConvolve",
+                       PS_ERR_UNKNOWN, false,
+                       PS_ERRORTEXT_psImageConvolve_FFT_FAILED);
+            psFree(out);
+            return NULL;
+        }
+
+        // convolution in fourier domain is just a pixel-wise multiplication
+        psImage* outFourier = psImageAlloc(numCols,numRows,inFourier->type.type);
+        psBinaryOp(outFourier,inFourier,"*",kernelFourier);
+
+        psImage* complexOut = psImageFFT(NULL, outFourier, PS_FFT_REVERSE);
+        if (complexOut == NULL) {
+            psErrorMsg(PS_ERRORNAME_DOMAIN "psImageConvolve",
+                       PS_ERR_UNKNOWN, false,
+                       PS_ERRORTEXT_psImageConvolve_FFT_FAILED);
+            psFree(out);
+            return NULL;
+        }
+
+        // since our image was real to start, the result is real
+        out = psImageReal(out,complexOut);
+
+        psFree(complexOut);
+        psFree(kernelFourier);
+        psFree(inFourier);
+        psFree(paddedKernel);
+
+    }
+
+    return out;
 }
Index: /trunk/psLib/src/image/psImageConvolve.h
===================================================================
--- /trunk/psLib/src/image/psImageConvolve.h	(revision 1862)
+++ /trunk/psLib/src/image/psImageConvolve.h	(revision 1863)
@@ -7,12 +7,12 @@
  *  @author Robert DeSonia, MHPCC
  *
- *  @version $Revision: 1.1 $ $Name: not supported by cvs2svn $
- *  @date $Date: 2004-08-28 01:18:28 $
+ *  @version $Revision: 1.2 $ $Name: not supported by cvs2svn $
+ *  @date $Date: 2004-09-23 18:30:57 $
  *
  *  Copyright 2004 Maui High Performance Computing Center, University of Hawaii
  */
 
-#ifndef PS_IMAGE_FFT_H
-#define PS_IMAGE_FFT_H
+#ifndef PS_IMAGE_CONVOLVE_H
+#define PS_IMAGE_CONVOLVE_H
 
 #include<stdbool.h>
@@ -20,15 +20,22 @@
 #include "psImage.h"
 #include "psVector.h"
+#include "psType.h"
+
+#define PS_TYPE_KERNEL PS_TYPE_F32     /**< the data member to use for kernel image */
+#define PS_TYPE_KERNEL_DATA F32        /**< the data member to use for kernel image */
+#define PS_TYPE_KERNEL_NAME "psF32"    /**< the data type for kernel as a string */
+
+typedef psF32 psKernelType;
 
 /** A convolution kernel */
 typedef struct
 {
+    psImage* image;                    ///< Kernel data, in the form of an image
     int xMin;                          ///< Most negative x index
     int yMin;                          ///< Most negative y index
     int xMax;                          ///< Most positive x index
     int yMax;                          ///< Most positive y index
-    psF32** kernel;                    ///< Pointer to the kernel data
-    psF32** p_kernelRows;              ///< Pointer to the rows of the kernel data
-    psImage* p_data;                   ///< Kernel data, in the form of an image
+    psKernelType** kernel;             ///< Pointer to the kernel data
+    psKernelType** p_kernelRows;       ///< Pointer to the rows of the kernel data; not intended for user use.
 }
 psKernel;
@@ -62,6 +69,6 @@
 psKernel* psKernelAlloc(
     int xMin,                          ///< Most negative x index
-    int xMax,                          ///< Most negative y index
-    int yMin,                          ///< Most positive x index
+    int xMax,                          ///< Most positive x index
+    int yMin,                          ///< Most negative y index
     int yMax                           ///< Most positive y index
 );
@@ -84,6 +91,8 @@
  */
 psKernel* psKernelGenerate(
-    const psVector* xShifts,           ///< list of shifts relative to a reference point
-    const psVector* yShifts            ///< list of shifts relative to a reference point
+    const psVector* tShifts,           ///< list of time shifts
+    const psVector* xShifts,           ///< list of x-axis shifts
+    const psVector* yShifts,           ///< list of y-axis shifts
+    bool relative
 );
 
Index: /trunk/psLib/src/imageops/psImageConvolve.c
===================================================================
--- /trunk/psLib/src/imageops/psImageConvolve.c	(revision 1862)
+++ /trunk/psLib/src/imageops/psImageConvolve.c	(revision 1863)
@@ -5,12 +5,15 @@
  *  @author Robert DeSonia, MHPCC
  *
- *  @version $Revision: 1.2 $ $Name: not supported by cvs2svn $
- *  @date $Date: 2004-09-21 22:30:19 $
+ *  @version $Revision: 1.3 $ $Name: not supported by cvs2svn $
+ *  @date $Date: 2004-09-23 18:30:57 $
  *
  *  Copyright 2004 Maui High Performance Computing Center, University of Hawaii
  */
 
+#include <string.h>
+
 #include "psImageConvolve.h"
 #include "psImageFFT.h"
+#include "psMatrixVectorArithmetic.h"
 #include "psMemory.h"
 #include "psLogMsg.h"
@@ -27,4 +30,5 @@
     int numCols;
 
+    // following is explicitly spelled out in the SDRS as a requirement
     if (yMin > yMax) {
         int temp = yMin;
@@ -37,4 +41,5 @@
     }
 
+    // following is explicitly spelled out in the SDRS as a requirement
     if (xMin > xMax) {
         int temp = xMin;
@@ -55,9 +60,9 @@
     result->yMin = yMin;
     result->yMax = yMax;
-    result->p_data = psImageAlloc(numCols,numRows,PS_TYPE_F32);
-    result->p_kernelRows = psAlloc(sizeof(psF32*)*numRows);
-
-    psF32** kernelRows = result->p_kernelRows;
-    psF32** imageRows = result->p_data->data.F32;
+    result->image = psImageAlloc(numCols,numRows,PS_TYPE_KERNEL);
+    result->p_kernelRows = psAlloc(sizeof(psKernelType*)*numRows);
+
+    psKernelType** kernelRows = result->p_kernelRows;
+    psKernelType** imageRows = result->image->data.PS_TYPE_KERNEL_DATA;
     for (int i = 0; i < numRows; i++) {
         kernelRows[i] = imageRows[i] - xMin;
@@ -73,13 +78,18 @@
 {
     if (ptr != NULL) {
-        psFree(ptr->p_data);
+        psFree(ptr->image);
         psFree(ptr->p_kernelRows);
     }
 }
 
-psKernel* psKernelGenerate(const psVector* xShifts, const psVector* yShifts)
+psKernel* psKernelGenerate(const psVector* tShifts,
+                           const psVector* xShifts,
+                           const psVector* yShifts,
+                           bool relative)
 {
     int x = 0;
     int y = 0;
+    int t = 0;
+    int deltaT = 0;
     int xMin = 0;
     int xMax = 0;
@@ -87,7 +97,7 @@
     int yMax = 0;
     int length = 0;
-    psF32 relativeTime = 1.0f;            // fraction of total time for each shift clock
+    psKernelType normalizeTime = 1.0;  // fraction of total time for each shift clock
     psKernel* result = NULL;
-    psF32** kernel = NULL;
+    psKernelType** kernel = NULL;
 
     // got non-NULL vectors?
@@ -100,36 +110,45 @@
 
     // types match?
-    if (xShifts->type.type != yShifts->type.type) {
+    if (xShifts->type.type != yShifts->type.type ||
+            tShifts->type.type != xShifts->type.type) {
         char* typeXStr;
         char* typeYStr;
+        char* typeTStr;
         PS_TYPE_NAME(typeXStr,xShifts->type.type);
         PS_TYPE_NAME(typeYStr,yShifts->type.type);
+        PS_TYPE_NAME(typeTStr,tShifts->type.type);
         psErrorMsg(PS_ERRORNAME_DOMAIN "psKernelGenerate",
                    PS_ERR_BAD_PARAMETER_TYPE, true,
                    PS_ERRORTEXT_psImageConvolve_SHIFT_TYPE_MISMATCH,
-                   typeXStr, typeYStr);
+                   typeTStr, typeXStr, typeYStr);
         return NULL;
     }
 
     // determine the usable length of the shift vector
-    if (xShifts->n != yShifts->n) {
+    length = xShifts->n;
+    if (length != yShifts->n ||
+            length != tShifts->n) {
         psLogMsg(__func__,PS_LOG_WARN,"Shift vectors found to be different sizes.");
-        length = xShifts->n;
         if (yShifts->n < length) {
             length = yShifts->n;
         }
-    } else {
-        length = xShifts->n;
-    }
-    relativeTime = 1 / (1+length); // 1+length 'cause we count origin before shift
-    // e.g., 1 time unit at origin + a time unit for each shift clock
+        if (tShifts->n < length) {
+            length = tShifts->n;
+        }
+    }
 
     #define 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; \
         for (int lcv = 0; lcv < length; lcv++) { \
-            x += xShiftData[lcv]; \
-            y += yShiftData[lcv]; \
+            if (relative) { \
+                x += xShiftData[lcv]; \
+                y += yShiftData[lcv]; \
+            } else { \
+                x = xShiftData[lcv]; \
+                y = yShiftData[lcv]; \
+            } \
             if (x < xMin) { \
                 xMin = x; \
@@ -146,12 +165,22 @@
         kernel = result->kernel; \
         \
-        kernel[0][0]+=relativeTime;    /* mark the original point as one exposure. */ \
-        \
-        x = 0; \
-        y = 0; \
-        for (int i = 0; i < length; i++) { \
-            x += xShiftData[i]; \
-            y += yShiftData[i]; \
-            kernel[y][x]+=relativeTime; \
+        x = xShiftData[0]; \
+        y = yShiftData[0]; \
+        t = tShiftData[0]; \
+        normalizeTime = 1.0 / (psKernelType)(tShiftData[length-1]-t); \
+        for (int i = 1; i < length; i++) { \
+            deltaT = t; \
+            if (relative) { \
+                t += tShiftData[i]; \
+                x += xShiftData[i]; \
+                y += yShiftData[i]; \
+            } else { \
+                t = tShiftData[i]; \
+                x = xShiftData[i]; \
+                y = yShiftData[i]; \
+            } \
+            deltaT = t - deltaT; \
+            \
+            kernel[y][x] += deltaT * normalizeTime; \
         } \
     }
@@ -186,6 +215,154 @@
 psImage* psImageConvolve(psImage* out, const psImage* in, const psKernel* kernel, bool direct)
 {
-
-
-    return NULL;
+    if (in == NULL) {
+        psFree(out);
+        return NULL;
+    }
+
+    if (kernel == NULL) {
+        psErrorMsg(PS_ERRORNAME_DOMAIN "psImageConvolve",
+                   PS_ERR_BAD_PARAMETER_NULL, true,
+                   PS_ERRORTEXT_psImageConvolve_KERNEL_NULL);
+        psFree(out);
+        return NULL;
+    }
+    int xMin = kernel->xMin;
+    int xMax = kernel->xMax;
+    int yMin = kernel->yMin;
+    int yMax = kernel->yMax;
+    psKernelType** kData = kernel->kernel;
+
+    // make the output image to the proper size and type
+    int numRows = in->numRows;
+    int numCols = in->numCols;
+
+
+
+    if (direct) {
+        // spatial convolution
+
+        #define SPATIAL_CONVOLVE_CASE(TYPE) \
+    case PS_TYPE_##TYPE: { \
+            ps##TYPE** inData = in->data.TYPE; \
+            out = psImageRecycle(out, numCols, numRows, PS_TYPE_##TYPE); \
+            for (int row=0;row<numRows;row++) { \
+                ps##TYPE* outRow = out->data.TYPE[row]; \
+                for (int col=0;col<numCols;col++) { \
+                    ps##TYPE pixel = 0.0; \
+                    for (int kRow = yMin; kRow < yMax; kRow++) { \
+                        if (row-kRow >= 0 && row-kRow < numRows) { \
+                            for (int kCol = xMin; kCol < xMax; kCol++) { \
+                                if (col-kCol >= 0 && col-kCol < numCols) { \
+                                    pixel += kData[kRow][kCol] * inData[row-kRow][col-kCol]; \
+                                } \
+                            } \
+                        } \
+                    } \
+                    outRow[col] = pixel; \
+                } \
+            } \
+        } \
+        break;
+
+        switch (in->type.type) {
+            SPATIAL_CONVOLVE_CASE(U8)
+            SPATIAL_CONVOLVE_CASE(U16)
+            SPATIAL_CONVOLVE_CASE(U32)
+            SPATIAL_CONVOLVE_CASE(U64)
+            SPATIAL_CONVOLVE_CASE(S8)
+            SPATIAL_CONVOLVE_CASE(S16)
+            SPATIAL_CONVOLVE_CASE(S32)
+            SPATIAL_CONVOLVE_CASE(S64)
+            SPATIAL_CONVOLVE_CASE(F32)
+            SPATIAL_CONVOLVE_CASE(F64)
+            SPATIAL_CONVOLVE_CASE(C32)
+            SPATIAL_CONVOLVE_CASE(C64)
+
+        default: {
+                char* typeStr;
+                PS_TYPE_NAME(typeStr,in->type.type);
+                psErrorMsg(PS_ERRORNAME_DOMAIN "psImageConvolve",
+                           PS_ERR_BAD_PARAMETER_TYPE, true,
+                           PS_ERRORTEXT_psImage_IMAGE_TYPE_UNSUPPORTED,
+                           typeStr);
+                psFree(out);
+                return NULL;
+
+            }
+        }
+
+
+    } else {
+        // fourier convolution
+        int kRows = kernel->image->numRows;
+        int kCols = kernel->image->numCols;
+        int x0 = (numCols - kCols) / 2;
+        int y0 = (numRows - kRows) / 2;
+        psImage* paddedKernel;
+
+        // check to see if kernel is smaller, otherwise padding it up will fail.
+        if (x0 < 0 || y0 < 0) {
+            psErrorMsg(PS_ERRORNAME_DOMAIN "psImageConvolve",
+                       PS_ERR_BAD_PARAMETER_SIZE, true,
+                       PS_ERRORTEXT_psImageConvolve_KERNEL_TOO_LARGE,
+                       kernel->image->numCols,kernel->image->numRows,
+                       numCols, numRows);
+            psFree(out);
+            return NULL;
+        }
+
+        // pad the kernel to the same size of image
+        paddedKernel = psImageAlloc(numCols,numRows,PS_TYPE_KERNEL);
+        memset(paddedKernel->data.V,0,sizeof(psKernelType)*numCols*numRows); // zeroize image
+        for (int row=0;row<kRows;row++) {
+            psKernelType* padRow = paddedKernel->data.PS_TYPE_KERNEL_DATA[row+y0];
+            psKernelType* kernelRow = kernel->image->data.PS_TYPE_KERNEL_DATA[row];
+            for (int col=0;col<kCols;col++) {
+                padRow[col+x0] = kernelRow[col];
+            }
+        }
+
+        psImage* kernelFourier = psImageFFT(NULL, paddedKernel, PS_FFT_FORWARD);
+        if (kernelFourier == NULL) {
+            psErrorMsg(PS_ERRORNAME_DOMAIN "psImageConvolve",
+                       PS_ERR_UNKNOWN, false,
+                       PS_ERRORTEXT_psImageConvolve_KERNEL_FFT_FAILED);
+            psFree(out);
+            return NULL;
+        }
+
+
+        psImage* inFourier = psImageFFT(NULL, in, PS_FFT_FORWARD);
+        if (inFourier == NULL) {
+            psErrorMsg(PS_ERRORNAME_DOMAIN "psImageConvolve",
+                       PS_ERR_UNKNOWN, false,
+                       PS_ERRORTEXT_psImageConvolve_FFT_FAILED);
+            psFree(out);
+            return NULL;
+        }
+
+        // convolution in fourier domain is just a pixel-wise multiplication
+        psImage* outFourier = psImageAlloc(numCols,numRows,inFourier->type.type);
+        psBinaryOp(outFourier,inFourier,"*",kernelFourier);
+
+        psImage* complexOut = psImageFFT(NULL, outFourier, PS_FFT_REVERSE);
+        if (complexOut == NULL) {
+            psErrorMsg(PS_ERRORNAME_DOMAIN "psImageConvolve",
+                       PS_ERR_UNKNOWN, false,
+                       PS_ERRORTEXT_psImageConvolve_FFT_FAILED);
+            psFree(out);
+            return NULL;
+        }
+
+        // since our image was real to start, the result is real
+        out = psImageReal(out,complexOut);
+
+        psFree(complexOut);
+        psFree(kernelFourier);
+        psFree(inFourier);
+        psFree(paddedKernel);
+
+    }
+
+    return out;
 }
Index: /trunk/psLib/src/imageops/psImageConvolve.h
===================================================================
--- /trunk/psLib/src/imageops/psImageConvolve.h	(revision 1862)
+++ /trunk/psLib/src/imageops/psImageConvolve.h	(revision 1863)
@@ -7,12 +7,12 @@
  *  @author Robert DeSonia, MHPCC
  *
- *  @version $Revision: 1.1 $ $Name: not supported by cvs2svn $
- *  @date $Date: 2004-08-28 01:18:28 $
+ *  @version $Revision: 1.2 $ $Name: not supported by cvs2svn $
+ *  @date $Date: 2004-09-23 18:30:57 $
  *
  *  Copyright 2004 Maui High Performance Computing Center, University of Hawaii
  */
 
-#ifndef PS_IMAGE_FFT_H
-#define PS_IMAGE_FFT_H
+#ifndef PS_IMAGE_CONVOLVE_H
+#define PS_IMAGE_CONVOLVE_H
 
 #include<stdbool.h>
@@ -20,15 +20,22 @@
 #include "psImage.h"
 #include "psVector.h"
+#include "psType.h"
+
+#define PS_TYPE_KERNEL PS_TYPE_F32     /**< the data member to use for kernel image */
+#define PS_TYPE_KERNEL_DATA F32        /**< the data member to use for kernel image */
+#define PS_TYPE_KERNEL_NAME "psF32"    /**< the data type for kernel as a string */
+
+typedef psF32 psKernelType;
 
 /** A convolution kernel */
 typedef struct
 {
+    psImage* image;                    ///< Kernel data, in the form of an image
     int xMin;                          ///< Most negative x index
     int yMin;                          ///< Most negative y index
     int xMax;                          ///< Most positive x index
     int yMax;                          ///< Most positive y index
-    psF32** kernel;                    ///< Pointer to the kernel data
-    psF32** p_kernelRows;              ///< Pointer to the rows of the kernel data
-    psImage* p_data;                   ///< Kernel data, in the form of an image
+    psKernelType** kernel;             ///< Pointer to the kernel data
+    psKernelType** p_kernelRows;       ///< Pointer to the rows of the kernel data; not intended for user use.
 }
 psKernel;
@@ -62,6 +69,6 @@
 psKernel* psKernelAlloc(
     int xMin,                          ///< Most negative x index
-    int xMax,                          ///< Most negative y index
-    int yMin,                          ///< Most positive x index
+    int xMax,                          ///< Most positive x index
+    int yMin,                          ///< Most negative y index
     int yMax                           ///< Most positive y index
 );
@@ -84,6 +91,8 @@
  */
 psKernel* psKernelGenerate(
-    const psVector* xShifts,           ///< list of shifts relative to a reference point
-    const psVector* yShifts            ///< list of shifts relative to a reference point
+    const psVector* tShifts,           ///< list of time shifts
+    const psVector* xShifts,           ///< list of x-axis shifts
+    const psVector* yShifts,           ///< list of y-axis shifts
+    bool relative
 );
 
