Index: /branches/desonia/psLib/src/image/psPixels.c
===================================================================
--- /branches/desonia/psLib/src/image/psPixels.c	(revision 3738)
+++ /branches/desonia/psLib/src/image/psPixels.c	(revision 3738)
@@ -0,0 +1,343 @@
+/** @file  psPixels.c
+ *
+ *  @brief Contains psPixel related functions
+ *
+ *  @ingroup Image
+ *
+ *  @author Robert DeSonia, MHPCC
+ *
+ *  @version $Revision: 1.1 $ $Name: not supported by cvs2svn $
+ *  @date $Date: 2005-04-21 21:18:23 $
+ *
+ *  Copyright 2004-2005 Maui High Performance Computing Center, University of Hawaii
+ */
+
+#include <string.h>
+#include <stdlib.h>
+
+#include "psPixels.h"
+#include "psMemory.h"
+
+typedef struct
+{
+    psS32 x;
+    psS32 y;
+}
+p_psPixelCoord;
+
+typedef int(*qsortCompareFcn)(const void *, const void *);
+
+static void pixelsFree(psPixels* pixels)
+{
+    if (pixels != NULL) {
+        psFree(pixels->x);
+        psFree(pixels->y);
+    }
+}
+
+// for use by qsort, etc.
+static int comparePixelCoord(p_psPixelCoord* coord1, p_psPixelCoord* coord2)
+{
+    // check row first
+    if (coord1->y < coord2->y) {
+        return -1;
+    }
+
+    if (coord1->y > coord2->y) {
+        return 1;
+    }
+
+    // rows are the same, so check column
+    if (coord1->x < coord2->x) {
+        return -1;
+    }
+
+    if (coord1->x > coord2->x) {
+        return 1;
+    }
+
+    return 0;
+}
+
+psPixels* psPixelsAlloc(int size)
+{
+    psPixels* out = psAlloc(sizeof(psPixels));
+
+    if (size > 0) {
+        out->x = psVectorAlloc(size, PS_TYPE_S32);
+        out->y = psVectorAlloc(size, PS_TYPE_S32);
+    } else {
+        out->x = NULL;
+        out->y = NULL;
+    }
+
+    psMemSetDeallocator(out, (psFreeFcn)pixelsFree);
+
+    return NULL;
+}
+
+psPixels* psPixelsRealloc(psPixels* pixels, int size)
+{
+    if (pixels == NULL) {
+        return psPixelsAlloc(size);
+    }
+
+    pixels->x = psVectorRealloc(pixels->x, size);
+    pixels->y = psVectorRealloc(pixels->y, size);
+
+    return pixels;
+}
+
+psImage *psPixelsToMask(psImage *out, const psPixels *pixels, const psRegion *region, unsigned int maskVal)
+{
+    // check that the input pixel vector is valid
+    if (pixels == NULL) {
+        // XXX: Error message
+        psFree(out);
+        return NULL;
+    }
+    psVector* xVec = pixels->x;
+    psVector* yVec = pixels->y;
+    if (xVec == NULL || yVec == NULL) {
+        // XXX: Error message
+        psFree(out);
+        return NULL;
+    }
+    if (xVec->type.type != PS_TYPE_S32) {
+        // XXX: Error message
+        psFree(out);
+        return NULL;
+    }
+    if (yVec->type.type != PS_TYPE_S32) {
+        // XXX: Error message
+        psFree(out);
+        return NULL;
+    }
+
+    // check if the input region is valid
+    if (region == NULL) {
+        // XXX: Error message
+        psFree(out);
+        return NULL;
+    }
+    int x0 = region->x0;
+    int x1 = region->x1;
+    int y0 = region->y0;
+    int y1 = region->y1;
+
+    // determine the output image size
+    int numRows = x1-x0;
+    int numCols = y1-y0;
+    if (numRows < 1 || numCols < 1) {
+        // XXX: Error message
+        psFree(out);
+        return NULL;
+    }
+
+    //  allocate the output image
+    out = psImageRecycle(out, numCols, numRows, PS_TYPE_MASK);
+    if (out == NULL) {
+        // XXX: Error message
+        return NULL;
+    }
+    *(psS32*)&out->row0 = x0;
+    *(psS32*)&out->col0 = y0;
+
+    // initialize image to all zeros
+    int columnByteSize = sizeof(PS_TYPE_MASK)*numCols;
+    for (int row = 0; row < numRows; row++) {
+        memset(out->data.U8[row],0,columnByteSize);
+    }
+
+    // determine the length of the pixel vector
+    int length = pixels->x->n;
+    if (pixels->y->n != length) {
+        // XXX: warning message
+        if (pixels->y->n < length) {
+            length = pixels->y->n;
+        }
+    }
+
+    // cycle through the vector of pixels and insert pixels into image
+    psMaskType** outData = out->data.PS_TYPE_MASK_DATA;
+    for (int p = 0; p < length; p++) {
+        psS32 x = xVec->data.S32[p];
+        psS32 y = yVec->data.S32[p];
+        // pixel in region?
+        if (x >= x0 && x < x1 && y >= y0 && y < y1) {
+            outData[x-x0][y-y0] |= maskVal;
+        }
+    }
+
+    return out;
+}
+
+psPixels *psMaskToPixels(psPixels *out, const psImage *mask, unsigned int maskVal)
+{
+    if (mask == NULL) {
+        // XXX: Error message
+        psFree(out);
+        return NULL;
+    }
+    if (mask->type.type != PS_TYPE_MASK) {
+        // XXX: Error message
+        psFree(out);
+        return NULL;
+    }
+    int numRows = mask->numRows;
+    int numCols = mask->numCols;
+
+    // assumption: number of masked pixels is relatively small compared to
+    // total pixels, so it is best to just start with a guess and resize if
+    // necessary
+    int minPixels = numRows*numCols/100; // initial guess, 1% of pixels masked
+    if (minPixels < 32) { // enforce a minimum size
+        minPixels = 32;
+    }
+    if (out == NULL) {
+        out = psPixelsAlloc(minPixels);
+    }
+    psVector* xVec = out->x;
+    psVector* yVec = out->y;
+
+    // check the x and y vector validity (type/minimum size)
+    if (xVec == NULL || xVec->type.type != PS_TYPE_S32 || xVec->nalloc < minPixels) {
+        xVec = psVectorRecycle(xVec,minPixels,PS_TYPE_S32);
+    }
+    if (yVec == NULL || yVec->type.type != PS_TYPE_S32 || yVec->nalloc < minPixels) {
+        yVec = psVectorRecycle(yVec, minPixels,PS_TYPE_S32);
+    }
+
+    // start with a blank list of pixels
+    xVec->n = 0;
+    yVec->n = 0;
+
+    // find the mask pixels in the image
+    int numPixels = 0;
+    for (int row=0; row<numRows; row++) {
+        psMaskType* maskRow = mask->data.PS_TYPE_MASK_DATA[row];
+        for (int col=0; col<numCols; col++) {
+            if ( (maskRow[col] | maskVal) != 0 ) {
+                // check the vector sizes, and expand if necessary
+                if (xVec->nalloc >= numPixels) {
+                    xVec = psVectorRealloc(xVec, 2*xVec->nalloc);
+                }
+                if (yVec->nalloc >= numPixels) {
+                    yVec = psVectorRealloc(yVec, 2*yVec->nalloc);
+                }
+
+                xVec->data.S32[numPixels] = col;
+                yVec->data.S32[numPixels] = row;
+                numPixels++;
+            }
+        }
+    }
+
+    // return the vectors to the psPixels struct
+    // (n.b., not assuming psVectorRealloc/psVectorRecycle, etc., didn't
+    //  relocate the vectors)
+    out->x = xVec;
+    out->y = yVec;
+
+    return out;
+}
+
+psPixels* psPixelsConcatenate(psPixels *out,const psPixels *pixels)
+{
+    if (pixels == NULL) {
+        // XXX: Error message
+        return NULL;
+    }
+    psVector* xPixels = pixels->x;
+    psVector* yPixels = pixels->y;
+
+    // verify that pixels has well formed vectors (type)
+    if (xPixels->type.type != PS_TYPE_S32 ||
+            yPixels->type.type != PS_TYPE_S32) {
+        // XXX: Error message
+        return NULL;
+    }
+
+    // determine the length of the pixel vector
+    int pixelsLen = xPixels->n;
+    if (yPixels->n != pixelsLen) {
+        // XXX: warning message
+        if (yPixels->n < pixelsLen) {
+            pixelsLen = yPixels->n;
+        }
+    }
+
+    if (out == NULL) {
+        // simple copy of pixels
+        out = psPixelsAlloc(0); // let psVectorCopy allocate the vector
+        out->x = psVectorCopy(out->x,pixels->x,PS_TYPE_S32);
+        out->y = psVectorCopy(out->y,pixels->y,PS_TYPE_S32);
+
+        return out;
+    }
+
+    // make sure the out vectors are allocated
+    psVector* xVec = out->x;
+    psVector* yVec = out->y;
+    if (xVec == NULL) {
+        out->x = xVec = psVectorAlloc(pixelsLen,PS_TYPE_S32);
+        xVec->n = 0;
+    }
+    if (yVec == NULL) {
+        out->y = yVec = psVectorAlloc(pixelsLen,PS_TYPE_S32);
+        yVec->n = 0;
+    }
+
+    // verify that out has well formed vectors (type/size)
+    if (xVec->type.type != PS_TYPE_S32 ||
+            yVec->type.type != PS_TYPE_S32) {
+        // XXX: Error message
+        return NULL;
+    }
+    if (xVec->n != yVec->n) {
+        // XXX: Error message
+        return NULL;
+    }
+    int outLen = xVec->n;
+
+
+    // populate an array of psPixelCoord structs with the out values
+    p_psPixelCoord* coordinates = psAlloc(sizeof(p_psPixelCoord)*(pixelsLen+outLen));
+    psS32* outXData = xVec->data.S32;
+    psS32* outYData = yVec->data.S32;
+    for (int n = 0; n < outLen; n++) {
+        coordinates[n].x = outXData[n];
+        coordinates[n].y = outYData[n];
+    }
+
+    // sort the coordinates array
+    qsort(coordinates, sizeof(p_psPixelCoord), outLen,
+          (qsortCompareFcn)comparePixelCoord);
+
+    // search out for coordinates in pixels
+    int end = outLen;
+    psS32* pixelsXData = xPixels->data.S32;
+    psS32* pixelsYData = yPixels->data.S32;
+    p_psPixelCoord pCoord;
+    for (int n = 0; n < pixelsLen; n++) {
+        pCoord.x = pixelsXData[n];
+        pCoord.y = pixelsYData[n];
+        if (bsearch(&pCoord, coordinates, sizeof(p_psPixelCoord), outLen,
+                    (qsortCompareFcn)comparePixelCoord) == NULL) {
+            coordinates[end++] = pCoord;
+        }
+    }
+
+    // transfer the coordinates data back to psPixels
+    out = psPixelsRealloc(out, end);
+    outXData = xVec->data.S32;
+    outYData = yVec->data.S32;
+    for (int n = 0; n < end; n++) {
+        outXData[n] = coordinates[n].x;
+        outYData[n] = coordinates[n].y;
+    }
+
+    psFree(coordinates);
+
+    return out;
+}
Index: /branches/desonia/psLib/src/image/psPixels.h
===================================================================
--- /branches/desonia/psLib/src/image/psPixels.h	(revision 3738)
+++ /branches/desonia/psLib/src/image/psPixels.h	(revision 3738)
@@ -0,0 +1,107 @@
+/** @file  psPixels.h
+ *
+ *  @brief Contains psPixel related functions
+ *
+ *  @ingroup Image
+ *
+ *  @author Robert DeSonia, MHPCC
+ *
+ *  @version $Revision: 1.1 $ $Name: not supported by cvs2svn $
+ *  @date $Date: 2005-04-21 21:18:23 $
+ *
+ *  Copyright 2004-2005 Maui High Performance Computing Center, University of Hawaii
+ */
+#ifndef PS_PIXELS_H
+#define PS_PIXELS_H
+
+#include "psImage.h"
+#include "psVector.h"
+
+/// @addtogroup Image
+/// @{
+
+/** list of pixel coordinates
+ *
+ *  Usually an image mask is the best way to carry information about what
+ *  pixels mean what. However, in the case where the number of pixels in which
+ *  we are interested is limited, it is more efï¬cient to simply carry a list
+ *  of pixels. An example of this is in the image combination code, where we
+ *  want to perform an operation on a relatively small fraction of pixels, and
+ *  it is inefï¬cient to go through an entire mask image checking each pixel.
+ *
+ */
+typedef struct
+{
+    psVector *x;                       ///< x coordinate
+    psVector *y;                       ///< y coordinate
+}
+psPixels;
+
+
+/** Allocates a new psPixels structure
+ *
+ *  @return psPixels*   new psPixels
+ */
+psPixels* psPixelsAlloc(
+    int size                           ///< the size of the coordinate vectors
+);
+
+/** resizes a psPixels structure
+ *
+ *  @return psPixels*   resized psPixels
+ */
+psPixels* psPixelsRealloc(
+    psPixels* pixels,                  ///< psPixels to resize, or NULL to create new psPixels
+    int size                           ///< the size of the coordinate vectors
+);
+
+/** Generate a psImage from a psPixels
+ *
+ *  psPixelsToMask shall return an image of type U8 with the pixels lying
+ *  within the speciï¬ed region set to the maskVal. The out image shall be
+ *  modiï¬ed if supplied, or allocated and returned if NULL. The size of the
+ *  output image shall be region->x1 - region->x0 by region->y1 - region->y0,
+ *  with out->x0 = region->x0 and out->y0 = region->y0. In the event that
+ *  either of pixels or region are NULL, the function shall generate an
+ *  error and return NULL.
+ *
+ *  @return psImage*    generated mask image
+ */
+psImage* psPixelsToMask(
+    psImage* out,                      ///< psImage to recycle, or NULL
+    const psPixels* pixels,            ///< list of pixels to use
+    const psRegion* region,            ///< region to define the output mask image
+    unsigned int maskVal               ///< the mask bit-values to act upon
+);
+
+/** Generate a psPixels from a mask psImage
+ *
+ *  psMaskToPixels shall return a psPixels consisting of the coordinates in
+ *  the mask that match the maskVal. The out pixel list shall be modiï¬ed if
+ *  supplied, or allocated and returned if NULL. In hte event that mask is
+ *  NULL, the function shall generate an error and return NULL.
+ *
+ *  @return psPixels*   generated psPixels pixel list
+ */
+psPixels* psMaskToPixels(
+    psPixels *out,                     ///< psPixels to recycle, or NULL
+    const psImage *mask,               ///< the input mask psImage
+    unsigned int maskVal               ///< the mask bit-values to act upon
+);
+
+/** Concatenates two psPixels
+ *
+ *  psPixelsConcatenate shall concatenate pixels onto out. In the event that
+ *  out is NULL, a new psPixels shall be allocated, and the contents of
+ *  pixels simply copied in. If pixels is NULL, the function shall generate
+ *  an error and return NULL. The function shall take care to ensure that
+ *  there are no duplicate pixels in out.
+ *
+ *  @return psPixels         Concatenated psPixel list
+ */
+psPixels* psPixelsConcatenate(
+    psPixels *out,                     ///< psPixels to recycle, or NULL
+    const psPixels *pixels             ///< psPixels to append to OUT
+);
+
+#endif
