Index: trunk/psLib/src/imageops/psImageConvolve.c
===================================================================
--- trunk/psLib/src/imageops/psImageConvolve.c	(revision 15320)
+++ trunk/psLib/src/imageops/psImageConvolve.c	(revision 15321)
@@ -7,6 +7,6 @@
 /// @author Eugene Magnier, IfA
 ///
-/// @version $Revision: 1.58 $ $Name: not supported by cvs2svn $
-/// @date $Date: 2007-10-16 23:31:03 $
+/// @version $Revision: 1.59 $ $Name: not supported by cvs2svn $
+/// @date $Date: 2007-10-17 01:49:12 $
 ///
 /// Copyright 2004-2007 Institute for Astronomy, University of Hawaii
@@ -61,7 +61,7 @@
 {
     // Check the inputs to make sure max > min; if not, switch.
+    // following is explicitly spelled out in the SDRS as a requirement
     if (yMin > yMax) {
-        psLogMsg(__func__, PS_LOG_WARN,
-                 "Specified yMin, %d, was greater than yMax, %d.  Values swapped.",
+        psWarning("Specified yMin, %d, was greater than yMax, %d.  Values swapped.",
                  yMin, yMax);
 
@@ -70,9 +70,6 @@
         yMax = temp;
     }
-
-    // following is explicitly spelled out in the SDRS as a requirement
     if (xMin > xMax) {
-        psLogMsg(__func__, PS_LOG_WARN,
-                 "Specified xMin, %d, was greater than xMax, %d.  Values swapped.",
+        psWarning("Specified xMin, %d, was greater than xMax, %d.  Values swapped.",
                  xMin, xMax);
 
@@ -313,21 +310,39 @@
 }
 
-psImage *psImageConvolveMaskDirect(const psImage *mask, psMaskType maskVal, const psKernel *kernel)
+psImage *psImageConvolveMaskDirect(psImage *out, const psImage *mask, psMaskType maskVal,
+                                   psMaskType setVal, int xMin, int xMax, int yMin, int yMax)
 {
     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;
+    if (out == mask && ((maskVal & setVal) || !setVal)) {
+        psError(PS_ERR_BAD_PARAMETER_VALUE, true,
+                "Can't convolve mask in-place if values to set contains values to convolve.");
+        return NULL;
+    }
+
+    if (yMin > yMax) {
+        psWarning("Specified yMin, %d, was greater than yMax, %d.  Values swapped.",
+                 yMin, yMax);
+
+        int temp = yMin;
+        yMin = yMax;
+        yMax = temp;
+    }
+    if (xMin > xMax) {
+        psWarning("Specified xMin, %d, was greater than xMax, %d.  Values swapped.",
+                 xMin, xMax);
+
+        int temp = xMin;
+        xMin = xMax;
+        xMax = temp;
+    }
 
     int numRows = mask->numRows;        // Number of rows
     int numCols = mask->numCols;        // Number of columns
 
-    psImage *out = psImageAlloc(numCols, numRows, PS_TYPE_MASK); // Output mask
+    if (!out) {
+        // Propagate the non-masked values
+        out = (psImage*)psBinaryOp(NULL, (const psPtr)mask, "&", psScalarAlloc(~maskVal, PS_TYPE_MASK));
+    }
 
     // Dereference mask images
@@ -335,24 +350,33 @@
     psMaskType **outData = out->data.PS_TYPE_MASK_DATA;
 
-    // Propagate the non-masked values
-    for (int row = 0; row < numRows; row++) {
-        for (int col = 0; col < numCols; col++) {
-            outData[row][col] = maskData[row][col] & ~maskVal;
-        }
-    }
-
-    for (int row = 0; row < numRows; row++) {
-        for (int col = 0; col < numCols; col++) {
-            if (maskData[row][col] & maskVal) {
-                // It's already masked --- move on
-                continue;
-            }
-            psMaskType pixel = 0;       // New pixel value
-            for (int kRow = PS_MAX(yMin, -row); kRow <= PS_MIN(yMax, numRows - row - 1); kRow++) {
-                for (int kCol = PS_MAX(xMin, -col); kCol <= PS_MIN(xMax, numCols - col - 1); kCol++) {
-                    pixel |= maskData[row + kRow][col + kCol] & maskVal;
+    if (setVal) {
+        // Grow any pixels matching maskVal, setting setVal
+        for (int row = 0; row < numRows; row++) {
+            for (int col = 0; col < numCols; col++) {
+                if (maskData[row][col] & maskVal) {
+                    for (int kRow = PS_MAX(yMin, -row); kRow <= PS_MIN(yMax, numRows - row - 1); kRow++) {
+                        for (int kCol = PS_MAX(xMin, -col); kCol <= PS_MIN(xMax, numCols - col - 1); kCol++) {
+                            outData[row + kRow][col + kCol] |= setVal;
+                        }
+                    }
                 }
             }
-            outData[row][col] |= pixel;
+        }
+    } else {
+        // Each pixel receives any maskVal bits set within the convolution window
+        for (int row = 0; row < numRows; row++) {
+            for (int col = 0; col < numCols; col++) {
+                psMaskType pixel = outData[row][col]; // Pixel value to set
+                if (pixel & maskVal) {
+                    // Already done this one
+                    continue;
+                }
+                for (int kRow = PS_MAX(yMin, -row); kRow <= PS_MIN(yMax, numRows - row - 1); kRow++) {
+                    for (int kCol = PS_MAX(xMin, -col); kCol <= PS_MIN(xMax, numCols - col - 1); kCol++) {
+                        pixel |= maskData[row][col] & maskVal;
+                    }
+                }
+                outData[row][col] = pixel;
+            }
         }
     }
@@ -494,26 +518,71 @@
 
 
-psImage *psImageConvolveMaskFFT(const psImage *mask, psMaskType maskVal, const psKernel *kernel, float thresh)
+psImage *psImageConvolveMaskFFT(psImage *out, const psImage *mask, psMaskType maskVal,
+                                psMaskType setVal, int xMin, int xMax, int yMin, int yMax, float thresh)
 {
     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);
     PS_ASSERT_FLOAT_LARGER_THAN(thresh, 0.0, NULL);
     PS_ASSERT_FLOAT_LESS_THAN(thresh, 1.0, NULL);
+    if (out == mask && (maskVal & setVal)) {
+        psError(PS_ERR_BAD_PARAMETER_VALUE, true,
+                "Can't convolve mask in-place if values to set contains values to convolve.");
+        return NULL;
+    }
+
+    if (yMin > yMax) {
+        psWarning("Specified yMin, %d, was greater than yMax, %d.  Values swapped.",
+                 yMin, yMax);
+
+        int temp = yMin;
+        yMin = yMax;
+        yMax = temp;
+    }
+    if (xMin > xMax) {
+        psWarning("Specified xMin, %d, was greater than xMax, %d.  Values swapped.",
+                 xMin, xMax);
+
+        int temp = xMin;
+        xMin = xMax;
+        xMax = temp;
+    }
 
     int numRows = mask->numRows, numCols = mask->numCols; // Size of image
 
-    psImage *onoff = (psImage*)psBinaryOp(NULL, (const psPtr)mask, "&", // Casting away const so I can use
-                                          psScalarAlloc(maskVal, PS_TYPE_MASK)); // Pixels on or off
-    psImage *copy = psImageCopy(NULL, onoff, PS_TYPE_F32); // Floating-point copy
-    psImage *convolved = psImageConvolveFFT(copy, NULL, 0, kernel, 0.0);
-    psFree(copy);
-
-    thresh *= maskVal;
+    if (!psMemIncrRefCounter(out)) {
+        out = psImageAlloc(numCols, numRows, PS_TYPE_MASK);
+    }
+
+    psImage *onoff = psImageAlloc(numCols, numRows, PS_TYPE_F32); // Pixels on or off
+    psImageInit(onoff, 0);
     for (int y = 0; y < numRows; y++) {
         for (int x = 0; x < numCols; x++) {
-            onoff->data.PS_TYPE_MASK_DATA[y][x] = (convolved->data.F32[y][x] >= thresh) ?
-                (mask->data.PS_TYPE_MASK_DATA[y][x] | maskVal) : mask->data.PS_TYPE_MASK_DATA[y][x];
+            if (mask->data.PS_TYPE_MASK_DATA[y][x] & maskVal) {
+                onoff->data.F32[y][x] = 1.0;
+            }
+        }
+    }
+
+    psKernel *kernel = psKernelAlloc(xMin, xMax, yMin, yMax);
+    psImageInit(kernel->image, 1.0);
+    psImage *convolved = psImageConvolveFFT(onoff, NULL, 0, kernel, 0.0);
+    psFree(onoff);
+    psFree(kernel);
+    if (!convolved) {
+        psError(PS_ERR_UNKNOWN, false, "Unable to convolve mask.");
+        psFree(out);
+        return NULL;
+    }
+
+    thresh *= maskVal;
+
+    if (!setVal) {
+        setVal = maskVal;
+    }
+
+    for (int y = 0; y < numRows; y++) {
+        for (int x = 0; x < numCols; x++) {
+            out->data.PS_TYPE_MASK_DATA[y][x] = (convolved->data.F32[y][x] >= thresh) ?
+                (mask->data.PS_TYPE_MASK_DATA[y][x] | setVal) : mask->data.PS_TYPE_MASK_DATA[y][x];
         }
     }
@@ -521,5 +590,5 @@
     psFree(convolved);
 
-    return onoff;
+    return out;
 }
 
