Index: trunk/psLib/src/imageops/psImageConvolve.c
===================================================================
--- trunk/psLib/src/imageops/psImageConvolve.c	(revision 12171)
+++ trunk/psLib/src/imageops/psImageConvolve.c	(revision 12179)
@@ -7,6 +7,6 @@
 /// @author Eugene Magnier, IfA
 ///
-/// @version $Revision: 1.47 $ $Name: not supported by cvs2svn $
-/// @date $Date: 2007-02-22 22:37:59 $
+/// @version $Revision: 1.48 $ $Name: not supported by cvs2svn $
+/// @date $Date: 2007-03-02 21:05:52 $
 ///
 /// Copyright 2004-2007 Institute for Astronomy, University of Hawaii
@@ -195,6 +195,5 @@
 }
 
-psImage *psImageConvolveDirect(psImage *out,
-                               const psImage *in,
+psImage *psImageConvolveDirect(const psImage *in,
                                const psKernel *kernel)
 {
@@ -214,8 +213,14 @@
     int numCols = in->numCols;          // Number of columns
 
+    psImage *out;                       // Image to be returned
+
+#if 0
+
+    // This is the usual way of doing the convolution, but it wastes time if there's a large number of zero
+    // pixels in the kernel.
 #define SPATIAL_CONVOLVE_CASE(TYPE) \
     case PS_TYPE_##TYPE: { \
-        ps##TYPE **inData = in->data.TYPE; \
-        out = psImageRecycle(out, numCols, numRows, PS_TYPE_##TYPE); \
+        ps##TYPE **inData = in->data.TYPE; /* Dereference input data */ \
+        out = psImageAlloc(numCols, numRows, PS_TYPE_##TYPE); \
         for (int row = 0; row < numRows; row++) { \
             ps##TYPE *outRow = out->data.TYPE[row]; \
@@ -233,4 +238,30 @@
     break;
 
+#else
+
+    // This turns the convolution inside-out, allowing us to skip kernel pixels that have no contribution.
+#define SPATIAL_CONVOLVE_CASE(TYPE) \
+    case PS_TYPE_##TYPE: { \
+        ps##TYPE **inData = in->data.TYPE; /* Dereference input data */ \
+        out = psImageAlloc(numCols, numRows, PS_TYPE_##TYPE); \
+        psImageInit(out, 0.0); \
+        for (int ky = yMin; ky <= yMax; ky++) { \
+            for (int kx = xMin; kx <= xMax; kx++) { \
+                float kValue = kernelData[ky][kx]; /* Kernel value */ \
+                if (kValue == 0.0) { \
+                    continue; \
+                } \
+                for (int y = PS_MAX(- ky, 0); y < PS_MIN(numRows, numRows - ky); y++) { \
+                    for (int x = PS_MAX(- kx, 0); x < PS_MIN(numCols, numCols - kx); x++) { \
+                        out->data.TYPE[y][x] += kValue * inData[y + ky][x + kx]; \
+                    } \
+                } \
+            } \
+        } \
+    } \
+    break;
+
+#endif
+
     switch (in->type.type) {
         SPATIAL_CONVOLVE_CASE(F32);
@@ -243,6 +274,45 @@
 }
 
-psImage *psImageConvolveFFT(psImage *out,
-                            const psImage *in,
+psImage *psImageMaskConvolve(const psImage *mask, psMaskType maskVal, const psKernel *kernel)
+{
+    PS_ASSERT_IMAGE_NON_NULL(mask, NULL);
+    PS_ASSERT_IMAGE_TYPE(mask, PS_TYPE_MASK, NULL);
+    PS_ASSERT_PTR_NON_NULL(kernel, NULL);
+    PS_ASSERT_PTR_NON_NULL(kernel->kernel, NULL);
+
+    // Pull out kernel parameters, for convenience
+    int xMin = kernel->xMin;
+    int xMax = kernel->xMax;
+    int yMin = kernel->yMin;
+    int yMax = kernel->yMax;
+
+    int numRows = mask->numRows;        // Number of rows
+    int numCols = mask->numCols;        // Number of columns
+
+    psMaskType **maskData = mask->data.PS_TYPE_MASK_DATA;
+    psImage *out = psImageAlloc(numCols, numRows, PS_TYPE_MASK);
+    psImageInit(out, 0);
+
+    for (int kRow = yMin; kRow <= yMax; kRow++) {
+        for (int kCol = xMin; kCol <= xMax; kCol++) {
+            psMaskType kValue = kernel->kernel[kRow][kCol]; // Value of the kernel
+            if (kValue == 0) {
+                continue;
+            }
+            for (int row = PS_MAX(kRow, 0); row < PS_MIN(numRows, numRows - kRow); row++) {
+                for (int col = PS_MAX(kCol, 0); col < PS_MIN(numCols, numCols - kCol); col++) {
+                    if (maskData[row][col] & maskVal) {
+                        out->data.PS_TYPE_MASK_DATA[row + kRow][col + kCol] = maskVal;
+                    }
+                }
+            }
+        }
+    }
+
+    return out;
+}
+
+
+psImage *psImageConvolveFFT(const psImage *in,
                             const psKernel *kernel,
                             float pad)
@@ -356,6 +426,6 @@
     // Trim off the padding, then renormalise (which also does a copy, so there's no parent for the output)
     psImage *convolved = psImageSubset(paddedConvolved, psRegionSet(0, numCols, 0, numRows));
-    out = (psImage*)psBinaryOp(out, convolved, "*",
-                               psScalarAlloc(1.0 / paddedCols / paddedRows, PS_TYPE_F32));
+    psImage *out = (psImage*)psBinaryOp(NULL, convolved, "*",
+                                        psScalarAlloc(1.0 / paddedCols / paddedRows, PS_TYPE_F32));
     psFree(convolved);
     psFree(paddedConvolved);
Index: trunk/psLib/src/imageops/psImageConvolve.h
===================================================================
--- trunk/psLib/src/imageops/psImageConvolve.h	(revision 12171)
+++ trunk/psLib/src/imageops/psImageConvolve.h	(revision 12179)
@@ -5,6 +5,6 @@
  * @author Robert DeSonia, MHPCC
  *
- * @version $Revision: 1.16 $ $Name: not supported by cvs2svn $
- * @date $Date: 2007-02-08 04:17:58 $
+ * @version $Revision: 1.17 $ $Name: not supported by cvs2svn $
+ * @date $Date: 2007-03-02 21:05:52 $
  * Copyright 2004-2005 Maui High Performance Computing Center, University of Hawaii
  */
@@ -112,5 +112,4 @@
 ///
 psImage *psImageConvolveDirect(
-    psImage *out,                       ///< a psImage to recycle.  If NULL, a new psImage is made.
     const psImage *in,                  ///< the psImage to convolve
     const psKernel *kernel              ///< kernel to colvolve with
@@ -122,5 +121,4 @@
 /// are suitably padded to avoid wrap-around effects.
 psImage *psImageConvolveFFT(
-    psImage *out,                       ///< a psImage to recycle.  If NULL, a new psImage is made.
     const psImage *in,                  ///< the psImage to convolve
     const psKernel *kernel,             ///< kernel to colvolve with
Index: trunk/psLib/test/imageops/tap_psImageConvolve2.c
===================================================================
--- trunk/psLib/test/imageops/tap_psImageConvolve2.c	(revision 12171)
+++ trunk/psLib/test/imageops/tap_psImageConvolve2.c	(revision 12179)
@@ -71,5 +71,5 @@
         psKernel *kernel = generateKernel();
 
-        psImage *convolved = psImageConvolveDirect(NULL, image, kernel);
+        psImage *convolved = psImageConvolveDirect(image, kernel);
         ok(convolved, "convolution result");
         skip_start(!convolved, 3, "convolution failed");
@@ -94,5 +94,5 @@
         psKernel *kernel = generateKernel();
 
-        psImage *convolved = psImageConvolveFFT(NULL, image, kernel, 0.0);
+        psImage *convolved = psImageConvolveFFT(image, kernel, 0.0);
         ok(convolved, "convolution result");
         skip_start(!convolved, 3, "convolution failed");
