Index: /trunk/Ohana/src/addstar/include/skycells.h
===================================================================
--- /trunk/Ohana/src/addstar/include/skycells.h	(revision 21047)
+++ /trunk/Ohana/src/addstar/include/skycells.h	(revision 21048)
@@ -12,5 +12,6 @@
 # include <glob.h>
 
-enum {SQUARES, TRIANGLES};
+enum {SQUARES, TRIANGLES, LOCAL};
+enum {TETRAHEDRON, CUBE, OCTOHEDRON, DODECAHEDRON, ICOSAHEDRON};
 
 typedef struct {
@@ -60,4 +61,5 @@
 int    VERBOSE;
 int    MODE;
+int    SOLID;
 int    FIX_NS;
 int    NMAX;
@@ -65,27 +67,34 @@
 double SCALE;
 double PADDING;
+int    LEVEL;
+
+double CENTER_RA, CENTER_DEC;
+double RANGE_RA,  RANGE_DEC;
 
 double EULER_A;
 double EULER_B;
 
-void         SetProtect                PROTO((int mode));
-int          SetSignals                PROTO(());
-int          Shutdown                  PROTO((char *message, ...); ) 
-void         TrapSignal                PROTO((int sig));
+void         SetProtect                	    PROTO((int mode));
+int          SetSignals                	    PROTO(());
+int          Shutdown                  	    PROTO((char *message, ...); ) 
+void         TrapSignal                	    PROTO((int sig));
 
-int 	     args_skycells 	       PROTO((int argc, char **argv));
-int 	     ConfigInit_skycells       PROTO((int *argc, char **argv));
-int 	     sky_tessalation 	       PROTO((FITS_DB *db, int level, int Nmax, int mode, double scale));
-int          sky_tessalation_init      PROTO((double scale));
-int 	     sky_tessalation_triangles PROTO((FITS_DB *db, int level, int Nmax));
-int 	     sky_tessalation_squares   PROTO((FITS_DB *db, int level, int Nmax));
-int 	     sky_triangle_to_image     PROTO((Image *image, SkyTriangle *triangle));
-int 	     sky_triangle_to_rectangle PROTO((SkyRectangle *image, SkyTriangle *triangle));
-int 	     sky_subdivide_image       PROTO((Image *output, SkyRectangle *input, int Nx, int Ny));
-int 	     sky_triangle_coords       PROTO((SkyTriangle *triangle));
-SkyTriangle *sky_divide_triangles      PROTO((SkyTriangle *in, int *ntriangles));
-SkyTriangle *sky_base_triangles        PROTO((int *ntriangles));
-int          sky_base_rotation         PROTO((SkyTriangle *base, int Nbase));
-Point        sky_divide_edge           PROTO((Point v1, Point v2));
+int 	     args_skycells 	       	    PROTO((int argc, char **argv));
+int 	     ConfigInit_skycells       	    PROTO((int *argc, char **argv));
+int 	     sky_tessellation 	       	    PROTO((FITS_DB *db, int level, int Nmax, int mode, double scale));
+int          sky_tessellation_init          PROTO((double scale));
+int 	     sky_tessellation_local         PROTO((FITS_DB *db, int level, int Nmax));
+int 	     sky_tessellation_triangles     PROTO((FITS_DB *db, int level, int Nmax));
+int 	     sky_tessellation_squares       PROTO((FITS_DB *db, int level, int Nmax));
+int 	     sky_triangle_to_image     	    PROTO((Image *image, SkyTriangle *triangle));
+int 	     sky_triangle_to_rectangle 	    PROTO((SkyRectangle *image, SkyTriangle *triangle));
+int          sky_rectangle_local            PROTO((SkyRectangle *rectangle));
+int 	     sky_subdivide_image       	    PROTO((Image *output, SkyRectangle *input, int Nx, int Ny));
+int 	     sky_triangle_coords       	    PROTO((SkyTriangle *triangle));
+SkyTriangle *sky_divide_triangles      	    PROTO((SkyTriangle *in, int *ntriangles));
+SkyTriangle *sky_base_triangles        	    PROTO((int *ntriangles));
+SkyTriangle *sky_base_triangles_icosahedron PROTO((int *ntriangles));
+int          sky_base_rotation         	    PROTO((SkyTriangle *base, int Nbase));
+Point        sky_divide_edge           	    PROTO((Point v1, Point v2));
 
 // XXX migrate to libdvo eventually
Index: /trunk/Ohana/src/addstar/src/args_skycells.c
===================================================================
--- /trunk/Ohana/src/addstar/src/args_skycells.c	(revision 21047)
+++ /trunk/Ohana/src/addstar/src/args_skycells.c	(revision 21048)
@@ -6,4 +6,6 @@
   int N;
   char *ptr;
+
+  if (argc == 1) goto escape;
 
   /* check for help request */
@@ -22,7 +24,63 @@
   /* what type of output files? */
   MODE = SQUARES;
-  if ((N = get_argument (argc, argv, "-triangles"))) {
-    MODE = TRIANGLES;
+  if ((N = get_argument (argc, argv, "-mode"))) {
     remove_argument (N, &argc, argv);
+    if (!strcasecmp (argv[N], "squares")) {
+      MODE = SQUARES;
+    }
+    if (!strcasecmp (argv[N], "triangles")) {
+      MODE = SQUARES;
+    }
+    if (!strcasecmp (argv[N], "local")) {
+      MODE = LOCAL;
+    }
+    remove_argument (N, &argc, argv);
+  }
+
+  /* what base solid? */
+  SOLID = ICOSAHEDRON;
+  if ((N = get_argument (argc, argv, "-solid"))) {
+    remove_argument (N, &argc, argv);
+    if (!strncasecmp (argv[N], "TETRAHEDRON", MIN(4, strlen(argv[N])))) {
+      SOLID = TETRAHEDRON;
+    }
+    if (!strncasecmp (argv[N], "CUBE", MIN(4, strlen(argv[N])))) {
+      SOLID = CUBE;
+    }
+    if (!strncasecmp (argv[N], "OCTOHEDRON", MIN(4, strlen(argv[N])))) {
+      SOLID = OCTOHEDRON;
+    }
+    if (!strncasecmp (argv[N], "DODECAHEDRON", MIN(4, strlen(argv[N])))) {
+      SOLID = DODECAHEDRON;
+    }
+    if (!strncasecmp (argv[N], "ICOSAHEDRON", MIN(4, strlen(argv[N])))) {
+      SOLID = ICOSAHEDRON;
+    }
+    remove_argument (N, &argc, argv);
+  }
+
+  if (MODE == LOCAL) {
+    // for local mode, need to define the center and range
+    if ((N = get_argument (argc, argv, "-center"))) {
+      remove_argument (N, &argc, argv);
+      CENTER_RA  = atof (argv[N]);
+      remove_argument (N, &argc, argv);
+      CENTER_DEC = atof (argv[N]);
+      remove_argument (N, &argc, argv);
+    } else {
+      fprintf (stderr, "missing -center RA DEC for LOCAL mode\n");
+      help ();
+    }
+    // for local mode, need to define the center and range
+    if ((N = get_argument (argc, argv, "-size"))) {
+      remove_argument (N, &argc, argv);
+      RANGE_RA  = atof (argv[N]);
+      remove_argument (N, &argc, argv);
+      RANGE_DEC = atof (argv[N]);
+      remove_argument (N, &argc, argv);
+    } else {
+      fprintf (stderr, "missing -size dRA dDEC for LOCAL mode\n");
+      help ();
+    }
   }
 
@@ -81,10 +139,21 @@
   }
 
-  if (argc == 2) {
-    strtol (argv[1], &ptr, 10);
-    if (*ptr == 0) return (TRUE);
+  LEVEL = 8;
+  if ((MODE != LOCAL) && (N = get_argument (argc, argv, "-level"))) {
+    remove_argument (N, &argc, argv);
+    LEVEL = strtol (argv[N], &ptr, 10);
+    remove_argument (N, &argc, argv);
+    if ((*ptr != 0) || (LEVEL < 0)) {
+      fprintf (stderr, "-level requires an integer (>= 0) argument\n");
+      help ();
+    }  
   }
 
-  fprintf (stderr, "USAGE: skycells (level) [-scale arcsec/pix] [-nx (Nx cells)] [-ny (Ny cells)]\n");
+  if (argc != 1) goto escape;
+
+  return (TRUE);
+
+escape:
+  fprintf (stderr, "USAGE: skycells [-mode mode] [-level level] [-scale arcsec/pix] [-nx (Nx cells)] [-ny (Ny cells)]\n");
   fprintf (stderr, "  [-h for details and other options]\n");
   exit (2);
@@ -96,14 +165,23 @@
   fprintf (stderr, "  skycells\n\n");
 
-  fprintf (stderr, "  -v                    	  : verbose mode\n");
+  fprintf (stderr, "  -mode (name)                : define the type of tessellation.  available options are:\n");
+  fprintf (stderr, "     SQUARE                   : generate rectangular skycells using icosahedron base solid (default)\n");
+  fprintf (stderr, "     TRIANGLE                 : generate triangular skycells using icosahedron base solid\n");
+  fprintf (stderr, "     LOCAL                    : generate a local tessellation around a spot on the sky\n");
+  fprintf (stderr, "                                 (Note that this tessellation does not cover the full sky)\n");
+  fprintf (stderr, "  -solid (name)               : specify the base solid\n");
+  fprintf (stderr, "                                value may be one of: TETRAHEDRON, CUBE, OCTOHEDRON, DODECAHEDRON, ICOSAHEDRON\n");
+  fprintf (stderr, "                                for convenience, only the first 4 characters are required\n");
+  fprintf (stderr, "  -v                          : verbose mode\n");
   fprintf (stderr, "  -triangles                  : save base triangles instead of skycells\n");
   fprintf (stderr, "  -fix-ns                     : orient skycells with y-axis aligned with Dec\n");
-  fprintf (stderr, "  -scale                      : set pixel scale (default 1.0 arcsec / pixel)\n");
-  fprintf (stderr, "  -padding                    : pad skycells by this fraction in each dimension\n");
-  fprintf (stderr, "  -nmax                    	  : only keep nmax skycells in memory\n");
-  fprintf (stderr, "  -nx                    	  : subdivide skycell projection in x\n");
-  fprintf (stderr, "  -ny                    	  : subdivide skycell projection in y\n");
-  fprintf (stderr, "  -help                 	  : this list\n");
-  fprintf (stderr, "  -h                    	  : this list\n\n");
+  fprintf (stderr, "  -scale (scale)              : set pixel scale in arcsec (default 1.0 arcsec / pixel)\n");
+  fprintf (stderr, "  -euler (A) (B)              : define Euler A and B rotation angles (degrees)\n");
+  fprintf (stderr, "  -padding (fraction)         : pad skycells by this fraction in each dimension\n");
+  fprintf (stderr, "  -nmax Nmax                  : only keep Nmax skycells in memory\n");
+  fprintf (stderr, "  -nx Nx                      : subdivide skycell projection in x by Nx\n");
+  fprintf (stderr, "  -ny Ny                      : subdivide skycell projection in y by Ny\n");
+  fprintf (stderr, "  -help                       : this list\n");
+  fprintf (stderr, "  -h                          : this list\n\n");
   exit (2);
 }
Index: /trunk/Ohana/src/addstar/src/sky_tessalation.c
===================================================================
--- /trunk/Ohana/src/addstar/src/sky_tessalation.c	(revision 21047)
+++ /trunk/Ohana/src/addstar/src/sky_tessalation.c	(revision 21048)
@@ -7,22 +7,27 @@
 static Coords *refcoords = NULL;
 
-int sky_tessalation (FITS_DB *db, int level, int Nmax, int mode, double scale) {
-
-  sky_tessalation_init (scale);
+int sky_tessellation (FITS_DB *db, int level, int Nmax, int mode, double scale) {
+
+  sky_tessellation_init (scale);
 
   if (mode == SQUARES) {
-    sky_tessalation_squares (db, level, Nmax);
+    sky_tessellation_squares (db, level, Nmax);
     return TRUE;
   }
 
   if (mode == TRIANGLES) {
-    sky_tessalation_triangles (db, level, Nmax);
+    sky_tessellation_triangles (db, level, Nmax);
     return TRUE;
   }
 
+  if (mode == LOCAL) {
+    sky_tessellation_local (db, level, Nmax);
+    return TRUE;
+  }
+
   return FALSE;
 }
 
-int sky_tessalation_triangles (FITS_DB *db, int level, int Nmax) {
+int sky_tessellation_triangles (FITS_DB *db, int level, int Nmax) {
 
   int i, j, Ndigit, Ntriangles, Nbase, Ntotal, Ltop, Nout, Nimages;
@@ -96,5 +101,5 @@
 }
 
-int sky_tessalation_squares (FITS_DB *db, int level, int Nmax) {
+int sky_tessellation_squares (FITS_DB *db, int level, int Nmax) {
 
   int i, j, Nname, Ndigit, Ntriangles, Nbase, Nimage, Ntotal, Ntop, Ltop, Nsubset, Nx, Ny;
@@ -186,4 +191,35 @@
     free (tri);
   }
+  return (TRUE);
+}
+
+// use CENTER_RA and CENTER_DEC as the starting point.  generate a single projection 
+// of size RANGE_RA and RANGE_DEC, and subdivide as specified.  This pseudo-tessellation may be used
+// for local projects such as the PS1 Medium Deep fields
+int sky_tessellation_local (FITS_DB *db, int level, int Nmax) {
+
+  int Nimage;
+  SkyRectangle rectangle;
+  Image *image;
+
+  // this tessellation consists of a single projection center with Nx * Ny cells
+  sky_rectangle_local (&rectangle);
+  strcpy (rectangle.name, "skycell");
+
+  // subdivide each image (Nx x Ny subcells)
+  Nimage = NX_SUB*NY_SUB;
+  ALLOCATE (image, Image, Nimage);
+
+  // convert the SkyRectangle to Images for output
+  sky_subdivide_image (image, &rectangle, NX_SUB, NY_SUB);
+
+  /* add the new images and save */
+  dvo_image_addrows (db, image, Nimage);
+  SetProtect (TRUE);
+  dvo_image_update (db, VERBOSE);
+  SetProtect (FALSE);
+  dvo_image_clear_vtable (db);
+
+  free (image);
   return (TRUE);
 }
@@ -402,4 +438,48 @@
 }
 
+// define the parameters of a single sky projection center
+int sky_rectangle_local (SkyRectangle *rectangle) {
+
+  int NX, NY;
+  float angle;
+
+  memset (rectangle, 0, sizeof(SkyRectangle));
+  rectangle[0].coords.crval1 = CENTER_RA;
+  rectangle[0].coords.crval2 = CENTER_DEC;
+
+  // we will add this as an option later
+  angle = 0.0;
+  if (FIX_NS) {
+    rectangle[0].coords.pc1_1 = +1.0;
+    rectangle[0].coords.pc1_2 = +0.0;
+    rectangle[0].coords.pc2_1 = -0.0;
+    rectangle[0].coords.pc2_2 = +1.0;
+  } else {
+    rectangle[0].coords.pc1_1 = +cos(angle);
+    rectangle[0].coords.pc1_2 = +sin(angle);
+    rectangle[0].coords.pc2_1 = -sin(angle);
+    rectangle[0].coords.pc2_2 = +cos(angle);
+  }
+  
+  // range values are in projected degrees
+  NX = RANGE_RA  * 3600.0 / SCALE;
+  NY = RANGE_DEC * 3600.0 / SCALE;
+
+  // crpix1,crpix2 is the projection center
+  rectangle[0].coords.crpix1 = 0.5*NX;
+  rectangle[0].coords.crpix2 = 0.5*NY;
+
+  rectangle[0].coords.cdelt1 = SCALE / 3600.0;
+  rectangle[0].coords.cdelt2 = SCALE / 3600.0;
+
+  strcpy (rectangle[0].coords.ctype, "DEC--TAN");
+
+  rectangle[0].NX = NX;
+  rectangle[0].NY = NY;
+  rectangle[0].code = 1; // this needs to be set more sensibly
+
+  return (TRUE);
+}
+
 // an allocated image set is supplied, we fill in the values
 int sky_subdivide_image (Image *output, SkyRectangle *input, int Nx, int Ny) {
@@ -517,8 +597,37 @@
 }
 
+SkyTriangle *sky_base_triangles (int *ntriangles) {
+
+  SkyTriangle *tri;
+
+  switch (SOLID) {
+    case TETRAHEDRON:
+      fprintf (stderr, "TETRAHEDRON is not yet defined\n");
+      exit (2);
+      break;
+    case CUBE:
+      fprintf (stderr, "CUBE is not yet defined\n");
+      exit (2);
+      break;
+    case OCTOHEDRON:
+      fprintf (stderr, "OCTOHEDRON is not yet defined\n");
+      exit (2);
+      break;
+    case DODECAHEDRON:
+      fprintf (stderr, "DODECAHEDRON is not yet defined\n");
+      exit (2);
+      break;
+    case ICOSAHEDRON:
+      tri = sky_base_triangles_icosahedron (ntriangles);
+  }
+
+  return tri;
+
+}
+
 # define THETA RAD_DEG*26.565
 # define D_PSI RAD_DEG*360.0/5.0
 
-SkyTriangle *sky_base_triangles (int *ntriangles) {
+SkyTriangle *sky_base_triangles_icosahedron (int *ntriangles) {
 
   int i;
@@ -642,5 +751,5 @@
 }
 
-int sky_tessalation_init (double scale) {
+int sky_tessellation_init (double scale) {
 
   ALLOCATE (refcoords, Coords, 1);
Index: /trunk/Ohana/src/addstar/src/skycells.c
===================================================================
--- /trunk/Ohana/src/addstar/src/skycells.c	(revision 21047)
+++ /trunk/Ohana/src/addstar/src/skycells.c	(revision 21048)
@@ -3,5 +3,5 @@
 int main (int argc, char **argv) {
 
-  int status, level;
+  int status;
   FITS_DB db;
 
@@ -9,6 +9,5 @@
   ConfigInit_skycells (&argc, argv);
   args_skycells (argc, argv);
-  level = atoi (argv[1]);
-  
+
   /*** update the image table ***/
   /* setup image table format and lock */
@@ -28,7 +27,7 @@
   }
 
-  // we have to put the database update calls deep down in the sky_tessalation code so we
+  // we have to put the database update calls deep down in the sky_tessellation code so we
   // can write out the skycells in limited-sized chunks.
-  sky_tessalation (&db, level, NMAX, MODE, SCALE);
+  sky_tessellation (&db, LEVEL, NMAX, MODE, SCALE);
 
   dvo_image_unlock (&db);
