gnuastro-commits
[Top][All Lists]
Advanced

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

[gnuastro-commits] master 6e11585 111/113: Imported recent work in maste


From: Mohammad Akhlaghi
Subject: [gnuastro-commits] master 6e11585 111/113: Imported recent work in master, minor conflicts fixed
Date: Fri, 16 Apr 2021 10:34:03 -0400 (EDT)

branch: master
commit 6e115856a6f8591a3cc181ad75fde0290bbf7cfa
Merge: 536b056 63d062a
Author: Mohammad Akhlaghi <mohammad@akhlaghi.org>
Commit: Mohammad Akhlaghi <mohammad@akhlaghi.org>

    Imported recent work in master, minor conflicts fixed
    
    There were only some minor conflicts that came up and were easily fixed.
---
 NEWS                                           |  68 +++++
 THANKS                                         |   2 +
 bin/arithmetic/arithmetic.c                    |  84 ++++++-
 bin/arithmetic/arithmetic.h                    |   1 +
 bin/buildprog/Makefile.am                      |   2 +
 bin/buildprog/args.h                           |  28 +++
 bin/buildprog/buildprog.c                      |  17 +-
 bin/buildprog/main.h                           |   2 +
 bin/buildprog/ui.c                             |  13 +
 bin/buildprog/ui.h                             |   4 +-
 bin/convertt/color.c                           | 330 ++++++++++++++++++++++++-
 bin/convertt/color.h                           |   3 +
 bin/convertt/main.h                            |   1 +
 bin/convertt/ui.c                              |  11 +-
 bin/cosmiccal/cosmiccal.c                      | 199 +++++++--------
 bin/crop/crop.c                                |   6 +-
 bin/statistics/Makefile.am                     |   4 +-
 bin/statistics/args.h                          |  15 ++
 bin/statistics/contour.c                       | 209 ++++++++++++++++
 bin/{convertt/color.h => statistics/contour.h} |  19 +-
 bin/statistics/main.h                          |   1 +
 bin/statistics/statistics.c                    |   7 +
 bin/statistics/ui.c                            |   2 +-
 bin/statistics/ui.h                            |   3 +-
 bin/table/args.h                               |   6 +-
 bin/table/arithmetic.c                         |  76 +++++-
 bin/table/arithmetic.h                         |   1 +
 bin/table/ui.c                                 |   4 +-
 bootstrap                                      |   2 +-
 bootstrap.conf                                 |   1 +
 doc/Makefile.am                                |   2 +-
 doc/announce-acknowledge.txt                   |   3 +
 doc/gnuastro.texi                              | 140 +++++++++--
 doc/release-checklist.txt                      |   2 +-
 lib/binary.c                                   |  91 +++++++
 lib/checkset.c                                 |  64 ++++-
 lib/fits.c                                     |   4 +
 lib/gnuastro/binary.h                          |   3 +
 lib/options.c                                  |   2 +-
 lib/wcs.c                                      |  11 +-
 40 files changed, 1274 insertions(+), 169 deletions(-)

diff --git a/NEWS b/NEWS
index 14c5897..53cce0e 100644
--- a/NEWS
+++ b/NEWS
@@ -8,20 +8,85 @@ See the end of the file for license conditions.
 ** New features
 
   Arithmetic:
+   - The new `add-dimension' operator will stack the popped operands in a
+     higher-dimensional dataset. For example to build a 3D cube from
+     individual 2D images/slices.
    --onedonstdout: when the output is one-dimensional, print the values on
      the standard output, not into a file.
 
+  BuildProgram:
+   - Will use common environment variables like LDFLAGS, CPPFLAGS and CC to
+     help in customizing the build of your program.
+   --cc: custom C compiler to use. Until now, `gcc' was hard-coded into the
+     source and there was no way to choose a custom C compiler.
+   --noenv: With this option, no environment variables will be read.
+
+  ConvertType:
+   - New `viridis' colormap (value for the `--colormap' option). This is
+     the default colormap of Python's Matplotlib, and is available in many
+     other plotting tools like LaTeX's PGFPlots.
+
+  Convolve:
+   - Spatial domain convolution now possible on 3D data cubes (with a 3D
+     kernel).
+
   CosmicCalculator:
    --lineatz: return the observed wavelength of a line if it was emitted at
      the redshift given to CosmicCalculator. You can either use known line
      names, or directly give a number as any emitted line's wavelength.
 
+  MakeCatalog:
+   - Catalogs from 3D inputs now available, with the following new options,
+     see book for more.
+     --spectrum: label's spectrum (across the third dimension).
+     --z: Flux-weighted position in 3rd dimension.
+     --geoz: Geometric center in third FITS axis.
+     --minz: Minimum third FITS axis position.
+     --maxz: Maximum third FITS axis position.
+     --clumpsz: Flux weighted center of all clumps in object in 3rd dim.
+     --clumpsgeoz: Geometric center of all clumps in object in 3rd dim.
+     --w3: Flux weighted center in third WCS axis.
+     --geow3: Geometric center in third WCS axis.
+     --clumpsw3: Flux wheighted center of all clumps in 3rd dim.
+     --clumpsgeow3: Geometric center of all clumps in 3rd dim.
+     --areaxy: Projected area in first two dimentions.
+     --geoareaxy: Projected geoarea in first two dimensions.
+
+  MakeProfiles:
+   - Can produce mock ellipsoids in a datacube (using X-Z-X Euler angles
+     for 3D orientation), the following options have been added, see the
+     book for more details.
+     --p2col: Second Euler angle (X-Z-X order).
+     --p3col: Third Euler angle (X-Z-X order).
+     --q2col: Axis ratio (major/dim3 in 3D).
+   - The `--kernel' option can build 3D kernels, see the description of
+     this option in the book for examples and details on how to run it.
+
+  Match:
+   - Matching of catalogs now possible using 3 coordinates (on catalogs
+     generated from 3D data cubes), see book for more.
+
+  Statistics:
+   --contour: compute a contour plot which can be directly fed into the
+     PGFPlots package of LaTeX for plotting the contours. Support for more
+     formats will be added based on the need/request.
+
   Table:
    --equal: Output only rows that have a value equal to the given value in
      the given column. For example `--equal=ID,2,4,5' will select only rows
      that have a value of 2, 4 and 5 in the `ID' column.
    --notequal: Output only rows that have a different value compared to the
      values given to this option in the given column.
+   - Column Arithmetic operators:
+     - `angular-distance': a new operator to easily find the angular
+       distance (along a great circle) between points in various table
+       columns, or the distances of all the points in the table rows with a
+       fixed point. See the book for examples and better explanation.
+
+  Library:
+   - gal_binary_connected_indexs: store indexs of connected components.
+   - gal_box_bound_ellipsoid_extent: Extent of 3D ellipsoid.
+   - gal_box_bound_ellipsoid: Bounding box for a 3D ellipsoid.
 
 ** Removed features
 
@@ -31,6 +96,9 @@ See the end of the file for license conditions.
   bug #56736: CosmicCalculator crash when a single value given to --obsline.
   bug #56747: ConvertType's SLS colormap has black pixels which should be 
orange.
   bug #56754: Wrong sigma clipping output when many values are equal.
+  bug #56999: Compilation error on macOS 10.9 not recognizing AT_FDCWD.
+  bug #57057: BuildProgram not using environment LDFLAGS or CPPFLAGS.
+  bug #57101: Crop segmentation fault when no overlap exists in image-mode.
 
 
 
diff --git a/THANKS b/THANKS
index 0420e36..0de4197 100644
--- a/THANKS
+++ b/THANKS
@@ -34,6 +34,7 @@ support in Gnuastro. The list is ordered alphabetically (by 
family name).
     Benjamin Clement                     benjamin.clement@univ-lyon1.fr
     Nima Dehdilani                       nimadehdilani@gmail.com
     Antonio Diaz Diaz                    antonio@gnu.org
+    Alexey Dokuchaev                     danfe@freebsd.org
     Pierre-Alain Duc                     pierre-alain.duc@astro.unistra.fr
     Elham Eftekhari                      elhamea@iac.es
     Gaspar Galaz                         ggalaz@astro.puc.cl
@@ -53,6 +54,7 @@ support in Gnuastro. The list is ordered alphabetically (by 
family name).
     Geoffry Krouchi                      geoffrey.krouchi@etu.univ-lyon1.fr
     Floriane Leclercq                    floriane.leclercq@univ-lyon1.fr
     Alan Lefor                           alefor@astr.tohoku.ac.jp
+    Sebastián Luna Valero                sluna@iaa.es
     Guillaume Mahler                     guillaume.mahler@univ-lyon1.fr
     Juan Molina Tobar                    juan.a.molina.t@gmail.com
     Francesco Montanari                  francesco.montanari@openmailbox.org
diff --git a/bin/arithmetic/arithmetic.c b/bin/arithmetic/arithmetic.c
index 6935036..82bbba3 100644
--- a/bin/arithmetic/arithmetic.c
+++ b/bin/arithmetic/arithmetic.c
@@ -928,7 +928,7 @@ arithmetic_unique(struct arithmeticparams *p, char *token, 
int operator)
   /* Remove all blank elements. */
   gal_blank_remove(input);
 
-  /* Clean up and add the collapsed dataset to the top of the operands. */
+  /* Add the collapsed dataset to the top of the operands. */
   operands_add(p, NULL, input);
 }
 
@@ -936,6 +936,82 @@ arithmetic_unique(struct arithmeticparams *p, char *token, 
int operator)
 
 
 
+void
+arithmetic_add_dimension(struct arithmeticparams *p, char *token, int operator)
+{
+  gal_data_t *out=NULL;
+  gal_data_t *tmp = operands_pop(p, token);
+  size_t i, num, dsize[3], ndim=3, nbytes=0;
+
+  /* Make sure the first operand is a number. */
+  if(tmp->size!=1)
+    error(EXIT_FAILURE, 0, "first popped operand to `%s' must be a "
+          "number (specifying how many datasets to use)", token);
+
+  /* Put the value into `num'. */
+  tmp=gal_data_copy_to_new_type_free(tmp, GAL_TYPE_SIZE_T);
+  num=*(size_t *)(tmp->array);
+  gal_data_free(tmp);
+
+  /* Pop all the datasets and put them in a list. */
+  for(i=0;i<num;++i)
+    {
+      /* Pop the operand. */
+      tmp=operands_pop(p, token);
+
+      /* Things that differ from the first dataset and the rest. */
+      if(out) /* Not the first. */
+        {
+          /* Basic sanity checks. */
+          if(tmp->type!=out->type)
+            error(EXIT_FAILURE, 0, "the operands to `%s' have to have the "
+                  "same data type (the inputs contain atleast two types: "
+                  "`%s' and `%s')", token, gal_type_name(tmp->type, 1),
+                  gal_type_name(out->type, 1));
+          if( tmp->ndim!=out->ndim-1
+              || tmp->dsize[0]!=out->dsize[1]
+              || tmp->dsize[1]!=out->dsize[2] )
+            error(EXIT_FAILURE, 0, "the operands to `%s' have to have the "
+                  "same size", token);
+        }
+      else  /* First popped operand. */
+        {
+          /* First popped operand, do necessary basic checks here. */
+          if(tmp->ndim!=2)
+            error(EXIT_FAILURE, 0, "currently only 2-dimensional datasets "
+                  "are acceptable for `%s', please get in touch with us at "
+                  "%s so we add functionality for different dimensions",
+                  token, PACKAGE_BUGREPORT);
+
+          /* Allocate the output dataset. */
+          dsize[0]=num;
+          dsize[1]=tmp->dsize[0];
+          dsize[2]=tmp->dsize[1];
+          out = gal_data_alloc(NULL, tmp->type, ndim, dsize, NULL, 0,
+                               p->cp.minmapsize, p->cp.quietmmap, NULL,
+                               NULL, NULL);
+
+          /* Get the number of bytes in each dataset. */
+          nbytes=gal_type_sizeof(tmp->type)*tmp->size;
+        }
+
+      /* Copy the dataset into the higher-dimensional output. */
+      memcpy(gal_pointer_increment(out->array, (num-1-i)*tmp->size,
+                                   tmp->type),
+             tmp->array, nbytes);
+
+      /* Clean up. */
+      gal_data_free(tmp);
+    }
+
+  /* Put the higher-dimensional output on the operands stack. */
+  operands_add(p, NULL, out);
+}
+
+
+
+
+
 
 
 
@@ -996,6 +1072,8 @@ arithmetic_set_operator(char *string, size_t *num_operands)
         { op=ARITHMETIC_OP_COLLAPSE_NUMBER;       *num_operands=0; }
       else if (!strcmp(string, "unique"))
         { op=ARITHMETIC_OP_UNIQUE;                *num_operands=0; }
+      else if (!strcmp(string, "add-dimension"))
+        { op=ARITHMETIC_OP_ADD_DIMENSION;         *num_operands=0; }
       else
         error(EXIT_FAILURE, 0, "the argument \"%s\" could not be "
               "interpretted as a file name, named dataset, number, "
@@ -1119,6 +1197,10 @@ arithmetic_operator_run(struct arithmeticparams *p, int 
operator,
           arithmetic_unique(p, operator_string, operator);
           break;
 
+        case ARITHMETIC_OP_ADD_DIMENSION:
+          arithmetic_add_dimension(p, operator_string, operator);
+          break;
+
         default:
           error(EXIT_FAILURE, 0, "%s: a bug! please contact us at "
                 "%s to fix the problem. The code %d is not "
diff --git a/bin/arithmetic/arithmetic.h b/bin/arithmetic/arithmetic.h
index d267a58..4e90d99 100644
--- a/bin/arithmetic/arithmetic.h
+++ b/bin/arithmetic/arithmetic.h
@@ -47,6 +47,7 @@ enum arithmetic_prog_operators
   ARITHMETIC_OP_COLLAPSE_MEAN,
   ARITHMETIC_OP_COLLAPSE_NUMBER,
   ARITHMETIC_OP_UNIQUE,
+  ARITHMETIC_OP_ADD_DIMENSION,
 };
 
 
diff --git a/bin/buildprog/Makefile.am b/bin/buildprog/Makefile.am
index e8ea17d..fd3f917 100644
--- a/bin/buildprog/Makefile.am
+++ b/bin/buildprog/Makefile.am
@@ -87,6 +87,8 @@ astbuildprog.conf: 
$(top_srcdir)/bin/buildprog/astbuildprog.conf.in
            echo " linkdir $$v" >> $@;                 \
          fi;                                          \
        done
+       echo "# Build-time LDFLAGS: $(LDFLAGS)" >> $@
+       echo "# Build-time CPPFLAGS: $(CPPFLAGS)" >> $@
 
 
 
diff --git a/bin/buildprog/args.h b/bin/buildprog/args.h
index 8607f4f..87872e9 100644
--- a/bin/buildprog/args.h
+++ b/bin/buildprog/args.h
@@ -32,6 +32,20 @@ along with Gnuastro. If not, see 
<http://www.gnu.org/licenses/>.
 struct argp_option program_options[] =
   {
     {
+      "cc",
+      UI_KEY_CC,
+      "STR",
+      0,
+      "Name of C compiler's executable.",
+      GAL_OPTIONS_GROUP_INPUT,
+      &p->cc,
+      GAL_TYPE_STRING,
+      GAL_OPTIONS_RANGE_ANY,
+      GAL_OPTIONS_NOT_MANDATORY,
+      GAL_OPTIONS_NOT_SET
+    },
+
+    {
       "includedir",
       UI_KEY_INCLUDE,
       "STR",
@@ -101,6 +115,20 @@ struct argp_option program_options[] =
       GAL_OPTIONS_NOT_SET
     },
 
+    {
+      "noenv",
+      UI_KEY_NOENV,
+      0,
+      0,
+      "No env. (e.g., LDFLAGS or CPPFLAGS) in build.",
+      GAL_OPTIONS_GROUP_INPUT,
+      &p->noenv,
+      GAL_OPTIONS_NO_ARG_TYPE,
+      GAL_OPTIONS_RANGE_ANY,
+      GAL_OPTIONS_NOT_MANDATORY,
+      GAL_OPTIONS_NOT_SET
+    },
+
 
 
 
diff --git a/bin/buildprog/buildprog.c b/bin/buildprog/buildprog.c
index ef706a8..8a67871 100644
--- a/bin/buildprog/buildprog.c
+++ b/bin/buildprog/buildprog.c
@@ -75,6 +75,7 @@ buildprog(struct buildprogparams *p)
      rest are arguments to be run later. */
   int retval;
   char *fullla;
+  char *ldflags=NULL, *cppflags=NULL;
   char *command, *optimize=NULL, *warning=NULL;
   char *include   = buildprog_as_one_string("-I", p->include);
   char *linkdir   = buildprog_as_one_string("-L", p->linkdir);
@@ -88,6 +89,13 @@ buildprog(struct buildprogparams *p)
       printf("---------------------------------\n");
     }
 
+  /* If environment should be read, read it. */
+  if(p->noenv==0)
+    {
+      ldflags=getenv("LDFLAGS");
+      cppflags=getenv("CPPFLAGS");
+    }
+
   /* Compiler options with values: */
   if(p->warning)
     if( asprintf(&warning,  "-W%s", p->warning)<0 )
@@ -103,17 +111,20 @@ buildprog(struct buildprogparams *p)
       error(EXIT_FAILURE, 0, "%s: asprintf allocation", __func__);
 
   /* Write the full Libtool command into a string (to run afterwards). */
-  if( asprintf(&command, "%s -c \"%s %s %s%s --mode=link gcc %s %s "
-               "%s %s %s %s %s -I%s %s -o %s\"",
+  if( asprintf(&command, "%s -c \"%s %s %s%s --mode=link %s %s %s "
+               "%s %s %s %s %s %s %s -I%s %s -o %s\"",
                GAL_CONFIG_GNULIBTOOL_SHELL,
                GAL_CONFIG_GNULIBTOOL_EXEC,
                p->cp.quiet ? "--quiet" : "",
-               p->tag      ? "--tag="   : "",
+               p->tag      ? "--tag="  : "",
                p->tag      ? p->tag    : "",
+               p->cc,
                warning     ? warning   : "",
                p->debug    ? "-g"      : "",
                optimize    ? optimize  : "",
+               cppflags    ? cppflags  : "",
                include     ? include   : "",
+               ldflags     ? ldflags   : "",
                linkdir     ? linkdir   : "",
                p->sourceargs->v,
                linklib     ?linklib    : "",
diff --git a/bin/buildprog/main.h b/bin/buildprog/main.h
index eb3ee1e..0a43dc0 100644
--- a/bin/buildprog/main.h
+++ b/bin/buildprog/main.h
@@ -49,6 +49,8 @@ struct buildprogparams
   gal_list_str_t     *linkdir;    /* Libraries to link against.         */
   gal_list_str_t     *linklib;    /* Libraries to link against.         */
   char                    *la;    /* Libtool `.la' instead of default.  */
+  char                    *cc;    /* C compiler to use.                 */
+  uint8_t               noenv;
 
   char                   *tag;    /* Libtool tag (programming language).*/
   char              *optimize;    /* Optimization level.                */
diff --git a/bin/buildprog/ui.c b/bin/buildprog/ui.c
index 6db0d66..83e2ef4 100644
--- a/bin/buildprog/ui.c
+++ b/bin/buildprog/ui.c
@@ -284,6 +284,19 @@ ui_preparations(struct buildprogparams *p)
   if(p->cp.output==NULL)
     p->cp.output=gal_checkset_automatic_output(&p->cp, p->sourceargs->v,
                                                EXEEXT);
+
+  /* Set the C compiler. Later we can add a check to make sure that `cc' is
+     actually in the PATH. */
+  if(p->cc==NULL)
+    {                                        /* No C compiler chosen. */
+      if(p->noenv==0)
+        {
+          p->cc=getenv("CC");                /* First check for `CC'. */
+          if(p->cc==NULL)
+            p->cc=getenv("GCC");             /* Then check for `GCC'. */
+        }
+      if(p->cc==NULL) p->cc="gcc";           /* Default: `gcc'.       */
+    }
 }
 
 
diff --git a/bin/buildprog/ui.h b/bin/buildprog/ui.h
index 0415117..53d9f64 100644
--- a/bin/buildprog/ui.h
+++ b/bin/buildprog/ui.h
@@ -32,12 +32,13 @@ along with Gnuastro. If not, see 
<http://www.gnu.org/licenses/>.
 
 /* Available letters for short options:
 
-   c e f i j k n p r s u v w x y z
+   f i j k n p r s u v w x y z
    A B C E G H J Q R X Y
 */
 enum option_keys_enum
 {
   /* With short-option version. */
+  UI_KEY_CC             = 'c',
   UI_KEY_INCLUDE        = 'I',
   UI_KEY_LINKDIR        = 'L',
   UI_KEY_LINKLIB        = 'l',
@@ -48,6 +49,7 @@ enum option_keys_enum
   UI_KEY_TAG            = 't',
   UI_KEY_DETELECOMPILED = 'd',
   UI_KEY_LA             = 'a',
+  UI_KEY_NOENV          = 'e',
 
   /* Only with long version (start with a value 1000, the rest will be set
      automatically). */
diff --git a/bin/convertt/color.c b/bin/convertt/color.c
index fc92a62..bd34cb7 100644
--- a/bin/convertt/color.c
+++ b/bin/convertt/color.c
@@ -435,14 +435,338 @@ color_from_mono_sls(struct converttparams *p)
 
 
 
+/* Values here copied from PGFPlots 1.16 source. They are a little more
+   precise than the matplotlib values:
+     https://github.com/BIDS/colormap/blob/master/colormaps.py
+   It was created by Stéfan van der Walt and Nathaniel Smith for
+   Matplotlib, see here for a more complete explanation:
+     https://bids.github.io/colormap */
+void
+color_from_mono_viridis(struct converttparams *p)
+{
+  gal_data_t *R, *G, *B, *channel;
+  float *r, *g, *b, *f, *fp, min, max;
+
+  /* Set the range, then convert the dataset to floating point. */
+  color_min_max(p, &min, 0);
+  color_min_max(p, &max, 1);
+  channel=gal_data_copy_to_new_type_free(p->chll, GAL_TYPE_FLOAT32);
+
+  /* Allocate the three datasets to keep the RGB colors. */
+  R=gal_data_alloc(NULL, GAL_TYPE_FLOAT32, channel->ndim,
+                   channel->dsize, channel->wcs, 0, p->cp.minmapsize,
+                   p->cp.quietmmap, "RED", NULL, "Red color channel.");
+  G=gal_data_alloc(NULL, GAL_TYPE_FLOAT32, channel->ndim,
+                   channel->dsize, channel->wcs, 0, p->cp.minmapsize,
+                   p->cp.quietmmap, "GREEN", NULL, "Green color channel.");
+  B=gal_data_alloc(NULL, GAL_TYPE_FLOAT32, channel->ndim,
+                   channel->dsize, channel->wcs, 0, p->cp.minmapsize,
+                   p->cp.quietmmap, "BLUE", NULL, "Blue color channel.");
+
+  /* Start the conversion. Note that the "Choroma" (`C') is fixed by our
+     definition. */
+  r=R->array;
+  g=G->array;
+  b=B->array;
+  fp=(f=channel->array)+channel->size;
+  do
+    {
+      if(isnan(*f))
+        *r=*g=*b=0.0;
+      else
+        switch( (int)((*f-min)/(max-min)*255) )
+          {
+          case 0:   *r=0.26700401; *g=0.00487433; *b=0.32941519; break;
+          case 1:   *r=0.26851048; *g=0.00960483; *b=0.33542652; break;
+          case 2:   *r=0.26994384; *g=0.01462494; *b=0.34137895; break;
+          case 3:   *r=0.27130489; *g=0.01994186; *b=0.34726862; break;
+          case 4:   *r=0.27259384; *g=0.02556309; *b=0.35309303; break;
+          case 5:   *r=0.27380934; *g=0.03149748; *b=0.35885256; break;
+          case 6:   *r=0.27495242; *g=0.03775181; *b=0.36454323; break;
+          case 7:   *r=0.27602238; *g=0.04416723; *b=0.37016418; break;
+          case 8:   *r=0.2770184 ; *g=0.05034437; *b=0.37571452; break;
+          case 9:   *r=0.27794143; *g=0.05632444; *b=0.38119074; break;
+          case 10:  *r=0.27879067; *g=0.06214536; *b=0.38659204; break;
+          case 11:  *r=0.2795655 ; *g=0.06783587; *b=0.39191723; break;
+          case 12:  *r=0.28026658; *g=0.07341724; *b=0.39716349; break;
+          case 13:  *r=0.28089358; *g=0.07890703; *b=0.40232944; break;
+          case 14:  *r=0.28144581; *g=0.0843197 ; *b=0.40741404; break;
+          case 15:  *r=0.28192358; *g=0.08966622; *b=0.41241521; break;
+          case 16:  *r=0.28232739; *g=0.09495545; *b=0.41733086; break;
+          case 17:  *r=0.28265633; *g=0.10019576; *b=0.42216032; break;
+          case 18:  *r=0.28291049; *g=0.10539345; *b=0.42690202; break;
+          case 19:  *r=0.28309095; *g=0.11055307; *b=0.43155375; break;
+          case 20:  *r=0.28319704; *g=0.11567966; *b=0.43611482; break;
+          case 21:  *r=0.28322882; *g=0.12077701; *b=0.44058404; break;
+          case 22:  *r=0.28318684; *g=0.12584799; *b=0.44496   ; break;
+          case 23:  *r=0.283072  ; *g=0.13089477; *b=0.44924127; break;
+          case 24:  *r=0.28288389; *g=0.13592005; *b=0.45342734; break;
+          case 25:  *r=0.28262297; *g=0.14092556; *b=0.45751726; break;
+          case 26:  *r=0.28229037; *g=0.14591233; *b=0.46150995; break;
+          case 27:  *r=0.28188676; *g=0.15088147; *b=0.46540474; break;
+          case 28:  *r=0.28141228; *g=0.15583425; *b=0.46920128; break;
+          case 29:  *r=0.28086773; *g=0.16077132; *b=0.47289909; break;
+          case 30:  *r=0.28025468; *g=0.16569272; *b=0.47649762; break;
+          case 31:  *r=0.27957399; *g=0.17059884; *b=0.47999675; break;
+          case 32:  *r=0.27882618; *g=0.1754902 ; *b=0.48339654; break;
+          case 33:  *r=0.27801236; *g=0.18036684; *b=0.48669702; break;
+          case 34:  *r=0.27713437; *g=0.18522836; *b=0.48989831; break;
+          case 35:  *r=0.27619376; *g=0.19007447; *b=0.49300074; break;
+          case 36:  *r=0.27519116; *g=0.1949054 ; *b=0.49600488; break;
+          case 37:  *r=0.27412802; *g=0.19972086; *b=0.49891131; break;
+          case 38:  *r=0.27300596; *g=0.20452049; *b=0.50172076; break;
+          case 39:  *r=0.27182812; *g=0.20930306; *b=0.50443413; break;
+          case 40:  *r=0.27059473; *g=0.21406899; *b=0.50705243; break;
+          case 41:  *r=0.26930756; *g=0.21881782; *b=0.50957678; break;
+          case 42:  *r=0.26796846; *g=0.22354911; *b=0.5120084 ; break;
+          case 43:  *r=0.26657984; *g=0.2282621 ; *b=0.5143487 ; break;
+          case 44:  *r=0.2651445 ; *g=0.23295593; *b=0.5165993 ; break;
+          case 45:  *r=0.2636632 ; *g=0.23763078; *b=0.51876163; break;
+          case 46:  *r=0.26213801; *g=0.24228619; *b=0.52083736; break;
+          case 47:  *r=0.26057103; *g=0.2469217 ; *b=0.52282822; break;
+          case 48:  *r=0.25896451; *g=0.25153685; *b=0.52473609; break;
+          case 49:  *r=0.25732244; *g=0.2561304 ; *b=0.52656332; break;
+          case 50:  *r=0.25564519; *g=0.26070284; *b=0.52831152; break;
+          case 51:  *r=0.25393498; *g=0.26525384; *b=0.52998273; break;
+          case 52:  *r=0.25219404; *g=0.26978306; *b=0.53157905; break;
+          case 53:  *r=0.25042462; *g=0.27429024; *b=0.53310261; break;
+          case 54:  *r=0.24862899; *g=0.27877509; *b=0.53455561; break;
+          case 55:  *r=0.2468114 ; *g=0.28323662; *b=0.53594093; break;
+          case 56:  *r=0.24497208; *g=0.28767547; *b=0.53726018; break;
+          case 57:  *r=0.24311324; *g=0.29209154; *b=0.53851561; break;
+          case 58:  *r=0.24123708; *g=0.29648471; *b=0.53970946; break;
+          case 59:  *r=0.23934575; *g=0.30085494; *b=0.54084398; break;
+          case 60:  *r=0.23744138; *g=0.30520222; *b=0.5419214 ; break;
+          case 61:  *r=0.23552606; *g=0.30952657; *b=0.54294396; break;
+          case 62:  *r=0.23360277; *g=0.31382773; *b=0.54391424; break;
+          case 63:  *r=0.2316735 ; *g=0.3181058 ; *b=0.54483444; break;
+          case 64:  *r=0.22973926; *g=0.32236127; *b=0.54570633; break;
+          case 65:  *r=0.22780192; *g=0.32659432; *b=0.546532  ; break;
+          case 66:  *r=0.2258633 ; *g=0.33080515; *b=0.54731353; break;
+          case 67:  *r=0.22392515; *g=0.334994  ; *b=0.54805291; break;
+          case 68:  *r=0.22198915; *g=0.33916114; *b=0.54875211; break;
+          case 69:  *r=0.22005691; *g=0.34330688; *b=0.54941304; break;
+          case 70:  *r=0.21812995; *g=0.34743154; *b=0.55003755; break;
+          case 71:  *r=0.21620971; *g=0.35153548; *b=0.55062743; break;
+          case 72:  *r=0.21429757; *g=0.35561907; *b=0.5511844 ; break;
+          case 73:  *r=0.21239477; *g=0.35968273; *b=0.55171011; break;
+          case 74:  *r=0.2105031 ; *g=0.36372671; *b=0.55220646; break;
+          case 75:  *r=0.20862342; *g=0.36775151; *b=0.55267486; break;
+          case 76:  *r=0.20675628; *g=0.37175775; *b=0.55311653; break;
+          case 77:  *r=0.20490257; *g=0.37574589; *b=0.55353282; break;
+          case 78:  *r=0.20306309; *g=0.37971644; *b=0.55392505; break;
+          case 79:  *r=0.20123854; *g=0.38366989; *b=0.55429441; break;
+          case 80:  *r=0.1994295 ; *g=0.38760678; *b=0.55464205; break;
+          case 81:  *r=0.1976365 ; *g=0.39152762; *b=0.55496905; break;
+          case 82:  *r=0.19585993; *g=0.39543297; *b=0.55527637; break;
+          case 83:  *r=0.19410009; *g=0.39932336; *b=0.55556494; break;
+          case 84:  *r=0.19235719; *g=0.40319934; *b=0.55583559; break;
+          case 85:  *r=0.19063135; *g=0.40706148; *b=0.55608907; break;
+          case 86:  *r=0.18892259; *g=0.41091033; *b=0.55632606; break;
+          case 87:  *r=0.18723083; *g=0.41474645; *b=0.55654717; break;
+          case 88:  *r=0.18555593; *g=0.4185704 ; *b=0.55675292; break;
+          case 89:  *r=0.18389763; *g=0.42238275; *b=0.55694377; break;
+          case 90:  *r=0.18225561; *g=0.42618405; *b=0.5571201 ; break;
+          case 91:  *r=0.18062949; *g=0.42997486; *b=0.55728221; break;
+          case 92:  *r=0.17901879; *g=0.43375572; *b=0.55743035; break;
+          case 93:  *r=0.17742298; *g=0.4375272 ; *b=0.55756466; break;
+          case 94:  *r=0.17584148; *g=0.44128981; *b=0.55768526; break;
+          case 95:  *r=0.17427363; *g=0.4450441 ; *b=0.55779216; break;
+          case 96:  *r=0.17271876; *g=0.4487906 ; *b=0.55788532; break;
+          case 97:  *r=0.17117615; *g=0.4525298 ; *b=0.55796464; break;
+          case 98:  *r=0.16964573; *g=0.45626209; *b=0.55803034; break;
+          case 99:  *r=0.16812641; *g=0.45998802; *b=0.55808199; break;
+          case 100: *r=0.1666171 ; *g=0.46370813; *b=0.55811913; break;
+          case 101: *r=0.16511703; *g=0.4674229 ; *b=0.55814141; break;
+          case 102: *r=0.16362543; *g=0.47113278; *b=0.55814842; break;
+          case 103: *r=0.16214155; *g=0.47483821; *b=0.55813967; break;
+          case 104: *r=0.16066467; *g=0.47853961; *b=0.55811466; break;
+          case 105: *r=0.15919413; *g=0.4822374 ; *b=0.5580728 ; break;
+          case 106: *r=0.15772933; *g=0.48593197; *b=0.55801347; break;
+          case 107: *r=0.15626973; *g=0.4896237 ; *b=0.557936  ; break;
+          case 108: *r=0.15481488; *g=0.49331293; *b=0.55783967; break;
+          case 109: *r=0.15336445; *g=0.49700003; *b=0.55772371; break;
+          case 110: *r=0.1519182 ; *g=0.50068529; *b=0.55758733; break;
+          case 111: *r=0.15047605; *g=0.50436904; *b=0.55742968; break;
+          case 112: *r=0.14903918; *g=0.50805136; *b=0.5572505 ; break;
+          case 113: *r=0.14760731; *g=0.51173263; *b=0.55704861; break;
+          case 114: *r=0.14618026; *g=0.51541316; *b=0.55682271; break;
+          case 115: *r=0.14475863; *g=0.51909319; *b=0.55657181; break;
+          case 116: *r=0.14334327; *g=0.52277292; *b=0.55629491; break;
+          case 117: *r=0.14193527; *g=0.52645254; *b=0.55599097; break;
+          case 118: *r=0.14053599; *g=0.53013219; *b=0.55565893; break;
+          case 119: *r=0.13914708; *g=0.53381201; *b=0.55529773; break;
+          case 120: *r=0.13777048; *g=0.53749213; *b=0.55490625; break;
+          case 121: *r=0.1364085 ; *g=0.54117264; *b=0.55448339; break;
+          case 122: *r=0.13506561; *g=0.54485335; *b=0.55402906; break;
+          case 123: *r=0.13374299; *g=0.54853458; *b=0.55354108; break;
+          case 124: *r=0.13244401; *g=0.55221637; *b=0.55301828; break;
+          case 125: *r=0.13117249; *g=0.55589872; *b=0.55245948; break;
+          case 126: *r=0.1299327 ; *g=0.55958162; *b=0.55186354; break;
+          case 127: *r=0.12872938; *g=0.56326503; *b=0.55122927; break;
+          case 128: *r=0.12756771; *g=0.56694891; *b=0.55055551; break;
+          case 129: *r=0.12645338; *g=0.57063316; *b=0.5498411 ; break;
+          case 130: *r=0.12539383; *g=0.57431754; *b=0.54908564; break;
+          case 131: *r=0.12439474; *g=0.57800205; *b=0.5482874 ; break;
+          case 132: *r=0.12346281; *g=0.58168661; *b=0.54744498; break;
+          case 133: *r=0.12260562; *g=0.58537105; *b=0.54655722; break;
+          case 134: *r=0.12183122; *g=0.58905521; *b=0.54562298; break;
+          case 135: *r=0.12114807; *g=0.59273889; *b=0.54464114; break;
+          case 136: *r=0.12056501; *g=0.59642187; *b=0.54361058; break;
+          case 137: *r=0.12009154; *g=0.60010387; *b=0.54253043; break;
+          case 138: *r=0.11973756; *g=0.60378459; *b=0.54139999; break;
+          case 139: *r=0.11951163; *g=0.60746388; *b=0.54021751; break;
+          case 140: *r=0.11942341; *g=0.61114146; *b=0.53898192; break;
+          case 141: *r=0.11948255; *g=0.61481702; *b=0.53769219; break;
+          case 142: *r=0.11969858; *g=0.61849025; *b=0.53634733; break;
+          case 143: *r=0.12008079; *g=0.62216081; *b=0.53494633; break;
+          case 144: *r=0.12063824; *g=0.62582833; *b=0.53348834; break;
+          case 145: *r=0.12137972; *g=0.62949242; *b=0.53197275; break;
+          case 146: *r=0.12231244; *g=0.63315277; *b=0.53039808; break;
+          case 147: *r=0.12344358; *g=0.63680899; *b=0.52876343; break;
+          case 148: *r=0.12477953; *g=0.64046069; *b=0.52706792; break;
+          case 149: *r=0.12632581; *g=0.64410744; *b=0.52531069; break;
+          case 150: *r=0.12808703; *g=0.64774881; *b=0.52349092; break;
+          case 151: *r=0.13006688; *g=0.65138436; *b=0.52160791; break;
+          case 152: *r=0.13226797; *g=0.65501363; *b=0.51966086; break;
+          case 153: *r=0.13469183; *g=0.65863619; *b=0.5176488 ; break;
+          case 154: *r=0.13733921; *g=0.66225157; *b=0.51557101; break;
+          case 155: *r=0.14020991; *g=0.66585927; *b=0.5134268 ; break;
+          case 156: *r=0.14330291; *g=0.66945881; *b=0.51121549; break;
+          case 157: *r=0.1466164 ; *g=0.67304968; *b=0.50893644; break;
+          case 158: *r=0.15014782; *g=0.67663139; *b=0.5065889 ; break;
+          case 159: *r=0.15389405; *g=0.68020343; *b=0.50417217; break;
+          case 160: *r=0.15785146; *g=0.68376525; *b=0.50168574; break;
+          case 161: *r=0.16201598; *g=0.68731632; *b=0.49912906; break;
+          case 162: *r=0.1663832 ; *g=0.69085611; *b=0.49650163; break;
+          case 163: *r=0.1709484 ; *g=0.69438405; *b=0.49380294; break;
+          case 164: *r=0.17570671; *g=0.6978996 ; *b=0.49103252; break;
+          case 165: *r=0.18065314; *g=0.70140222; *b=0.48818938; break;
+          case 166: *r=0.18578266; *g=0.70489133; *b=0.48527326; break;
+          case 167: *r=0.19109018; *g=0.70836635; *b=0.48228395; break;
+          case 168: *r=0.19657063; *g=0.71182668; *b=0.47922108; break;
+          case 169: *r=0.20221902; *g=0.71527175; *b=0.47608431; break;
+          case 170: *r=0.20803045; *g=0.71870095; *b=0.4728733 ; break;
+          case 171: *r=0.21400015; *g=0.72211371; *b=0.46958774; break;
+          case 172: *r=0.22012381; *g=0.72550945; *b=0.46622638; break;
+          case 173: *r=0.2263969 ; *g=0.72888753; *b=0.46278934; break;
+          case 174: *r=0.23281498; *g=0.73224735; *b=0.45927675; break;
+          case 175: *r=0.2393739 ; *g=0.73558828; *b=0.45568838; break;
+          case 176: *r=0.24606968; *g=0.73890972; *b=0.45202405; break;
+          case 177: *r=0.25289851; *g=0.74221104; *b=0.44828355; break;
+          case 178: *r=0.25985676; *g=0.74549162; *b=0.44446673; break;
+          case 179: *r=0.26694127; *g=0.74875084; *b=0.44057284; break;
+          case 180: *r=0.27414922; *g=0.75198807; *b=0.4366009 ; break;
+          case 181: *r=0.28147681; *g=0.75520266; *b=0.43255207; break;
+          case 182: *r=0.28892102; *g=0.75839399; *b=0.42842626; break;
+          case 183: *r=0.29647899; *g=0.76156142; *b=0.42422341; break;
+          case 184: *r=0.30414796; *g=0.76470433; *b=0.41994346; break;
+          case 185: *r=0.31192534; *g=0.76782207; *b=0.41558638; break;
+          case 186: *r=0.3198086 ; *g=0.77091403; *b=0.41115215; break;
+          case 187: *r=0.3277958 ; *g=0.77397953; *b=0.40664011; break;
+          case 188: *r=0.33588539; *g=0.7770179 ; *b=0.40204917; break;
+          case 189: *r=0.34407411; *g=0.78002855; *b=0.39738103; break;
+          case 190: *r=0.35235985; *g=0.78301086; *b=0.39263579; break;
+          case 191: *r=0.36074053; *g=0.78596419; *b=0.38781353; break;
+          case 192: *r=0.3692142 ; *g=0.78888793; *b=0.38291438; break;
+          case 193: *r=0.37777892; *g=0.79178146; *b=0.3779385 ; break;
+          case 194: *r=0.38643282; *g=0.79464415; *b=0.37288606; break;
+          case 195: *r=0.39517408; *g=0.79747541; *b=0.36775726; break;
+          case 196: *r=0.40400101; *g=0.80027461; *b=0.36255223; break;
+          case 197: *r=0.4129135 ; *g=0.80304099; *b=0.35726893; break;
+          case 198: *r=0.42190813; *g=0.80577412; *b=0.35191009; break;
+          case 199: *r=0.43098317; *g=0.80847343; *b=0.34647607; break;
+          case 200: *r=0.44013691; *g=0.81113836; *b=0.3409673 ; break;
+          case 201: *r=0.44936763; *g=0.81376835; *b=0.33538426; break;
+          case 202: *r=0.45867362; *g=0.81636288; *b=0.32972749; break;
+          case 203: *r=0.46805314; *g=0.81892143; *b=0.32399761; break;
+          case 204: *r=0.47750446; *g=0.82144351; *b=0.31819529; break;
+          case 205: *r=0.4870258 ; *g=0.82392862; *b=0.31232133; break;
+          case 206: *r=0.49661536; *g=0.82637633; *b=0.30637661; break;
+          case 207: *r=0.5062713 ; *g=0.82878621; *b=0.30036211; break;
+          case 208: *r=0.51599182; *g=0.83115784; *b=0.29427888; break;
+          case 209: *r=0.52577622; *g=0.83349064; *b=0.2881265 ; break;
+          case 210: *r=0.5356211 ; *g=0.83578452; *b=0.28190832; break;
+          case 211: *r=0.5455244 ; *g=0.83803918; *b=0.27562602; break;
+          case 212: *r=0.55548397; *g=0.84025437; *b=0.26928147; break;
+          case 213: *r=0.5654976 ; *g=0.8424299 ; *b=0.26287683; break;
+          case 214: *r=0.57556297; *g=0.84456561; *b=0.25641457; break;
+          case 215: *r=0.58567772; *g=0.84666139; *b=0.24989748; break;
+          case 216: *r=0.59583934; *g=0.84871722; *b=0.24332878; break;
+          case 217: *r=0.60604528; *g=0.8507331 ; *b=0.23671214; break;
+          case 218: *r=0.61629283; *g=0.85270912; *b=0.23005179; break;
+          case 219: *r=0.62657923; *g=0.85464543; *b=0.22335258; break;
+          case 220: *r=0.63690157; *g=0.85654226; *b=0.21662012; break;
+          case 221: *r=0.64725685; *g=0.85839991; *b=0.20986086; break;
+          case 222: *r=0.65764197; *g=0.86021878; *b=0.20308229; break;
+          case 223: *r=0.66805369; *g=0.86199932; *b=0.19629307; break;
+          case 224: *r=0.67848868; *g=0.86374211; *b=0.18950326; break;
+          case 225: *r=0.68894351; *g=0.86544779; *b=0.18272455; break;
+          case 226: *r=0.69941463; *g=0.86711711; *b=0.17597055; break;
+          case 227: *r=0.70989842; *g=0.86875092; *b=0.16925712; break;
+          case 228: *r=0.72039115; *g=0.87035015; *b=0.16260273; break;
+          case 229: *r=0.73088902; *g=0.87191584; *b=0.15602894; break;
+          case 230: *r=0.74138803; *g=0.87344918; *b=0.14956101; break;
+          case 231: *r=0.75188414; *g=0.87495143; *b=0.14322828; break;
+          case 232: *r=0.76237342; *g=0.87642392; *b=0.13706449; break;
+          case 233: *r=0.77285183; *g=0.87786808; *b=0.13110864; break;
+          case 234: *r=0.78331535; *g=0.87928545; *b=0.12540538; break;
+          case 235: *r=0.79375994; *g=0.88067763; *b=0.12000532; break;
+          case 236: *r=0.80418159; *g=0.88204632; *b=0.11496505; break;
+          case 237: *r=0.81457634; *g=0.88339329; *b=0.11034678; break;
+          case 238: *r=0.82494028; *g=0.88472036; *b=0.10621724; break;
+          case 239: *r=0.83526959; *g=0.88602943; *b=0.1026459 ; break;
+          case 240: *r=0.84556056; *g=0.88732243; *b=0.09970219; break;
+          case 241: *r=0.8558096 ; *g=0.88860134; *b=0.09745186; break;
+          case 242: *r=0.86601325; *g=0.88986815; *b=0.09595277; break;
+          case 243: *r=0.87616824; *g=0.89112487; *b=0.09525046; break;
+          case 244: *r=0.88627146; *g=0.89237353; *b=0.09537439; break;
+          case 245: *r=0.89632002; *g=0.89361614; *b=0.09633538; break;
+          case 246: *r=0.90631121; *g=0.89485467; *b=0.09812496; break;
+          case 247: *r=0.91624212; *g=0.89609127; *b=0.1007168 ; break;
+          case 248: *r=0.92610579; *g=0.89732977; *b=0.10407067; break;
+          case 249: *r=0.93590444; *g=0.8985704 ; *b=0.10813094; break;
+          case 250: *r=0.94563626; *g=0.899815  ; *b=0.11283773; break;
+          case 251: *r=0.95529972; *g=0.90106534; *b=0.11812832; break;
+          case 252: *r=0.96489353; *g=0.90232311; *b=0.12394051; break;
+          case 253: *r=0.97441665; *g=0.90358991; *b=0.13021494; break;
+          case 254: *r=0.98386829; *g=0.90486726; *b=0.13689671; break;
+          case 255: *r=0.99324789; *g=0.90615657; *b=0.1439362 ; break;
+          }
+
+      /* Convert the RGB values to 0 and 255.  With the steps above, they
+         are between 0 and 1. */
+      *r++ *= 255;
+      *g++ *= 255;
+      *b++ *= 255;
+    }
+  while(++f<fp);
+
+  /* Convert the type to unsigned char. */
+  R=gal_data_copy_to_new_type_free(R, GAL_TYPE_UINT8);
+  G=gal_data_copy_to_new_type_free(G, GAL_TYPE_UINT8);
+  B=gal_data_copy_to_new_type_free(B, GAL_TYPE_UINT8);
+  p->chll=R;
+  p->chll->next=G;
+  p->chll->next->next=B;
+
+  /* Clean up. */
+  gal_data_free(channel);
+}
+
+
+
+
+
 void
 color_map_prepare(struct converttparams *p)
 {
   switch(p->colormap->status)
     {
-    case COLOR_HSV:  color_from_mono_hsv(p);     break;
-    case COLOR_SLS:  color_from_mono_sls(p);     break;
-    case COLOR_GRAY: convertt_scale_to_uchar(p); break;
+    case COLOR_HSV:          color_from_mono_hsv(p); break;
+    case COLOR_SLS:          color_from_mono_sls(p); break;
+    case COLOR_VIRIDIS:      color_from_mono_viridis(p); break;
+    case COLOR_GRAY:         convertt_scale_to_uchar(p); break;
     default:
       error(EXIT_FAILURE, 0, "%s: a bug! Please contact us at %s to fix "
             "the problem. The value %d is not a recognized color-space "
diff --git a/bin/convertt/color.h b/bin/convertt/color.h
index a856ca9..7b477ea 100644
--- a/bin/convertt/color.h
+++ b/bin/convertt/color.h
@@ -33,6 +33,9 @@ void
 color_from_mono_sls(struct converttparams *p);
 
 void
+color_from_mono_viridis(struct converttparams *p);
+
+void
 color_rgb_to_hsv(struct converttparams *p);
 
 #endif
diff --git a/bin/convertt/main.h b/bin/convertt/main.h
index 6b69968..e051602 100644
--- a/bin/convertt/main.h
+++ b/bin/convertt/main.h
@@ -56,6 +56,7 @@ enum colorspace_names
   COLOR_RGB,
   COLOR_HSV,
   COLOR_SLS,
+  COLOR_VIRIDIS,
   COLOR_GRAY,
 };
 
diff --git a/bin/convertt/ui.c b/bin/convertt/ui.c
index 616314f..f5f1df7 100644
--- a/bin/convertt/ui.c
+++ b/bin/convertt/ui.c
@@ -237,13 +237,14 @@ ui_colormap_sanity_check(struct converttparams *p)
 
   /* See how many parameters are necessary. */
   strarr=p->colormap->array;
-  if     ( !strcmp(strarr[0],"hsv" )) { ccode=COLOR_HSV;  nparams=2; }
-  else if( !strcmp(strarr[0],"sls" )) { ccode=COLOR_SLS;  nparams=0; }
+  if     ( !strcmp(strarr[0],"hsv"))     { ccode=COLOR_HSV;     nparams=2; }
+  else if( !strcmp(strarr[0],"sls"))     { ccode=COLOR_SLS;     nparams=0; }
+  else if( !strcmp(strarr[0],"viridis")) { ccode=COLOR_VIRIDIS; nparams=0; }
   else if( !strcmp(strarr[0],"gray") || !strcmp(strarr[0],"grey"))
                                       { ccode=COLOR_GRAY; nparams=0; }
   else
-    error(EXIT_FAILURE, 0, "`%s' not recognized as a color-space given "
-          "to `--monotocolor'", strarr[0]);
+    error(EXIT_FAILURE, 0, "`%s' not recognized as a colormap given "
+          "to `--colormap'", strarr[0]);
   p->colormap->status=ccode;
 
   /* Check if the proper number of parameters are given for this color
@@ -644,7 +645,7 @@ ui_prepare_input_channels(struct converttparams *p)
       if( p->colormap==NULL )
         error(EXIT_FAILURE, 0, "no colormap! When there is only one input "
               "channel, it is necessary to specify a color map. For "
-              "example `gray', `hsv', or `sls'.\n\n"
+              "example `gray', `hsv', `viridis' or `sls'.\n\n"
               "For more on ConvertType's color mapping, see the "
               "description under `--colormap' in the Gnuastro book:\n\n"
               "   $ info astconvertt");
diff --git a/bin/cosmiccal/cosmiccal.c b/bin/cosmiccal/cosmiccal.c
index a7d665f..b42ec7d 100644
--- a/bin/cosmiccal/cosmiccal.c
+++ b/bin/cosmiccal/cosmiccal.c
@@ -165,106 +165,111 @@ cosmiccal(struct cosmiccalparams *p)
   if(p->specific)
     {
       for(tmp=p->specific;tmp!=NULL;tmp=tmp->next)
-        switch(tmp->v)
-          {
-          case UI_KEY_USEDREDSHIFT:
-            printf("%g ",
-                   p->redshift==MAIN_REDSHIFT_ZERO ? 0.0f: p->redshift);
-            break;
-
-          case UI_KEY_AGENOW:
-            printf("%f ", gal_cosmology_age(0.0f, p->H0, p->olambda,
-                                            p->omatter, p->oradiation));
-            break;
-
-          case UI_KEY_CRITICALDENSITYNOW:
-            printf("%e ", gal_cosmology_critical_density(0.0f, p->H0,
-                                                         p->olambda,
-                                                         p->omatter,
-                                                         p->oradiation));
-            break;
-
-          case UI_KEY_PROPERDISTANCE:
-            printf("%f ", gal_cosmology_proper_distance(p->redshift, p->H0,
-                                                        p->olambda,
-                                                        p->omatter,
-                                                        p->oradiation));
-            break;
-
-          case UI_KEY_ANGULARDIMDIST:
-            printf("%f ", gal_cosmology_angular_distance(p->redshift, p->H0,
-                                                         p->olambda,
-                                                         p->omatter,
-                                                         p->oradiation));
-            break;
-
-          case UI_KEY_ARCSECTANDIST:
-            printf("%f ", ( gal_cosmology_angular_distance(p->redshift, p->H0,
+        {
+          switch(tmp->v)
+            {
+            case UI_KEY_USEDREDSHIFT:
+              printf("%g",
+                     p->redshift==MAIN_REDSHIFT_ZERO ? 0.0f: p->redshift);
+              break;
+
+            case UI_KEY_AGENOW:
+              printf("%f", gal_cosmology_age(0.0f, p->H0, p->olambda,
+                                              p->omatter, p->oradiation));
+              break;
+
+            case UI_KEY_CRITICALDENSITYNOW:
+              printf("%e", gal_cosmology_critical_density(0.0f, p->H0,
                                                            p->olambda,
                                                            p->omatter,
-                                                           p->oradiation)
-                            * 1000 * M_PI / 3600 / 180 ) );
-            break;
-
-          case UI_KEY_LUMINOSITYDIST:
-            printf("%f ", gal_cosmology_luminosity_distance(p->redshift,
-                                                            p->H0,
-                                                            p->olambda,
-                                                            p->omatter,
-                                                            p->oradiation));
-            break;
-
-          case UI_KEY_DISTANCEMODULUS:
-            printf("%f ", gal_cosmology_distance_modulus(p->redshift, p->H0,
-                                                         p->olambda,
-                                                         p->omatter,
-                                                         p->oradiation));
-            break;
-
-          case UI_KEY_ABSMAGCONV:
-            printf("%f ", gal_cosmology_to_absolute_mag(p->redshift, p->H0,
-                                                        p->olambda,
-                                                        p->omatter,
-                                                        p->oradiation));
-            break;
-
-          case UI_KEY_AGE:
-            printf("%f ", gal_cosmology_age(p->redshift, p->H0, p->olambda,
-                                            p->omatter, p->oradiation));
-            break;
-
-          case UI_KEY_LOOKBACKTIME:
-            curage=gal_cosmology_age(0.0f, p->H0, p->olambda, p->omatter,
+                                                           p->oradiation));
+              break;
+
+            case UI_KEY_PROPERDISTANCE:
+              printf("%f", gal_cosmology_proper_distance(p->redshift, p->H0,
+                                                          p->olambda,
+                                                          p->omatter,
+                                                          p->oradiation));
+              break;
+
+            case UI_KEY_ANGULARDIMDIST:
+              printf("%f", gal_cosmology_angular_distance(p->redshift, p->H0,
+                                                           p->olambda,
+                                                           p->omatter,
+                                                           p->oradiation));
+              break;
+
+            case UI_KEY_ARCSECTANDIST:
+              printf("%f", ( gal_cosmology_angular_distance(p->redshift, p->H0,
+                                                             p->olambda,
+                                                             p->omatter,
+                                                             p->oradiation)
+                              * 1000 * M_PI / 3600 / 180 ) );
+              break;
+
+            case UI_KEY_LUMINOSITYDIST:
+              printf("%f", gal_cosmology_luminosity_distance(p->redshift,
+                                                              p->H0,
+                                                              p->olambda,
+                                                              p->omatter,
+                                                              p->oradiation));
+              break;
+
+            case UI_KEY_DISTANCEMODULUS:
+              printf("%f", gal_cosmology_distance_modulus(p->redshift, p->H0,
+                                                           p->olambda,
+                                                           p->omatter,
+                                                           p->oradiation));
+              break;
+
+            case UI_KEY_ABSMAGCONV:
+              printf("%f", gal_cosmology_to_absolute_mag(p->redshift, p->H0,
+                                                          p->olambda,
+                                                          p->omatter,
+                                                          p->oradiation));
+              break;
+
+            case UI_KEY_AGE:
+              printf("%f", gal_cosmology_age(p->redshift, p->H0, p->olambda,
+                                              p->omatter, p->oradiation));
+              break;
+
+            case UI_KEY_LOOKBACKTIME:
+              curage=gal_cosmology_age(0.0f, p->H0, p->olambda, p->omatter,
+                                       p->oradiation);
+              zage=gal_cosmology_age(p->redshift, p->H0, p->olambda, 
p->omatter,
                                      p->oradiation);
-            zage=gal_cosmology_age(p->redshift, p->H0, p->olambda, p->omatter,
-                                   p->oradiation);
-            printf("%f ", curage-zage);
-            break;
-
-          case UI_KEY_CRITICALDENSITY:
-            printf("%e ", gal_cosmology_critical_density(p->redshift, p->H0,
-                                                         p->olambda,
-                                                         p->omatter,
-                                                         p->oradiation));
-            break;
-
-          case UI_KEY_VOLUME:
-            printf("%f ", gal_cosmology_comoving_volume(p->redshift, p->H0,
-                                                        p->olambda,
-                                                        p->omatter,
-                                                        p->oradiation));
-            break;
-
-          case UI_KEY_LINEATZ:
-            printf("%g ", gal_list_f64_pop(&p->specific_arg)*(1+p->redshift));
-            break;
-
-          default:
-            error(EXIT_FAILURE, 0, "%s: a bug! Please contact us at %s to "
-                  "fix the problem. The code %d is not recognized as a "
-                  "single value calculation code", __func__,
-                  PACKAGE_BUGREPORT, tmp->v);
-          }
+              printf("%f", curage-zage);
+              break;
+
+            case UI_KEY_CRITICALDENSITY:
+              printf("%e", gal_cosmology_critical_density(p->redshift, p->H0,
+                                                           p->olambda,
+                                                           p->omatter,
+                                                           p->oradiation));
+              break;
+
+            case UI_KEY_VOLUME:
+              printf("%f", gal_cosmology_comoving_volume(p->redshift, p->H0,
+                                                          p->olambda,
+                                                          p->omatter,
+                                                          p->oradiation));
+              break;
+
+            case UI_KEY_LINEATZ:
+              printf("%g", gal_list_f64_pop(&p->specific_arg)*(1+p->redshift));
+              break;
+
+            default:
+              error(EXIT_FAILURE, 0, "%s: a bug! Please contact us at %s to "
+                    "fix the problem. The code %d is not recognized as a "
+                    "single value calculation code", __func__,
+                    PACKAGE_BUGREPORT, tmp->v);
+            }
+
+          /* Only add a space-character if there are more results to print. */
+          if(tmp->next) printf(" ");
+        }
 
       /* Print a new-line character to finish the output. */
       printf("\n");
diff --git a/bin/crop/crop.c b/bin/crop/crop.c
index 3e19f71..88802a9 100644
--- a/bin/crop/crop.c
+++ b/bin/crop/crop.c
@@ -224,6 +224,10 @@ crop_mode_img(void *inparam)
       /* Crop the image. */
       onecrop(crp);
 
+      /* If there was no overlap, then no FITS pointer is created, so
+         `numimg' should be set to zero. */
+      if(crp->outfits==NULL) crp->numimg=0;
+
       /* Check the final output: */
       if(crp->numimg)
         {
@@ -235,7 +239,7 @@ crop_mode_img(void *inparam)
           status=0;
           if( fits_close_file(crp->outfits, &status) )
             gal_fits_io_error(status, "CFITSIO could not close "
-                                   "the opened file");
+                              "the opened file");
 
           /* Remove the output image if its center was not filled. */
           if(crp->centerfilled==0)
diff --git a/bin/statistics/Makefile.am b/bin/statistics/Makefile.am
index 4106976..540757c 100644
--- a/bin/statistics/Makefile.am
+++ b/bin/statistics/Makefile.am
@@ -35,9 +35,9 @@ bin_PROGRAMS = aststatistics
 aststatistics_LDADD = $(top_builddir)/bootstrapped/lib/libgnu.la \
                       -lgnuastro $(MAYBE_NORPATH)
 
-aststatistics_SOURCES = main.c ui.c sky.c statistics.c
+aststatistics_SOURCES = main.c ui.c contour.c sky.c statistics.c
 
-EXTRA_DIST = main.h authors-cite.h args.h ui.h sky.h statistics.h
+EXTRA_DIST = main.h authors-cite.h args.h ui.h sky.h statistics.h contour.h
 
 
 
diff --git a/bin/statistics/args.h b/bin/statistics/args.h
index 3eaed38..9ee8852 100644
--- a/bin/statistics/args.h
+++ b/bin/statistics/args.h
@@ -475,6 +475,21 @@ struct argp_option program_options[] =
       GAL_OPTIONS_NOT_MANDATORY,
       GAL_OPTIONS_NOT_SET
     },
+    {
+      "contour",
+      UI_KEY_CONTOUR,
+      "STR",
+      0,
+      "Contour levels, save in PGFPlots format.",
+      UI_GROUP_PARTICULAR_STAT,
+      &p->contour,
+      GAL_OPTIONS_NO_ARG_TYPE,
+      GAL_OPTIONS_RANGE_0_OR_1,
+      GAL_OPTIONS_NOT_MANDATORY,
+      GAL_OPTIONS_NOT_SET,
+      gal_options_parse_csv_float64
+    },
+
 
 
 
diff --git a/bin/statistics/contour.c b/bin/statistics/contour.c
new file mode 100644
index 0000000..ffdb2e0
--- /dev/null
+++ b/bin/statistics/contour.c
@@ -0,0 +1,209 @@
+/*********************************************************************
+Statistics - Statistical analysis on input dataset.
+Statistics is part of GNU Astronomy Utilities (Gnuastro) package.
+
+Original author:
+     Mohammad Akhlaghi <mohammad@akhlaghi.org>
+Contributing author(s):
+Copyright (C) 2019, Free Software Foundation, Inc.
+
+Gnuastro is free software: you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation, either version 3 of the License, or (at your
+option) any later version.
+
+Gnuastro is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Gnuastro. If not, see <http://www.gnu.org/licenses/>.
+**********************************************************************/
+#include <config.h>
+
+#include <stdio.h>
+#include <errno.h>
+#include <error.h>
+#include <stdlib.h>
+
+#include <gnuastro-internal/checkset.h>
+
+#include <gnuastro/wcs.h>
+#include <gnuastro/binary.h>
+#include <gnuastro/arithmetic.h>
+
+#include "main.h"
+#include "contour.h"
+
+/* Pixels containing contour */
+static gal_data_t *
+contour_pixels(gal_data_t *input, double level, size_t minmapsize,
+               int quietmmap)
+{
+  size_t one=1;
+  uint8_t *b, *a, *af;
+  int flags=GAL_ARITHMETIC_NUMOK;
+  gal_data_t *number, *thresh, *eroded;
+
+  /* Allocate the single-element dataset to use in arithmetic.*/
+  number=gal_data_alloc(NULL, GAL_TYPE_FLOAT64, 1, &one, NULL, 1,
+                        -1, 1, NULL, NULL, NULL);
+  *(double *)(number->array)=level;
+
+  /* Only keep the pixels above the requested level, we are using the
+     arithmetic library to not have to worry about the type of the
+     input. */
+  thresh=gal_arithmetic(GAL_ARITHMETIC_OP_GT, 1, flags, input, number);
+
+  /* Erode the thresholded image by one. */
+  eroded=gal_binary_erode(thresh, 1, 1, 0);
+
+  /* Only keep the outer pixels. */
+  b=eroded->array;
+  af=(a=thresh->array)+thresh->size;
+  do if(*b++ == 1) *a=0; while(++a<af);
+
+  /* Clean up and return. */
+  gal_data_free(number);
+  gal_data_free(eroded);
+  return thresh;
+}
+
+
+
+
+
+/* Given the indexs of the contours, write them in the proper format. */
+static void
+contour_pgfplots(gal_data_t *edgeindexs, gal_data_t *input, float level,
+                 FILE *fp)
+{
+  double *xa, *ya;
+  gal_data_t *x, *y, *tmp;
+  size_t *s, *sf, w=input->dsize[1];
+
+  /* Go through each connected edge and add the contour positions. */
+  for(tmp=edgeindexs; tmp!=NULL; tmp=tmp->next)
+    if(tmp->size>10)
+      {
+        if(input->wcs)
+          {
+            {
+              /* Allocate the coordinate arrays. */
+              x=gal_data_alloc(NULL, GAL_TYPE_FLOAT64, 1, &tmp->size,
+                               NULL, 0, -1, 1, NULL, NULL, NULL);
+              y=gal_data_alloc(NULL, GAL_TYPE_FLOAT64, 1, &tmp->size,
+                               NULL, 0, -1, 1, NULL, NULL, NULL);
+
+              /* Fill in the coordinates. */
+              xa=x->array;
+              ya=y->array;
+              sf=(s=tmp->array)+tmp->size;
+              do {*xa++=*s%w+1; *ya++=*s/w+1;} while(++s<sf);
+
+              /* Convert the pixel positions to WCS. */
+              x->next=y;
+              gal_wcs_img_to_world(x, input->wcs, 1);
+
+              /* Write them. */
+              xa=x->array;
+              ya=y->array;
+              sf=(s=tmp->array)+tmp->size;
+              do
+                {fprintf(fp, "%.10f  %.10f  %f\n", *xa++, *ya++, level);}
+              while(++s<sf);
+
+              /* Clean up. */
+              gal_data_free(x);
+              gal_data_free(y);
+            }
+          }
+        else
+          {
+            sf=(s=tmp->array)+tmp->size;
+            do
+              {fprintf(fp, "%zu  %zu  %f\n", *s%w+1, *s/w+1, level);}
+            while(++s<sf);
+          }
+
+        /* To separate the different connected regions, we'll need to put
+           an empty line between them. */
+        fprintf(fp, "\n");
+      }
+}
+
+
+
+
+
+/* Contour for each level. */
+static void
+contour_level(gal_data_t *input, double level, FILE *fp,
+              size_t minmapsize, int quietmmap)
+{
+  gal_data_t *edge, *edgeindexs;
+
+  /* Find the edge pixels given this threshold. */
+  edge=contour_pixels(input, level, minmapsize, quietmmap);
+
+  /* Indexs of the edges (separated by groups of connected edges). */
+  edgeindexs=gal_binary_connected_indexs(edge, 2);
+
+  /* Make the PGFPlots contours. */
+  contour_pgfplots(edgeindexs, input, level, fp);
+
+  /* Clean up and return. */
+  gal_list_data_free(edgeindexs);
+  gal_data_free(edge);
+}
+
+
+
+
+
+void
+contour(struct statisticsparams *p)
+{
+  FILE *fp;
+  char *outname;
+  double *d, *df;
+  uint8_t keepinputdir=p->cp.keepinputdir;
+
+  /* Make sure the dataset is 2D. */
+  if(p->input->ndim!=2)
+    error(EXIT_FAILURE, 0, "contours are currently only supported for "
+          "2D datasets (images). The input dataset has %zu dimensions",
+          p->input->ndim);
+
+  /* Make sure the output doesn't exist. */
+  p->cp.keepinputdir = p->cp.output ? 1 : keepinputdir;
+  outname=gal_checkset_automatic_output(&p->cp,
+                                        ( p->cp.output
+                                          ? p->cp.output
+                                          : p->inputname ), "_contour.txt");
+  p->cp.keepinputdir=keepinputdir;
+
+  /* Open the output file. */
+  fp=fopen(outname, "w+");
+
+  /* Print basic information about the columns. */
+  fprintf(fp, "# %s Contour positions\n", PACKAGE_STRING);
+  fprintf(fp, "# Column 1: Coord_1 [position,f64] Position in first axis.\n");
+  fprintf(fp, "# Column 2: Coord_2 [position,f64] Position in second axis.\n");
+  fprintf(fp, "# Column 3: Level   [value,   f32] Contour level.\n");
+  fprintf(fp, "#\n");
+  fprintf(fp, "# Each connected contour is separated by an empty line.\n");
+  fprintf(fp, "# This format is recognized in PGFPlots (package of LaTeX).\n");
+
+  /* Estimate the contours for each level. */
+  df=(d=p->contour->array)+p->contour->size;
+  do
+    contour_level(p->input, *d, fp, p->cp.minmapsize,
+                  p->cp.quietmmap);
+  while(++d<df);
+
+  /* Clean up and cose the file. */
+  free(outname);
+  fclose(fp);
+}
diff --git a/bin/convertt/color.h b/bin/statistics/contour.h
similarity index 67%
copy from bin/convertt/color.h
copy to bin/statistics/contour.h
index a856ca9..4d59c86 100644
--- a/bin/convertt/color.h
+++ b/bin/statistics/contour.h
@@ -1,11 +1,11 @@
 /*********************************************************************
-ConvertType - Convert between various types of files.
-ConvertType is part of GNU Astronomy Utilities (Gnuastro) package.
+Statistics - Statistical analysis on input dataset.
+Statistics is part of GNU Astronomy Utilities (Gnuastro) package.
 
 Original author:
      Mohammad Akhlaghi <mohammad@akhlaghi.org>
 Contributing author(s):
-Copyright (C) 2015-2019, Free Software Foundation, Inc.
+Copyright (C) 2019, Free Software Foundation, Inc.
 
 Gnuastro is free software: you can redistribute it and/or modify it
 under the terms of the GNU General Public License as published by the
@@ -20,19 +20,12 @@ General Public License for more details.
 You should have received a copy of the GNU General Public License
 along with Gnuastro. If not, see <http://www.gnu.org/licenses/>.
 **********************************************************************/
-#ifndef COLOR_H
-#define COLOR_H
+#ifndef CONTOUR_H
+#define CONTOUR_H
 
 void
-color_map_prepare(struct converttparams *p);
+contour(struct statisticsparams *p);
 
-void
-color_from_mono_hsv(struct converttparams *p);
-
-void
-color_from_mono_sls(struct converttparams *p);
 
-void
-color_rgb_to_hsv(struct converttparams *p);
 
 #endif
diff --git a/bin/statistics/main.h b/bin/statistics/main.h
index 7e835cc..7455dc8 100644
--- a/bin/statistics/main.h
+++ b/bin/statistics/main.h
@@ -74,6 +74,7 @@ struct statisticsparams
   double            mirror;  /* Mirror value for hist and CFP.           */
   uint8_t              sky;  /* Find the Sky value over the image.       */
   uint8_t        sigmaclip;  /* So sigma-clipping over all dataset.      */
+  gal_data_t      *contour;  /* Levels to show contours.                 */
 
   size_t           numbins;  /* Number of bins in histogram or CFP.      */
   size_t      numasciibins;  /* Number of bins in ASCII plots.           */
diff --git a/bin/statistics/statistics.c b/bin/statistics/statistics.c
index db87377..3a36134 100644
--- a/bin/statistics/statistics.c
+++ b/bin/statistics/statistics.c
@@ -46,6 +46,7 @@ along with Gnuastro. If not, see 
<http://www.gnu.org/licenses/>.
 
 #include "ui.h"
 #include "sky.h"
+#include "contour.h"
 #include "statistics.h"
 
 
@@ -1024,6 +1025,12 @@ statistics(struct statisticsparams *p)
       print_basic_info=0;
     }
 
+  if(p->contour)
+    {
+      contour(p);
+      print_basic_info=0;
+    }
+
   /* Print the ASCII plots if requested. */
   if(p->asciihist || p->asciicfp)
     {
diff --git a/bin/statistics/ui.c b/bin/statistics/ui.c
index 86597e1..e590b51 100644
--- a/bin/statistics/ui.c
+++ b/bin/statistics/ui.c
@@ -904,7 +904,7 @@ ui_preparations(struct statisticsparams *p)
   ui_out_of_range_to_blank(p);
 
   /* If we are not to work on tiles, then re-order and change the input. */
-  if(p->ontile==0 && p->sky==0)
+  if(p->ontile==0 && p->sky==0 && p->contour==NULL)
     {
       /* Only keep the elements we want. */
       gal_blank_remove(p->input);
diff --git a/bin/statistics/ui.h b/bin/statistics/ui.h
index 8b2422b..d1aab3b 100644
--- a/bin/statistics/ui.h
+++ b/bin/statistics/ui.h
@@ -46,7 +46,7 @@ enum program_args_groups
 /* Available letters for short options:
 
    a b e f j p v w x z
-   B G J L R W X Y
+   B G J L W X Y
 */
 enum option_keys_enum
 {
@@ -70,6 +70,7 @@ enum option_keys_enum
   UI_KEY_INTERPOLATE  = 'i',
   UI_KEY_SKY          = 'y',
   UI_KEY_KERNEL       = 'k',
+  UI_KEY_CONTOUR      = 'R',
 
   /* Only with long version (start with a value 1000, the rest will be set
      automatically). */
diff --git a/bin/table/args.h b/bin/table/args.h
index 2f2506e..11d2c21 100644
--- a/bin/table/args.h
+++ b/bin/table/args.h
@@ -130,7 +130,7 @@ struct argp_option program_options[] =
     {
       "equal",
       UI_KEY_EQUAL,
-      "STR,FLT,FLT",
+      "STR,FLT[,...]",
       0,
       "Column, values to keep in output.",
       UI_GROUP_OUTROWS,
@@ -144,7 +144,7 @@ struct argp_option program_options[] =
     {
       "notequal",
       UI_KEY_NOTEQUAL,
-      "STR,FLT,FLT",
+      "STR,FLT[,...]",
       0,
       "Column, values to remove from output.",
       UI_GROUP_OUTROWS,
@@ -158,7 +158,7 @@ struct argp_option program_options[] =
     {
       "sort",
       UI_KEY_SORT,
-      "STR,INT",
+      "STR/INT",
       0,
       "Column name or number for sorting.",
       UI_GROUP_OUTROWS,
diff --git a/bin/table/arithmetic.c b/bin/table/arithmetic.c
index 5eb073f..279a9a5 100644
--- a/bin/table/arithmetic.c
+++ b/bin/table/arithmetic.c
@@ -106,6 +106,7 @@ arithmetic_operator_name(int operator)
       {
       case ARITHMETIC_TABLE_OP_WCSTOIMG: out="wcstoimg"; break;
       case ARITHMETIC_TABLE_OP_IMGTOWCS: out="imgtowcs"; break;
+      case ARITHMETIC_TABLE_OP_ANGULARDISTANCE: out="angular-distance"; break;
       default:
         error(EXIT_FAILURE, 0, "%s: a bug! Please contact us at %s to fix "
               "the problem. %d is not a recognized operator code", __func__,
@@ -153,9 +154,11 @@ arithmetic_set_operator(struct tableparams *p, char 
*string,
   if( op==GAL_ARITHMETIC_OP_INVALID )
     {
       if(      !strncmp(string, "wcstoimg", 8))
-        { op=ARITHMETIC_TABLE_OP_WCSTOIMG;   *num_operands=0; }
+        { op=ARITHMETIC_TABLE_OP_WCSTOIMG; *num_operands=0; }
       else if (!strncmp(string, "imgtowcs", 8))
-        { op=ARITHMETIC_TABLE_OP_IMGTOWCS;   *num_operands=0; }
+        { op=ARITHMETIC_TABLE_OP_IMGTOWCS; *num_operands=0; }
+      else if (!strncmp(string, "angular-distance", 8))
+        { op=ARITHMETIC_TABLE_OP_ANGULARDISTANCE; *num_operands=0; }
       else
         { op=GAL_ARITHMETIC_OP_INVALID; *num_operands=GAL_BLANK_INT; }
     }
@@ -430,6 +433,68 @@ arithmetic_wcs(struct tableparams *p, gal_data_t **stack, 
int operator)
 
 
 
+static void
+arithmetic_angular_dist(struct tableparams *p, gal_data_t **stack, int 
operator)
+{
+  size_t i, j;
+  double *o, *a1, *a2, *b1, *b2;
+  gal_data_t *a, *b, *tmp, *out;
+
+  /* Pop the columns for point `b'.*/
+  tmp=arithmetic_stack_pop(stack, operator);
+  tmp=gal_data_copy_to_new_type_free(tmp, GAL_TYPE_FLOAT64);
+  b=arithmetic_stack_pop(stack, operator);
+  b=gal_data_copy_to_new_type_free(b, GAL_TYPE_FLOAT64);
+  b->next=tmp;
+
+  /* Pop the columns for point `a'.*/
+  tmp=arithmetic_stack_pop(stack, operator);
+  tmp=gal_data_copy_to_new_type_free(tmp, GAL_TYPE_FLOAT64);
+  a=arithmetic_stack_pop(stack, operator);
+  a=gal_data_copy_to_new_type_free(a, GAL_TYPE_FLOAT64);
+  a->next=tmp;
+
+  /* Make sure the sizes are consistant: note that one point can have a
+     single coordinate, but we don't know which one. */
+  if(a->size!=a->next->size)
+    error(EXIT_FAILURE, 0, "the sizes of the third and fourth operands "
+          "of the `%s' operator (respectively containing %zu and %zu "
+          "numbers) must be equal", arithmetic_operator_name(operator),
+          a->next->size, a->size);
+  if(b->size!=b->next->size)
+    error(EXIT_FAILURE, 0, "the sizes of the third and fourth operands "
+          "of the `%s' operator (respectively containing %zu and %zu "
+          "numbers) must be equal", arithmetic_operator_name(operator),
+          b->next->size, b->size);
+
+  /* Make the output array based on the largest size. */
+  out=gal_data_alloc(NULL, GAL_TYPE_FLOAT64, 1,
+                     (a->size>b->size ? &a->size : &b->size), NULL, 0,
+                     p->cp.minmapsize, p->cp.quietmmap, "angular-dist",
+                     NULL, "Angular distance between input points");
+
+  /* Measure the distances.  */
+  o=out->array;
+  a1=a->array; a2=a->next->array;
+  b1=b->array; b2=b->next->array;
+  if(a->size==1 || b->size==1) /* One of them is a single point. */
+    for(i=0;i<a->size;++i)
+      for(j=0;j<b->size;++j)
+        o[a->size>b->size?i:j] = gal_wcs_angular_distance_deg(a1[i], a2[i],
+                                                              b1[j], b2[j]);
+  else                         /* Both have the same length. */
+    for(i=0;i<a->size;++i)     /* (all were originally from the same table) */
+      o[i] = gal_wcs_angular_distance_deg(a1[i], a2[i], b1[i], b2[i]);
+
+  /* Clean up and put the output dataset onto the stack. */
+  gal_list_data_free(a);
+  gal_list_data_free(b);
+  gal_list_data_add(stack, out);
+}
+
+
+
+
 
 
 
@@ -545,6 +610,10 @@ arithmetic_operator_run(struct tableparams *p, gal_data_t 
**stack,
           arithmetic_wcs(p, stack, operator);
           break;
 
+        case ARITHMETIC_TABLE_OP_ANGULARDISTANCE:
+          arithmetic_angular_dist(p, stack, operator);
+          break;
+
         default:
           error(EXIT_FAILURE, 0, "%s: a bug! Please contact us at %s to "
                 "fix the problem. The operator code %d is not recognized",
@@ -605,7 +674,7 @@ arithmetic_reverse_polish(struct tableparams *p, struct 
column_pack *outpack)
       /* A small sanity check. */
       if(single->size==1 && p->table && single->size!=p->table->size)
         error(EXIT_FAILURE, 0, "the arithmetic operation resulted in a "
-              "a single value, but other columns have also been requested "
+              "single value, but other columns have also been requested "
               "which have more elements/rows");
 
       /* Set `single->next' to NULL so it isn't treated as a list and
@@ -643,7 +712,6 @@ arithmetic_operate(struct tableparams *p)
   size_t i;
   struct column_pack *outpack;
 
-
   /* From now on, we will be looking for columns from the index in
      `colarray', so to keep things clean, we'll set all the `next' elements
      to NULL. */
diff --git a/bin/table/arithmetic.h b/bin/table/arithmetic.h
index dc75d61..7695484 100644
--- a/bin/table/arithmetic.h
+++ b/bin/table/arithmetic.h
@@ -37,6 +37,7 @@ enum arithmetic_operators
 {
  ARITHMETIC_TABLE_OP_WCSTOIMG = GAL_ARITHMETIC_OP_LAST_CODE,
  ARITHMETIC_TABLE_OP_IMGTOWCS,
+ ARITHMETIC_TABLE_OP_ANGULARDISTANCE,
 };
 
 
diff --git a/bin/table/ui.c b/bin/table/ui.c
index d12cc4b..63226a6 100644
--- a/bin/table/ui.c
+++ b/bin/table/ui.c
@@ -675,7 +675,7 @@ ui_check_select_sort_before(struct tableparams *p, 
gal_list_str_t *lines,
                             size_t *nselect, size_t *origoutncols,
                             size_t *sortindout, size_t **selectindout_out,
                             size_t **selecttypeout_out)
-{;
+{
   gal_data_t *dtmp, *allcols;
   size_t sortind=GAL_BLANK_SIZE_T;
   gal_list_sizet_t *tmp, *indexll;
@@ -850,7 +850,7 @@ ui_check_select_sort_before(struct tableparams *p, 
gal_list_str_t *lines,
                   {
                     selecttypeout[i]=k;
                     selectindout[i]=allncols++;
-                    gal_list_str_add(&add, dtmp->name, 0);
+                    gal_list_str_add(&add, dtmp->name, 1);
                   }
               }
             ++i;
diff --git a/bootstrap b/bootstrap
index 5b08e7e..e273ea7 100755
--- a/bootstrap
+++ b/bootstrap
@@ -166,7 +166,7 @@ bootstrap_epilogue() { :; }
 # specified directory.  Fill in the first %s with the destination
 # directory and the second with the domain name.
 po_download_command_format=\
-"wget --mirror --level=1 -nd -q -A.po -P '%s' \
+"wget --mirror --level=1 -nd -nv -A.po -P '%s' \
  https://translationproject.org/latest/%s/";
 
 # Prefer a non-empty tarname (4th argument of AC_INIT if given), else
diff --git a/bootstrap.conf b/bootstrap.conf
index 9275622..a298ac2 100644
--- a/bootstrap.conf
+++ b/bootstrap.conf
@@ -223,6 +223,7 @@ gnulib_modules="
     stdint
     strtod
     mktime
+    fcntl-h
     havelib
     memmove
     getline
diff --git a/doc/Makefile.am b/doc/Makefile.am
index 3082fb4..8e85d02 100644
--- a/doc/Makefile.am
+++ b/doc/Makefile.am
@@ -24,7 +24,7 @@
 
 
 ## Set the shell
-SHELL=/bin/bash
+SHELL=/bin/sh
 
 BUILT_SOURCES = $(srcdir)/authors.texi
 
diff --git a/doc/announce-acknowledge.txt b/doc/announce-acknowledge.txt
index 1f9dc27..1edfc78 100644
--- a/doc/announce-acknowledge.txt
+++ b/doc/announce-acknowledge.txt
@@ -1,6 +1,9 @@
 Alphabetically ordered list to acknowledge in the next release.
 
+Hamed Altafi
+Alexey Dokuchaev
 Raúl Infante Sainz
+Sebastián Luna Valero
 
 
 
diff --git a/doc/gnuastro.texi b/doc/gnuastro.texi
index fd62f19..8b4dbc7 100644
--- a/doc/gnuastro.texi
+++ b/doc/gnuastro.texi
@@ -1097,7 +1097,8 @@ Please take the time to have a look at the following 
essays and FAQs for a compl
 @cindex Linux
 @cindex GNU/Linux
 @cindex GNU C library
-@cindex GNU Compiler Collection
+@cindex GCC: GNU Compiler Collection
+@cindex GNU Compiler Collection (GCC)
 In short, the Linux kernel@footnote{In Unix-like operating systems, the kernel 
connects software and hardware worlds.} is built using the GNU C library 
(glibc) and GNU compiler collection (gcc).
 The Linux kernel software alone is just a means for other software to access 
the hardware resources, it is useless alone: to say ``running Linux'', is like 
saying ``driving your carburetor''.
 
@@ -7728,6 +7729,14 @@ This is because of the unique position the first FITS 
extension has in the FITS
 @item --primaryimghdu
 Copy or cut an image HDU to the zero-th HDU/extension a file that doesn't yet 
exist.
 This option is thus irrelevant if the output file already exists or the 
copied/cut extension is a FITS table.
+For example with the commands below, first we make sure that @file{out.fits} 
doesn't exist, then we copy the first extension of @file{in.fits} to the 
zero-th extension of @file{out.fits}.
+
+@example
+$ rm -f out.fits
+$ astfits in.fits --copy=1 --primaryimghdu --output=out.fits
+@end example
+
+If we hadn't used @option{--primaryimghdu}, then the zero-th extension of 
@file{out.fits} would have no data, and its second extension would host the 
copied image (just like any other output of Gnuastro).
 
 @end table
 
@@ -8397,7 +8406,7 @@ To print to the standard output, set the output name to 
`@file{stdout}'.
 @cindex Image
 @cindex Color
 @cindex Pixels
-@cindex Colorspace
+@cindex Colormap
 @cindex Primary colors
 Color is defined by mixing various measurements/filters.
 In digital monitors or common digital cameras, colors are displayed/stored by 
mixing the three basic colors of red, green and blue (RGB) with various 
proportions.
@@ -8417,8 +8426,8 @@ In ConvertType, you can do this by giving each separate 
single-channel dataset (
 
 @cindex Grayscale
 @cindex Visualization
-@cindex Colorspace, HSV
-@cindex Colorspace, gray-scale
+@cindex Colormap, HSV
+@cindex Colormap, gray-scale
 @cindex HSV: Hue Saturation Value
 As discussed above, color is not defined when a dataset/image contains a 
single value for each pixel.
 However, we interact with scientific datasets through monitors or printers 
(which allow multiple values per pixel and produce color with them).
@@ -8474,8 +8483,8 @@ One line examples:
 ## Convert an image in FITS to PDF:
 $ astconvertt image.fits --output=pdf
 
-## Similar to before, but use the SLS color map:
-$ astconvertt image.fits --colormap=sls --output=pdf
+## Similar to before, but use the Viridis color map:
+$ astconvertt image.fits --colormap=viridis --output=pdf
 
 ## Convert an image in JPEG to FITS (with multiple extensions
 ## if its color):
@@ -8605,11 +8614,17 @@ However, you can limit the range of hue (to show only a 
special color range) by
 The mapping of a single-channel dataset to HSV is done through the Hue and 
Value elements: Lower dataset elements have lower ``value'' @emph{and} lower 
``hue''.
 This creates darker colors for fainter parts, while also respecting the range 
of colors.
 
+@item viridis
+@cindex matplotlib
+@cindex Colormap: Viridis
+@cindex Viridis: Colormap
+Viridis is the default colormap of the popular Matplotlib module of Python and 
available in many other visualization tools like PGFPlots.
+
 @item sls
 @cindex DS9
 @cindex SAO DS9
 @cindex SLS Color
-@cindex Colorspace: SLS
+@cindex Colormap: SLS
 The SLS color range, taken from the commonly used @url{http://ds9.si.edu,SAO 
DS9}.
 The advantage of this color range is that it ranges from black to dark blue, 
and finishes with red and white.
 So unlike the HSV color range, it includes black and white and brighter colors 
(like yellow, red and white) show the larger values.
@@ -8801,6 +8816,35 @@ $ asttable table.fits -cID,RA -cDEC \
 
 @item imgtowcs
 Similar to @code{wcstoimg}, except that image/dataset coordinates are 
converted to WCS coordinates.
+
+@item angular-distance
+Return the spherical angular distance (along a great circle, in degrees) 
between the given two points.
+Note that each point needs two coordinates (in degrees), so this operator 
needs four operands.
+The first and second popped operands are considered to belong to one point and 
the third and fourth popped operands to the second point.
+
+Each of the input points can be a single coordinate or a full table column 
(containing many points.
+In other words, the following commands are all valid:
+
+@example
+$ asttable table.fits \
+           -c"arith RA1 DEC1 RA2 DEC2 angular-distance"
+$ asttable table.fits \
+           -c"arith RA DEC 12.345 6.789 angular-distance"
+$ asttable table.fits \
+           -c"arith 12.345 6.789 RA DEC angular-distance"
+@end example
+
+In the first case we are assuming that @file{table.fits} has the following 
four columns @code{RA1}, @code{DEC1}, @code{RA2}, @code{DEC2}.
+The returned column by this operator would be the difference between two 
points in each row with coordinates like the following (@code{RA1}, 
@code{DEC1}) and (@code{RA2}, @code{DEC2}).
+In other words, for each row, the angular distance between different points is 
calculated.
+
+In the second and third cases (which are identical), it is assumed that 
@file{table.fits} has the two columns @code{RA} and @code{DEC}.
+The returned column by this operator will be the difference of each row with 
the fixed point of (12.345, 6.789).
+
+The distance (along a great circle) on a sphere between two points is 
calculated with the equation below, where @mymath{r_1}, @mymath{r_2}, 
@mymath{d_1} and @mymath{d_2} are the right ascensions and declinations of 
points 1 and 2.
+
+@dispmath {\cos(d)=\sin(d_1)\sin(d_2)+\cos(d_1)\cos(d_2)\cos(r_1-r_2)}
+
 @end table
 
 
@@ -9859,6 +9903,25 @@ Similar to @option{collapse-sum}, but the returned 
dataset will have the same nu
 @item collapse-max
 Similar to @option{collapse-sum}, but the returned dataset will have the same 
numeric type as the input and will contain the maximum value for each pixel 
along the collapsed dimension.
 
+@item add-dimension
+Build a higher-dimensional dataset from all the input datasets stacked after 
one another (along the slowest dimension).
+The first popped operand has to be a single number.
+It is used by the operator to know how many operands it should pop from the 
stack (and the size of the output in the new dimension).
+The rest of the operands must have the same size and numerical data type.
+This operator currently only works for 2D input operands, please contact us if 
you want inputs to have different dimensions.
+
+The output's WCS (which should have a different dimensionality compared to the 
inputs) can be read from another file with the @option{--wcsfile} option.
+If no file is specified for the WCS, the first dataset's WCS will be used, you 
can later add/change the necessary WCS keywords with the FITS keyword 
modification features of the Fits program (see @ref{Fits}).
+
+If your datasets don't have the same type, you can use the type transformation 
operators of Arithmetic that are discussed below.
+Just beware of overflow if you are transforming to a smaller type, see 
@ref{Numeric data types}.
+
+For example if you want to put the three @file{img1.fits}, @file{img2.fits} 
and @file{img3.fits} images (each a 2D dataset) into one 3D datacube, you can 
use this command:
+
+@example
+$ astarithmetic img1.fits img2.fits img3.fits 3 add-dimension
+@end example
+
 @item unique
 Remove all duplicate (and blank) elements from the first popped operand.
 The unique elements of the dataset will be stored in a single-dimensional 
dataset.
@@ -12594,6 +12657,19 @@ If the @option{--oneelempertile} option is called, 
then one element/pixel will b
 Otherwise, the output will have the same size as the input, but each element 
will have the value corresponding to that tile's value.
 If multiple single valued operations are called, then for each operation there 
will be one extension in the output FITS file.
 
+@item -R FLT[,FLT[,FLT...]]
+@itemx --contour=FLT[,FLT[,FLT...]]
+@cindex Contour
+@cindex Plot: contour
+Write the contours for the requested levels in a file ending with 
@file{_contour.txt}.
+It will have three columns: the first two are the coordinates of each point 
and the third is the level it belongs to (one of the input values).
+Each disconnected contour region will be separated by a blank line.
+This is the requested format for adding contours with PGFPlots in @LaTeX{}.
+If any other format can be useful for your work please let us know so we can 
add it.
+If the image has World Coordinate System information, the written coordinates 
will be in RA and Dec, otherwise, they will be in pixel coordinates.
+
+Note that currently, this is a very crude/simple implementation, please let us 
know if you find problematic situations so we can fix it.
+
 @item -y
 @itemx --sky
 Estimate the Sky value on each tile as fully described in @ref{Quantifying 
signal in a tile}.
@@ -14013,7 +14089,6 @@ images}.
 
 
 
-
 @node MakeCatalog, Match, Segment, Data analysis
 @section MakeCatalog
 
@@ -15399,7 +15474,6 @@ The first number is the semi-major axis.
 The second and third are the two axis ratios.
 The last three are the three Euler angles in units of degrees in the ZXZ order 
as fully described in @ref{Defining an ellipse and ellipsoid}.
 @end table
-
 @end table
 @end table
 
@@ -17648,8 +17722,8 @@ When the unified product has a @code{main} function, 
this function is the produc
 When the product doesn't have a @code{main} function, the linker's product is 
a library and its exported functions can be linked to other executables (it has 
many entry points).
 @end enumerate
 
-@cindex GCC
-@cindex GNU Compiler Collection
+@cindex GCC: GNU Compiler Collection
+@cindex GNU Compiler Collection (GCC)
 The GNU Compiler Collection (or GCC for short) will do all three steps.
 So as a first example, from Gnuastro's source, go to @file{tests/lib/}.
 This directory contains the library tests, you can use these as some simple 
tutorials.
@@ -17743,12 +17817,18 @@ $ astbuildprog --onlybuild myprogram.c
 @end example
 
 If BuildProgram is to run, it needs a C programming language source file as 
input.
-By default it will compile and link the program to build the a final 
executable file and run it.
+By default it will compile and link the given source into a final executable 
program and run it.
 The built executable name can be set with the optional @option{--output} 
option.
-When no output name is set, BuildProgram will use Gnuastro's @ref{Automatic 
output}, and remove the suffix of the input and use that as the output name.
+When no output name is set, BuildProgram will use Gnuastro's @ref{Automatic 
output} system to remove the suffix of the input source file (usually 
@file{.c}) and use the resulting name as the built program name.
+
 For the full list of options that BuildProgram shares with other Gnuastro 
programs, see @ref{Common options}.
 You may also use Gnuastro's @ref{Configuration files} to specify other 
libraries/headers to use for special directories and not have to type them in 
every time.
 
+The C compiler can be chosen with the @option{--cc} option, or environment 
variables, please see the description of @option{--cc} for more.
+The two common @code{LDFLAGS} and @code{CPPFLAGS} environment variables are 
also checked and used in the build by default.
+Using environment variables can be disabled with the @option{--noenv} option.
+Just note that BuildProgram also keeps the important flags in these 
environment variables in its configuration file, so in many cases, when you 
needed them to build Gnuastro, you won't need them in BuildProgram.
+
 The first argument is considered to be the C source file that must be compiled 
and linked.
 Any other arguments (non-option tokens on the command-line) will be passed 
onto the program when BuildProgram wants to run it.
 Recall that by default BuildProgram will run the program after building it.
@@ -17759,6 +17839,19 @@ When the @option{--quiet} option (see @ref{Operating 
mode options}) is not calle
 Once your program grows and you break it up into multiple files (which are 
much more easily managed with Make), you can use the linking flags of the 
non-quiet output in your @code{Makefile}.
 
 @table @option
+@item -c STR
+@itemx --cc=STR
+@cindex C compiler
+@cindex Compiler, C
+@cindex GCC: GNU Compiler Collection
+@cindex GNU Compiler Collection (GCC)
+C compiler to use for the compilation, if not given environment variables will 
be used as described in the next paragraph.
+If the compiler is in your systems's search path, you can simply give its 
name, for example @option{--cc=gcc}.
+If its not in your system's search path, you can give its full path, for 
example @option{--cc=/path/to/your/custom/cc}.
+
+If this option has no value after parsing the command-line and all 
configuration files (see @ref{Configuration file precedence}), then 
BuildProgram will look into the following environment variables in the given 
order @code{CC} and @code{GCC}.
+If they are also not defined, BuildProgram will ultimately default to the 
@command{gcc} command which is present in many systems (sometimes as a link to 
other compilers).
+
 @item -I STR
 @itemx --includedir=STR
 @cindex GNU CPP
@@ -17796,7 +17889,8 @@ See @ref{Linking} for a thorough introduction.
 @item -O INT/STR
 @itemx --optimize=INT/STR
 @cindex Optimization
-@cindex GNU Compiler Collection
+@cindex GCC: GNU Compiler Collection
+@cindex GNU Compiler Collection (GCC)
 Compiler optimization level: 0 (for no optimization, good debugging), 1, 2, 3 
(for the highest level of optimizations).
 From the GNU Compiler Collection (GCC) manual: ``Without any optimization 
option, the compiler's goal is to reduce the cost of compilation and to make 
debugging produce the expected results.
 Statements are independent: if you stop the program with a break point between 
statements, you can then assign a new value to any variable or change the 
program counter to any other statement in the function and get exactly the 
results you expect from the source code.
@@ -17844,6 +17938,15 @@ Use the given @file{.la} file (Libtool control file) 
instead of the one that was
 The Libtool control file keeps all the necessary information for building and 
linking a program with a library built by Libtool.
 The default @file{prefix/lib/libgnuastro.la} keeps all the information 
necessary to build a program using the Gnuastro library gathered during 
configure time (see @ref{Installation directory} for prefix).
 This option is useful when you prefer to use another Libtool control file.
+
+@item -e
+@itemx --noenv
+@cindex @code{CC}
+@cindex @code{GCC}
+@cindex @code{LDFLAGS}
+@cindex @code{CPPFLAGS}
+Don't use environment variables in the build, just use the values given to the 
options.
+As described above, environment variables like @code{CC}, @code{GCC}, 
@code{LDFLAGS},  @code{CPPFLAGS} will be read by default and used in the build 
if they have been defined.
 @end table
 
 
@@ -23794,6 +23897,12 @@ non-zero pixels in @code{binary} will be considered as 
foreground (and will
 be labeled). Blank pixels in the input will also be blank in the output.
 @end deftypefun
 
+@deftypefun {gal_data_t *} gal_binary_connected_indexs(gal_data_t 
@code{*binary}, int @code{connectivity})
+Build a @code{gal_data_t} linked list, where each node of the list contains an 
array with indexs of the connected regions.
+Therefore the arrays of each node can have a different size.
+Note that the indexs will only be calculated on the pixels with a value of 1 
and internally, it will temporarily change the values to 2 (and return them 
back to 1 in the end).
+@end deftypefun
+
 @deftypefun {gal_data_t *} gal_binary_connected_adjacency_matrix (gal_data_t 
@code{*adjacency}, size_t @code{*numconnected})
 @cindex Adjacency matrix
 @cindex Matrix, adjacency
@@ -25322,7 +25431,8 @@ functions that don't define too many variables and 
whose only purpose is to
 run the lower-level functions in a specific order and with checks.
 
 @cindex Optimization flag
-@cindex GNU Compiler Collection
+@cindex GCC: GNU Compiler Collection
+@cindex GNU Compiler Collection (GCC)
 In general you can be very liberal in breaking up the functions into
 smaller parts, the GNU Compiler Collection (GCC) will automatically compile
 the functions as inline functions when the optimizations are turned on. So
diff --git a/doc/release-checklist.txt b/doc/release-checklist.txt
index b176738..042ad7b 100644
--- a/doc/release-checklist.txt
+++ b/doc/release-checklist.txt
@@ -83,7 +83,7 @@ all the commits needed for this release have been completed.
  - Update the version and build Gnuastro, all done with the `-p' option of
    `./developer-build'. But we'll give it a `pure-junk' directory so it
    doesn't actually upload the build. Then go into the build directory and
-   run `make distcheck'.
+   run `make distcheck -j8'.
 
      $ ./developer-build -p pure-junk
 
diff --git a/lib/binary.c b/lib/binary.c
index 8420b86..a99461e 100644
--- a/lib/binary.c
+++ b/lib/binary.c
@@ -491,6 +491,97 @@ gal_binary_connected_components(gal_data_t *binary, 
gal_data_t **out,
 
 
 
+/* Put the indexs of connected labels in a list of `gal_data_t's, each with
+   a one-dimensional array that has the indexs of that connected
+   component.*/
+#define BINARY_CONINDEX_VAL 2
+gal_data_t *
+gal_binary_connected_indexs(gal_data_t *binary, int connectivity)
+{
+  uint8_t *b, *bf;
+  gal_data_t *lines=NULL;
+  size_t p, i, onelabnum, *onelabarr;
+  gal_list_sizet_t *Q=NULL, *onelab=NULL;
+  size_t *dinc=gal_dimension_increment(binary->ndim, binary->dsize);
+
+  /* Small sanity checks. */
+  if(binary->type!=GAL_TYPE_UINT8)
+    error(EXIT_FAILURE, 0, "%s: the input data set type must be `uint8'",
+          __func__);
+  if(binary->block)
+    error(EXIT_FAILURE, 0, "%s: currently, the input data structure to "
+          "must not be a tile", __func__);
+
+  /* Go over all the pixels and do a breadth-first search. */
+  b=binary->array;
+  for(i=0;i<binary->size;++i)
+    /* A pixel that has already been recorded is given a value of
+       `BINARY_CONINDEX_VAL'. */
+    if( b[i]==1 )
+      {
+        /* Add this pixel to the queue of pixels to work with. */
+       b[i]=BINARY_CONINDEX_VAL;
+        gal_list_sizet_add(&Q, i);
+        gal_list_sizet_add(&onelab, i);
+
+        /* While a pixel remains in the queue, continue labelling and
+           searching for neighbors. */
+        while(Q!=NULL)
+          {
+            /* Pop an element from the queue. */
+            p=gal_list_sizet_pop(&Q);
+
+            /* Go over all its neighbors and add them to the list if they
+               haven't already been labeled. */
+            GAL_DIMENSION_NEIGHBOR_OP(p, binary->ndim, binary->dsize,
+                                      connectivity, dinc,
+              {
+                if( b[nind]==1 )
+                  {
+                   b[nind]=BINARY_CONINDEX_VAL;
+                    gal_list_sizet_add(&Q, nind);
+                   gal_list_sizet_add(&onelab, nind);
+                  }
+              } );
+          }
+
+       /* Parsing has finished, put all the indexs into an array. */
+       onelabarr=gal_list_sizet_to_array(onelab, 1, &onelabnum);
+       gal_list_data_add_alloc(&lines, onelabarr, GAL_TYPE_SIZE_T, 1,
+                               &onelabnum, NULL, 0, -1, 1, NULL, NULL, NULL);
+
+       /* Clean up. */
+       gal_list_sizet_free(onelab);
+       onelab=NULL;
+      }
+
+  /* Reverse the order. */
+  gal_list_data_reverse(&lines);
+
+  /* For a check
+  {
+    gal_data_t *test=lines->next;
+    size_t *b, *bf;
+    bf=(b=test->array)+test->size;
+    do printf("%zu\n", *b++);
+    while(b<bf);
+    exit(0);
+  }
+  */
+
+  /* Set all the `2' values back to `1'. */
+  bf=(b=binary->array)+binary->size;
+  do if(*b==BINARY_CONINDEX_VAL) *b=1; while(++b<bf);
+
+  /* Clean up and return the total number. */
+  free(dinc);
+  return lines;
+}
+
+
+
+
+
 /* Given an adjacency matrix (which should be binary), find the number of
    connected objects and return an array of new labels for each old
    label.  */
diff --git a/lib/checkset.c b/lib/checkset.c
index 0cc2098..1464e1f 100644
--- a/lib/checkset.c
+++ b/lib/checkset.c
@@ -595,6 +595,49 @@ gal_checkset_automatic_output(struct 
gal_options_common_params *cp,
 
 
 
+/* Check write-ability by trying to make a temporary file. Return 0 if the
+   directory is writable, and `errno' if it isn't. We won't be using
+   `facccessat' because its not available on some systems (macOS 10.9 and
+   earlier, see https://github.com/conda-forge/staged-recipes/pull/9723
+   ). */
+static int
+checkset_directory_writable(char *dirname)
+{
+  int file_d;
+  int errnum=0;
+  char *tmpname;
+
+  /* Set the template for the temporary file (accounting for the possible
+     extra `/'). */
+  if(dirname[strlen(dirname)-1]=='/')
+    tmpname=gal_checkset_malloc_cat(dirname, "gnuastroXXXXXX");
+  else
+    tmpname=gal_checkset_malloc_cat(dirname, "/gnuastroXXXXXX");
+
+  /* Make the temporary file (with the temporary name) and open it. */
+  errno=0;
+  file_d=mkstemp(tmpname);
+
+  /* See if the file was opened (and thus created). */
+  if(file_d==-1) errnum=errno;
+  else
+    { /* The file was created, close the file. */
+      errno=0;
+      if( close(file_d) == -1 ) errnum=errno;
+      else
+        {/* The file was closed, delete it. */
+          errno=0;
+          if(unlink(tmpname)==-1) errnum=errno;
+        }
+    }
+
+  /* Return the final value. */
+  return errnum;
+}
+
+
+
+
 /* Check if dirname is actually a real directory and that we can
    actually write inside of it. To insure all conditions an actual
    file will be made */
@@ -645,26 +688,27 @@ gal_checkset_check_dir_write_add_slash(char **dirname)
 
 
 
-/* If the given directory exists and is writable, then nothing is done. If
-   it doesn't, it will be created. If it fails at creating the file, or the
-   file isn't writable it returns a non-zero value: the errno, which can be
-   directly used in `error'. */
+/* If the given directory exists and is writable, then nothing is done and
+   this function returns 0. If it doesn't, it will be created. If it fails
+   at creating the file, or the file isn't writable it returns a non-zero
+   value: the errno, which can be directly used in `error'. */
 int
 gal_checkset_mkdir(char *dirname)
 {
   int errnum=0;
   struct stat st={0};
+
+  /* See if the directory exists. */
   if( stat(dirname, &st) == -1 )
-    {
+    { /* The directory doesn't exist, try making it. */
       errno=0;
       if( mkdir(dirname, 0700) == -1 )
         errnum=errno;
     }
   else
-    {
-      errno=0;
-      if( faccessat(AT_FDCWD, dirname, W_OK, AT_EACCESS) == -1 )
-        errnum=errno;
-    }
+    /* The directory exists, see if its writable. */
+    errnum=checkset_directory_writable(dirname);
+
+  /* Return the final `errno'. */
   return errnum;
 }
diff --git a/lib/fits.c b/lib/fits.c
index 06f7381..82af7e0 100644
--- a/lib/fits.c
+++ b/lib/fits.c
@@ -1592,6 +1592,10 @@ gal_fits_key_write_version_in_ptr(gal_fits_list_key_t 
**keylist, char *title,
   const char *wcslibversion_const;
 #endif
 
+  /* Small sanity check. */
+  if(fptr==NULL)
+    error(EXIT_FAILURE, 0, "%s: input FITS pointer is NULL", __func__);
+
   /* If any header keywords are specified, add them: */
   if(keylist && *keylist)
     {
diff --git a/lib/gnuastro/binary.h b/lib/gnuastro/binary.h
index 5a4b391..786cfd9 100644
--- a/lib/gnuastro/binary.h
+++ b/lib/gnuastro/binary.h
@@ -90,6 +90,9 @@ gal_binary_connected_components(gal_data_t *binary, 
gal_data_t **out,
                                 int connectivity);
 
 gal_data_t *
+gal_binary_connected_indexs(gal_data_t *binary, int connectivity);
+
+gal_data_t *
 gal_binary_connected_adjacency_matrix(gal_data_t *adjacency,
                                       size_t *numnewlabs);
 
diff --git a/lib/options.c b/lib/options.c
index d29b32f..b71d8c3 100644
--- a/lib/options.c
+++ b/lib/options.c
@@ -270,7 +270,7 @@ gal_options_print_citation(struct argp_option *option, char 
*arg,
     "        eid = {1},\n"
     "      pages = {1},\n"
     "        doi = {10.1088/0067-0049/220/1/1},\n"
-    "     adsurl = {http://adsabs.harvard.edu/abs/2015ApJS..220....1A},\n";
+    "     adsurl = {https://ui.adsabs.harvard.edu/abs/2015ApJS..220....1A},\n";
     "    adsnote = {Provided by the SAO/NASA Astrophysics Data System}\n"
     "  }";
 
diff --git a/lib/wcs.c b/lib/wcs.c
index b838db2..d0f9a77 100644
--- a/lib/wcs.c
+++ b/lib/wcs.c
@@ -847,6 +847,10 @@ wcs_convert_sanity_check_alloc(gal_data_t *coords, struct 
wcsprm *wcs,
   gal_data_t *tmp;
   size_t ndim=0, firstsize=0, size=coords->size;
 
+  /* Make sure a WCS structure is actually given. */
+  if(wcs==NULL)
+    error(EXIT_FAILURE, 0, "%s: input WCS structure is NULL", func);
+
   for(tmp=coords; tmp!=NULL; tmp=tmp->next)
     {
       /* Count how many coordinates are given. */
@@ -961,13 +965,13 @@ gal_data_t *
 gal_wcs_world_to_img(gal_data_t *coords, struct wcsprm *wcs, int inplace)
 {
   gal_data_t *out;
-  int status, *stat=NULL, ncoord=coords->size, nelem=wcs->naxis;
+  int status, *stat=NULL, ncoord=coords->size, nelem;
   double *phi=NULL, *theta=NULL, *world=NULL, *pixcrd=NULL, *imgcrd=NULL;
 
   /* Some sanity checks. */
   wcs_convert_sanity_check_alloc(coords, wcs, __func__, &stat, &phi, &theta,
                                  &world, &pixcrd, &imgcrd);
-
+  nelem=wcs->naxis; /* We have to make sure a WCS is given first. */
 
   /* Write the values from the input list of separate columns into a single
      array (WCSLIB input). */
@@ -1022,12 +1026,13 @@ gal_data_t *
 gal_wcs_img_to_world(gal_data_t *coords, struct wcsprm *wcs, int inplace)
 {
   gal_data_t *out;
-  int status, *stat=NULL, ncoord=coords->size, nelem=wcs->naxis;
+  int status, *stat=NULL, ncoord=coords->size, nelem;
   double *phi=NULL, *theta=NULL, *world=NULL, *pixcrd=NULL, *imgcrd=NULL;
 
   /* Some sanity checks. */
   wcs_convert_sanity_check_alloc(coords, wcs, __func__, &stat, &phi, &theta,
                                  &world, &pixcrd, &imgcrd);
+  nelem=wcs->naxis; /* We have to make sure a WCS is given first. */
 
 
   /* Write the values from the input list of separate columns into a single



reply via email to

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