Index: trunk/Ohana/src/libdvo/include/dvo.h
===================================================================
--- trunk/Ohana/src/libdvo/include/dvo.h	(revision 27816)
+++ trunk/Ohana/src/libdvo/include/dvo.h	(revision 27817)
@@ -443,4 +443,5 @@
 void sort_image_subset (Image *image, off_t *subset, off_t N);
 void sort_coords_index (double *X, double *Y, off_t *S, off_t N);
+void sort_coords_indexonly (double *X, double *Y, off_t *S, off_t N);
 void sort_regions (SkyRegion *region, off_t N);
 
Index: trunk/Ohana/src/libdvo/src/dvosorts.c
===================================================================
--- trunk/Ohana/src/libdvo/src/dvosorts.c	(revision 27816)
+++ trunk/Ohana/src/libdvo/src/dvosorts.c	(revision 27817)
@@ -46,4 +46,19 @@
 }
 
+/* sort a coordinate pair (X,Y) and the associated index (S) */
+void sort_coords_indexonly (double *X, double *Y, off_t *S, off_t N) {
+  
+# define SWAPFUNC(A,B){ off_t itmp; \
+  itmp = S[A]; S[A] = S[B]; S[B] = itmp; \
+}
+# define COMPARE(A,B)(X[S[A]] < X[S[B]])
+
+  OHANA_SORT (N, COMPARE, SWAPFUNC);
+
+# undef SWAPFUNC
+# undef COMPARE
+
+}
+
 void sort_regions (SkyRegion *region, off_t N) {
 
Index: trunk/Ohana/src/libkapa/src/KapaColors.c
===================================================================
--- trunk/Ohana/src/libkapa/src/KapaColors.c	(revision 27816)
+++ trunk/Ohana/src/libkapa/src/KapaColors.c	(revision 27817)
@@ -37,4 +37,6 @@
     }	
   }
+  if (!strcasecmp (name, "none")) return (-1);
+
   fprintf (stderr, "color may be one of:\n");
   for (i = 0; i < N_KAPA_COLORS; i++) {
Index: trunk/Ohana/src/opihi/cmd.basic/break.c
===================================================================
--- trunk/Ohana/src/opihi/cmd.basic/break.c	(revision 27816)
+++ trunk/Ohana/src/opihi/cmd.basic/break.c	(revision 27817)
@@ -1,15 +1,16 @@
 # include "basic.h"
 
+// auto_break is currently a global
 int exec_break (int argc, char **argv) {
 
   int N, value;
 
+  if ((N = get_argument (argc, argv, "-h"))) goto usage;
+  if ((N = get_argument (argc, argv, "-help"))) goto usage;
+  if ((N = get_argument (argc, argv, "--help"))) goto usage;
+
   if ((N = get_argument (argc, argv, "-auto"))) {
     remove_argument (N, &argc, argv);
-    value = -1;
-    if (!strcasecmp (argv[N], "on")) value = 1;
-    if (!strcasecmp (argv[N], "off")) value = 0;
-    if (value == -1) {
-      gprint (GP_ERR, "USAGE: break -auto [on / off]\n");
+    if (N == argc) {
       if (auto_break) 
 	gprint (GP_ERR, "auto break on\n");
@@ -18,10 +19,17 @@
       return (FALSE);
     }
+    value = -1;
+    if (!strcasecmp (argv[N], "on")) value = 1;
+    if (!strcasecmp (argv[N], "off")) value = 0;
+    if (value == -1) goto usage;
     auto_break = value;
     return (TRUE);
   }
-
+  
   loop_break = TRUE;
   return (FALSE);
-
+  
+usage:
+  gprint (GP_ERR, "USAGE: break -auto [on / off]\n");
+  return (FALSE);
 }
Index: trunk/Ohana/src/opihi/cmd.data/Makefile
===================================================================
--- trunk/Ohana/src/opihi/cmd.data/Makefile	(revision 27816)
+++ trunk/Ohana/src/opihi/cmd.data/Makefile	(revision 27817)
@@ -72,4 +72,5 @@
 $(SRC)/lookup.$(ARCH).o	\
 $(SRC)/matrix.$(ARCH).o	\
+$(SRC)/match2d.$(ARCH).o	\
 $(SRC)/mkrgb.$(ARCH).o	\
 $(SRC)/mcreate.$(ARCH).o	\
Index: trunk/Ohana/src/opihi/cmd.data/create.c
===================================================================
--- trunk/Ohana/src/opihi/cmd.data/create.c	(revision 27816)
+++ trunk/Ohana/src/opihi/cmd.data/create.c	(revision 27817)
@@ -14,5 +14,6 @@
 
   if ((argc != 5) && (argc != 4)) {
-    gprint (GP_ERR, "USAGE: create vector start end [delta]\n");
+    gprint (GP_ERR, "USAGE: create vector start end [delta] [-int]\n");
+    gprint (GP_ERR, " -int : resulting vector is integer type (delta must be integer)\n");
     return (FALSE);
   }
@@ -20,8 +21,9 @@
   if ((vec = SelectVector (argv[1], ANYVECTOR, TRUE)) == NULL) return (FALSE);
 
+  delta = 1;
   start = atof (argv[2]);
   end   = atof (argv[3]);
-  delta = 1;
   if (argc == 5) delta = atof (argv[4]);
+
   if ((start == end) || (delta == 0)) {
     gprint (GP_ERR, "error in value: %f to %f, %f\n", start, end, delta);
Index: trunk/Ohana/src/opihi/cmd.data/fit1d.c
===================================================================
--- trunk/Ohana/src/opihi/cmd.data/fit1d.c	(revision 27816)
+++ trunk/Ohana/src/opihi/cmd.data/fit1d.c	(revision 27817)
@@ -53,9 +53,9 @@
     return (FALSE);
   }
-  REQUIRE_VECTOR_FLT (xvec, FALSE); 
-  REQUIRE_VECTOR_FLT (yvec, FALSE); 
+  CastVector (xvec, OPIHI_FLT);
+  CastVector (yvec, OPIHI_FLT);
 
   if (Weight) {
-    REQUIRE_VECTOR_FLT (dyvec, FALSE); 
+    CastVector (dyvec, OPIHI_FLT);
     if (xvec[0].Nelements != dyvec[0].Nelements) {
       gprint (GP_ERR, "vectors must have same length\n");
Index: trunk/Ohana/src/opihi/cmd.data/fit2d.c
===================================================================
--- trunk/Ohana/src/opihi/cmd.data/fit2d.c	(revision 27816)
+++ trunk/Ohana/src/opihi/cmd.data/fit2d.c	(revision 27817)
@@ -64,10 +64,10 @@
     return (FALSE);
   }
-  REQUIRE_VECTOR_FLT (xvec, FALSE); 
-  REQUIRE_VECTOR_FLT (yvec, FALSE); 
-  REQUIRE_VECTOR_FLT (zvec, FALSE); 
+  CastVector (xvec, OPIHI_FLT);
+  CastVector (yvec, OPIHI_FLT);
+  CastVector (zvec, OPIHI_FLT);
 
   if (Weight) {
-    REQUIRE_VECTOR_FLT (dzvec, FALSE); 
+    CastVector (dzvec, OPIHI_FLT);
     if (xvec[0].Nelements != dzvec[0].Nelements) {
       gprint (GP_ERR, "vectors must have same length\n");
Index: trunk/Ohana/src/opihi/cmd.data/histogram.c
===================================================================
--- trunk/Ohana/src/opihi/cmd.data/histogram.c	(revision 27816)
+++ trunk/Ohana/src/opihi/cmd.data/histogram.c	(revision 27817)
@@ -3,11 +3,18 @@
 int histogram (int argc, char **argv) {
   
-  int i, bin, Nbins;
+  int i, N, bin, Nbins;
   opihi_int *OUT;
   opihi_flt start, end, delta;
-  Vector *xvec, *yvec;
+  Vector *xvec, *yvec, *range;
+
+  range = NULL;
+  if ((N = get_argument (argc, argv, "-range"))) {
+    remove_argument (N, &argc, argv);
+    if ((range = SelectVector (argv[N], ANYVECTOR, TRUE)) == NULL) return (FALSE);    
+    remove_argument (N, &argc, argv);
+  }
 
   if ((argc != 6) && (argc != 5)) {
-    gprint (GP_ERR, "USAGE: hist invec outvec start end [delta]\n");
+    gprint (GP_ERR, "USAGE: hist invec outvec start end [delta] [-range range]\n");
     return (FALSE);
   }
@@ -31,4 +38,11 @@
   if ((xvec = SelectVector (argv[1], OLDVECTOR, TRUE)) == NULL) return (FALSE);
   if ((yvec = SelectVector (argv[2], ANYVECTOR, TRUE)) == NULL) return (FALSE);
+
+  if (range) {
+    ResetVector (range, OPIHI_FLT, Nbins);
+    for (i = 0; i < range[0].Nelements; i++) {
+      range[0].elements.Flt[i] = start + i*delta;
+    }
+  }
 
   ResetVector (yvec, OPIHI_INT, Nbins);
Index: trunk/Ohana/src/opihi/cmd.data/init.c
===================================================================
--- trunk/Ohana/src/opihi/cmd.data/init.c	(revision 27816)
+++ trunk/Ohana/src/opihi/cmd.data/init.c	(revision 27817)
@@ -61,4 +61,5 @@
 int lookup           PROTO((int, char **));
 int matrix           PROTO((int, char **));
+int match2d          PROTO((int, char **));
 int mkrgb            PROTO((int, char **));
 int mcreate          PROTO((int, char **));
@@ -201,4 +202,5 @@
   {1, "iminterp",     minterp,          "interpolate image pixels"},
   {1, "matrix",       matrix,           "matrix math operations"},
+  {1, "match2d",      match2d,          "match 2 pairs of X,Y vectors and return matched indexes"},
   {1, "mkrgb",        mkrgb,            "convert 3 images to rgb jpeg (use Kapa for better control)"},
   {1, "mset",         mset,             "insert a vector in an image"},
Index: trunk/Ohana/src/opihi/cmd.data/match2d.c
===================================================================
--- trunk/Ohana/src/opihi/cmd.data/match2d.c	(revision 27817)
+++ trunk/Ohana/src/opihi/cmd.data/match2d.c	(revision 27817)
@@ -0,0 +1,133 @@
+# include "data.h"
+int find_matches2d (Vector *X1, Vector *Y1, Vector *X2, Vector *Y2, double Radius, Vector *index1, Vector *index2);
+
+// match2d (X1) (Y1) (X2) (Y2) (Radius) [-index1 (index1)] [-index2 (index2)] [-nomatch1 nomatch1] [-nomatch2 nomatch2]
+// X1[Index1] <=> X2[Index2] (etc)
+int match2d (int argc, char **argv) {
+  
+  int N;
+  double Radius;
+  char *endptr;
+  Vector *X1vec, *Y1vec, *X2vec, *Y2vec;
+  Vector *index1, *index2;
+
+  if ((N = get_argument (argc, argv, "-index1"))) {
+    remove_argument (N, &argc, argv);
+    if ((index1 = SelectVector (argv[N], ANYVECTOR, TRUE)) == NULL) return (FALSE);    
+    remove_argument (N, &argc, argv);
+  } else {
+    if ((index1 = SelectVector ("index1", ANYVECTOR, TRUE)) == NULL) return (FALSE);    
+  }
+
+  if ((N = get_argument (argc, argv, "-index2"))) {
+    remove_argument (N, &argc, argv);
+    if ((index2 = SelectVector (argv[N], ANYVECTOR, TRUE)) == NULL) return (FALSE);    
+    remove_argument (N, &argc, argv);
+  } else {
+    if ((index2 = SelectVector ("index2", ANYVECTOR, TRUE)) == NULL) return (FALSE);    
+  }
+
+  if (argc != 6) {
+    gprint (GP_ERR, "USAGE: match2d X1 Y1 X2 Y2 Radius [-index1 (index1)] [-index2 (index2)] [-closest]\n");
+    // gprint (GP_ERR, "USAGE: match2d X1 Y1 X2 Y2 Radius [-index1 (index1)] [-index2 (index2)] [-closest]\n");
+    // gprint (GP_ERR, "  if -closest is provided, index1 & index2 will have the same length as X1 and X2 (respectively)\n");
+    // gprint (GP_ERR, "    with either the index of the match or a value of -1 for non-matches\n");
+    return (FALSE);
+  }
+
+  if ((X1vec = SelectVector (argv[1], OLDVECTOR, TRUE)) == NULL) return (FALSE);    
+  if ((Y1vec = SelectVector (argv[2], OLDVECTOR, TRUE)) == NULL) return (FALSE);    
+  if ((X2vec = SelectVector (argv[3], OLDVECTOR, TRUE)) == NULL) return (FALSE);    
+  if ((Y2vec = SelectVector (argv[4], OLDVECTOR, TRUE)) == NULL) return (FALSE);    
+
+  if (X1vec[0].Nelements != Y1vec[0].Nelements) {
+    gprint (GP_ERR, "X1 & Y1 vectors must have same length\n");
+    return (FALSE);
+  }
+  if (X2vec[0].Nelements != Y2vec[0].Nelements) {
+    gprint (GP_ERR, "X2 & Y2 vectors must have same length\n");
+    return (FALSE);
+  }
+
+  REQUIRE_VECTOR_FLT (X1vec, FALSE); 
+  REQUIRE_VECTOR_FLT (Y1vec, FALSE); 
+  REQUIRE_VECTOR_FLT (X2vec, FALSE); 
+  REQUIRE_VECTOR_FLT (Y2vec, FALSE); 
+
+  Radius = strtod (argv[5], &endptr);
+  if (*endptr) {
+    gprint (GP_ERR, "Radius must be numerical (%s)\n", argv[5]);
+    return (FALSE);
+  }
+
+  find_matches2d (X1vec, Y1vec, X2vec, Y2vec, Radius, index1, index2);
+
+  return (TRUE);
+}
+
+// we are not defining a relative offset DX,DY for now
+int find_matches2d (Vector *X1, Vector *Y1, Vector *X2, Vector *Y2, double Radius, Vector *index1, Vector *index2) {
+  
+  off_t i, j, first_j, I, J, *N1, *N2, Nmatch, NMATCH, DMATCH;
+  double dX, dY, dR, Radius2;
+
+  NMATCH = MAX(MAX(0.01*X1->Nelements, 0.01*X2->Nelements), 100);
+  DMATCH = NMATCH;
+
+  ResetVector (index1, OPIHI_INT, NMATCH);
+  ResetVector (index2, OPIHI_INT, NMATCH);
+
+  ALLOCATE (N1, off_t, X1->Nelements);
+  ALLOCATE (N2, off_t, X2->Nelements);
+
+  for (i = 0; i < X1->Nelements; i++) { N1[i] = i; }
+  for (i = 0; i < X2->Nelements; i++) { N2[i] = i; }
+
+  sort_coords_indexonly (X1->elements.Flt, Y1->elements.Flt, N1, X1->Nelements);
+  sort_coords_indexonly (X2->elements.Flt, Y2->elements.Flt, N2, X2->Nelements);
+
+  Radius2 = Radius*Radius;
+
+  Nmatch = 0;
+  for (i = j = 0; (i < X1->Nelements) && (j < X2->Nelements);) {
+    I = N1[i];
+    J = N2[j];
+
+    dX = X1->elements.Flt[I] - X2->elements.Flt[J];
+
+    if (dX <= -1.02*Radius) { i++; continue; }
+    if (dX >= +1.02*Radius) { j++; continue; }
+
+    // look for all matches of list2() to list1(i)
+    first_j = j;
+    for (j = first_j; (dX > -1.02*Radius) && (j < X2->Nelements); j++) {
+      J = N2[j];
+      dX = X1->elements.Flt[I] - X2->elements.Flt[J];
+      dY = Y1->elements.Flt[I] - Y2->elements.Flt[J];
+      dR = dX*dX + dY*dY;
+      if (dR < Radius2) {
+	index1->elements.Int[Nmatch] = I;
+	index2->elements.Int[Nmatch] = J;
+
+	// XXX track matches 1 and 2 with internal vector, save new nomatch index vectors
+	// after this loop
+
+	Nmatch ++;
+	if (Nmatch >= NMATCH) {
+	  NMATCH += DMATCH;
+	  REALLOCATE (index1->elements.Int, opihi_int, NMATCH);
+	  REALLOCATE (index2->elements.Int, opihi_int, NMATCH);
+	}
+      }
+    }
+    j = first_j;
+    i++;
+  }
+  index1->Nelements = Nmatch;
+  index2->Nelements = Nmatch;
+
+  free (N1);
+  free (N2);
+
+  return (TRUE);
+}
