Index: trunk/psLib/src/collections/Makefile.am
===================================================================
--- trunk/psLib/src/collections/Makefile.am	(revision 3740)
+++ trunk/psLib/src/collections/Makefile.am	(revision 3761)
@@ -15,4 +15,5 @@
 	psBitSet.c \
 	psVector.c \
+	psPixels.c \
 	psList.c \
 	psScalar.c \
Index: trunk/psLib/src/collections/psPixels.c
===================================================================
--- trunk/psLib/src/collections/psPixels.c	(revision 3761)
+++ trunk/psLib/src/collections/psPixels.c	(revision 3761)
@@ -0,0 +1,262 @@
+/** @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-23 00:10:19 $
+ *
+ *  Copyright 2004-2005 Maui High Performance Computing Center, University of Hawaii
+ */
+
+#include <string.h>
+#include <stdlib.h>
+
+#include "psPixels.h"
+#include "psMemory.h"
+
+typedef int(*qsortCompareFcn)(const void *, const void *);
+
+static void pixelsFree(psPixels* pixels)
+{
+    if (pixels != NULL) {
+        psFree(pixels->data);
+    }
+}
+
+// for use by qsort, etc.
+static int comparePixelCoord(psPixelCoord* coord1, 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->data = psAlloc(sizeof(psPixelCoord)*size);
+    } else {
+        out->data = NULL;
+    }
+    out->n = 0;
+    out->nalloc = size;
+
+    psMemSetDeallocator(out, (psFreeFcn)pixelsFree);
+
+    return NULL;
+}
+
+psPixels* psPixelsRealloc(psPixels* pixels, int size)
+{
+    if (pixels == NULL) {
+        return psPixelsAlloc(size);
+    }
+
+    pixels->data = psRealloc(pixels->data, sizeof(psPixelCoord)*size);
+
+    pixels->nalloc = size;
+    if (pixels->n > pixels->nalloc) {
+        pixels->n = pixels->nalloc;
+    }
+
+    return pixels;
+}
+
+psPixels* psPixelsCopy(psPixels* out, const psPixels* in)
+{
+    if (in == NULL) {
+        return NULL;
+    }
+
+    out = psPixelsRealloc(out, in->n);
+
+    memcpy(in->data,out->data, in->n*sizeof(psPixelCoord));
+    out->n = in->n;
+
+    return out;
+}
+
+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;
+    }
+    psPixelCoord* data = pixels->data;
+    if (data == NULL) {
+        // 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->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 = data[p].x;
+        psS32 y = data[p].y;
+        // 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;
+    }
+
+    // check out's validity (allocated/minimum size)
+    if (out == NULL || out->data == NULL || out->nalloc < minPixels) {
+        out = psPixelsRealloc(out,minPixels);
+    }
+
+    // start with a blank list of pixels
+    out->n = 0;
+
+    // find the mask pixels in the image
+    int numPixels = 0;
+    psPixelCoord* data = out->data;
+    int nalloc = out->nalloc;
+    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 (nalloc >= numPixels) {
+                    out = psPixelsRealloc(out, 2*nalloc);
+                    nalloc = out->nalloc;
+                    data = out->data;
+                }
+
+                data[numPixels].x = col;
+                data[numPixels].y = row;
+                numPixels++;
+            }
+        }
+    }
+
+    return out;
+}
+
+psPixels* psPixelsConcatenate(psPixels *out,const psPixels *pixels)
+{
+    if (pixels == NULL) {
+        // XXX: Error message
+        return NULL;
+    }
+    int pixelsN = pixels->n;
+    psPixelCoord* pixelsData = pixels->data;
+
+    if (out == NULL) {
+        // simple copy pixels
+        out = psPixelsCopy(out,pixels);
+        return out;
+    }
+
+    // make sure the out is large enough to fit the result
+    int outN = out->n;
+    out = psPixelsRealloc(out,outN + pixelsN);
+    psPixelCoord* outData = out->data;
+
+    // sort the OUT array to help in searching for duplicates later
+    qsort(outData, sizeof(psPixelCoord), outN,
+          (qsortCompareFcn)comparePixelCoord);
+
+    // add non-duplicate values in pixels to out
+    psPixelCoord pCoord;
+    int end = outN;
+    for (int n = 0; n < pixelsN; n++) {
+        pCoord = pixelsData[n];
+        if (bsearch(&pCoord, outData, sizeof(psPixelCoord), outN,
+                    (qsortCompareFcn)comparePixelCoord) == NULL) {
+            // no match in OUT array of this value
+            outData[end++] = pCoord;
+        }
+    }
+    out->n = end; // set number of elements to reflect added data
+
+    return out;
+}
Index: trunk/psLib/src/collections/psPixels.h
===================================================================
--- trunk/psLib/src/collections/psPixels.h	(revision 3761)
+++ trunk/psLib/src/collections/psPixels.h	(revision 3761)
@@ -0,0 +1,127 @@
+/** @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-23 00:10:19 $
+ *
+ *  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
+/// @{
+
+typedef struct
+{
+    psS32 x;
+    psS32 y;
+}
+psPixelCoord;
+
+/** 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
+{
+    int n;
+    int nalloc;
+    psPixelCoord* data;
+}
+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
+);
+
+/** Copies a psPixels object
+ *
+ *  Makes a deep copy of the data in a psPixels object.  Any data in the OUT
+ *  parameter will be destroyed and OUT will be resized, if necessary.
+ *
+ *  @return psPixels*   a new psPixels that is a duplicate to IN
+ */
+psPixels* psPixelsCopy(
+    psPixels* out,                     ///< psPixels struct to recycle, or NULL
+    const psPixels* in                 ///< psPixels struct to copy
+);
+
+/** 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
