Index: /trunk/psLib/src/astro/psCoord.h
===================================================================
--- /trunk/psLib/src/astro/psCoord.h	(revision 6873)
+++ /trunk/psLib/src/astro/psCoord.h	(revision 6874)
@@ -11,6 +11,6 @@
  *  @author GLG, MHPCC
  *
- *  @version $Revision: 1.50 $ $Name: not supported by cvs2svn $
- *  @date $Date: 2006-01-28 01:31:44 $
+ *  @version $Revision: 1.51 $ $Name: not supported by cvs2svn $
+ *  @date $Date: 2006-04-17 22:00:03 $
  *
  *  Copyright 2004-2005 Maui High Performance Computing Center, University of Hawaii
@@ -26,4 +26,5 @@
 #include "psPolynomial.h"
 #include "psPixels.h"
+#include "psRegion.h"
 //#include "psTime.h"
 
Index: /trunk/psLib/src/fits/psFitsImage.c
===================================================================
--- /trunk/psLib/src/fits/psFitsImage.c	(revision 6873)
+++ /trunk/psLib/src/fits/psFitsImage.c	(revision 6874)
@@ -7,6 +7,6 @@
  *  @author Robert DeSonia, MHPCC
  *
- *  @version $Revision: 1.2 $ $Name: not supported by cvs2svn $
- *  @date $Date: 2006-04-04 19:52:42 $
+ *  @version $Revision: 1.3 $ $Name: not supported by cvs2svn $
+ *  @date $Date: 2006-04-17 22:00:03 $
  *
  *  Copyright 2004-2005 Maui High Performance Computing Center, University of Hawaii
@@ -120,6 +120,5 @@
 }
 
-psImage* psFitsReadImage(psImage* output, // a psImage to recycle.
-                         const psFits* fits,    // the psFits object
+psImage* psFitsReadImage(const psFits* fits,    // the psFits object
                          psRegion region, // the region in the FITS image to read
                          int z)           // the z-plane in the FITS image cube to read
@@ -140,5 +139,4 @@
         psError(PS_ERR_BAD_PARAMETER_NULL, true,
                 PS_ERRORTEXT_psFits_NULL);
-        psFree(output);
         return NULL;
     }
@@ -166,5 +164,4 @@
                 PS_ERRORTEXT_psFits_DATATYPE_UNKNOWN,
                 fitsErr);
-        psFree(output);
         return NULL;
     }
@@ -176,5 +173,4 @@
                 PS_ERRORTEXT_psFits_IMAGE_DIM_UNKNOWN,
                 fitsErr);
-        psFree(output);
         return NULL;
     }
@@ -185,5 +181,4 @@
                 PS_ERRORTEXT_psFits_IMAGE_DIMENSION_UNSUPPORTED,
                 nAxis);
-        psFree(output);
         return NULL;
     }
@@ -195,5 +190,4 @@
                 PS_ERRORTEXT_psFits_IMAGE_SIZE_UNKNOWN,
                 fitsErr);
-        psFree(output);
         return NULL;
     }
@@ -260,18 +254,10 @@
                 PS_ERRORTEXT_psFits_FITS_TYPE_UNSUPPORTED,
                 bitPix);
-        psFree(output);
-        return NULL;
-    }
-
-    output = psImageRecycle(output,
-                            lastPixel[0]-firstPixel[0]+1,
-                            lastPixel[1]-firstPixel[1]+1,
-                            datatype);
-
-    if (output == NULL) {
-        psError(PS_ERR_UNKNOWN, false,
-                "Failed to allocate a properly sized image.");
-        return false;
-    }
+        return NULL;
+    }
+
+    psImage *output = psImageAlloc(lastPixel[0]-firstPixel[0]+1,
+                                   lastPixel[1]-firstPixel[1]+1,
+                                   datatype);
 
     // n.b., this assumes contiguous image buffer
@@ -532,2 +518,157 @@
 }
 
+psArray *psFitsReadImageCube(const psFits *fits, psRegion region)
+{
+    int nAxis = 0;                      // Number of axes
+    long nAxes[3];                      // Number of pixels on each axis
+    int status = 0;                     // cfitsio status value
+    char fitsErr[80] = "";              // CFITSIO error message string
+
+    if (fits == NULL) {
+        psError(PS_ERR_BAD_PARAMETER_NULL, true,
+                PS_ERRORTEXT_psFits_NULL);
+        return NULL;
+    }
+
+    // Some of this replicates what is in psFitsReadImage, so it's a little inefficient.  But it saves
+    // code replication, and should be sufficient for our needs.
+
+    if (fits_get_img_dim(fits->fd, &nAxis, &status) != 0) {
+        (void)fits_get_errstatus(status, fitsErr);
+        psError(PS_ERR_IO, true,
+                PS_ERRORTEXT_psFits_IMAGE_DIM_UNKNOWN,
+                fitsErr);
+        return NULL;
+    }
+
+    if (nAxis == 2) {
+        psArray *images = psArrayAlloc(1); // Single image plane
+        images->data[0] = psFitsReadImage(fits, region, 0);
+        return images;
+    }
+    if (nAxis == 3) {
+        if (fits_get_img_size(fits->fd, nAxis, nAxes, &status) != 0) {
+            (void)fits_get_errstatus(status, fitsErr);
+            psError(PS_ERR_IO, true,
+                    PS_ERRORTEXT_psFits_IMAGE_SIZE_UNKNOWN,
+                    fitsErr);
+            return NULL;
+        }
+
+        psArray *images = psArrayAlloc(nAxes[2]); // Array of image planes
+        for (int i = 0; i < nAxes[2]; i++) {
+            images->data[i] = psFitsReadImage(fits, region, i);
+        }
+
+        return images;
+    }
+
+    // Bad dimensionality
+    psError(PS_ERR_IO, true, PS_ERRORTEXT_psFits_IMAGE_DIMENSION_UNSUPPORTED, nAxis);
+    return NULL;
+}
+
+bool psFitsWriteImageCube(psFits *fits, psMetadata *header, const psArray *input, const char *extname)
+{
+    if (fits == NULL) {
+        psError(PS_ERR_BAD_PARAMETER_NULL, true,
+                PS_ERRORTEXT_psFits_NULL);
+        return false;
+    }
+
+    if (input == NULL) {
+        psError(PS_ERR_BAD_PARAMETER_NULL, true,
+                PS_ERRORTEXT_psFits_IMAGE_NULL);
+        return false;
+    }
+
+    if (input->n == 0) {
+        psError(PS_ERR_BAD_PARAMETER_SIZE, true, PS_ERRORTEXT_psFits_ARRAY_EMPTY);
+        return false;
+    }
+
+    if (input->n == 1) {
+        // The problem reduces to one already solved
+        return psFitsWriteImage(fits, header, input->data[0], 1, extname);
+    }
+
+    // Check that all images are of the same size
+    psImage *testImage = input->data[0];// First image off the array
+    int numCols = testImage->numCols;   // Number of columns
+    int numRows = testImage->numRows;   // Number of rows
+    for (int i = 1; i < input->n; i++) {
+        testImage = input->data[i];
+        if (testImage->numCols != numCols || testImage->numRows != numRows) {
+            psError(PS_ERR_BAD_PARAMETER_SIZE, true, PS_ERRORTEXT_psFits_ARRAY_SIZE_DIFFER);
+            return false;
+        }
+    }
+
+    // Need to check the header to make sure NAXIS and NAXIS[1-3] are correct
+    psMetadata *headerCopy = NULL;      // Copy of header
+    if (header) {
+        headerCopy = psMemIncrRefCounter(header);
+    } else {
+        headerCopy = psMetadataAlloc();
+    }
+    bool update = psMetadataAddS32(headerCopy, PS_LIST_HEAD, "NAXIS", PS_META_REPLACE, "Dimensionality", 3) &&
+                  psMetadataAddS32(headerCopy, PS_LIST_HEAD, "NAXIS1", PS_META_REPLACE, "Number of columns", numCols) &&
+                  psMetadataAddS32(headerCopy, PS_LIST_HEAD, "NAXIS2", PS_META_REPLACE, "Number of rows", numRows) &&
+                  psMetadataAddS32(headerCopy, PS_LIST_HEAD, "NAXIS3", PS_META_REPLACE, "Number of image planes",
+                                   input->n);
+    if (! update) {
+        psError(PS_ERR_UNKNOWN, false, PS_ERRORTEXT_psFits_METADATA_ADD_FAILED,
+                "NAXIS, NAXIS1, NAXIS2, NAXIS3");
+        psFree(headerCopy);
+        return false;
+    }
+
+    // Now we can safely write the images out.
+    // The first is an psFitsImageWrite to create the extension.
+    // The next are psFitsImageUpdate to write into the extension.
+    if (! psFitsWriteImage(fits, headerCopy, input->data[0], input->n, extname)) {
+        psError(PS_ERR_UNKNOWN, false, PS_ERRORTEXT_psFits_WRITE_PLANE_FAILED, 0);
+        psFree(headerCopy);
+        return false;
+    }
+    psFree(headerCopy);                 // Free, or drop reference
+
+    for (int i = 1; i < input->n; i++) {
+        if (! psFitsUpdateImage(fits, input->data[i], 0, 0, i)) {
+            psError(PS_ERR_UNKNOWN, false, PS_ERRORTEXT_psFits_WRITE_PLANE_FAILED, i);
+            return false;
+        }
+    }
+
+    return true;
+}
+
+bool psFitsUpdateImageCube(psFits *fits, const psArray *input, int x0, int y0)
+{
+    if (fits == NULL) {
+        psError(PS_ERR_BAD_PARAMETER_NULL, true,
+                PS_ERRORTEXT_psFits_NULL);
+        return false;
+    }
+
+    if (input == NULL) {
+        psError(PS_ERR_BAD_PARAMETER_NULL, true,
+                PS_ERRORTEXT_psFits_IMAGE_NULL);
+        return false;
+    }
+
+    if (input->n == 0) {
+        psError(PS_ERR_BAD_PARAMETER_SIZE, true, PS_ERRORTEXT_psFits_ARRAY_EMPTY);
+        return false;
+    }
+
+    for (int i = 0; i < input->n; i++) {
+        if (! psFitsUpdateImage(fits, input->data[i], x0, y0, i)) {
+            psError(PS_ERR_UNKNOWN, false, PS_ERRORTEXT_psFits_UPDATE_PLANE_FAILED, i);
+            return false;
+        }
+    }
+
+    return true;
+}
+
Index: /trunk/psLib/src/fits/psFitsImage.h
===================================================================
--- /trunk/psLib/src/fits/psFitsImage.h	(revision 6873)
+++ /trunk/psLib/src/fits/psFitsImage.h	(revision 6874)
@@ -7,6 +7,6 @@
  *  @author Robert DeSonia, MHPCC
  *
- *  @version $Revision: 1.2 $ $Name: not supported by cvs2svn $
- *  @date $Date: 2006-04-04 19:52:42 $
+ *  @version $Revision: 1.3 $ $Name: not supported by cvs2svn $
+ *  @date $Date: 2006-04-17 22:00:03 $
  *
  *  Copyright 2004-2005 Maui High Performance Computing Center, University of Hawaii
@@ -32,5 +32,4 @@
  */
 psImage* psFitsReadImage(
-    psImage* out,                      ///< a psImage to recycle.
     const psFits* fits,                ///< the psFits object
     psRegion region,                   ///< the region in the FITS image to read
@@ -78,4 +77,8 @@
 );
 
+psArray *psFitsReadImageCube(const psFits *fits, psRegion region);
+bool psFitsWriteImageCube(psFits *fits, psMetadata *header, const psArray *input, const char *extname);
+bool psFitsUpdateImageCube(psFits *fits, const psArray *input, int x0, int y0);
+
 /// @}
 
Index: /trunk/psLib/src/imageops/psImageStats.c
===================================================================
--- /trunk/psLib/src/imageops/psImageStats.c	(revision 6873)
+++ /trunk/psLib/src/imageops/psImageStats.c	(revision 6874)
@@ -9,6 +9,6 @@
  *  @author GLG, MHPCC
  *
- *  @version $Revision: 1.92 $ $Name: not supported by cvs2svn $
- *  @date $Date: 2006-04-05 01:49:40 $
+ *  @version $Revision: 1.93 $ $Name: not supported by cvs2svn $
+ *  @date $Date: 2006-04-17 22:00:03 $
  *
  *  Copyright 2004-2005 Maui High Performance Computing Center, University of Hawaii
@@ -31,4 +31,6 @@
 #include "psConstants.h"
 #include "psErrorText.h"
+#include "psRegion.h"
+#include "psRegionForImage.h"
 
 /// This routine must determine the various statistics for the image.
@@ -748,9 +750,9 @@
         return -1;
     }/* else if (col0 == col1 && row0 == row1) {
-                psError(PS_ERR_BAD_PARAMETER_VALUE, true,
-                        "Invalid psRegion specified.  Region contains only 1 pixel.\n");
-                return -1;
-            }
-        */
+                    psError(PS_ERR_BAD_PARAMETER_VALUE, true,
+                            "Invalid psRegion specified.  Region contains only 1 pixel.\n");
+                    return -1;
+                }
+            */
     x0 = col0;
     x1 = col1;
Index: /trunk/psLib/src/imageops/psImageStats.h
===================================================================
--- /trunk/psLib/src/imageops/psImageStats.h	(revision 6873)
+++ /trunk/psLib/src/imageops/psImageStats.h	(revision 6874)
@@ -9,6 +9,6 @@
 *  @author GLG, MHPCC
 *
-*  @version $Revision: 1.27 $ $Name: not supported by cvs2svn $
-*  @date $Date: 2005-09-26 22:35:53 $
+*  @version $Revision: 1.28 $ $Name: not supported by cvs2svn $
+*  @date $Date: 2006-04-17 22:00:03 $
 *
 *  Copyright 2004-2005 Maui High Performance Computing Center, University of Hawaii
@@ -22,4 +22,5 @@
 #include "psStats.h"
 #include "psPolynomial.h"
+#include "psRegion.h"
 
 /// @addtogroup ImageStats
Index: /trunk/psLib/src/imageops/psImageStructManip.h
===================================================================
--- /trunk/psLib/src/imageops/psImageStructManip.h	(revision 6873)
+++ /trunk/psLib/src/imageops/psImageStructManip.h	(revision 6874)
@@ -8,6 +8,6 @@
 *  @author Robert DeSonia, MHPCC
 *
-*  @version $Revision: 1.3 $ $Name: not supported by cvs2svn $
-*  @date $Date: 2005-06-08 23:40:45 $
+*  @version $Revision: 1.4 $ $Name: not supported by cvs2svn $
+*  @date $Date: 2006-04-17 22:00:03 $
 *
 *  Copyright 2004-2005 Maui High Performance Computing Center, University of Hawaii
@@ -18,4 +18,5 @@
 
 #include "psImage.h"
+#include "psRegion.h"
 
 /// @addtogroup Image
Index: /trunk/psLib/src/math/Makefile.am
===================================================================
--- /trunk/psLib/src/math/Makefile.am	(revision 6873)
+++ /trunk/psLib/src/math/Makefile.am	(revision 6874)
@@ -13,4 +13,6 @@
 	psMinimizePolyFit.c \
 	psRandom.c \
+	psRegion.c \
+	psRegionForImage.c \
 	psPolynomial.c \
 	psSpline.c \
@@ -31,4 +33,6 @@
 	psMinimizePolyFit.h \
 	psRandom.h \
+	psRegion.h \
+	psRegionForImage.h \
 	psPolynomial.h \
 	psSpline.h \
Index: /trunk/psLib/src/math/psRegion.c
===================================================================
--- /trunk/psLib/src/math/psRegion.c	(revision 6874)
+++ /trunk/psLib/src/math/psRegion.c	(revision 6874)
@@ -0,0 +1,85 @@
+#include <stdio.h>
+#include <math.h>
+#include "psMemory.h"
+#include "psError.h"
+#include "psErrorText.h"
+#include "psRegion.h"
+
+psRegion *psRegionAlloc(float x0,
+                        float x1,
+                        float y0,
+                        float y1)
+{
+    psRegion *region = psAlloc(sizeof(psRegion)); // New region, to be returned
+    // No complex structures, so no special deallocator
+    *region = psRegionSet(x0, x1, y0, y1);
+    return region;
+}
+
+psRegion psRegionSet(float x0,
+                     float x1,
+                     float y0,
+                     float y1)
+{
+    psRegion out;
+
+    out.x0 = x0;
+    out.y0 = y0;
+    out.x1 = x1;
+    out.y1 = y1;
+
+    return out;
+}
+
+psRegion psRegionFromString(const char* region)
+{
+    psS32 col0;
+    psS32 col1;
+    psS32 row0;
+    psS32 row1;
+
+    // section should be of the form '[col0:col1,row0:row1]'
+    if (region == NULL) {
+        return psRegionSet(0,0,0,0);
+    }
+
+    if (sscanf(region,"[%d:%d,%d:%d]",&col0,&col1,&row0,&row1) < 4) {
+        psError(PS_ERR_BAD_PARAMETER_NULL, true,
+                PS_ERRORTEXT_psImage_SUBSECTION_INVALID,
+                region);
+        return psRegionSet(NAN,NAN,NAN,NAN);
+    }
+
+    if (col0 > col1 || row0 > row1) {
+        psError(PS_ERR_BAD_PARAMETER_VALUE, true,
+                PS_ERRORTEXT_psImage_SUBSET_RANGE_MALFORMED,
+                col0,col1,row0,row1);
+        return psRegionSet(NAN,NAN,NAN,NAN);
+    }
+
+    return psRegionSet(col0-1,col1,row0-1,row1);
+}
+
+psString psRegionToString(const psRegion region)
+{
+    char tmpText[256]; // big enough to store any region as text
+
+    snprintf(tmpText,256,"[%g:%g,%g:%g]",
+             region.x0+1, region.x1,
+             region.y0+1, region.y1);
+
+    return psStringCopy(tmpText);
+}
+
+
+// define a square region centered on the given coordinate
+psRegion psRegionForSquare(double x,
+                           double y,
+                           double radius)
+{
+    psRegion region;
+    region = psRegionSet (x - radius, x + radius + 1,
+                          y - radius, y + radius + 1);
+    return (region);
+}
+
Index: /trunk/psLib/src/math/psRegion.h
===================================================================
--- /trunk/psLib/src/math/psRegion.h	(revision 6874)
+++ /trunk/psLib/src/math/psRegion.h	(revision 6874)
@@ -0,0 +1,73 @@
+#ifndef PS_REGION_H
+#define PS_REGION_H
+
+#include "psString.h"
+
+/** Basic image region structure.
+ *
+ * Struct for specifying a rectangular area in an image.
+ *
+ */
+typedef struct
+{
+    float x0;                         ///< the first column of the region.
+    float x1;                         ///< the last column of the region.
+    float y0;                         ///< the first row of the region.
+    float y1;                         ///< the last row of the region.
+}
+psRegion;
+
+/** Create a pointer to a psRegion, with associated psMemBlock.
+ *
+ * @return psRegion* : a new psRegion.
+ */
+psRegion *psRegionAlloc(float x0,       ///< the first column of the region.
+                        float x1,       ///< the last column of the region + 1.
+                        float y0,       ///< the first row of the region.
+                        float y1        ///< the last row of the region + 1.
+                       );
+
+/** Create a psRegion with the specified attributes.
+ *
+ *  @return psRegion : a cooresponding psRegion.
+ */
+psRegion psRegionSet(
+    float x0,                          ///< the first column of the region.
+    float x1,                          ///< the last column of the region + 1.
+    float y0,                          ///< the first row of the region.
+    float y1                           ///< the last row of the region + 1.
+);
+
+/** Create a psRegion with the attribute values given as a string.
+ *
+ *  Create a psRegion with the attribute values given as a string.  The format
+ *  shall be of the standard IRAF form '[x0:x1,y0:y1]'
+ *
+ *  @return psRegion:  A new psRegion struct, or NULL is not successful.
+ */
+psRegion psRegionFromString(
+    const char* region                 ///< image rectangular region in the form '[x0:x1,y0:y1]'
+);
+
+/** Create a string of the standard IRAF form '[x0:x1,y0:y1]' from a psRegion.
+ *
+ *  @return psString:  A new string representing the psRegion as text, or NULL
+ *                  is not successful.
+ */
+psString psRegionToString(
+    const psRegion region              ///< the psRegion to convert to a string
+);
+
+/** Defines a region corresponding to the square with center at coordinate x,y
+ *  and with coderadius.  The width of the square is 2radius + 1.
+ *
+ *  @return psRegion:       the newly defined psRegion.
+ */
+psRegion psRegionForSquare(
+    double x,                           ///< x coordinate at square-center
+    double y,                           ///< y coordinate at square-center
+    double radius                       ///< radius of square
+);
+
+
+#endif
Index: /trunk/psLib/src/math/psRegionForImage.c
===================================================================
--- /trunk/psLib/src/math/psRegionForImage.c	(revision 6874)
+++ /trunk/psLib/src/math/psRegionForImage.c	(revision 6874)
@@ -0,0 +1,61 @@
+#include <stdio.h>
+#include "psError.h"
+#include "psRegion.h"
+#include "psImage.h"
+#include "psRegionForImage.h"
+
+// set actual region based on image parameters:
+// - compensate for negative upper limits
+// - force range to be on this image
+// - saturate on upper and lower limits of image
+// - flip x0,x1 if x0>x1
+// - flip y0,y1 if y0>y1
+// psRegion in refers to coordinates in the *parent* image
+psRegion psRegionForImage(psImage *image,
+                          psRegion in)
+{
+
+    //    if (image == NULL) {
+    //        return in;
+    //    }
+    PS_ASSERT_IMAGE_NON_NULL(image, in);
+    //if the region is [0,0,0,0], the whole image (or subimage) is to be included.
+    if (in.x0 == 0 && in.x1 == 0 && in.y0 == 0 && in.y1 == 0) {
+        in.x0 = image->col0;
+        in.x1 = image->col0 + image->numCols - 1;
+        in.y0 = image->row0;
+        in.y1 = image->row0 + image->numRows - 1;
+        return (in);
+    }
+
+    // convert non-positive upper-limits
+    // XXX note that the upper limit in these cases is defined relative to the subimage
+    // also note that truncation limits to the valid subimage pixels
+    in.x1 = (in.x1 <= 0) ? (image->col0 + image->numCols + in.x1) : in.x1;
+    in.y1 = (in.y1 <= 0) ? (image->row0 + image->numRows + in.y1) : in.y1;
+
+    // force the upper-limits to be on the image
+    in.x1 = PS_MIN(image->col0 + image->numCols, in.x1);
+    in.y1 = PS_MIN(image->row0 + image->numRows, in.y1);
+
+    // force the lower-limits to be on the image
+    in.x0 = PS_MAX(image->col0, in.x0);
+    in.y0 = PS_MAX(image->row0, in.y0);
+    in.x0 = PS_MIN(image->col0 + image->numCols, in.x0);
+    in.y0 = PS_MIN(image->row0 + image->numRows, in.y0);
+
+    // flip start and end if out of order
+    if (in.x0 > in.x1) {
+        psError (PS_ERR_BAD_PARAMETER_VALUE, true,
+                 "Invalid region in psRegionForImage.  x0 > x1.  Values have been swapped.\n");
+        PS_SWAP (in.x0, in.x1);
+    }
+    if (in.y0 > in.y1) {
+        psError (PS_ERR_BAD_PARAMETER_VALUE, true,
+                 "Invalid region in psRegionForImage.  y0 > y1.  Values have been swapped.\n");
+        PS_SWAP (in.y0, in.y1);
+    }
+
+    return (in);
+}
+
Index: /trunk/psLib/src/math/psRegionForImage.h
===================================================================
--- /trunk/psLib/src/math/psRegionForImage.h	(revision 6874)
+++ /trunk/psLib/src/math/psRegionForImage.h	(revision 6874)
@@ -0,0 +1,26 @@
+#ifndef PS_REGION_FOR_IMAGE_H
+#define PS_REGION_FOR_IMAGE_H
+
+
+/** Sets an actual region based on image parameters.
+ *
+ *  An image region defined with negative upper limits may be rationalized for the bounds of a
+ *  specific image with psRegionForImage.  The output of this function is a region with negative
+ *  upper limits replaced by their corrected value appropriate to the given image.  In addition,
+ *  the lower and upper limits are foced to lie within the bounds of the image.  If the lower-
+ *  limit coordinates are lewss than the lower bound of the image, they are limited to the lower
+ *  bound of the image.  Conversely, if the upper-limit coordinates are greater than the upper
+ *  bound of the image, they are truncated to define only valid pixels.  If the lower-limit
+ *  coordinates are greater than the upper bounds of the image, or the upper-limit coordinates
+ *  are less than the lower bounds of the image, the coordinates should saturate on those limits.
+ *
+ *  @return psRegion:       A region with negative upper limits replaced by the corrected
+ */
+psRegion psRegionForImage(
+    psImage *image,                    ///< the image for which the region is to be set
+    psRegion in                        ///< the image region limits
+);
+
+
+
+#endif
Index: /trunk/psLib/src/mathtypes/psImage.c
===================================================================
--- /trunk/psLib/src/mathtypes/psImage.c	(revision 6873)
+++ /trunk/psLib/src/mathtypes/psImage.c	(revision 6874)
@@ -9,6 +9,6 @@
  *  @author Ross Harman, MHPCC
  *
- *  @version $Revision: 1.101 $ $Name: not supported by cvs2svn $
- *  @date $Date: 2006-04-05 01:49:41 $
+ *  @version $Revision: 1.102 $ $Name: not supported by cvs2svn $
+ *  @date $Date: 2006-04-17 22:00:03 $
  *
  *  Copyright 2004-2005 Maui High Performance Computing Center, University of Hawaii
@@ -104,4 +104,6 @@
 
 
+// XXX these have been moved to psRegion* in src/math/
+# if 0
 psRegion psRegionSet(float x0,
                      float x1,
@@ -160,5 +162,4 @@
     return psStringCopy(tmpText);
 }
-
 
 // set actual region based on image parameters:
@@ -227,4 +228,5 @@
     return (region);
 }
+# endif /* commented-out psRegion functions */
 
 bool psImageInit (psImage *image,...)
Index: /trunk/psLib/src/mathtypes/psImage.h
===================================================================
--- /trunk/psLib/src/mathtypes/psImage.h	(revision 6873)
+++ /trunk/psLib/src/mathtypes/psImage.h	(revision 6874)
@@ -11,6 +11,6 @@
  *  @author Ross Harman, MHPCC
  *
- *  @version $Revision: 1.74 $ $Name: not supported by cvs2svn $
- *  @date $Date: 2006-01-28 01:12:14 $
+ *  @version $Revision: 1.75 $ $Name: not supported by cvs2svn $
+ *  @date $Date: 2006-04-17 22:00:03 $
  *
  *  Copyright 2004-2005 Maui High Performance Computing Center, University of Hawaii
@@ -84,4 +84,6 @@
                 #define P_PSIMAGE_SET_TYPE(img,t) *(psMathType*)&img->type = t
 
+                        // XXX moved to psRegion.h in src/math
+                        # if 0
                         /** Basic image region structure.
                          *
@@ -97,4 +99,5 @@
                         }
                         psRegion;
+# endif
 
 /** Create an image of the specified size and type.
@@ -124,4 +127,6 @@
 
 
+// XXX these have been moved to psRegion* in src/math
+# if 0
 /** Create a psRegion with the specified attributes.
  *
@@ -184,4 +189,5 @@
     double radius                       ///< radius of square
 );
+# endif /* commented-out psRegions */
 
 /** Initializes the image with the given value.
Index: /trunk/psLib/src/psErrorText_en.dat
===================================================================
--- /trunk/psLib/src/psErrorText_en.dat	(revision 6873)
+++ /trunk/psLib/src/psErrorText_en.dat	(revision 6874)
@@ -147,5 +147,9 @@
 psFits_METADATA_ADD_FAILED             Failed to add metadata item, %s.
 psFits_WRITE_FAILED                    Could not write data to file.\nCFITSIO Error: %s
+psFits_WRITE_PLANE_FAILED              Could not write image plane %d.
+psFits_UPDATE_PLANE_FAILED             Could not update image plane %d.
 psFits_IMAGE_NULL                      The input psImage was NULL.  Need a non-NULL psImage for operation to be performed.
+psFits_ARRAY_EMPTY                     The input array was empty.
+psFits_ARRAY_SIZE_DIFFER               The sizes of images in the array differ.
 psFits_METADATA_NULL                   The input psMetadata was NULL.  Need a non-NULL psMetadata for operation to be performed.
 psFits_METADATA_PTYPE_UNSUPPORTED      A metadata item's primative type, %d, is not supported.
Index: /trunk/psLib/src/pslib_strict.h
===================================================================
--- /trunk/psLib/src/pslib_strict.h	(revision 6873)
+++ /trunk/psLib/src/pslib_strict.h	(revision 6874)
@@ -9,6 +9,6 @@
 *  @author Eric Van Alst, MHPCC
 *
-*  @version $Revision: 1.15 $ $Name: not supported by cvs2svn $
-*  @date $Date: 2006-02-28 20:03:22 $
+*  @version $Revision: 1.16 $ $Name: not supported by cvs2svn $
+*  @date $Date: 2006-04-17 22:00:03 $
 *
 *  Copyright 2004-2005 Maui High Performance Computing Center, University of Hawaii
@@ -58,4 +58,6 @@
 #include "psMinimizePolyFit.h"
 #include "psRandom.h"
+#include "psRegion.h"
+#include "psRegionForImage.h"
 #include "psPolynomial.h"
 #include "psSpline.h"
Index: /trunk/psLib/src/sys/psString.c
===================================================================
--- /trunk/psLib/src/sys/psString.c	(revision 6873)
+++ /trunk/psLib/src/sys/psString.c	(revision 6874)
@@ -13,6 +13,6 @@
  *  @author David Robbins, MHPCC
  *
- *  @version $Revision: 1.24 $ $Name: not supported by cvs2svn $
- *  @date $Date: 2006-02-01 20:40:56 $
+ *  @version $Revision: 1.25 $ $Name: not supported by cvs2svn $
+ *  @date $Date: 2006-04-17 22:00:03 $
  *
  *  Copyright 2004-2005 Maui High Performance Computing Center, University of Hawaii
@@ -214,2 +214,43 @@
 }
 
+// given the input string, search for all copies of the key, and replace with the replacement value
+// the input string may be freed if not needed
+char *psStringSubstitute (char *input, char *replace, char *key)
+{
+
+    char *p;
+
+    if (key == NULL)
+        return input;
+    if (strlen(key) == 0)
+        return input;
+
+    while (true) {
+        p = strstr (input, key);
+        if (p == NULL)
+            return input;
+
+        // we have input = xxxkeyxxx
+        // we want output = xxxreplacexxx
+
+        // this is safe since we will subtract strlen(key) elements from input
+        char *output = psAlloc(strlen(input) + strlen(replace) + 1);
+        int Nc = p - input;
+
+        // copy the first segement into 'output'
+        strncpy (output, input, Nc);
+
+        // copy the key replacement to the start of the key
+
+        strcpy (&output[Nc], replace);
+        Nc += strlen (replace);
+
+        // copy the remainder to the end of the replacement
+        strcpy (&output[Nc], p + strlen(key));
+
+        psFree (input);
+        input = output;
+    }
+    return input;
+}
+
Index: /trunk/psLib/src/sys/psString.h
===================================================================
--- /trunk/psLib/src/sys/psString.h	(revision 6873)
+++ /trunk/psLib/src/sys/psString.h	(revision 6874)
@@ -14,6 +14,6 @@
  *  @author David Robbins, MHPCC
  *
- *  @version $Revision: 1.18 $ $Name: not supported by cvs2svn $
- *  @date $Date: 2006-02-01 20:40:56 $
+ *  @version $Revision: 1.19 $ $Name: not supported by cvs2svn $
+ *  @date $Date: 2006-04-17 22:00:03 $
  *
  *  Copyright 2004-2005 Maui High Performance Computing Center, University of Hawaii
@@ -103,4 +103,12 @@
 );
 
+// given the input string, search for all copies of the key, and replace with the replacement value
+// the input string may be freed if not needed
+char *psStringSubstitute (
+    char *input,    ///< input string to be modified
+    char *replace,    ///< replacement value
+    char *key    ///< string to be replaced in input
+);
+
 /** @} */// Doxygen - End of SystemGroup Functions
 
Index: /trunk/psLib/src/sys/psType.h
===================================================================
--- /trunk/psLib/src/sys/psType.h	(revision 6873)
+++ /trunk/psLib/src/sys/psType.h	(revision 6874)
@@ -10,6 +10,6 @@
 *  @author Ross Harman, MHPCC
 *
-*  @version $Revision: 1.46 $ $Name: not supported by cvs2svn $
-*  @date $Date: 2006-02-08 00:00:35 $
+*  @version $Revision: 1.47 $ $Name: not supported by cvs2svn $
+*  @date $Date: 2006-04-17 22:00:03 $
 *
 *  Copyright 2004-2005 Maui High Performance Computing Center, University of Hawaii
@@ -130,4 +130,5 @@
     PS_DATA_POLYNOMIAL4D,              ///< psPolynomial4D
     PS_DATA_PROJECTION,                ///< psProjection
+    PS_DATA_REGION,                    ///< psRegion
     PS_DATA_SCALAR,                    ///< psScalar
     PS_DATA_SPHERE,                    ///< psSphere
Index: /trunk/psLib/src/types/psMetadata.c
===================================================================
--- /trunk/psLib/src/types/psMetadata.c	(revision 6873)
+++ /trunk/psLib/src/types/psMetadata.c	(revision 6874)
@@ -12,6 +12,6 @@
  *  @author Ross Harman, MHPCC
  *
- *  @version $Revision: 1.101 $ $Name: not supported by cvs2svn $
- *  @date $Date: 2006-03-08 21:09:16 $
+ *  @version $Revision: 1.102 $ $Name: not supported by cvs2svn $
+ *  @date $Date: 2006-04-17 22:00:03 $
  *
  *  Copyright 2004-2005 Maui High Performance Computing Center, University of Hawaii
@@ -293,4 +293,5 @@
     case     PS_DATA_POLYNOMIAL4D:              // psPolynomial4D
     case     PS_DATA_PROJECTION:                // psProjection
+    case     PS_DATA_REGION:                  // psRegion
     case     PS_DATA_SCALAR:                    // psScalar
     case     PS_DATA_SPHERE:                    // psSphere
@@ -341,4 +342,76 @@
 }
 
+
+psMetadataItem *psMetadataItemCopy(const psMetadataItem *in
+                                  )
+{
+    PS_ASSERT_PTR_NON_NULL(in,NULL);
+
+    psMetadataItem *newItem = NULL;     // New metadata item, to be returned
+
+    #define PS_METADATA_ITEM_COPY_CASE(NAME,TYPE) \
+case PS_DATA_##NAME: \
+    newItem = psMetadataItemAlloc(in->name, PS_DATA_##NAME, in->comment, in->data.TYPE); \
+    break; \
+
+    switch (in->type) {
+        // Simple types
+        PS_METADATA_ITEM_COPY_CASE(BOOL,B);
+        PS_METADATA_ITEM_COPY_CASE(S8,S8);
+        PS_METADATA_ITEM_COPY_CASE(S16,S16);
+        PS_METADATA_ITEM_COPY_CASE(S32,S32);
+        PS_METADATA_ITEM_COPY_CASE(U8,U8);
+        PS_METADATA_ITEM_COPY_CASE(U16,U16);
+        PS_METADATA_ITEM_COPY_CASE(U32,U32);
+        PS_METADATA_ITEM_COPY_CASE(F32,F32);
+        PS_METADATA_ITEM_COPY_CASE(F64,F64);
+        PS_METADATA_ITEM_COPY_CASE(STRING,V); // This will copy the string, not point at it.
+    case PS_DATA_VECTOR: {
+            psVector *vecCopy = psVectorCopy(NULL, (psVector*)(in->data.V),
+                                             ((psVector*)(in->data.V))->type.type);
+            if (vecCopy == NULL) {
+                psError(PS_ERR_BAD_PARAMETER_NULL, false,
+                        "Error copying vector.  Vector skipped.\n");
+            } else {
+                newItem = psMetadataItemAlloc(in->name, PS_DATA_VECTOR, in->comment, vecCopy);
+                psFree(vecCopy);    // Drop reference
+            }
+            break;
+        }
+    case PS_DATA_TIME: {
+            psTime *timeCopy = p_psTimeCopy( (psTime*)(in->data.V) );
+            if (timeCopy == NULL) {
+                psError(PS_ERR_BAD_PARAMETER_NULL, false,
+                        "Error copying time.  Time skipped.\n");
+            } else {
+                newItem = psMetadataItemAlloc(in->name, PS_DATA_TIME, in->comment, timeCopy);
+                psFree(timeCopy);   // Drop reference
+            }
+            break;
+        }
+    case PS_DATA_METADATA: {
+            // Metadata: copy the next level and stuff that in too
+            psMetadata *metadata = psMetadataCopy(NULL, in->data.md);
+            newItem = psMetadataItemAlloc(in->name, PS_DATA_METADATA, in->comment, metadata);
+            psFree(metadata);       // Drop reference
+            break;
+        }
+    case PS_DATA_REGION: {
+            psRegion *region = in->data.V; // The region
+            psRegion *new = psRegionAlloc(region->x0, region->x1, region->y0, region->y1); // Copy of the region
+            newItem = psMetadataItemAlloc(in->name, PS_DATA_REGION, in->comment, new);
+            psFree(new);                  // Drop reference
+            break;
+        }
+    default:
+        // Other kinds of pointers
+        psLogMsg(__func__, PS_LOG_WARN, "Copying a pointer in the metadata item: %x\n", in->type);
+        newItem = psMetadataItemAlloc(in->name, in->type, in->comment, in->data.V);
+        break;
+    }
+
+    return newItem;
+}
+
 psMetadata *psMetadataCopy(psMetadata *out,
                            const psMetadata *in)
@@ -349,19 +422,6 @@
         out = psMetadataAlloc();
     }
-    //    psMetadataItem *item = NULL;
-    psMetadataIterator *iter = NULL;
-    iter = psMetadataIteratorAlloc(*(psMetadata**)&in, PS_LIST_HEAD, NULL);
-    /*
-        item = psMetadataGetAndIncrement(iter);
-        while (item != NULL) {
-            psMetadataAddItem(out, item, PS_LIST_TAIL, 0);
-            item = psMetadataGetAndIncrement(iter);
-        }
-        psFree(item);
-        psFree(iter);
-        return out;
-    */
+    psMetadataIterator *iter = psMetadataIteratorAlloc(*(psMetadata**)&in, PS_LIST_HEAD, NULL);
     psMetadataItem *inItem = NULL;
-    unsigned long numPointers = 0;      // Number of pointers we were forced to copy
     while ((inItem = psMetadataGetAndIncrement(iter))) {
         // Need to look for MULTI, which won't be picked up using the iterator.
@@ -370,85 +430,17 @@
         if (multiCheckItem->type == PS_DATA_METADATA_MULTI) {
             psTrace(__func__, 10, "MULTI: %s (%s)\n", inItem->name, inItem->comment);
-            flag = PS_DATA_METADATA_MULTI;
+            flag = PS_META_DUPLICATE_OK;
         }
         psTrace(__func__, 5, "Copying %s (%s)...\n", inItem->name, inItem->comment);
 
-
-        //        case PS_TYPE_##NAME:
-        #define PS_METADATA_COPY_CASE(NAME,TYPE) \
-    case PS_DATA_##NAME: \
-        if (! psMetadataAdd(out, PS_LIST_TAIL, inItem->name, \
-                            PS_DATA_##NAME | flag, inItem->comment, inItem->data.TYPE)) { \
-            psErrorStackPrint(stderr, "Error copying %s (%s) in the metadata\n", \
-                              inItem->name, inItem->comment); \
-        } \
-        break;
-
-        switch (inItem->type) {
-            // Numerical types
-            PS_METADATA_COPY_CASE(BOOL,B);
-            PS_METADATA_COPY_CASE(S8,S8);
-            PS_METADATA_COPY_CASE(S16,S16);
-            PS_METADATA_COPY_CASE(S32,S32);
-            PS_METADATA_COPY_CASE(U8,U8);
-            PS_METADATA_COPY_CASE(U16,U16);
-            PS_METADATA_COPY_CASE(U32,U32);
-            PS_METADATA_COPY_CASE(F32,F32);
-            PS_METADATA_COPY_CASE(F64,F64);
-
-        case PS_DATA_VECTOR: {
-                psVector *vecCopy = psVectorCopy(NULL, (psVector*)(inItem->data.V),
-                                                 ((psVector*)(inItem->data.V))->type.type);
-                if (vecCopy == NULL) {
-                    psError(PS_ERR_BAD_PARAMETER_NULL, false,
-                            "Error copying vector.  Vector skipped.\n");
-                } else {
-                    psMetadataAddVector(out, PS_LIST_TAIL, inItem->name, flag,
-                                        inItem->comment, vecCopy);
-                    psFree(vecCopy);
-                }
-                break;
-            }
-        case PS_DATA_TIME: {
-                psTime *timeCopy = p_psTimeCopy( (psTime*)(inItem->data.V) );
-                if (timeCopy == NULL) {
-                    psError(PS_ERR_BAD_PARAMETER_NULL, false,
-                            "Error copying time.  Time skipped.\n");
-                } else {
-                    psMetadataAddTime(out, PS_LIST_TAIL, inItem->name, flag,
-                                      inItem->comment, timeCopy);
-                    psFree(timeCopy);
-                }
-                break;
-            }
-            // String: relying on the fact that this will copy the string, not point at it.
-        case PS_DATA_STRING:
-            psMetadataAdd(out, PS_LIST_TAIL, inItem->name, PS_DATA_STRING |
-                          flag, inItem->comment, inItem->data.V);
-            break;
-            // Metadata: copy the next level and stuff that in too
-        case PS_DATA_METADATA: {
-                psMetadata *metadata = psMetadataCopy(NULL, inItem->data.md);
-                psMetadataAdd(out, PS_LIST_TAIL, inItem->name,
-                              PS_DATA_METADATA | flag, inItem->comment, metadata);
-                psFree(metadata);
-                break;
-            }
-            // Other kinds of pointers
-        default:
-            numPointers++;
-            psTrace(__func__, 10, "Copying a pointer in the metadata: %x\n", inItem->type);
-            psMetadataAdd(out, PS_LIST_TAIL, inItem->name, inItem->type | flag,
-                          inItem->comment, inItem->data.V);
-            break;
-        }
+        // Copy the item and add it on
+        psMetadataItem *newItem = psMetadataItemCopy(inItem); // Copied item
+        if (!psMetadataAddItem(out, newItem, PS_LIST_TAIL, flag)) {
+            psErrorStackPrint(stderr, "Error copying %s (%s) in the metadata\n", inItem->name,
+                              inItem->comment);
+        }
+        psFree(newItem);                // Drop reference
     }
     psFree(iter);
-
-    if (numPointers > 0) {
-        psLogMsg(__func__, PS_LOG_WARN,
-                 "Forced to copy %d pointers when copying metadata.  Updating the "
-                 "copied psMetadata will affect the original!\n", numPointers);
-    }
 
     return out;
@@ -528,4 +520,7 @@
         } else {
             // default is to error on duplicate entry.
+            if ((flags & PS_META_NO_REPLACE) != 0) {
+                return true;
+            }
             psError(PS_ERR_BAD_PARAMETER_VALUE, true,
                     PS_ERRORTEXT_psMetadata_DUPLICATE_NOT_ALLOWED);
@@ -554,6 +549,5 @@
                    const char *name,
                    int format,
-                   const char *comment,
-                   ...)
+                   const char *comment,...)
 {
     PS_ASSERT_PTR_NON_NULL(md,false);
@@ -1140,5 +1134,21 @@
             psMetadataPrint(item->data.V, level + 1);
             break;
+        case PS_DATA_REGION: {
+                psString region = psRegionToString(*(psRegion*)item->data.V);
+                printf("%s", region);
+                psFree(region);
+                break;
+            }
+        case PS_DATA_LIST:
+            printf("<a list of unknown contents>");
+            break;
+        case PS_DATA_TIME: {
+                psString time = psTimeToISO(item->data.V);
+                printf("%s", time);
+                psFree(time);
+                break;
+            }
         default:
+            printf("\n");
             psError(PS_ERR_IO, false, "Non-printable metadata type: %x\n", item->type);
         }
Index: /trunk/psLib/src/types/psMetadata.h
===================================================================
--- /trunk/psLib/src/types/psMetadata.h	(revision 6873)
+++ /trunk/psLib/src/types/psMetadata.h	(revision 6874)
@@ -11,6 +11,6 @@
 *  @author Ross Harman, MHPCC
 *
-*  @version $Revision: 1.74 $ $Name: not supported by cvs2svn $
-*  @date $Date: 2006-01-30 20:28:33 $
+*  @version $Revision: 1.75 $ $Name: not supported by cvs2svn $
+*  @date $Date: 2006-04-17 22:00:03 $
 *
 *  Copyright 2004-2005 Maui High Performance Computing Center, University of Hawaii
@@ -59,6 +59,7 @@
     PS_META_DEFAULT = 0,               ///< default behaviour (duplicate entry is an error)
     PS_META_REPLACE = 0x1000000,       ///< allow entry to be replaced
-    PS_META_DUPLICATE_OK = 0x2000000,  ///< allow duplicate entries
-    PS_META_NULL = 0x4000000           ///< psMetadataItem.data is a NULL value
+    PS_META_NO_REPLACE = 0x2000000,    ///< duplicate entry is silently skipped
+    PS_META_DUPLICATE_OK = 0x4000000,  ///< allow duplicate entries
+    PS_META_NULL = 0x8000000           ///< psMetadataItem.data is a NULL value
 } psMetadataFlags;
 
@@ -342,4 +343,12 @@
 );
 
+/** Creates a new copy of a psMetadataItem.
+ *
+ * @return psMetadataItem*: the copy of the psMetadataItem
+ */
+psMetadataItem *psMetadataItemCopy(const psMetadataItem *in ///< metadata item to be copied
+                                  );
+
+
 /** Creates a new copy of all the psMetadataItems in the psMetadata collection, in, and
  *  returns them in out, or creates a new container if out is NULL.
@@ -939,4 +948,14 @@
 
 
+psPolynomial2D *psPolynomial2DfromMD (psMetadata *folder);
+bool psPolynomial2DtoMD (psMetadata *md, psPolynomial2D *poly, char *format, ...);
+
+psPolynomial3D *psPolynomial3DfromMD (psMetadata *folder);
+bool psPolynomial3DtoMD (psMetadata *md, psPolynomial3D *poly, char *format, ...);
+
+psPolynomial4D *psPolynomial4DfromMD (psMetadata *folder);
+bool psPolynomial4DtoMD (psMetadata *md, psPolynomial4D *poly, char *format, ...);
+
+
 /// @}
 
Index: /trunk/psLib/src/types/psPixels.h
===================================================================
--- /trunk/psLib/src/types/psPixels.h	(revision 6873)
+++ /trunk/psLib/src/types/psPixels.h	(revision 6874)
@@ -7,6 +7,6 @@
  *  @author Robert DeSonia, MHPCC
  *
- *  @version $Revision: 1.19 $ $Name: not supported by cvs2svn $
- *  @date $Date: 2006-02-28 02:53:03 $
+ *  @version $Revision: 1.20 $ $Name: not supported by cvs2svn $
+ *  @date $Date: 2006-04-17 22:00:03 $
  *
  *  Copyright 2004-2005 Maui High Performance Computing Center, University of Hawaii
@@ -17,4 +17,5 @@
 #include "psImage.h"
 #include "psVector.h"
+#include "psRegion.h"
 
 /// @addtogroup Image
@@ -125,5 +126,5 @@
  *
  *  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
+ *  the mask that match the maskVal. The out pixel list shall be modified if
  *  supplied, or allocated and returned if NULL. In hte event that mask is
  *  NULL, the function shall generate an error and return NULL.
Index: /trunk/psModules/src/astrom/pmFPAConstruct.c
===================================================================
--- /trunk/psModules/src/astrom/pmFPAConstruct.c	(revision 6873)
+++ /trunk/psModules/src/astrom/pmFPAConstruct.c	(revision 6874)
@@ -104,4 +104,6 @@
         return NULL;
     }
+    // XXX EAM test
+    fprintf (stderr, "phu name: %s == %s\n", keyword, name);
     return psMetadataItemParseString(resultItem);
 }
Index: unk/psModules/src/objects/psEllipse.c
===================================================================
--- /trunk/psModules/src/objects/psEllipse.c	(revision 6873)
+++ 	(revision )
@@ -1,62 +1,0 @@
-# include "pslib.h"
-# include "psEllipse.h"
-
-EllipseAxes EllipseMomentsToAxes (EllipseMoments moments)
-{
-
-    EllipseAxes axes;
-
-    double f = sqrt (0.25*PS_SQR(moments.x2 - moments.y2) + PS_SQR(moments.xy));
-    if (f > (moments.x2 + moments.y2) / 2.0) {
-        f = 0.98*(moments.x2 + moments.y2) / 2.0;
-    }
-
-    axes.major = sqrt (0.5*(moments.x2 + moments.y2) + f);
-    axes.minor = sqrt (0.5*(moments.x2 + moments.y2) - f);
-    axes.theta = atan2 (2*moments.xy, moments.x2 - moments.y2) / 2;
-    // theta in radians
-
-    return (axes);
-}
-
-EllipseShape EllipseAxesToShape (EllipseAxes axes)
-{
-
-    EllipseShape shape;
-
-    double r1 = 1.0 / PS_SQR(axes.major) + 1.0 / PS_SQR(axes.minor);
-    double r2 = 1.0 / PS_SQR(axes.major) - 1.0 / PS_SQR(axes.minor);
-
-    double sxr = r1 + r2*cos(2*axes.theta);
-    double syr = r1 - r2*cos(2*axes.theta);
-
-    shape.sx = 1.0 / sqrt(sxr);
-    shape.sy = 1.0 / sqrt(syr);
-    shape.sxy = r2*sin(2*axes.theta);
-
-    return (shape);
-}
-
-EllipseAxes EllipseShapeToAxes (EllipseShape shape)
-{
-
-    EllipseAxes axes;
-
-    double f1 = 1.0 / PS_SQR(shape.sx) + 1.0 / PS_SQR(shape.sy);
-    double f2 = 1.0 / PS_SQR(shape.sx) - 1.0 / PS_SQR(shape.sy);
-
-    // force the axis ratio to be less than 10
-    double r1 = 0.5*0.95*sqrt (PS_SQR(f1) - PS_SQR(f2));
-
-    shape.sxy = PS_MIN(PS_MAX(shape.sxy, -r1), r1);
-
-    axes.theta = atan2 (-2.0*shape.sxy, f2) / 2.0;
-
-    double Ar = 0.25*f1 + 0.25*sqrt(PS_SQR(f2) + 4*PS_SQR(shape.sxy));
-    double Br = 0.25*f1 - 0.25*sqrt(PS_SQR(f2) + 4*PS_SQR(shape.sxy));
-
-    axes.minor = 1.0 / sqrt (Ar);
-    axes.major = 1.0 / sqrt (Br);
-
-    return (axes);
-}
Index: unk/psModules/src/objects/psEllipse.h
===================================================================
--- /trunk/psModules/src/objects/psEllipse.h	(revision 6873)
+++ 	(revision )
@@ -1,30 +1,0 @@
-// strucures to define elliptical shape parameters
-typedef struct
-{
-    double major;
-    double minor;
-    double theta;
-}
-EllipseAxes;
-
-typedef struct
-{
-    double x2;
-    double y2;
-    double xy;
-}
-EllipseMoments;
-
-typedef struct
-{
-    double sx;
-    double sy;
-    double sxy;
-}
-EllipseShape;
-
-// conversions between elliptical shape representations
-EllipseAxes EllipseMomentsToAxes (EllipseMoments moments);
-EllipseShape EllipseAxesToShape (EllipseAxes axes);
-EllipseAxes EllipseShapeToAxes (EllipseShape shape);
-
Index: /trunk/psModules/src/pslib/psMetadataItemParse.c
===================================================================
--- /trunk/psModules/src/pslib/psMetadataItemParse.c	(revision 6873)
+++ /trunk/psModules/src/pslib/psMetadataItemParse.c	(revision 6874)
@@ -1,4 +1,8 @@
 #include <stdio.h>
 #include "pslib.h"
+
+# define PS_METADATA_ITEM_PARSE_NUMBER(INTYPE,OUTTYPE) \
+case PS_DATA_##INTYPE: { \
+    return (ps##OUTTYPE)(item->data.INTYPE); } \
 
 psF32 psMetadataItemParseF32(psMetadataItem *item
@@ -6,12 +10,12 @@
 {
     switch (item->type) {
-    case PS_DATA_F32:
-        return item->data.F32;
-    case PS_DATA_F64:
-        // Assume it's OK to truncate to floating point from double
-        return (float)item->data.F64;
-    case PS_DATA_S32:
-        // Promote to float
-        return (float)item->data.S32;
+        PS_METADATA_ITEM_PARSE_NUMBER (F32, F32);
+        PS_METADATA_ITEM_PARSE_NUMBER (F64, F32);
+        PS_METADATA_ITEM_PARSE_NUMBER (S8,  F32);
+        PS_METADATA_ITEM_PARSE_NUMBER (S16, F32);
+        PS_METADATA_ITEM_PARSE_NUMBER (S32, F32);
+        PS_METADATA_ITEM_PARSE_NUMBER (U8,  F32);
+        PS_METADATA_ITEM_PARSE_NUMBER (U16, F32);
+        PS_METADATA_ITEM_PARSE_NUMBER (U32, F32);
     default:
         psError(PS_ERR_IO, true, "Item %s (%s) is not of floating point type (%x) --- treating as NaN.\n",
@@ -25,12 +29,12 @@
 {
     switch (item->type) {
-    case PS_TYPE_F64:
-        return item->data.F64;
-    case PS_TYPE_F32:
-        // Promote to double
-        return (double)item->data.F32;
-    case PS_TYPE_S32:
-        // Promote to double
-        return (double)item->data.S32;
+        PS_METADATA_ITEM_PARSE_NUMBER (F32, F64);
+        PS_METADATA_ITEM_PARSE_NUMBER (F64, F64);
+        PS_METADATA_ITEM_PARSE_NUMBER (S8,  F64);
+        PS_METADATA_ITEM_PARSE_NUMBER (S16, F64);
+        PS_METADATA_ITEM_PARSE_NUMBER (S32, F64);
+        PS_METADATA_ITEM_PARSE_NUMBER (U8,  F64);
+        PS_METADATA_ITEM_PARSE_NUMBER (U16, F64);
+        PS_METADATA_ITEM_PARSE_NUMBER (U32, F64);
     default:
         psError(PS_ERR_IO, true, "Item %s (%s) is not of double-precision floating point type (%x) "
@@ -61,4 +65,10 @@
 }
 
+# define PS_METADATA_ITEM_PARSE_STRING(TYPE,MODE) \
+case PS_DATA_##TYPE: { \
+    psString value = NULL; \
+    psStringAppend(&value, MODE, item->data.TYPE); \
+    return value; } \
+
 psString psMetadataItemParseString(psMetadataItem *item
                                   )
@@ -67,14 +77,14 @@
     case PS_DATA_STRING:
         return psMemIncrRefCounter(item->data.V);
-    case PS_DATA_F32: {
-            psString value = NULL;    // String to return
-            psStringAppend(&value, "%f", item->data.F32);
-            return value;
-        }
-    case PS_DATA_S32: {
-            psString value = NULL;    // String to return
-            psStringAppend(&value, "%d", item->data.S32);
-            return value;
-        }
+
+        PS_METADATA_ITEM_PARSE_STRING(F32, "%f");
+        PS_METADATA_ITEM_PARSE_STRING(F64, "%f");
+        PS_METADATA_ITEM_PARSE_STRING(S8,  "%d");
+        PS_METADATA_ITEM_PARSE_STRING(S16, "%d");
+        PS_METADATA_ITEM_PARSE_STRING(S32, "%d");
+        PS_METADATA_ITEM_PARSE_STRING(U8,  "%d");
+        PS_METADATA_ITEM_PARSE_STRING(U16, "%d");
+        PS_METADATA_ITEM_PARSE_STRING(U32, "%d");
+
     default:
         psError(PS_ERR_IO, true, "Item %s (%s) is not of string type (%x) --- treating as "
@@ -84,2 +94,17 @@
 }
 
+
+# if 0
+case PS_DATA_F32:
+{
+psString value = NULL;    // String to return
+psStringAppend(&value, "%f", item->data.F32);
+    return value;
+}
+case PS_DATA_S32:
+{
+    psString value = NULL;    // String to return
+    psStringAppend(&value, "%d", item->data.S32);
+    return value;
+}
+# endif
