gnuastro-commits
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[gnuastro-commits] master 7a2a9c4: Table: New --inpolygon, --outpolygon


From: Mohammad Akhlaghi
Subject: [gnuastro-commits] master 7a2a9c4: Table: New --inpolygon, --outpolygon and --polygon options added
Date: Sun, 10 May 2020 13:30:26 -0400 (EDT)

branch: master
commit 7a2a9c4af056f3b71111e270ee4fb35069090280
Author: Sachin Kumar Singh <address@hidden>
Commit: Mohammad Akhlaghi <address@hidden>

    Table: New --inpolygon, --outpolygon and --polygon options added
    
    With the new `--inpolygon' and `--outpolygon' options, it is now possible
    to select rows based on their position relative to a polygon (either inside
    of it or outside). The `--polygon' option is shared between the two and is
    used to specify the actual polygon.
    
    Since we wanted Table's `--polygon' option to be parsed identially to
    Crop's, the polygon parsing function of Crop was moved into the options.h
    library as `gal_options_parse_colon_sep_csv' which is now used in both Crop
    and Table.
---
 NEWS                            |   3 +
 bin/crop/args.h                 |   3 +-
 bin/crop/main.h                 |   2 +-
 bin/crop/onecrop.c              | 106 --------------------------
 bin/crop/onecrop.h              |   3 -
 bin/crop/ui.c                   |  26 +++++--
 bin/table/args.h                |  42 +++++++++++
 bin/table/main.h                |   5 ++
 bin/table/table.c               |  86 +++++++++++++++++++++
 bin/table/ui.c                  |  73 +++++++++++++++---
 bin/table/ui.h                  |   4 +
 doc/gnuastro.texi               |  30 ++++++++
 lib/gnuastro-internal/options.h |   4 +
 lib/options.c                   | 161 +++++++++++++++++++++++++++++++++++++++-
 14 files changed, 422 insertions(+), 126 deletions(-)

diff --git a/NEWS b/NEWS
index 10ab205..5808dc8 100644
--- a/NEWS
+++ b/NEWS
@@ -50,6 +50,9 @@ See the end of the file for license conditions.
   Table:
    --equal: Can now work on columns with string type also.
    --notequal: Can now work on columns with string type also.
+   --polygon: Polygon to use in `--inpolygon' or `--outpolygon'.
+   --inpolygon: Select rows that are inside the polygon of `--polygon'.
+   --outpolygon: Select rows that are outside the polygon of `--polygon'.
    --catcolumn: Concatenate tables by column (keeping number of rows fixed).
    --catcolhdu: Specify the HDU/extension of the FITS files of --catcolumn.
    - New operators in column arithmetic:
diff --git a/bin/crop/args.h b/bin/crop/args.h
index 1c03781..86a22f6 100644
--- a/bin/crop/args.h
+++ b/bin/crop/args.h
@@ -265,7 +265,8 @@ struct argp_option program_options[] =
       GAL_TYPE_STRING,
       GAL_OPTIONS_RANGE_ANY,
       GAL_OPTIONS_NOT_MANDATORY,
-      GAL_OPTIONS_NOT_SET
+      GAL_OPTIONS_NOT_SET,
+      gal_options_parse_colon_sep_csv
     },
     {
       "polygonout",
diff --git a/bin/crop/main.h b/bin/crop/main.h
index b167a5a..7b01e23 100644
--- a/bin/crop/main.h
+++ b/bin/crop/main.h
@@ -95,7 +95,7 @@ struct cropparams
   char                *namecol;  /* Filename (without suffix) of crop col.*/
   gal_list_str_t     *coordcol;  /* Column in cat containing coordinates. */
   char                *section;  /* Section string.                       */
-  char                *polygon;  /* Input string of polygon vertices.     */
+  gal_data_t          *polygon;  /* Input string of polygon vertices.     */
   uint8_t           polygonout;  /* ==1: Keep the inner polygon region.   */
   uint8_t          polygonsort;  /* Don't sort polygon vertices.          */
 
diff --git a/bin/crop/onecrop.c b/bin/crop/onecrop.c
index 24343a2..86e2e92 100644
--- a/bin/crop/onecrop.c
+++ b/bin/crop/onecrop.c
@@ -195,112 +195,6 @@ onecrop_parse_section(struct cropparams *p, size_t *dsize,
 
 
 
-
-void
-onecrop_parse_polygon(struct cropparams *p)
-{
-  size_t dim=0;
-  char *tailptr;
-  char *pt=p->polygon;
-  double read, *array;
-  gal_list_f64_t *vertices=NULL;
-
-  /* If control reached here, then the cropped region is not defined by its
-     center. So it makes no sense to check if the center is blank. */
-  p->checkcenter=0;
-
-  /* Parse the string. */
-  while(*pt!='\0')
-    {
-      switch(*pt)
-        {
-        case ',':
-          ++dim;
-          if(dim==2)
-            error(EXIT_FAILURE, 0, "Extra `,` in `%s`", p->polygon);
-          ++pt;
-          break;
-        case ':':
-          if(dim==0)
-            error(EXIT_FAILURE, 0, "not enough coordinates for at least "
-                  "one polygon vertex (in %s)", p->polygon);
-          dim=0;
-          ++pt;
-          break;
-        default:
-          break;
-        }
-
-      /* strtod will skip white spaces if they are before a number,
-         but not when they are before a : or ,. So we need to remove
-         all white spaces. White spaces are usually put beside each
-         other, so if one is encountered, go along the string until
-         the white space characters finish.  */
-      if(isspace(*pt))
-        ++pt;
-      else
-        {
-          /* Read the number: */
-          read=strtod(pt, &tailptr);
-
-          /* Check if there actually was a number.
-          printf("\n\n------\n%zu: %f (%s)\n", dim, read, tailptr);
-          */
-
-          /* Make sure if a number was read at all? */
-          if(tailptr==pt) /* No number was read! */
-            error(EXIT_FAILURE, 0, "%s could not be parsed as a floating "
-                  "point number", tailptr);
-
-          /* Check if there are no extra characters in the number, for
-             example we don't have a case like `1.00132.17', or
-             1.01i:2.0. Such errors are not uncommon when typing large
-             numbers, and if ignored, they can lead to unpredictable
-             results, so its best to abort and inform the user. */
-          if( *tailptr!='\0'
-              && !isspace(*tailptr)
-              && strchr(":,", *tailptr)==NULL )
-            error(EXIT_FAILURE, 0, "'%s' is an invalid floating point number "
-                  "sequence in the value to the `--polygon' option, error "
-                  "detected at '%s'", pt, tailptr);
-
-          /* Add the read coordinate to the list of coordinates. */
-          gal_list_f64_add(&vertices, read);
-
-          /* The job here is done, start from tailptr */
-          pt=tailptr;
-        }
-    }
-
-  /* Put the coordinates into an array while reversing their order so they
-     correspond to the user's order, then put it in the right place.*/
-  array=gal_list_f64_to_array(vertices, 1, &p->nvertices);
-  if(p->mode==IMGCROP_MODE_IMG) { p->ipolygon=array; p->wpolygon=NULL;  }
-  else                          { p->ipolygon=NULL;  p->wpolygon=array; }
-
-  /* The number of vertices is actually the number of nodes in the list
-     divided by the dimension of the dataset (note that we were counting
-     the dimension from 0. */
-  p->nvertices/=(dim+1);
-
-  /* For a check:
-  {
-    size_t i;
-    double *polygon=p->mode==IMGCROP_MODE_IMG?p->ipolygon:p->wpolygon;
-    for(i=0;i<p->nvertices;++i)
-      printf("(%f, %f)\n", polygon[i*2], polygon[i*2+1]);
-  }
-  exit(0);
-  */
-
-  /* Clean up: */
-  gal_list_f64_free(vertices);
-}
-
-
-
-
-
 static void
 onecrop_ipolygon_fl(double *ipolygon, size_t nvertices, long *fpixel,
                     long *lpixel)
diff --git a/bin/crop/onecrop.h b/bin/crop/onecrop.h
index f59202b..d2ef458 100644
--- a/bin/crop/onecrop.h
+++ b/bin/crop/onecrop.h
@@ -60,9 +60,6 @@ struct onecropparams
 };
 
 void
-onecrop_parse_polygon(struct cropparams *p);
-
-void
 onecrop_name(struct onecropparams *crp);
 
 void
diff --git a/bin/crop/ui.c b/bin/crop/ui.c
index 5806708..2df86fd 100644
--- a/bin/crop/ui.c
+++ b/bin/crop/ui.c
@@ -373,16 +373,32 @@ ui_read_check_only_options(struct cropparams *p)
      in the proper format. */
   if(p->polygon)
     {
-      onecrop_parse_polygon(p);
+      /* The number of vertices is half the total number of given values
+         (currently only 2D spaces are considered so each vertice has 2
+         coordinates. */
+      p->nvertices=p->polygon->size/2;
+
+      /* Basic sanity checks. */
       if(p->nvertices<3)
         error(EXIT_FAILURE, 0, "a polygon has to have 3 or more vertices, "
-              "you have only given %zu (%s)", p->nvertices, p->polygon);
+              "you have only given %zu", p->nvertices);
       if(p->polygonout && p->numin>1)
         error(EXIT_FAILURE, 0, "currently in WCS mode, `--polygonout' can "
               "only be set to zero when there is one image, you have given "
-              "%zu images. For multiple images the region will be very large. "
-              "It is best if you first crop out the larger region you want "
-              "into one image, then mask the polygon", p->numin);
+              "%zu images. For multiple images the region will be very "
+              "large. It is best if you first crop out the larger region "
+              "you want into one image, then mask the polygon", p->numin);
+
+      /* Put the coordinates into an array while reversing their order so
+         they correspond to the user's order, then put it in the right
+         place.*/
+      darray=p->polygon->array;
+      if(p->mode==IMGCROP_MODE_IMG) {p->ipolygon=darray; p->wpolygon=NULL;  }
+      else                          {p->ipolygon=NULL;   p->wpolygon=darray;}
+
+      /* We know that the cropped region is not defined by its center. So
+         it makes no sense to check if the center is blank. */
+      p->checkcenter=0;
     }
   else
     p->wpolygon=p->ipolygon=NULL;
diff --git a/bin/table/args.h b/bin/table/args.h
index e11cc5f..f66434b 100644
--- a/bin/table/args.h
+++ b/bin/table/args.h
@@ -154,6 +154,48 @@ struct argp_option program_options[] =
       gal_options_parse_name_and_float64s
     },
     {
+      "inpolygon",
+      UI_KEY_INPOLYGON,
+      "STR,STR",
+      0,
+      "Coord. columns that are inside `--polygon'.",
+      GAL_OPTIONS_GROUP_INPUT,
+      &p->inpolygon,
+      GAL_TYPE_STRING,
+      GAL_OPTIONS_RANGE_ANY,
+      GAL_OPTIONS_NOT_MANDATORY,
+      GAL_OPTIONS_NOT_SET,
+      gal_options_parse_csv_strings
+    },
+    {
+      "outpolygon",
+      UI_KEY_OUTPOLYGON,
+      "STR,STR",
+      0,
+      "Coord. columns that are outside `--polygon'.",
+      GAL_OPTIONS_GROUP_INPUT,
+      &p->outpolygon,
+      GAL_TYPE_STRING,
+      GAL_OPTIONS_RANGE_ANY,
+      GAL_OPTIONS_NOT_MANDATORY,
+      GAL_OPTIONS_NOT_SET,
+      gal_options_parse_csv_strings
+    },
+    {
+      "polygon",
+      UI_KEY_POLYGON,
+      "FLT:FLT[,...]",
+      0,
+      "Polygon for `--inpolygon' or `--outpolygon'.",
+      UI_GROUP_OUTROWS,
+      &p->polygon,
+      GAL_TYPE_STRING,
+      GAL_OPTIONS_RANGE_ANY,
+      GAL_OPTIONS_NOT_MANDATORY,
+      GAL_OPTIONS_NOT_SET,
+      gal_options_parse_colon_sep_csv
+    },
+    {
       "equal",
       UI_KEY_EQUAL,
       "STR,FLT[,...]",
diff --git a/bin/table/main.h b/bin/table/main.h
index b1444e2..2f34834 100644
--- a/bin/table/main.h
+++ b/bin/table/main.h
@@ -38,6 +38,8 @@ enum select_types
 {
  /* Different types of row-selection */
  SELECT_TYPE_RANGE,             /* 0 by C standard */
+ SELECT_TYPE_INPOLYGON,
+ SELECT_TYPE_OUTPOLYGON,
  SELECT_TYPE_EQUAL,
  SELECT_TYPE_NOTEQUAL,
 
@@ -89,6 +91,9 @@ struct tableparams
   uint8_t         information;  /* ==1: only print FITS information.    */
   uint8_t     colinfoinstdout;  /* ==1: print column metadata in CL.    */
   gal_data_t           *range;  /* Range to limit output.               */
+  gal_data_t       *inpolygon;  /* Columns to check if inside polygon.  */
+  gal_data_t      *outpolygon;  /* Columns to check if outside polygon. */
+  gal_data_t         *polygon;  /* Values of vertices of the polygon.   */
   gal_data_t           *equal;  /* Values to keep in output.            */
   gal_data_t        *notequal;  /* Values to not include in output.     */
   char                  *sort;  /* Column name or number for sorting.   */
diff --git a/bin/table/table.c b/bin/table/table.c
index ed28574..b2170e1 100644
--- a/bin/table/table.c
+++ b/bin/table/table.c
@@ -37,6 +37,7 @@ along with Gnuastro. If not, see 
<http://www.gnu.org/licenses/>.
 #include <gnuastro/table.h>
 #include <gnuastro/qsort.h>
 #include <gnuastro/pointer.h>
+#include <gnuastro/polygon.h>
 #include <gnuastro/arithmetic.h>
 #include <gnuastro/statistics.h>
 #include <gnuastro/permutation.h>
@@ -136,6 +137,83 @@ table_selection_range(struct tableparams *p, gal_data_t 
*col)
 
 
 
+/* Read column value of any type as a double for the polygon options. */
+static double
+selection_polygon_read_point(gal_data_t *col, size_t i)
+{
+  /* Check and assign the points to the points array. */
+  switch(col->type)
+    {
+    case GAL_TYPE_INT8:    return (( int8_t   *)col->array)[i];
+    case GAL_TYPE_UINT8:   return (( uint8_t  *)col->array)[i];
+    case GAL_TYPE_UINT16:  return (( uint16_t *)col->array)[i];
+    case GAL_TYPE_INT16:   return (( int16_t  *)col->array)[i];
+    case GAL_TYPE_UINT32:  return (( uint32_t *)col->array)[i];
+    case GAL_TYPE_INT32:   return (( int32_t  *)col->array)[i];
+    case GAL_TYPE_UINT64:  return (( uint64_t *)col->array)[i];
+    case GAL_TYPE_INT64:   return (( int64_t  *)col->array)[i];
+    case GAL_TYPE_FLOAT32: return (( float    *)col->array)[i];
+    case GAL_TYPE_FLOAT64: return (( double   *)col->array)[i];
+    default:
+      error(EXIT_FAILURE, 0, "%s: type code %d not recognized",
+            __func__, col->type);
+    }
+
+  /* Control should not reach here. */
+  error(EXIT_FAILURE, 0, "%s: a bug! Please contact us at %s to fix the "
+        "problem. Control should not reach the end of this function",
+        __func__, PACKAGE_BUGREPORT);
+  return NAN;
+}
+
+
+
+
+
+/* Mask the rows that are not in the given polygon. */
+static gal_data_t *
+table_selection_polygon(struct tableparams *p, gal_data_t *col1,
+                        gal_data_t *col2, int in1out0)
+{
+  uint8_t *oarr;
+  double point[2];
+  gal_data_t *out=NULL;
+  size_t i, psize=p->polygon->size/2;
+
+  /* Allocate the output array: This array will have a `0' for the points
+     which are inside the polygon and `1' for those that are outside of it
+     (to be masked/removed from the input). */
+  out=gal_data_alloc(NULL, GAL_TYPE_UINT8, 1, col1->dsize, NULL, 0, -1, 1,
+                     NULL, NULL, NULL);
+  oarr=out->array;
+
+  /* Loop through all the rows in the given columns and check the points.*/
+  for(i=0; i<col1->size; i++)
+    {
+      /* Read the column values as a double. */
+      point[0]=selection_polygon_read_point(col1, i);
+      point[1]=selection_polygon_read_point(col2, i);
+
+      /* For `--inpolygon', if point is inside polygon, put 0, otherwise
+         1. Note that we are building a mask for the rows that must be
+         discarded, so we want `1' for the points we don't want. */
+      oarr[i] = (in1out0
+                 ? !gal_polygon_is_inside(p->polygon->array, point, psize)
+                 :  gal_polygon_is_inside(p->polygon->array, point, psize));
+
+      /* For a check
+      printf("(%f,%f): %s, %u\n", point[0], point[1], oarr[i]);
+      */
+    }
+
+  /* Return the output column. */
+  return out;
+}
+
+
+
+
+
 /* Given a string dataset and a single string, return a `uint8_t' array
    with the same size as the string dataset that has a `1' for all the
    elements that are equal. */
@@ -284,6 +362,14 @@ table_selection(struct tableparams *p)
           addmask=table_selection_range(p, tmp->col);
           break;
 
+        /* `--inpolygon' and `--outpolygon' need two columns. */
+        case SELECT_TYPE_INPOLYGON:
+        case SELECT_TYPE_OUTPOLYGON:
+          addmask=table_selection_polygon(p, tmp->col, tmp->next->col,
+                                          tmp->type==SELECT_TYPE_INPOLYGON);
+          tmp=tmp->next;
+          break;
+
         case SELECT_TYPE_EQUAL:
           addmask=table_selection_equal_or_notequal(p, tmp->col, 0);
           break;
diff --git a/bin/table/ui.c b/bin/table/ui.c
index 1fc3517..38556a7 100644
--- a/bin/table/ui.c
+++ b/bin/table/ui.c
@@ -249,6 +249,28 @@ ui_read_check_only_options(struct tableparams *p)
                 "be smaller than the second (%g)", darr[0], darr[1]);
       }
 
+  /* Basic checks for `--inpolygon' or `--outpolygon'. */
+  if(p->inpolygon || p->outpolygon)
+    {
+      if(p->inpolygon && p->outpolygon)
+        error(EXIT_FAILURE, 0, "`--inpolygon' and `--outpolygon' options "
+              "cannot be called together");
+
+      if(p->inpolygon && p->inpolygon->size!=2)
+        error(EXIT_FAILURE, 0, "two columns (for coordinates) can "
+              "be given to `--inpolygon'");
+
+      if(p->outpolygon && p->outpolygon->size!=2)
+        error(EXIT_FAILURE, 0, "two columns (for coordinates) can "
+              "be given to `--outpolygon'");
+
+      if(p->polygon==NULL)
+        error(EXIT_FAILURE, 0, "no polygon specified for `--inpolygon' or "
+              "`--outpolygon'! Please provide the vertices of the desired "
+              "polygon with the `--polygon' option in this format: "
+              "v1x,v1y:v2x,v2y:v3x,v3y:...");
+    }
+
 
   /* Make sure `--head' and `--tail' aren't given together. */
   if(p->head!=GAL_BLANK_SIZE_T && p->tail!=GAL_BLANK_SIZE_T)
@@ -676,24 +698,52 @@ ui_check_select_sort_before(struct tableparams *p, 
gal_list_str_t *lines,
                             size_t *sortindout, size_t **selectindout_out,
                             size_t **selecttypeout_out)
 {
-  gal_data_t *dtmp, *allcols;
-  size_t sortind=GAL_BLANK_SIZE_T;
+  char **strarr;
   gal_list_sizet_t *tmp, *indexll;
   gal_list_str_t *stmp, *add=NULL;
   int tableformat, selecthasname=0;
+  size_t one=1, sortind=GAL_BLANK_SIZE_T;
   size_t *selectind=NULL, *selecttype=NULL;
   size_t *selectindout=NULL, *selecttypeout=NULL;
   size_t i, j, k, *s, *sf, allncols, numcols, numrows;
+  gal_data_t *dtmp, *allcols, *inpolytmp=NULL, *outpolytmp=NULL;
 
   /* Important note: these have to be in the same order as the `enum
-     select_types' in `main.h'. */
-  gal_data_t *select[SELECT_TYPE_NUMBER]={p->range, p->equal, p->notequal};
+     select_types' in `main.h'. We'll fill the two polygon elements
+     later. */
+  gal_data_t *select[SELECT_TYPE_NUMBER]={p->range, NULL, NULL,
+                                          p->equal, p->notequal};
+
+
+  /* The inpolygon dataset is currently a single dataset with two elements
+     (strings). But we need to have it as two linked datasets with a set
+     name. */
+  if(p->inpolygon)
+    {
+      strarr=p->inpolygon->array;
+      inpolytmp=gal_data_alloc(NULL, GAL_TYPE_UINT8, 1, &one, NULL, 1, -1, 1,
+                               strarr[0], NULL, NULL);
+      inpolytmp->next=gal_data_alloc(NULL, GAL_TYPE_UINT8, 1, &one, NULL,
+                                     1, -1, 1, strarr[1], NULL, NULL);
+      select[SELECT_TYPE_INPOLYGON]=inpolytmp;
+    }
+  if(p->outpolygon)
+    {
+      strarr=p->outpolygon->array;
+      outpolytmp=gal_data_alloc(NULL, GAL_TYPE_UINT8, 1, &one, NULL, 1, -1, 1,
+                               strarr[0], NULL, NULL);
+      outpolytmp->next=gal_data_alloc(NULL, GAL_TYPE_UINT8, 1, &one, NULL,
+                                     1, -1, 1, strarr[1], NULL, NULL);
+      select[SELECT_TYPE_OUTPOLYGON]=outpolytmp;
+    }
 
 
   /* Allocate necessary spaces. */
   if(p->selection)
     {
       *nselect = ( gal_list_data_number(p->range)
+                   + gal_list_data_number(inpolytmp)
+                   + gal_list_data_number(outpolytmp)
                    + gal_list_data_number(p->equal)
                    + gal_list_data_number(p->notequal) );
       selectind=gal_pointer_allocate(GAL_TYPE_SIZE_T, *nselect, 0,
@@ -712,7 +762,7 @@ ui_check_select_sort_before(struct tableparams *p, 
gal_list_str_t *lines,
 
   /* See if the given columns are numbers or names. */
   i=0;
-  if(p->sort)  sortind  = ui_check_select_sort_read_col_ind(p->sort);
+  if(p->sort) sortind=ui_check_select_sort_read_col_ind(p->sort);
   if(p->selection)
     for(k=0;k<SELECT_TYPE_NUMBER;++k)
       for(dtmp=select[k];dtmp!=NULL;dtmp=dtmp->next)
@@ -740,7 +790,8 @@ ui_check_select_sort_before(struct tableparams *p, 
gal_list_str_t *lines,
     for(i=0;i<*nselect;++i)
       if(selectind[i]!=GAL_BLANK_SIZE_T && selectind[i]>=numcols)
         error(EXIT_FAILURE, 0, "%s has %zu columns, less than the column "
-              "number given to  `--range', `--equal', or `--sort' (%zu)",
+              "number given to  `--range', `--inpolygon', `--outpolygon', "
+              "`--equal', or `--sort' (%zu)",
               gal_fits_name_save_as_string(p->filename, p->cp.hdu), numcols,
               selectind[i]);
 
@@ -873,6 +924,8 @@ ui_check_select_sort_before(struct tableparams *p, 
gal_list_str_t *lines,
   if(selectind) free(selectind);
   if(selecttype) free(selecttype);
   gal_data_array_free(allcols, numcols, 0);
+  if(inpolytmp) gal_list_data_free(inpolytmp);
+  if(outpolytmp) gal_list_data_free(outpolytmp);
 }
 
 
@@ -978,13 +1031,15 @@ ui_preparations(struct tableparams *p)
 
 
   /* If any kind of row-selection is requested set `p->selection' to 1. */
-  p->selection = p->range || p->equal || p->notequal;
+  p->selection = ( p->range || p->inpolygon || p->outpolygon || p->equal
+                   || p->notequal );
+
 
   /* If row sorting or selection are requested, see if we should read any
      extra columns. */
   if(p->selection || p->sort)
-    ui_check_select_sort_before(p, lines, &nselect, &origoutncols, &sortindout,
-                                &selectindout, &selecttypeout);
+    ui_check_select_sort_before(p, lines, &nselect, &origoutncols,
+                                &sortindout, &selectindout, &selecttypeout);
 
 
   /* If we have any arithmetic operations, we need to make sure how many
diff --git a/bin/table/ui.h b/bin/table/ui.h
index 72fa2d5..9d27a80 100644
--- a/bin/table/ui.h
+++ b/bin/table/ui.h
@@ -61,8 +61,12 @@ enum option_keys_enum
   UI_KEY_TAIL            = 't',
   UI_KEY_CATCOLUMN       = 'C',
   UI_KEY_CATCOLHDU       = 'u',
+
   /* Only with long version (start with a value 1000, the rest will be set
      automatically). */
+  UI_KEY_POLYGON         = 1000,
+  UI_KEY_INPOLYGON,
+  UI_KEY_OUTPOLYGON,
 };
 
 
diff --git a/doc/gnuastro.texi b/doc/gnuastro.texi
index 329feb9..7129279 100644
--- a/doc/gnuastro.texi
+++ b/doc/gnuastro.texi
@@ -9368,6 +9368,36 @@ This is good when you just want to select using one 
column's values, but don't n
 For one example of using this option, see the example under
 @option{--sigclip-median} in @ref{Invoking aststatistics}.
 
+@item --inpolygon=STR1,STR2
+Only return rows where the given coordinates are inside the polygon specified 
by the @option{--polygon} option.
+The coordinate columns are the given @code{STR1} and @code{STR2} columns, they 
can be a column name or counter (see @ref{Selecting table columns}).
+
+Note that the chosen columns doesn't have to be in the output columns (which 
are specified by the @code{--column} option).
+For example if we want to select rows in the polygon specified in @ref{Dataset 
inspection and cropping}, this option can be used like this (you can remove the 
double quotations and write them all in one line if you remove the white-spaces 
around the colon separating the column vertices):
+
+@example
+asttable table.fits --inpolygon=RA,DEC      \
+         --polygon="53.187414,-27.779152    \
+                    : 53.159507,-27.759633  \
+                    : 53.134517,-27.787144  \
+                    : 53.161906,-27.807208" \
+@end example
+
+@cartouche
+@noindent
+@strong{Flat/Euclidean space: } The @option{--inpolygon} option assumes a 
flat/Euclidean space so it is only correct for RA and Dec when the polygon size 
is very small like the example above.
+If your polygon is a degree or larger, it may not return correct results.
+We are working on other options for this.
+@end cartouche
+
+@item --outpolygon=STR1,STR2
+Only return rows where the given coordinates are outside the polygon specified 
by the @option{--polygon} option.
+This option is very similar to the @option{--inpolygon} option, so see the 
description there for more.
+
+@item --polygon=FLT:FLT,...
+The polygon to use for the @code{--inpolygon} and @option{--outpolygon} 
options.
+The values to this option is parsed in the same way that the Crop program, see 
its description there for more: @ref{Crop options}.
+
 @item -e STR,INT/FLT,...
 @itemx --equal=STR,INT/FLT,...
 Only output rows that are equal to the given number(s) in the given column.
diff --git a/lib/gnuastro-internal/options.h b/lib/gnuastro-internal/options.h
index dd0e678..ec02c61 100644
--- a/lib/gnuastro-internal/options.h
+++ b/lib/gnuastro-internal/options.h
@@ -315,6 +315,10 @@ void *
 gal_options_parse_name_and_float64s(struct argp_option *option, char *arg,
                                     char *filename, size_t lineno, void *junk);
 
+void *
+gal_options_parse_colon_sep_csv(struct argp_option *option, char *arg,
+                                char *filename, size_t lineno, void *junk);
+
 
 /**********************************************************************/
 /************            Command-line options           ***************/
diff --git a/lib/options.c b/lib/options.c
index f93fc60..7e5599c 100644
--- a/lib/options.c
+++ b/lib/options.c
@@ -1152,7 +1152,7 @@ gal_options_parse_name_and_values(struct argp_option 
*option, char *arg,
   /* We want to print the stored values. */
   if(lineno==-1)
     {
-      /* Set the value pointer to `dataset'. */
+      /* Set the value pointer to `existing'. */
       existing=*(gal_data_t **)(option->value);
       if(str0_f641) darray = existing->array;
       else          strarr = existing->array;
@@ -1173,6 +1173,8 @@ gal_options_parse_name_and_values(struct argp_option 
*option, char *arg,
           if(str0_f641) nc += sprintf(sstr+nc, "%g,", darray[i]);
           else          nc += sprintf(sstr+nc, "%s,", strarr[i]);
         }
+
+      /* Finish the string. */
       sstr[nc-1]='\0';
 
       /* Copy the string into a dynamically allocated space, because it
@@ -1259,6 +1261,163 @@ gal_options_parse_name_and_float64s(struct argp_option 
*option, char *arg,
 
 
 
+/* Parse strings like this: `num1,num2:num3,n4:num5,num6' and return it as
+   a data container array: all elements are simply placed after each other
+   in the array. */
+static gal_data_t *
+options_parse_colon_sep_csv(char *instring, char *filename, size_t lineno)
+{
+  char *tailptr;
+  gal_data_t *out;
+  char *pt=instring;
+  size_t dim=0, size;
+  double read, *array;
+  gal_list_f64_t *vertices=NULL;
+
+  /* Parse the string. */
+  while(*pt!='\0')
+    {
+      switch(*pt)
+        {
+        case ',':
+          ++dim;
+          if(dim==2)
+            error_at_line(EXIT_FAILURE, 0, filename, lineno,
+                          "Extra `,` in `%s`", instring);
+          ++pt;
+          break;
+        case ':':
+          if(dim==0)
+            error_at_line(EXIT_FAILURE, 0, filename, lineno,
+                          "not enough coordinates for at least "
+                          "one polygon vertex (in %s)", instring);
+          dim=0;
+          ++pt;
+          break;
+        default:
+          break;
+        }
+
+      /* strtod will skip white spaces if they are before a number,
+         but not when they are before a : or ,. So we need to remove
+         all white spaces. White spaces are usually put beside each
+         other, so if one is encountered, go along the string until
+         the white space characters finish.  */
+      if(isspace(*pt))
+        ++pt;
+      else
+        {
+          /* Read the number: */
+          read=strtod(pt, &tailptr);
+
+          /* Check if there actually was a number.
+          printf("\n\n------\n%zu: %f (%s)\n", dim, read, tailptr);
+          */
+
+          /* Make sure if a number was read at all? */
+          if(tailptr==pt) /* No number was read! */
+            error_at_line(EXIT_FAILURE, 0, filename, lineno,
+                          "%s could not be parsed as a floating point "
+                          "number", tailptr);
+
+          /* Check if there are no extra characters in the number, for
+             example we don't have a case like `1.00132.17', or
+             1.01i:2.0. Such errors are not uncommon when typing large
+             numbers, and if ignored, they can lead to unpredictable
+             results, so its best to abort and inform the user. */
+          if( *tailptr!='\0'
+              && !isspace(*tailptr)
+              && strchr(":,", *tailptr)==NULL )
+            error_at_line(EXIT_FAILURE, 0, filename, lineno,
+                          "'%s' is an invalid floating point number "
+                          "sequence in the value to the `--polygon' "
+                          "option, error detected at '%s'", pt, tailptr);
+
+          /* Add the read coordinate to the list of coordinates. */
+          gal_list_f64_add(&vertices, read);
+
+          /* The job here is done, start from tailptr */
+          pt=tailptr;
+        }
+    }
+
+  /* Convert the list to an array, put it in a data structure, clean up and
+     return. */
+  array=gal_list_f64_to_array(vertices, 1, &size);
+  out=gal_data_alloc(array, GAL_TYPE_FLOAT64, 1, &size, NULL, 0, -1, 1,
+                     NULL, NULL, NULL);
+  gal_list_f64_free(vertices);
+  return out;
+}
+
+
+
+
+
+/* Parse strings that are given to a function in this format
+   `num1,num2:num3,n4:num5,num6' */
+void *
+gal_options_parse_colon_sep_csv(struct argp_option *option, char *arg,
+                                char *filename, size_t lineno, void *junk)
+{
+  double *darray;
+  size_t i, nc, size;
+  gal_data_t *tmp, *dataset, *existing;
+  char *str, sstr[GAL_OPTIONS_STATIC_MEM_FOR_VALUES];
+
+  /* We want to print the stored values. */
+  if(lineno==-1)
+    {
+      /* Set the value pointer to `existing'. */
+      existing=*(gal_data_t **)(option->value);
+      darray=existing->array;
+
+      /* Start printing the values. */
+      nc=0;
+      size=existing->size;
+      for(i=0;i<size;i+=2)
+        {
+          /* Make sure we aren't passing the allocated space. */
+          if( nc > GAL_OPTIONS_STATIC_MEM_FOR_VALUES-100 )
+            error(EXIT_FAILURE, 0, "%s: a bug! please contact us at %s so we "
+                  "can address the problem. The number of necessary "
+                  "characters in the statically allocated string has become "
+                  "too close to %d", __func__, PACKAGE_BUGREPORT,
+                  GAL_OPTIONS_STATIC_MEM_FOR_VALUES);
+
+          /* Print the two values in the expected format. */
+          nc += sprintf(sstr+nc, "%.6f,%.6f%s", darray[i], darray[i+1],
+                        (i==(size-2) ? "" : ":") );
+        }
+
+      /* Finish the string. */
+      sstr[nc-1]='\0';
+
+      /* Copy the string into a dynamically allocated space, because it
+         will be freed later.*/
+      gal_checkset_allocate_copy(sstr, &str);
+      return str;
+    }
+  else
+    {
+      /* Parse the desired format and put it in this option's pointer. */
+      dataset=options_parse_colon_sep_csv(arg, filename, lineno);
+
+      /* Add the given dataset to the end of an existing dataset. */
+      existing = *(gal_data_t **)(option->value);
+      if(existing)
+        {
+          for(tmp=existing;tmp!=NULL;tmp=tmp->next)
+            if(tmp->next==NULL) { tmp->next=dataset; break; }
+        }
+      else
+        *(gal_data_t **)(option->value) = dataset;
+
+      /* In this scenario, there is no NULL value. */
+      return NULL;
+    }
+}
+
 
 
 



reply via email to

[Prev in Thread] Current Thread [Next in Thread]