Index: trunk/psLib/src/image/psImageManip.c
===================================================================
--- trunk/psLib/src/image/psImageManip.c	(revision 1205)
+++ trunk/psLib/src/image/psImageManip.c	(revision 1216)
@@ -10,6 +10,6 @@
  *  @author Ross Harman, MHPCC
  *
- *  @version $Revision: 1.1 $ $Name: not supported by cvs2svn $
- *  @date $Date: 2004-07-09 21:48:07 $
+ *  @version $Revision: 1.2 $ $Name: not supported by cvs2svn $
+ *  @date $Date: 2004-07-14 23:22:49 $
  *
  *  Copyright 2004 Maui High Performance Computing Center, University of Hawaii
@@ -17,9 +17,14 @@
 #include <math.h>                      // for isfinite(), etc.
 #include <stdlib.h>
+#include <stdbool.h>
 
 #include "psError.h"
 #include "psImage.h"
-
-int psImageClip(psImage* input,float min,float vmin,float max,float vmax)
+#include "psStats.h"
+#include "psMemory.h"
+
+bool getSpecifiedStatValue(const psStats* stats, double* value);
+
+int psImageClip(psImage* input, psF64 min, psF64 vmin, psF64 max, psF64 vmax)
 {
     int numClipped = 0;
@@ -41,6 +46,16 @@
     switch (input->type.type) {
 
-        #define psImageClipCase(type)\
+        #define psImageClipCase(type,typename) \
     case PS_TYPE_##type: { \
+            if (vmin < PS_MIN_##type || vmin > PS_MAX_##type) { \
+                psError(__func__, "Specified vmin (%g) is outside of image's " \
+                        typename " pixel range", \
+                        vmin); \
+            } \
+            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; \
@@ -59,13 +74,24 @@
         } \
         break;
-        #define psImageClipCaseComplex(type)\
+
+        #define psImageClipCaseComplex(type,typename,absfcn)\
     case PS_TYPE_##type: { \
+            if (vmin < PS_MIN_##type || vmin > PS_MAX_##type) { \
+                psError(__func__, "Specified vmin (%g) is outside of image's " \
+                        typename " pixel range", \
+                        vmin); \
+            } \
+            if (vmax > PS_MAX_##type || vmax < PS_MIN_##type) { \
+                psError(__func__, "Specified vmax (%g) is outside of image's " \
+                        typename " pixel range", \
+                        vmax); \
+            } \
             for (unsigned int row = 0;row<numRows;row++) { \
                 ps##type* inputRow = input->data.type[row]; \
                 for (unsigned int col = 0; col < numCols; col++) { \
-                    if (cabsf(inputRow[col]) < min) { \
+                    if (absfcn(inputRow[col]) < min) { \
                         inputRow[col] = (ps##type)vmin; \
                         numClipped++; \
-                    } else if (cabsf(inputRow[col]) > max) { \
+                    } else if (absfcn(inputRow[col]) > max) { \
                         inputRow[col] = (ps##type)vmax; \
                         numClipped++; \
@@ -76,16 +102,16 @@
         break;
 
-        psImageClipCase(S8)
-        psImageClipCase(S16)
-        psImageClipCase(S32)
-        psImageClipCase(S64)
-        psImageClipCase(U8)
-        psImageClipCase(U16)
-        psImageClipCase(U32)
-        psImageClipCase(U64)
-        psImageClipCase(F32)
-        psImageClipCase(F64)
-        psImageClipCaseComplex(C32)
-        psImageClipCaseComplex(C64)
+        psImageClipCase(S8,"psS8")
+        psImageClipCase(S16,"psS16")
+        psImageClipCase(S32,"psS32")
+        psImageClipCase(S64,"psS64")
+        psImageClipCase(U8,"psU8")
+        psImageClipCase(U16,"psU16")
+        psImageClipCase(U32,"psU32")
+        psImageClipCase(U64,"psU64")
+        psImageClipCase(F32,"psF32")
+        psImageClipCase(F64,"psF64")
+        psImageClipCaseComplex(C32,"psC32",cabsf)
+        psImageClipCaseComplex(C64,"psC64",cabs)
 
     default:
@@ -97,5 +123,5 @@
 }
 
-int psImageClipNaN(psImage* input,float value)
+int psImageClipNaN(psImage* input,psF64 value)
 {
     int numClipped = 0;
@@ -240,2 +266,220 @@
     return 0;
 }
+
+int psImageClipComplexRegion(psImage* input, psC64 min, psC64 vmin, psC64 max, psC64 vmax)
+{
+    int numClipped = 0;
+    unsigned int numRows;
+    unsigned int numCols;
+    psF64 realMin = creal(min);
+    psF64 imagMin = cimag(min);
+    psF64 realMax = creal(max);
+    psF64 imagMax = cimag(max);
+
+    if (input == NULL) {
+        return 0;
+    }
+
+    if ( realMax < realMin ) {
+        psError(__func__,"psImageClipComplexRegion can not be invoked with "
+                "max < min in the real image space.");
+        return 0;
+    }
+    if ( imagMax < imagMin ) {
+        psError(__func__,"psImageClipComplexRegion can not be invoked with "
+                "max < min in the imaginary image space.");
+        return 0;
+    }
+
+    numRows = input->numRows;
+    numCols = input->numCols;
+
+    switch (input->type.type) {
+
+        #define psImageClipComplexRegionCase(type,typename,realfcn,imagfcn) \
+    case PS_TYPE_##type: { \
+            if (realfcn(vmin) < PS_MIN_##type || imagfcn(vmin) < PS_MIN_##type || \
+                    realfcn(vmin) > PS_MAX_##type || imagfcn(vmin) > PS_MAX_##type ) { \
+                psError(__func__, "Specified vmin (%g%+gi) is outside of image's " \
+                        typename " pixel range", \
+                        realfcn(vmin),imagfcn(vmin)); \
+            } \
+            if (realfcn(vmax) > PS_MAX_##type || imagfcn(vmax) > PS_MAX_##type || \
+                    realfcn(vmax) < PS_MIN_##type || imagfcn(vmax) < PS_MIN_##type ) { \
+                psError(__func__, "Specified vmax (%g%+gi) is outside of image's " \
+                        typename " pixel range", \
+                        realfcn(vmax),imagfcn(vmax)); \
+            } \
+            for (unsigned int row = 0;row<numRows;row++) { \
+                ps##type* inputRow = input->data.type[row]; \
+                for (unsigned int col = 0; col < numCols; col++) { \
+                    if ( (realfcn(inputRow[col]) > realMax) || (imagfcn(inputRow[col]) > imagMax) ) { \
+                        inputRow[col] = (ps##type)vmin; \
+                        numClipped++; \
+                    } else if ( (realfcn(inputRow[col]) < realMin) || (imagfcn(inputRow[col]) < imagMax) ){ \
+                        inputRow[col] = (ps##type)vmax; \
+                        numClipped++; \
+                    } \
+                } \
+            } \
+        } \
+        break;
+
+        psImageClipComplexRegionCase(C32,"psC32",crealf,cimagf)
+        psImageClipComplexRegionCase(C64,"psC64",creal,cimag)
+
+    default:
+        psError(__func__,"psImageClip does not support the given datatype (%d)",
+                input->type.type);
+    }
+
+    return numClipped;
+}
+
+bool getSpecifiedStatValue(const psStats* stats, double* value)
+{
+
+    switch (stats->options &
+            ! (PS_STAT_USE_RANGE | PS_STAT_USE_BINSIZE | PS_STAT_ROBUST_FOR_SAMPLE)) {
+    case PS_STAT_SAMPLE_MEAN:
+        *value = stats->sampleMean;
+        return true;
+
+    case PS_STAT_SAMPLE_MEDIAN:
+        *value = stats->sampleMedian;
+        return true;
+
+    case PS_STAT_SAMPLE_STDEV:
+        *value = stats->sampleStdev;
+        return true;
+
+    case PS_STAT_ROBUST_MEAN:
+        *value = stats->robustMean;
+        return true;
+
+    case PS_STAT_ROBUST_MEDIAN:
+        *value = stats->robustMedian;
+        return true;
+
+    case PS_STAT_ROBUST_MODE:
+        *value = stats->robustMode;
+        return true;
+
+    case PS_STAT_ROBUST_STDEV:
+        *value = stats->robustStdev;
+        return true;
+
+    case PS_STAT_CLIPPED_MEAN:
+        *value = stats->clippedMean;
+        return true;
+
+    case PS_STAT_CLIPPED_STDEV:
+        *value = stats->clippedStdev;
+        return true;
+
+    case PS_STAT_MAX:
+        *value = stats->max;
+        return true;
+
+    case PS_STAT_MIN:
+        *value = stats->min;
+        return true;
+
+    default:
+        return false;
+    }
+}
+
+
+psImage* psImageRebin(psImage* out,const psImage* in,unsigned int scale,const psStats* stats)
+{
+    int inRows;
+    int inCols;
+    int outRows;
+    int outCols;
+    psVector* vec;            // vector to hold the values of a single bin.
+    psStats* myStats;
+    double statVal;
+
+    if (in == NULL) {
+        psError(__func__,"Input image is NULL.");
+        return NULL;
+    }
+
+    if (scale < 1) {
+        psError(__func__,"The scale must be positive.");
+        return NULL;
+    }
+
+    if (stats == NULL) {
+        psError(__func__,"The stats input can not be NULL.");
+        return NULL;
+    }
+
+    if (getSpecifiedStatValue(stats,&statVal) == false) {
+        psError(__func__,"The stat options didn't specify a single supported statistic type.");
+        return NULL;
+    }
+
+    myStats = psAlloc(sizeof(psStats));
+    *myStats = *stats;
+
+    vec = psVectorAlloc(scale*scale,in->type.type);
+
+    // create output image.
+    inRows = in->numRows;
+    inCols = in->numCols;
+    outRows = (inRows+scale-1) / scale;   // round-up for remainders
+    outCols = (inCols+scale-1) / scale;   // round-up for remainders
+    out = psImageRecycle(out,outCols,outRows,in->type.type);
+
+    #define PS_IMAGE_REBIN_CASE(type) \
+case PS_TYPE_##type: { \
+        ps##type* vecData = vec->data.type; \
+        for (int row = 0; row < outRows; row++) { \
+            ps##type* outRowData = out->data.type[row]; \
+            int inCurrentRow = row*scale; \
+            int inNextRow = (row+1)*scale; \
+            for (int col = 0; col < outCols; col++) { \
+                int inCurrentCol = col*scale; \
+                int inNextCol = (col+1)*scale; \
+                int n = 0; \
+                for (int inRow = inCurrentRow; inRow < inNextRow && inRow < inRows; inRow++) { \
+                    ps##type* inRowData = in->data.type[inRow]; \
+                    for (int inCol = inCurrentCol; inCol < inNextCol && inCol < inCols; inCol++) { \
+                        vecData[n++] = inRowData[inCol]; \
+                    } \
+                } \
+                vec->n = n; \
+                myStats = psVectorStats(myStats,vec,NULL,0); \
+                getSpecifiedStatValue(myStats,&statVal); \
+                outRowData[col] = (ps##type)statVal; \
+            } \
+        } \
+    } \
+    break;
+
+    switch (in->type.type) {
+        PS_IMAGE_REBIN_CASE(U8);
+        PS_IMAGE_REBIN_CASE(U16);
+        PS_IMAGE_REBIN_CASE(U32);
+        PS_IMAGE_REBIN_CASE(U64);
+        PS_IMAGE_REBIN_CASE(S8);
+        PS_IMAGE_REBIN_CASE(S16);
+        PS_IMAGE_REBIN_CASE(S32);
+        PS_IMAGE_REBIN_CASE(S64);
+        PS_IMAGE_REBIN_CASE(F32);
+        PS_IMAGE_REBIN_CASE(F64);
+        PS_IMAGE_REBIN_CASE(C32);
+        PS_IMAGE_REBIN_CASE(C64);
+    default:
+        psError(__func__,"Input image type not supported.");
+        psFree(out);
+        out = NULL;
+    }
+
+    psFree(vec);
+    psFree(myStats);
+
+    return out;
+}
