/** @file  tst_psImageExtraction.c
*
*  @brief Contains the tests for psImageExtraction.[ch]
*
*
*  @author Robert DeSonia, MHPCC
*
*  @version $Revision: 1.21 $ $Name: not supported by cvs2svn $
*  @date $Date: 2005-02-23 21:36:57 $
*
*  Copyright 2004-2005 Maui High Performance Computing Center, University of Hawaii
*/
#include<stdlib.h>
#include<string.h>

#include "psTest.h"
#include "pslib.h"
#include "psType.h"

static psS32 testImageSlice(void);
static psS32 testImageSubset(void);
static psS32 testImageSubsection(void);
static psS32 testImageTrim(void);
static psS32 testImageCut(void);
static psS32 testImageRadialCut(void);


testDescription tests[] = {
                              {testImageSubset,547,"psImageSubset",0,false},
                              {testImageSubset,550,"psImageSubset",0,true},
                              {testImageSubsection,730,"psImageSubsection",0,false},
                              {testImageSlice, 552, "psImageSlice", 0, false},
                              {testImageTrim, 744, "psImageTrim", 0, false},
                              {testImageCut, 555, "psImageCut", 0, false},
                              {testImageRadialCut, 557, "psImageRadialCut", 0, false},
                              {NULL}
                          };

psS32 main( psS32 argc, char* argv[] )
{
    return ! runTestSuite( stderr, "psImage", tests, argc, argv );
}

psS32 testImageSlice(void)
{
    const psS32 r = 200;
    const psS32 c = 300;
    const psS32 m = r / 2 -1;
    const psS32 n = r / 4 -1;
    psVector* out = NULL;
    psImage* image;
    psVector* positions = psVectorAlloc( r, PS_TYPE_U32 );
    psImage* mask = psImageAlloc( c, r, PS_TYPE_MASK );
    psStats* stat = psStatsAlloc( PS_STAT_SAMPLE_MEDIAN );

    /*
        This function shall extract pixels from a specified region of a psImage
        structure into a vector using a specified statistical method.

        Verify the returned psVector structure contains expected data, if the 
        input psImage input has known data and the psStats structure specifies 
        a known statistical method. At least two different statistical methods 
        should be used within a valid range of psImage data. Allow for a delta 
        when comparing results to allow for testing a different platforms. Two 
        cases should be used for each possible direction. Data region cases 
        should include 0x0, 1x1, Nx1, 1xN, NxN, MxN
     
     */

    for ( psS32 row = 0;row < r;row++ ) {
        psMaskType* maskRow = mask->data.PS_TYPE_MASK_DATA[row];
        for ( psS32 col = 0;col < c;col++ ) {
            maskRow[ col ] = 0;
        }
    }

    #define PSIMAGESLICE_TEST1(TYPE,M,N,DIRECTION,TRUTH_SIZE,TRUTHPIX_X,TRUTHPIX_Y,TESTNUM) \
    image = psImageAlloc( c, r, PS_TYPE_##TYPE ); \
    for ( psS32 row = 0;row < r;row++ ) { \
        ps##TYPE *imageRow = image->data.TYPE[ row ]; \
        ps##TYPE rowOffset = row * 2; \
        for ( psS32 col = 0;col < c;col++ ) { \
            imageRow[ col ] = col + rowOffset; \
        } \
    } \
    out = psImageSlice(out,positions,image,mask,1,c/10,r/10,c/10+M,r/10+N,DIRECTION,stat); \
    \
    if (out->n != TRUTH_SIZE) { \
        psError(PS_ERR_UNKNOWN,true,"Number of results is wrong (%d, not %d)", \
                out->n,n); \
        return TESTNUM*4+1; \
    } \
    \
    if (positions->n != TRUTH_SIZE) { \
        psError(PS_ERR_UNKNOWN,true,"Number of results for positions vector is wrong (%d, not %d)", \
                out->n,n); \
        return TESTNUM*4+2; \
    } \
    \
    for (psS32 i=0;i<out->n;i++) { \
        if (fabs(out->data.F64[i]-image->data.TYPE[r/10+TRUTHPIX_Y][c/10+TRUTHPIX_X]) > 1.0/(psF64)r) { \
            psError(PS_ERR_UNKNOWN,true,"Improper result at position %d.  Got %g, expected %g",i, \
                    out->data.F64[i],image->data.TYPE[r/10+TRUTHPIX_Y][c/10+TRUTHPIX_X]); \
            return TESTNUM*4+3; \
        } \
        if (DIRECTION == PS_CUT_X_POS || DIRECTION == PS_CUT_X_NEG) { \
            if (positions->data.U32[i] != c/10+TRUTHPIX_X) { \
                psError(PS_ERR_UNKNOWN,true,"Improper positions (%d vs %d) result @ %d.", \
                        positions->data.U32[i],c/10+TRUTHPIX_X,i); \
                return TESTNUM*4+4; \
            } \
        } else { \
            if (positions->data.U32[i] != r/10+TRUTHPIX_Y) { \
                psError(PS_ERR_UNKNOWN,true,"Improper positions (%d vs %d) result @ %d.", \
                        positions->data.U32[i],r/10+TRUTHPIX_Y,i); \
                return TESTNUM*4+4; \
            } \
        } \
    } \
    psFree(image);

    #define PSIMAGESLICE_TEST(TYPE) \
    /* test MxN case */ \
    PSIMAGESLICE_TEST1(TYPE, m, n, PS_CUT_X_POS, m, i, n / 2, 0 ); \
    PSIMAGESLICE_TEST1(TYPE, m, n, PS_CUT_X_NEG, m, m - 1 - i, n / 2, 1 ); \
    PSIMAGESLICE_TEST1(TYPE, m, n, PS_CUT_Y_POS, n, m / 2, i, 2 ); \
    PSIMAGESLICE_TEST1(TYPE, m, n, PS_CUT_Y_NEG, n, m / 2, n - 1 - i, 3 ); \
    \
    /* test Mx1 case */ \
    PSIMAGESLICE_TEST1(TYPE, m, 1, PS_CUT_X_POS, m, i, 0, 4 ); \
    PSIMAGESLICE_TEST1(TYPE, m, 1, PS_CUT_X_NEG, m, m - 1 - i, 0, 5 ); \
    PSIMAGESLICE_TEST1(TYPE, m, 1, PS_CUT_Y_POS, 1, m / 2, 0, 6 ); \
    PSIMAGESLICE_TEST1(TYPE, m, 1, PS_CUT_Y_NEG, 1, m / 2, 0, 7 ); \
    \
    /* test 1xN case */ \
    PSIMAGESLICE_TEST1(TYPE, 1, n, PS_CUT_X_POS, 1, 0, n / 2, 8 ); \
    PSIMAGESLICE_TEST1(TYPE, 1, n, PS_CUT_X_NEG, 1, 0, n / 2, 9 ); \
    PSIMAGESLICE_TEST1(TYPE, 1, n, PS_CUT_Y_POS, n, 0, i, 10 ); \
    PSIMAGESLICE_TEST1(TYPE, 1, n, PS_CUT_Y_NEG, n, 0, n - 1 - i, 11 ); \
    \
    /* test 1x1 case */ \
    PSIMAGESLICE_TEST1(TYPE, 1, 1, PS_CUT_X_POS, 1, 0, 0, 12 ); \
    PSIMAGESLICE_TEST1(TYPE, 1, 1, PS_CUT_X_NEG, 1, 0, 0, 13 ); \
    PSIMAGESLICE_TEST1(TYPE, 1, 1, PS_CUT_Y_POS, 1, 0, 0, 14 ); \
    PSIMAGESLICE_TEST1(TYPE, 1, 1, PS_CUT_Y_NEG, 1, 0, 0, 15 ); \

    PSIMAGESLICE_TEST(F32);
    PSIMAGESLICE_TEST(F64);
    PSIMAGESLICE_TEST(U16);

    image = psImageAlloc( c, r, PS_TYPE_F32 );

    /*
       Verify the returned psVector structure pointer is null and program 
       execution doesn't stop, if input psImage input is null.

    */
    psLogMsg( __func__, PS_LOG_INFO, "Following should be an error." );
    out = psImageSlice( out,
                        NULL, NULL,
                        NULL, 0,
                        c/10, r/10,
                        c/10 + 1, r/10 + 1,
                        PS_CUT_X_POS,
                        stat );
    if ( out != NULL ) {
        psError( PS_ERR_UNKNOWN,true, "Giving a NULL image, psImageSlice didn't return NULL as expected" );
        return 101;
    }


    /*
       Verify the returned psVector structure pointer is null and program 
       execution doesn't stop, if input psStats stats is null.
    */
    psLogMsg( __func__, PS_LOG_INFO, "Following should be an error." );
    out = psImageSlice( out,
                        NULL, image,
                        mask, 1,
                        c/10, r/10,
                        c/10 + 1,
                        r/10 + 1,
                        PS_CUT_X_POS,
                        NULL );
    if ( out != NULL ) {
        psError( PS_ERR_UNKNOWN,true, "Giving a NULL stat struct, psImageSlice didn't return NULL as expected" );
        return 102;
    }
    /*

       Verify the returned psVector structure pointer is null and program 
       executions doesn't stop, if the input direction is not set to one of 
       the two valid values.
    */
    psLogMsg( __func__, PS_LOG_INFO, "Following should be an error." );
    out = psImageSlice( out, NULL,
                        image,
                        mask, 1,
                        c/10, r/10,
                        c/10+1, r/10+1,
                        5,
                        stat);
    if ( out != NULL ) {
        psError( PS_ERR_UNKNOWN,true, "Giving a bogus direction flag, psImageSlice didn't return NULL as expected" );
        return 103;
    }

    /*
       Verify the returned psVector structure pointer is null and program 
       execution doesn't stop, if the input nrow and/or ncol are zero.
    */
    psLogMsg( __func__, PS_LOG_INFO, "Following should be an error." );
    out = psImageSlice( out,
                        NULL,
                        image,
                        mask, 1,
                        c/10, r/10,
                        c/10, r/10,
                        PS_CUT_X_POS,
                        stat );
    if ( out != NULL ) {
        psError( PS_ERR_UNKNOWN,true, "Giving a 0x0 region, psImageSlice didn't return NULL as expected" );
        return 104;
    }

    /*
       Verify the returned psVector structure pointer is null and program 
       execution doesn't stop, if the inputs row, col, nrow, ncol specify a 
       regions of data that is not within the input psImage structure.
    */
    psLogMsg( __func__, PS_LOG_INFO, "Following should be an error." );
    out = psImageSlice( out, NULL,
                        image,
                        mask, 1,
                        c+1, r/10,
                        c+2, r/10+10,
                        PS_CUT_X_POS,
                        stat );
    if ( out != NULL ) {
        psError( PS_ERR_UNKNOWN,true, "Giving an invalid x position, psImageSlice didn't return NULL as expected" );
        return 105;
    }

    psLogMsg( __func__, PS_LOG_INFO, "Following should be an error." );
    out = psImageSlice( out, NULL,
                        image,
                        mask, 1,
                        c/10, r+1,
                        c/10+1,r+5,
                        PS_CUT_X_POS,
                        stat );
    if ( out != NULL ) {
        psError( PS_ERR_UNKNOWN,true, "Giving an invalid y position, psImageSlice didn't return NULL as expected" );
        return 106;
    }

    psLogMsg( __func__, PS_LOG_INFO, "Following should be an error." );
    out = psImageSlice( out, NULL,
                        image,
                        mask, 1,
                        c/10, r/10,
                        c+1, r/10+1,
                        PS_CUT_X_POS,
                        stat);
    if ( out != NULL ) {
        psError( PS_ERR_UNKNOWN,true, "Giving an invalid numCols, psImageSlice didn't return NULL as expected" );
        return 107;
    }

    psLogMsg( __func__, PS_LOG_INFO, "Following should be an error." );
    out = psImageSlice( out, NULL,
                        image,
                        mask, 1,
                        c/10, r/10,
                        c/10+1, r + 1,
                        PS_CUT_X_POS,
                        stat);
    if ( out != NULL ) {
        psError( PS_ERR_UNKNOWN,true, "Giving an invalid numRows, psImageSlice didn't return NULL as expected" );
        return 108;
    }

    /*
       Verify the returned psVector structure pointer is null and program 
       execution doesn't stop, if the input psStat structure member options is 
       zero which indicates no statistic method specified.
    */
    psLogMsg( __func__, PS_LOG_INFO, "Following should be an error." );
    stat->options = 0;
    out = psImageSlice( out, NULL,
                        image,
                        mask, 1,
                        c/10, r/10,
                        c/10+1, r/10+1,
                        PS_CUT_X_POS,
                        stat);
    if ( out != NULL ) {
        psError( PS_ERR_UNKNOWN,true, "Giving an invalid numRows, psImageSlice didn't return NULL as expected" );
        return 109;
    }

    /* Verify that a mask of different size than the input image returns null and program
       execution doesn't stop.
    */
    psLogMsg( __func__, PS_LOG_INFO, "Following should be an error mask size != image size.");
    stat->options = PS_STAT_SAMPLE_MEDIAN;
    psImage* maskSz = psImageAlloc( r, c, PS_TYPE_MASK );
    out = psImageSlice( out, NULL,
                        image,
                        maskSz, 1,
                        c/10, r/10,
                        c/10+1, r/10+1,
                        PS_CUT_X_POS,
                        stat);
    if ( out != NULL ) {
        psError( PS_ERR_UNKNOWN,true, "Mask size different than image size didn't return NULL as expected" );
        return 110;
    }

    /* Verify the a invalid type mask returns null and program execution doesn't stop.
    */
    psLogMsg( __func__, PS_LOG_INFO, "Following should be an error invalid mask type.");
    psImage* maskS8 = psImageAlloc( c, r, PS_TYPE_S8 );
    out =  psImageSlice( out, NULL,
                         image,
                         maskS8, 1,
                         c/10, r/10,
                         c/10+1, r/10+1,
                         PS_CUT_X_POS,
                         stat);
    if ( out != NULL ) {
        psError( PS_ERR_UNKNOWN,true, "Mask invalid type didn't return NULL as expected.");
        return 111;
    }

    psFree( image );
    psFree( positions );
    psFree( mask );
    psFree( out );
    psFree( stat );
    psFree( maskS8 );
    psFree( maskSz );

    return 0;

}

// #547: psImageSubset shall create child image of a specified size from a parent psImage structure
psS32 testImageSubset(void)
{
    psImage preSubsetStruct;
    psImage* original;
    psImage* subset1 = NULL;
    psImage* subset2 = NULL;
    psImage* subset3 = NULL;
    psS32 c = 128;
    psS32 r = 256;

    original = psImageAlloc(c,r,PS_TYPE_U32);
    for (psS32 row=0;row<r;row++) {
        for (psS32 col=0;col<c;col++) {
            original->data.F32[row][col] = row*1000+col;
        }
    }

    memcpy(&preSubsetStruct,original,sizeof(psImage));

    subset2 = psImageSubset(original,c/4,r/4,c/4+c/2,r/4+r/2);

    subset3 = psImageSubset(original,0,0,c/2,r/2);

    psLogMsg(__func__,PS_LOG_INFO,"Verify the returned psImage structure members nrow and ncol are equal to "
             "the input parameter nrow and ncol respectively.");

    if (subset2->numCols != c/2 || subset2->numRows != r/2) {
        psError(PS_ERR_UNKNOWN,true,"psImageSubset output size was not proper(%dx%d, should be %dx%d).",
                subset2->numCols, subset2->numRows, c/2,r/2);
        return 1;
    }

    if (subset3->numCols != c/2 || subset3->numRows != r/2) {
        psError(PS_ERR_UNKNOWN,true,"psImageSubset output size was not proper(%dx%d, should be %dx%d).",
                subset3->numCols, subset3->numRows, c/2,r/2);
        return 2;
    }

    psLogMsg(__func__,PS_LOG_INFO,"Verify the returned psImage structure contains expected values in the "
             "row member, if the input psImage structure image contains known values.");

    for (psS32 row=0;row<r/2;row++) {
        for (psS32 col=0;col<c/2;col++) {
            if (subset2->data.U32[row][col] != original->data.U32[row+r/4][col+c/4]) {
                psError(PS_ERR_UNKNOWN,true,"psImageSubset output #1 was wrong at %dx%d (%d vs %d).",
                        row,col,subset2->data.U32[row][col], original->data.U32[row+r/4][col+c/4]);
                return 3;
            }
            if (subset3->data.U32[row][col] != original->data.U32[row][col]) {
                psError(PS_ERR_UNKNOWN,true,"psImageSubset output #1 was wrong at %dx%d (%d vs %d).",
                        row,col,subset2->data.U32[row][col], original->data.U32[row][col]);
                return 4;
            }
        }
    }

    psLogMsg(__func__,PS_LOG_INFO,"Verify the returned psImage structure member type is equal to the input "
             "psImage structure member type.");

    if (subset2->type.type != PS_TYPE_U32) {
        psError(PS_ERR_UNKNOWN,true,"psImageSubset output type was not proper(%d, should be %d).",
                subset2->type.type, PS_TYPE_U32);
        return 6;
    }
    if (subset3->type.type != PS_TYPE_U32) {
        psError(PS_ERR_UNKNOWN,true,"psImageSubset output type was not proper(%d, should be %d).",
                subset3->type.type, PS_TYPE_U32);
        return 7;
    }

    psLogMsg(__func__,PS_LOG_INFO,"Verify the returned psImage structure members row0 and col0 are equal to "
             "the input parameters row0 and col0 respectively.");

    if (subset2->col0 != c/4 || subset2->row0 != r/4) {
        psError(PS_ERR_UNKNOWN,true,"psImageSubset didn't set col0/row0 for subset2 (%d/%d, should be %d/%d).",
                subset2->col0,subset2->row0,c/4,r/4);
        return 8;
    }
    if (subset3->col0 != 0 || subset3->row0 != 0) {
        psError(PS_ERR_UNKNOWN,true,"psImageSubset didn't set col0/row0 for subset3 (%d/%d, should be %d/%d).",
                subset3->col0,subset3->row0,0,0);
        return 9;
    }

    psLogMsg(__func__,PS_LOG_INFO,"Verify the returned psImage structure member parent is equal to the "
             "input psImage structure pointer image.");

    if (subset2->parent != original || subset3->parent != original) {
        psError(PS_ERR_UNKNOWN,true,"psImageSubset didn't set parent.");
        return 10;
    }

    psLogMsg(__func__,PS_LOG_INFO,"Verify the returned psImage structure member children is null.");

    if (subset2->children != NULL || subset3->children != NULL) {
        psError(PS_ERR_UNKNOWN,true,"psImageSubset didn't set children to NULL.");
        return 11;
    }

    psLogMsg(__func__,PS_LOG_INFO,"Verify the input psImage structure image only has the following members "
             "changed: 1) Nchildren is increased by one. 2) parent contains pointer psImage structure "
             "out at parent[Nchildren-1].");

    if (original->children == NULL || original->children->n != 2) {
        psError(PS_ERR_UNKNOWN,true,"psImageSubset didn't increment number of children by one per subset.");
        return 12;
    }
    if (original->children->data[0] != subset2 || original->children->data[1] != subset3) {
        psError(PS_ERR_UNKNOWN,true,"psImageSubset didn't properly store the children pointers.");
        return 13;
    }

    psLogMsg(__func__,PS_LOG_INFO,"Verify the returned psImage structure pointer is null and program "
             "execution doesn't stop, if the input parameter image is null. Also verified the input "
             "psImage structure is not modified.");

    psLogMsg(__func__,PS_LOG_INFO,"An error should follow...");
    subset1 = psImageSubset(NULL,0,0,c/2,r/2);
    if (subset1 != NULL) {
        psError(PS_ERR_UNKNOWN,true,"psImageSubset didn't return NULL when input image was NULL.");
        return 14;
    }

    psLogMsg(__func__,PS_LOG_INFO,"Verify the returned psImage structure pointer is null and program "
             " execution doesn't stop, if the input parameters nrow and/or ncol are zero. Also verify "
             "input psImage structure is not modified.");

    memcpy(&preSubsetStruct,original,sizeof(psImage));
    psLogMsg(__func__,PS_LOG_INFO,"An error should follow...");
    subset1 = psImageSubset(original,0,r/2,c/2,r/2);
    if (subset1 != NULL) {
        psError(PS_ERR_UNKNOWN,true,"psImageSubset didn't return NULL when numRows=0.");
        return 15;
    }
    psLogMsg(__func__,PS_LOG_INFO,"An error should follow...");
    subset1 = psImageSubset(original,c/2,0,c/2,r/2);
    if (subset1 != NULL) {
        psError(PS_ERR_UNKNOWN,true,"psImageSubset didn't return NULL when numCols=0.");
        return 16;
    }
    if (memcmp(original,&preSubsetStruct,sizeof(psImage)) != 0) {
        psError(PS_ERR_UNKNOWN,true,"psImageSubset changed the original struct though it failed to subset.");
        return 17;
    }


    psLogMsg(__func__,PS_LOG_INFO,"Verify the returned psImage structure pointer is null and program "
             "execution doesn't stop, if the input parameters row0 and col0 are not within the range of "
             "values of psImage structure image.");

    psLogMsg(__func__,PS_LOG_INFO,"An error should follow...");
    subset1 = psImageSubset(original,0,0,c/2,r*2);
    if (subset1 != NULL) {
        psError(PS_ERR_UNKNOWN,true,"psImageSubset didn't return NULL when subset origin was outside of "
                "image (via cols).");
        return 18;
    }
    psLogMsg(__func__,PS_LOG_INFO,"An error should follow...");
    subset1 = psImageSubset(original,0,0,c*2,r/2);
    if (subset1 != NULL) {
        psError(PS_ERR_UNKNOWN,true,"psImageSubset didn't return NULL when subset origin was outside of "
                "image (via rows).");
        return 19;
    }
    psLogMsg(__func__,PS_LOG_INFO,"An error should follow...");
    subset1 = psImageSubset(original,-1,0,c/2,r/2);
    if (subset1 != NULL) {
        psError(PS_ERR_UNKNOWN,true,"psImageSubset didn't return NULL when subset origin was outside of "
                "image (col0=-1).");
        return 20;
    }
    psLogMsg(__func__,PS_LOG_INFO,"An error should follow...");
    subset1 = psImageSubset(original,0,-1,c/2,r/2);
    if (subset1 != NULL) {
        psError(PS_ERR_UNKNOWN,true,"psImageSubset didn't return NULL when subset origin was outside of "
                "image (row0=-1).");
        return 21;
    }

    psLogMsg(__func__,PS_LOG_INFO,"Verify the returned psImage structure pointer is null and program "
             "execution doesn't stop if the input parameters nrow, ncol, row0 and col0 specify a range of "
             "data not within the input psImage structure image.  Also verify the input psImage structure "
             "is not modified.");

    psLogMsg(__func__,PS_LOG_INFO,"An error should follow...");
    subset1 = psImageSubset(original,0,0,c/2,r+1);
    if (subset1 != NULL) {
        psError(PS_ERR_UNKNOWN,true,"psImageSubset didn't return NULL when subset was outside of image (via rows).");
        return 22;
    }
    psLogMsg(__func__,PS_LOG_INFO,"An error should follow...");
    subset1 = psImageSubset(original,0,0,c+1,r/2);
    if (subset1 != NULL) {
        psError(PS_ERR_UNKNOWN,true,"psImageSubset didn't return NULL when subset was outside of image (via cols).");
        return 23;
    }
    psLogMsg(__func__,PS_LOG_INFO,"An error should follow...");
    subset1 = psImageSubset(original,0,0,c+1,r+1);
    if (subset1 != NULL) {
        psError(PS_ERR_UNKNOWN,true,"psImageSubset didn't return NULL when subset was outside of image (via row+cols).");
        return 24;
    }

    psLogMsg(__func__, PS_LOG_INFO, "psImageFreeChildren shall deallocate any children images of a "
             "psImage structure");

    memcpy(&preSubsetStruct,original,sizeof(psImage));

    psImageFreeChildren(original);

    // Verify the returned psImage structure member Nchildren is set to zero.
    if (original->children != NULL && original->children->n > 0) {
        psError(PS_ERR_UNKNOWN,true,"psImageFreeChildren didn't set number of children to zero.");
        return 25;
    }

    //Verify the returned psImage structure members type, nrow, ncol, row0, col0, rows and parent are not
    // modified.
    if (preSubsetStruct.numRows != original->numRows ||
            preSubsetStruct.numCols != original->numCols ||
            preSubsetStruct.row0 != original->row0 ||
            preSubsetStruct.col0 != original->col0) {

        psError(PS_ERR_UNKNOWN,true,"psImageFreeChildren modified parent's non-children elements.");
        return 27;
    }

    psFree(original);

    return 0;
}

// #730: psImageSubsection shall create child image of a specified size from a parent psImage structure
psS32 testImageSubsection(void)
{
    psImage* original;
    psImage* subset;
    psS32 c = 128;
    psS32 r = 256;
    psS32 i;
    psS32 numRegions = 4;
    psS32 x1[] = {  0, 32, 64, 32};
    psS32 x2[] = { 32, 64,127, 64};
    psS32 y1[] = {  0, 32, 32,128};
    psS32 y2[] = { 32, 64, 64,255};

    original = psImageAlloc(c,r,PS_TYPE_U32);
    for (psS32 row=0;row<r;row++) {
        for (psS32 col=0;col<c;col++) {
            original->data.F32[row][col] = row*1000+col;
        }
    }

    for (i=0; i<numRegions; i++) {
        char sectionStr[64];
        sprintf(sectionStr,"[%d:%d,%d:%d]",x1[i],x2[i],y1[i],y2[i]);

        psLogMsg(__func__,PS_LOG_INFO,"Testing subsection %s.",
                 sectionStr);

        subset = psImageSubsection(original,sectionStr);

        if (subset == NULL) {
            psError(PS_ERR_UNKNOWN,true,"psImageSubsection returned a NULL with a subset of %s.",
                    sectionStr);
            return 10*i+1;
        }

        if (subset->type.type != PS_TYPE_U32) {
            psError(PS_ERR_UNKNOWN,true,"psImageSubsection output type was not proper(%d, should be %d).",
                    subset->type.type, PS_TYPE_U32);
            return 10*i+2;
        }

        if (subset->col0 != x1[i] || subset->row0 != y1[i]) {
            psError(PS_ERR_UNKNOWN,true,"psImageSubsection didn't set properly col0/row0 (%d/%d, should be %d/%d).",
                    subset->col0,subset->row0,x1[i],y1[i]);
            return 10*i+3;
        }

        if (subset->parent != original) {
            psError(PS_ERR_UNKNOWN,true,"psImageSubsection didn't set parent.");
            return 10*i+4;
        }

        if (subset->children != NULL) {
            psError(PS_ERR_UNKNOWN,true,"psImageSubsection didn't set children to NULL.");
            return 10*i+5;
        }

        if (original->children == NULL || original->children->n != i+1) {
            psError(PS_ERR_UNKNOWN,true,"psImageSubsection didn't increment number of children by one per subset.");
            return 10*i+6;
        }


        if (original->children->data[i] != subset) {
            psError(PS_ERR_UNKNOWN,true,"psImageSubsection didn't properly store the children pointer.");
            return 10*i+7;
        }

        psS32 numCols = x2[i]-x1[i]+1;
        psS32 numRows = y2[i]-y1[i]+1;
        if (subset->numCols != numCols || subset->numRows != numRows) {
            psError(PS_ERR_UNKNOWN,true,"psImageSubsection output size was not proper(%dx%d, should be %dx%d).",
                    subset->numCols, subset->numRows, numCols, numRows);
            return 10*i+8;
        }

        for (psS32 row=0;row<numRows;row++) {
            for (psS32 col=0;col<numCols;col++) {
                if (subset->data.U32[row][col] != original->data.U32[row+y1[i]][col+x1[i]]) {
                    psError(PS_ERR_UNKNOWN,true,"psImageSubset output #1 was wrong at %dx%d (%d vs %d).",
                            row,col,subset->data.U32[row][col], original->data.U32[row+y1[i]][col+x1[i]]);
                    return 10*i+9;
                }
            }
        }
    }

    psLogMsg(__func__,PS_LOG_INFO,"An error should follow (x1>x2)");
    subset = psImageSubsection(original,"[64:32,32:64]");
    if (subset != NULL) {
        psError(PS_ERR_UNKNOWN,true,"psImageSubsection didn't return NULL when x1 > x2.");
        return 10*i+10;
    }

    psLogMsg(__func__,PS_LOG_INFO,"An error should follow (y1>y2)");
    subset = psImageSubsection(original,"[32:64,64:32]");
    if (subset != NULL) {
        psError(PS_ERR_UNKNOWN,true,"psImageSubsection didn't return NULL when y1 > y2.");
        return 10*i+11;
    }

    psLogMsg(__func__,PS_LOG_INFO,"An error should follow (x2>nCols)");
    subset = psImageSubsection(original,"[64:256,32:64]"); // assumes c<256
    if (subset != NULL) {
        psError(PS_ERR_UNKNOWN, true,"psImageSubsection didn't return NULL when x2 > c.");
        return 10*i+12;
    }

    psLogMsg(__func__,PS_LOG_INFO,"An error should follow (y2>=nRows)");
    subset = psImageSubsection(original,"[32:64,64:256]"); // assumes r==256
    if (subset != NULL) {
        psError(PS_ERR_UNKNOWN, true,"psImageSubsection didn't return NULL when y2 > r.");
        return 10*i+13;
    }

    psLogMsg(__func__,PS_LOG_INFO,"An error should follow (malformed string - no brackets)");
    subset = psImageSubsection(original,"32:64,32:64");
    if (subset != NULL) {
        psError(PS_ERR_UNKNOWN, true,"psImageSubsection didn't return NULL when subsection was '32:64,32:64'.");
        return 10*i+14;
    }

    psLogMsg(__func__,PS_LOG_INFO,"An error should follow (malformed string - no colons)");
    subset = psImageSubsection(original,"[32-64,32-64]");
    if (subset != NULL) {
        psError(PS_ERR_UNKNOWN, true,"psImageSubsection didn't return NULL when subsection was '[32-64,32-64]'.");
        return 10*i+15;
    }

    psLogMsg(__func__,PS_LOG_INFO,"An error should follow (malformed string - not four numbers)");
    subset = psImageSubsection(original,"[32:64,32]");
    if (subset != NULL) {
        psError(PS_ERR_UNKNOWN, true,"psImageSubsection didn't return NULL when subsection was '[32:64,32]'.");
        return 10*i+16;
    }

    psLogMsg(__func__,PS_LOG_INFO,"An error should follow (image is NULL)");
    subset = psImageSubsection(NULL,"[32:64,32:64]");
    if (subset != NULL) {
        psError(PS_ERR_UNKNOWN, true,"psImageSubsection didn't return NULL when image was NULL.");
        return 10*i+17;
    }

    psLogMsg(__func__,PS_LOG_INFO,"An error should follow (subsection string is NULL)");
    subset = psImageSubsection(original,NULL);
    if (subset != NULL) {
        psError(PS_ERR_UNKNOWN, true,"psImageSubsection didn't return NULL when subsection was NULL.");
        return 10*i+18;
    }

    psFree(original);

    return 0;
}

static psS32 testImageTrim(void)
{
    psS32 r = 200;
    psS32 c = 300;
    psS32 qtrR = r/4;
    psS32 qtrC = c/4;
    psS32 halfR = r/2;
    psS32 halfC = c/2;

    psImage* image = psImageAlloc(c,r,PS_TYPE_F32);
    for (psS32 row = 0; row < image->numRows; row++) {
        for (psS32 col = 0; col < image->numCols; col++) {
            image->data.F32[row][col] = (psF32)col + (psF32)row/1000.0f;
        }
    }

    /*
        1. invoke psImageTrim with non-NULL image, and a valid region 
           x0,y0->x1,y1 (using only positive values). Verify that:
            a. the return psImage is the same as the input psImage.
            b. the size of the psImage is x1-x0 by y1-y0.
            c. the pixel values coorespond to the region [x0:x1-1,y0:y1-1].
    */
    psImage* image1 = psImageCopy(NULL,image,PS_TYPE_F32);
    psImage* image2 = psImageTrim(image1,qtrC,qtrR,qtrC+halfC,qtrR+halfR);

    if (image1 != image2) {
        psLogMsg(__func__,PS_LOG_ERROR,
                 "Return value not same as input value.  Not done in-place?");
        return 1;
    }

    if (image2->numCols != halfC ||
            image2->numRows != halfR) {
        psLogMsg(__func__,PS_LOG_ERROR,
                 "The resulting image size was %dx%d, but should be %dx%d.",
                 image2->numCols, image2->numRows,
                 halfC, halfR);
        return 2;
    }

    for (psS32 row = 0; row < image2->numRows; row++) {
        for (psS32 col = 0; col < image2->numCols; col++) {
            if (fabsf(image2->data.F32[row][col] - image->data.F32[row+qtrR][col+qtrC]) > FLT_EPSILON) {
                psLogMsg(__func__,PS_LOG_ERROR,
                         "The value at (%d,%d) was %g, but should be %g.",
                         col,row,
                         image2->data.F32[row][col],
                         image->data.F32[row+qtrR][col+qtrC]);
                return 3;
            }
        }
    }

    /*
        2. invoke psImageTrim with non-NULL image and valid region where x1=0, 
           y1=0. Verify that:
            a. the return psImage size is numCols-x0 by numRows-y0
            b. the pixel values coorespond to the region 
               [x0:numCols-1,y0:numRows-1].
    */
    image1 = psImageCopy(image1,image,PS_TYPE_F32);
    image2 = psImageTrim(image1,qtrC,qtrR,0,0);

    if (image1 != image2) {
        psLogMsg(__func__,PS_LOG_ERROR,
                 "Return value not same as input value.  Not done in-place?");
        return 11;
    }

    if (image2->numCols != image->numCols-qtrC ||
            image2->numRows != image->numRows-qtrR) {
        psLogMsg(__func__,PS_LOG_ERROR,
                 "The resulting image size was %dx%d, but should be %dx%d.",
                 image2->numCols, image2->numRows,
                 image->numCols-qtrC, image->numRows-qtrR);
        return 12;
    }

    for (psS32 row = 0; row < image2->numRows; row++) {
        for (psS32 col = 0; col < image2->numCols; col++) {
            if (fabsf(image2->data.F32[row][col] -
                      image->data.F32[row+qtrR][col+qtrC]) > FLT_EPSILON) {
                psLogMsg(__func__,PS_LOG_ERROR,
                         "The value at (%d,%d) was %g, but should be %g.",
                         col,row,
                         image2->data.F32[row][col],
                         image->data.F32[row+qtrR][col+qtrC]);
                return 13;
            }
        }
    }

    /*
        4. invoke psImageTrim with x1<0, y1<0. Verify:
            a. the psImage size is (numCols+x1)-x0 by (numRows+y1)-y0.
            b. the pixel values coorespond to the region 
               [x0:numCols+x1-1,y0:numRows+y1-1].

    */
    image1 = psImageCopy(image1,image,PS_TYPE_F32);
    image2 = psImageTrim(image1,qtrC,qtrR,-qtrC,-qtrR);

    if (image1 != image2) {
        psLogMsg(__func__,PS_LOG_ERROR,
                 "Return value not same as input value.  Not done in-place?");
        return 21;
    }

    if (image2->numCols != image->numCols-qtrC-qtrC ||
            image2->numRows != image->numRows-qtrR-qtrR) {
        psLogMsg(__func__,PS_LOG_ERROR,
                 "The resulting image size was %dx%d, but should be %dx%d.",
                 image2->numCols, image2->numRows,
                 image->numCols-qtrC, image->numRows-qtrR);
        return 22;
    }

    for (psS32 row = 0; row < image2->numRows; row++) {
        for (psS32 col = 0; col < image2->numCols; col++) {
            if (fabsf(image2->data.F32[row][col] -
                      image->data.F32[row+qtrR][col+qtrC]) > FLT_EPSILON) {
                psLogMsg(__func__,PS_LOG_ERROR,
                         "The value at (%d,%d) was %g, but should be %g.",
                         col,row,
                         image2->data.F32[row][col],
                         image->data.F32[row+qtrR][col+qtrC]);
                return 23;
            }
        }
    }

    psFree(image2);

    /*
        6. invoke psImageTrim with image=NULL Verify:
            a. execution does not cease.
            b. return value is NULL
            c. appropriate error is generated.
    */

    image2 = psImageTrim(NULL,qtrC,qtrR,0,0);

    if (image2 != NULL) {
        psLogMsg(__func__,PS_LOG_ERROR,
                 "psImageTrim did not return NULL given a NULL input image.");
        return 31;
    }
    psErr* err = psErrorLast();
    if (err == NULL || err->code != PS_ERR_BAD_PARAMETER_NULL) {
        psLogMsg(__func__,PS_LOG_ERROR,
                 "psImageTrim did not generate an appropriate error for NULL input image.");
        psErrorStackPrint(stderr,"Error Stack:");
        return 32;
    }
    psFree(err);

    image1 = psImageCopy(NULL,image,PS_TYPE_F32);
    image2 = psImageTrim(image1,-1,0,0,0);

    if (image2 != NULL) {
        psLogMsg(__func__,PS_LOG_ERROR,
                 "psImageTrim did not return NULL given x0=-1.");
        return 33;
    }
    err = psErrorLast();
    if (err == NULL || err->code != PS_ERR_BAD_PARAMETER_VALUE) {
        psLogMsg(__func__,PS_LOG_ERROR,
                 "psImageTrim did not generate an appropriate error for x0=-1.");
        psErrorStackPrint(stderr,"Error Stack:");
        return 34;
    }
    psFree(err);

    image1 = psImageCopy(NULL,image,PS_TYPE_F32);
    image2 = psImageTrim(image1,0,-1,0,0);

    if (image2 != NULL) {
        psLogMsg(__func__,PS_LOG_ERROR,
                 "psImageTrim did not return NULL given y0=-1.");
        return 35;
    }
    err = psErrorLast();
    if (err == NULL || err->code != PS_ERR_BAD_PARAMETER_VALUE) {
        psLogMsg(__func__,PS_LOG_ERROR,
                 "psImageTrim did not generate an appropriate error for y0=-1.");
        psErrorStackPrint(stderr,"Error Stack:");
        return 36;
    }
    psFree(err);

    image1 = psImageCopy(NULL,image,PS_TYPE_F32);
    image2 = psImageTrim(image1,0,0,image->numCols+1,0);

    if (image2 != NULL) {
        psLogMsg(__func__,PS_LOG_ERROR,
                 "psImageTrim did not return NULL given x1=numCols+1.");
        return 37;
    }
    err = psErrorLast();
    if (err == NULL || err->code != PS_ERR_BAD_PARAMETER_VALUE) {
        psLogMsg(__func__,PS_LOG_ERROR,
                 "psImageTrim did not generate an appropriate error for x1=numCols+1.");
        psErrorStackPrint(stderr,"Error Stack:");
        return 38;
    }
    psFree(err);

    image1 = psImageCopy(NULL,image,PS_TYPE_F32);
    image2 = psImageTrim(image1,0,0,0,image->numRows+1);

    if (image2 != NULL) {
        psLogMsg(__func__,PS_LOG_ERROR,
                 "psImageTrim did not return NULL given y1=numRows+1.");
        return 39;
    }
    err = psErrorLast();
    if (err == NULL || err->code != PS_ERR_BAD_PARAMETER_VALUE) {
        psLogMsg(__func__,PS_LOG_ERROR,
                 "psImageTrim did not generate an appropriate error for y1=numRows+1.");
        psErrorStackPrint(stderr,"Error Stack:");
        return 40;
    }
    psFree(err);

    image1 = psImageCopy(NULL,image,PS_TYPE_F32);
    image2 = psImageTrim(image1,0,0,-image->numCols,0);

    if (image2 != NULL) {
        psLogMsg(__func__,PS_LOG_ERROR,
                 "psImageTrim did not return NULL given x1=-numCols.");
        return 41;
    }
    err = psErrorLast();
    if (err == NULL || err->code != PS_ERR_BAD_PARAMETER_VALUE) {
        psLogMsg(__func__,PS_LOG_ERROR,
                 "psImageTrim did not generate an appropriate error for x1=-numCols.");
        psErrorStackPrint(stderr,"Error Stack:");
        return 42;
    }
    psFree(err);

    image1 = psImageCopy(NULL,image,PS_TYPE_F32);
    image2 = psImageTrim(image1,0,0,0,-image->numRows);

    if (image2 != NULL) {
        psLogMsg(__func__,PS_LOG_ERROR,
                 "psImageTrim did not return NULL given y1=-numRows.");
        return 41;
    }
    err = psErrorLast();
    if (err == NULL || err->code != PS_ERR_BAD_PARAMETER_VALUE) {
        psLogMsg(__func__,PS_LOG_ERROR,
                 "psImageTrim did not generate an appropriate error for y1=-numRows.");
        psErrorStackPrint(stderr,"Error Stack:");
        return 42;
    }
    psFree(err);

    psFree(image);
    return 0;
}

static psS32 testImageCut(void)
{
    psS32 c = 300;
    psS32 r = 200;
    psS32 numPoints = 15;
    float startCol[] = { 40,150, 40,  0,280, 40,280, -1,300, 20, 20, 20, 20, 20, 20};
    float endCol[] =   {240,150,240,299, 40,240, 40,240,240, -1,300,240,240,240,240};
    float startRow[] = { 20, 10,100,  0, 20,180,180, 10, 10, 10, 10, -1,200, 10, 10};
    float endRow[] =   {160,180,100,199,160, 10, 10,180,180,180,180,180,180, -1,200};
    psBool success[] = {true,true,true,true,true,true,true,false,false,false,false,false,false,false,false};
    psU32 length = 100;

    psImage* image = psImageAlloc(c,r,PS_TYPE_F32);
    psImage* mask = psImageAlloc(c,r,PS_TYPE_MASK);
    for (psS32 row = 0; row < image->numRows; row++) {
        for (psS32 col = 0; col < image->numCols; col++) {
            image->data.F32[row][col] = (psF32)col + (psF32)row/1000.0f;
            if ((row & 0x0F) == 0) {
                mask->data.PS_TYPE_MASK_DATA[row][col] = 1;
            } else {
                mask->data.PS_TYPE_MASK_DATA[row][col] = 0;
            }
        }
    }
    psVector* rows = psVectorAlloc(length,PS_TYPE_F32);
    psVector* cols = psVectorAlloc(length,PS_TYPE_F32);

    psVector* result = NULL;
    for (psS32 n = 0; n < numPoints; n++) {
        psVector* orig = result;
        if (! success[n]) {
            psLogMsg(__func__,PS_LOG_INFO,"The following should be an error.");
        }
        if (n == 1) {
            result = psImageCut(result,
                                cols,rows,
                                image,
                                NULL,0,
                                startCol[n], startRow[n],
                                endCol[n], endRow[n],
                                length,
                                PS_INTERPOLATE_FLAT);
        } else {
            result = psImageCut(result,
                                cols,rows,
                                image,
                                mask,1,
                                startCol[n], startRow[n],
                                endCol[n], endRow[n],
                                length,
                                PS_INTERPOLATE_FLAT);
        }

        if (success[n]) {
            if (result == NULL) {
                psLogMsg(__func__,PS_LOG_ERROR,
                         "psImageCut returned NULL instead of a valid result.");
                return n*10+1;
            }

            if (orig != NULL && orig != result) {
                psLogMsg(__func__,PS_LOG_ERROR,
                         "psImageCut didn't recycle the out parameter properly.");
                return n*10+2;
            }

            float deltaRow = (endRow[n]-startRow[n])/(length-1);
            float deltaCol = (endCol[n]-startCol[n])/(length-1);
            psF32 truth;
            for (psS32 i = 0; i < length; i++) {
                float x = (float)startCol[n]+(float)i*deltaCol;
                float y = (float)startRow[n]+(float)i*deltaRow;
                if (n == 1) {
                    truth = psImagePixelInterpolate( image, x, y,
                                                     NULL,0,0,PS_INTERPOLATE_FLAT);
                } else {
                    truth = psImagePixelInterpolate( image, x, y,
                                                     mask,1,0,PS_INTERPOLATE_FLAT);
                }
                if (fabs(result->data.F32[i]-truth) > FLT_EPSILON) {
                    psLogMsg(__func__,PS_LOG_ERROR,
                             "Bad result in position %d; Found %g but expected %g.",
                             i, result->data.F32[i], truth);
                    return n*10+5;
                }
                if (fabsf(x - cols->data.F32[i]) > FLT_EPSILON ||
                        fabsf(y - rows->data.F32[i]) > FLT_EPSILON) {
                    psLogMsg(__func__,PS_LOG_ERROR,
                             "Bad resulting col/row at index %d; Found (%g,%g) but expected (%g,%g).",
                             i, cols->data.F32[i], rows->data.F32[i], x, y);
                    return n*10+6;
                }
            }
        } else {
            if (result != NULL) {
                psLogMsg(__func__,PS_LOG_ERROR,
                         "psImageCut did not return NULL with a cut of (%g,%g)->(%g,%g).",
                         startCol[n],startRow[n],endCol[n],endRow[n]);
                return n*10+7;
            }
            psErr* err = psErrorLast();
            if (err->code != PS_ERR_BAD_PARAMETER_VALUE) {
                psLogMsg(__func__,PS_LOG_ERROR,
                         "psImageCut did not generate proper error message.");
                return 105;
            }
            psFree(err);
        }
    }

    psLogMsg(__func__,PS_LOG_INFO,"Following should be an error (NULL image).");
    result = psImageCut(result,
                        cols,rows,
                        NULL,
                        mask,1,
                        startCol[0], startRow[0],
                        endCol[0], endRow[0],
                        length,
                        PS_INTERPOLATE_FLAT);
    if (result != NULL) {
        psLogMsg(__func__,PS_LOG_ERROR,
                 "psImageCut did not return NULL given NULL image.");
        return 100;
    }
    psErr* err = psErrorLast();
    if (err->code != PS_ERR_BAD_PARAMETER_NULL) {
        psLogMsg(__func__,PS_LOG_ERROR,
                 "psImageCut did not generate proper error message given NULL image.");
        return 101;
    }
    psFree(err);

    psLogMsg(__func__,PS_LOG_INFO,"Following should be an error (length=0).");
    result = psImageCut(result,
                        cols,rows,
                        image,
                        mask,1,
                        startCol[0], startRow[0],
                        endCol[0], endRow[0],
                        0,
                        PS_INTERPOLATE_FLAT);
    if (result != NULL) {
        psLogMsg(__func__,PS_LOG_ERROR,
                 "psImageCut did not return NULL given length=0.");
        return 102;
    }
    err = psErrorLast();
    if (err->code != PS_ERR_BAD_PARAMETER_VALUE) {
        psLogMsg(__func__,PS_LOG_ERROR,
                 "psImageCut did not generate proper error message given length=0.");
        return 103;
    }
    psFree(err);

    psFree(result);
    psFree(image);
    psFree(mask);
    psFree(rows);
    psFree(cols);

    return 0;
}

static psS32 testImageRadialCut(void)
{
    psS32 c = 300;
    psS32 r = 200;
    psS32 centerX = c/2;
    psS32 centerY = r/2;
    psErr* err = NULL;

    psImage* image = psImageAlloc(c,r,PS_TYPE_F32);
    psImage* mask = psImageAlloc(c,r,PS_TYPE_MASK);
    for (psS32 row = 0; row < image->numRows; row++) {
        for (psS32 col = 0; col < image->numCols; col++) {
            image->data.F32[row][col] = sqrtf((col-centerX)*(col-centerX)+(row-centerY)*(row-centerY));
            if ((row & 0x0F) == 0) {
                mask->data.PS_TYPE_MASK_DATA[row][col] = 1;
            } else {
                mask->data.PS_TYPE_MASK_DATA[row][col] = 0;
            }
        }
    }

    psStats* stat = psStatsAlloc(PS_STAT_SAMPLE_MEAN);
    psVector* radii = psVectorAlloc(10,PS_TYPE_F32);
    for (psS32 i=0; i < 10; i++) {
        radii->data.F32[i] = 10+i*10;
    }

    psVector* result = NULL;

    result = psImageRadialCut(result,image,mask,1,centerX,centerY,radii,stat);

    if (result == NULL) {
        psLogMsg(__func__,PS_LOG_ERROR,
                 "Return value of NULL unexpected.");
        return 1;
    }

    if (result->type.type != PS_TYPE_F64) {
        psLogMsg(__func__,PS_LOG_ERROR,
                 "Return type not psF64, as expected.");
        return 2;
    }

    for (psS32 i=0; i < 9; i++) {
        if (fabs(result->data.F64[i] - (15.0+i*10)) > 1) {
            psLogMsg(__func__,PS_LOG_ERROR,
                     "Result was not as expected for radii #%d (%g, expected %d +/- 1)",
                     result->data.F64[i], (15.0+i*10) );
            return 3+i;
        }
    }

    // again, but without mask
    psVector* orig = result;
    result = psImageRadialCut(result,image,NULL,1,centerX,centerY,radii,stat);

    if (result == NULL) {
        psLogMsg(__func__,PS_LOG_ERROR,
                 "Return value of NULL unexpected.");
        return 12;
    }

    if (result != orig) {
        psLogMsg(__func__,PS_LOG_ERROR,
                 "Return value of is not same as input parameter 'out'.");
        return 13;
    }

    for (psS32 i=0; i < 9; i++) {
        if (fabs(result->data.F64[i] - (15.0+i*10)) > 1) {
            psLogMsg(__func__,PS_LOG_ERROR,
                     "Result was not as expected for radii #%d (%g, expected %d +/- 1)",
                     result->data.F64[i], (15.0+i*10) );
            return 14+i;
        }
    }

    // NULL input image...
    psLogMsg(__func__,PS_LOG_INFO,"Following should be an error.");
    result = psImageRadialCut(result,NULL,NULL,1,centerX,centerY,radii,stat);

    if (result != NULL) {
        psLogMsg(__func__,PS_LOG_ERROR,
                 "Return value not NULL as expected.");
        return 23;
    }

    err = psErrorLast();
    if (err->code != PS_ERR_BAD_PARAMETER_NULL) {
        psLogMsg(__func__,PS_LOG_ERROR,
                 "psImageRadialCut did not generate proper error message.");
        return 24;
    }
    psFree(err);

    // NULL input radii...
    psLogMsg(__func__,PS_LOG_INFO,"Following should be an error.");
    result = psImageRadialCut(result,image,mask,1,centerX,centerY,NULL,stat);

    if (result != NULL) {
        psLogMsg(__func__,PS_LOG_ERROR,
                 "Return value not NULL as expected.");
        return 23;
    }

    err = psErrorLast();
    if (err->code != PS_ERR_BAD_PARAMETER_NULL) {
        psLogMsg(__func__,PS_LOG_ERROR,
                 "psImageRadialCut did not generate proper error message.");
        return 24;
    }
    psFree(err);

    // NULL input stat...
    psLogMsg(__func__,PS_LOG_INFO,"Following should be an error.");
    result = psImageRadialCut(result,image,mask,1,centerX,centerY,radii,NULL);

    if (result != NULL) {
        psLogMsg(__func__,PS_LOG_ERROR,
                 "Return value not NULL as expected.");
        return 23;
    }

    err = psErrorLast();
    if (err->code != PS_ERR_BAD_PARAMETER_NULL) {
        psLogMsg(__func__,PS_LOG_ERROR,
                 "psImageRadialCut did not generate proper error message.");
        return 24;
    }
    psFree(err);

    // Bad center X
    psLogMsg(__func__,PS_LOG_INFO,"Following should be an error.");
    result = psImageRadialCut(result,image,mask,1,
                              c+1,centerY,radii,stat);

    if (result != NULL) {
        psLogMsg(__func__,PS_LOG_ERROR,
                 "Return value not NULL as expected.");
        return 25;
    }

    err = psErrorLast();
    if (err->code != PS_ERR_BAD_PARAMETER_VALUE) {
        psLogMsg(__func__,PS_LOG_ERROR,
                 "psImageRadialCut did not generate proper error message.");
        return 26;
    }
    psFree(err);

    // Bad center Y
    psLogMsg(__func__,PS_LOG_INFO,"Following should be an error.");
    result = psImageRadialCut(result,image,mask,1,
                              centerX,r+1,radii,stat);

    if (result != NULL) {
        psLogMsg(__func__,PS_LOG_ERROR,
                 "Return value not NULL as expected.");
        return 27;
    }

    err = psErrorLast();
    if (err->code != PS_ERR_BAD_PARAMETER_VALUE) {
        psLogMsg(__func__,PS_LOG_ERROR,
                 "psImageRadialCut did not generate proper error message.");
        return 28;
    }
    psFree(err);

    // Bad mask type (N.B., swapped image/mask to do this)
    psLogMsg(__func__,PS_LOG_INFO,"Following should be an error.");
    result = psImageRadialCut(result,mask,image,1,
                              centerX,r+1,radii,stat);

    if (result != NULL) {
        psLogMsg(__func__,PS_LOG_ERROR,
                 "Return value not NULL as expected.");
        return 29;
    }

    err = psErrorLast();
    if (err->code != PS_ERR_BAD_PARAMETER_TYPE) {
        psLogMsg(__func__,PS_LOG_ERROR,
                 "psImageRadialCut did not generate proper error message.");
        return 30;
    }
    psFree(err);

    // Bad mask size
    psImage* mask2 = psImageAlloc(c/2,r/2,PS_TYPE_MASK);
    psLogMsg(__func__,PS_LOG_INFO,"Following should be an error.");
    result = psImageRadialCut(result,image, mask2, 1,
                              centerX,centerY,radii,stat);
    psFree(mask2);
    if (result != NULL) {
        psLogMsg(__func__,PS_LOG_ERROR,
                 "Return value not NULL as expected.");
        return 31;
    }

    err = psErrorLast();
    if (err->code != PS_ERR_BAD_PARAMETER_SIZE) {
        psLogMsg(__func__,PS_LOG_ERROR,
                 "psImageRadialCut did not generate proper error message.");
        return 32;
    }
    psFree(err);

    // Bad radii size
    psVector* radii2 = psVectorAlloc(1,PS_TYPE_MASK);
    psLogMsg(__func__,PS_LOG_INFO,"Following should be an error.");
    result = psImageRadialCut(result,image, mask, 1,
                              centerX,centerY,radii2,stat);
    psFree(radii2);
    if (result != NULL) {
        psLogMsg(__func__,PS_LOG_ERROR,
                 "Return value not NULL as expected.");
        return 33;
    }

    err = psErrorLast();
    if (err->code != PS_ERR_BAD_PARAMETER_SIZE) {
        psLogMsg(__func__,PS_LOG_ERROR,
                 "psImageRadialCut did not generate proper error message.");
        return 34;
    }
    psFree(err);

    // bad input stat option...
    stat->options = 0;
    psLogMsg(__func__,PS_LOG_INFO,"Following should be an error.");
    result = psImageRadialCut(result,image,mask,1,centerX,centerY,radii,stat);
    stat->options = PS_STAT_SAMPLE_MEAN;

    if (result != NULL) {
        psLogMsg(__func__,PS_LOG_ERROR,
                 "Return value not NULL as expected.");
        return 35;
    }

    err = psErrorLast();
    if (err->code != PS_ERR_BAD_PARAMETER_VALUE) {
        psLogMsg(__func__,PS_LOG_ERROR,
                 "psImageRadialCut did not generate proper error message.");
        return 36;
    }
    psFree(err);

    psFree(image);
    psFree(mask);
    psFree(radii);
    psFree(stat);
    psFree(result);

    return 0;
}
