home *** CD-ROM | disk | FTP | other *** search
- /*--------------------------------------------------------------------
- * The GMT-system: @(#)grd2cpt.c 2.12 08 Jun 1995
- *
- * Copyright (c) 1991-1995 by P. Wessel and W. H. F. Smith
- * See README file for copying and redistribution conditions.
- *--------------------------------------------------------------------*/
- /*
- * grd2cpt reads a 2d binary gridded grdfile and creates a continous-color-
- * pallette cpt file, with a non-linear histogram-equalized mapping between
- * hue and data value. (The linear mapping can be made with makecpt.)
- *
- * Creates a cumulative distribution function f(z) describing the data
- * in the grdfile. f(z) is sampled at z values supplied by the user
- * [with -S option] or guessed from the sample mean and standard deviation.
- * f(z) is then found by looping over the grd array for each z and counting
- * data values <= z. Once f(z) is found then
- * hue(z) = hue_min + (hue_max - hue_min) * f(z), where hue_min and
- * hue_max can be set by user or default to 300, 0.
- *
- * The goal here is to have something that gets the inexperienced user
- * started with a .cpt file that will do nice image processing.
- *
- * Author: Walter H. F. Smith
- * Date: 12-JAN-1994
- *
- */
-
- #include "gmt.h"
-
- struct CDF_CPT {
- double z; /* Data value */
- double f; /* Cumulative distribution function f(z) */
- } *cdf_cpt = NULL;
-
- main (argc, argv)
- int argc;
- char **argv;
- {
-
- int i, j, nxy, nfound, ngood, ncdf, pad[4];
- int lastr, lastg, lastb, thisr, thisg, thisb;
-
- BOOLEAN error = FALSE, set_limits = FALSE, set_z_vals = FALSE, monochrome = FALSE;
-
- double min_limit, max_limit, min_hue, max_hue;
- double lasthue, thishue, sat, val;
- double z_start, z_stop, z_inc;
- double mean, sd, min_gray, max_gray;
-
- char *grdfile;
-
- struct GRD_HEADER grd;
-
- float *zdata;
-
- min_hue = 300.0;
- max_hue = 0.0;
- min_gray = 0.0;
- max_gray = 1.0;
- grdfile = CNULL;
- pad[3] = pad[2] = pad[1] = pad[0] = 0;
-
- argc = gmt_begin (argc, argv);
-
- for (i = 1; !error && i < argc; i++) {
- if (argv[i][0] == '-') {
- switch (argv[i][1]) {
-
- /* Common parameters */
-
- case 'V':
- case '\0':
- error += get_common_args (argv[i], 0, 0, 0, 0);
- break;
-
- /* Supplemental parameters */
-
- case 'C':
- if (sscanf(&argv[i][2], "%lf/%lf", &min_hue, &max_hue) != 2) {
- fprintf(stderr,"%s: GMT SYNTAX ERROR -C option: Cannot decode hues\n", gmt_program);
- error++;
- }
- else {
- if (min_hue < 0.0 || min_hue >= 360.0 || max_hue < 0.0 || max_hue > 360.0) {
- fprintf(stderr,"%s: GMT SYNTAX ERROR -C option: Hues our of 0-360 range\n", gmt_program);
- error++;
- }
- }
- break;
- case 'L':
- if (sscanf(&argv[i][2], "%lf/%lf", &min_limit, &max_limit) != 2) {
- fprintf(stderr,"%s: GMT SYNTAX ERROR -L option: Cannot decode limits\n", gmt_program);
- error++;
- }
- else {
- if (min_limit >= max_limit) {
- fprintf(stderr,"%s: GMT SYNTAX ERROR -L option: min_limit must be less than max_limit.\n", gmt_program);
- error++;
- }
- }
- if (!error) set_limits = TRUE;
- break;
- case 'M':
- monochrome = TRUE;
- if (argv[i][2] && sscanf(&argv[i][2], "%lf/%lf", &min_gray, &max_gray) != 2) {
- fprintf(stderr,"%s: GMT SYNTAX ERROR -M option: Cannot decode gray values\n", gmt_program);
- error++;
- }
- break;
- case 'S':
- if (sscanf(&argv[i][2], "%lf/%lf/%lf", &z_start, &z_stop, &z_inc) != 3) {
- fprintf(stderr,"%s: GMT SYNTAX ERROR -S option: Cannot decode values\n", gmt_program);
- error++;
- }
- else {
- if (z_stop <= z_start || z_inc <= 0.0) {
- fprintf(stderr,"%s: GMT SYNTAX ERROR -S option: Bad arguments\n", gmt_program);
- error++;
- }
- }
- if (!error) set_z_vals = TRUE;
- break;
-
- default:
- error = TRUE;
- gmt_default_error (argv[i][1]);
- break;
- }
- }
- else {
- grdfile = argv[i];
- if (read_grd_info (grdfile, &grd)) {
- fprintf (stderr, "grd2cpt: Error opening file %s\n", grdfile);
- error++;
- }
- }
- }
-
- if (argc == 1 || gmt_quick) {
- fprintf (stderr,"grd2cpt %s - Make a histogram-equalized color palette table from a grdfile\n\n", GMT_VERSION);
- fprintf (stderr, "usage: grd2cpt <grdfile> [-C<min_hue>/<max_hue>] [-L<min_limit>/<max_limit>]\n");
- fprintf (stderr, " [-M[<mingray>/<maxgray>]] [-S<z_start>/<z_stop>/<z_inc>] [-V]\n");
-
- if (gmt_quick) exit(-1);
-
- fprintf (stderr, " <grdfile> is the name of the 2-D binary data set\n");
- fprintf (stderr, "\n\tOPTIONS:\n");
- explain_option ('H');
- fprintf (stderr, " -C Set the hues to use at min and max data values. [300/0].\n");
- fprintf (stderr, " -L Limit the range of the data [Default uses actual min,max of data].\n");
- fprintf (stderr, " -M Set Monochrome (gray). Optionally set the gray levels for min,max data,\n");
- fprintf (stderr, " using a scale where 0 = black and 1 = white. [0/1]\n");
- fprintf (stderr, " -S Sample points should Step from z_start to z_stop by z_inc [Default guesses some values].\n");
- explain_option ('V');
- exit(-1);
- }
-
- if (error) exit (-1);
-
- nxy = grd.nx * grd.ny;
- zdata = (float *) memory (CNULL, nxy, sizeof (float), "grd2cpt");
-
- if (read_grd (grdfile, &grd, zdata, 0.0, 0.0, 0.0, 0.0, pad, FALSE) ) {
- fprintf(stderr,"grd2cpt: Error reading grdfile.\n");
- free((char *)zdata);
- exit(-1);
- }
-
- /* Loop over the file and find NaNs. If set limits, may create more NaNs */
- nfound = 0;
- mean = 0.0;
- sd = 0.0;
- if (set_limits) {
- /* Loop over the grdfile, and set anything outside the limiting values to NaN. */
-
- grd.z_min = min_limit;
- grd.z_max = max_limit;
- for (i = 0; i < nxy; i++) {
- if (bad_float ((double)zdata[i]))
- nfound++;
- else {
- if (zdata[i] < min_limit || zdata[i] > max_limit) {
- nfound++;
- zdata[i] = gmt_NaN;
- }
- else {
- mean += zdata[i];
- sd += zdata[i] * zdata[i];
- }
- }
- }
- }
- else {
- min_limit = grd.z_max; /* This is just to double check grd.z_min, grd.z_max */
- max_limit = grd.z_min;
- for (i = 0; i < nxy; i++) {
- if (bad_float ((double)zdata[i]))
- nfound++;
- else {
- if (zdata[i] < min_limit) min_limit = zdata[i];
- if (zdata[i] > max_limit) max_limit = zdata[i];
- mean += zdata[i];
- sd += zdata[i] * zdata[i];
- }
- }
- grd.z_min = min_limit;
- grd.z_max = max_limit;
- }
- ngood = nxy - nfound; /* This is the number of non-NaN points for the cdf function */
- mean /= ngood;
- sd /= ngood;
- sd = sqrt(sd - mean*mean);
- if (gmtdefs.verbose) fprintf(stderr,"grd2cpt: Mean and S.D. of data are %.8lg %.8lg\n", mean, sd);
-
- /* Now the zdata are ready. Decide how to make steps in z. */
- if (set_z_vals) {
- ncdf = (grd.z_min < z_start) ? 1 : 0;
- ncdf += floor((z_stop - z_start)/z_inc) + 1;
- if (grd.z_max > z_stop) ncdf++;
- cdf_cpt = (struct CDF_CPT *)memory(CNULL, ncdf, sizeof(struct CDF_CPT), "grd2cpt");
- if (grd.z_min < z_start) {
- cdf_cpt[0].z = grd.z_min;
- cdf_cpt[1].z = z_start;
- i = 2;
- }
- else {
- cdf_cpt[0].z = z_start;
- i = 1;
- }
- j = (grd.z_max > z_stop) ? ncdf - 1 : ncdf;
- while (i < j) {
- cdf_cpt[i].z = cdf_cpt[i-1].z + z_inc;
- i++;
- }
- if (j == ncdf-1) cdf_cpt[j].z = grd.z_max;
- }
- else {
- /* This is completely ad-hoc. It chooses z based on steps
- of 0.1 for a Gaussian CDF: */
- ncdf = 11;
- cdf_cpt = (struct CDF_CPT *)memory(CNULL, ncdf, sizeof(struct CDF_CPT), "grd2cpt");
- cdf_cpt[0].z = grd.z_min;
- cdf_cpt[1].z = mean - 1.28155 * sd;
- cdf_cpt[2].z = mean - 0.84162 * sd;
- cdf_cpt[3].z = mean - 0.52440 * sd;
- cdf_cpt[4].z = mean - 0.25335 * sd;
- cdf_cpt[5].z = mean;
- cdf_cpt[6].z = mean + 0.25335 * sd;
- cdf_cpt[7].z = mean + 0.52440 * sd;
- cdf_cpt[8].z = mean + 0.84162 * sd;
- cdf_cpt[9].z = mean + 1.28155 * sd;
- cdf_cpt[10].z = grd.z_max;
- }
-
- /* Get here when we are ready to go. cdf_cpt[].z contains the sample points. */
- for (j = 0; j < ncdf; j++) {
- if (cdf_cpt[j].z <= grd.z_min)
- cdf_cpt[j].f = 0.0;
- else if (cdf_cpt[j].z >= grd.z_max)
- cdf_cpt[j].f = 1.0;
- else {
- nfound = 0;
- for (i = 0; i < nxy; i++) {
- if (!bad_float((double)zdata[i]) && zdata[i] <= cdf_cpt[j].z) nfound++;
- }
- cdf_cpt[j].f = (double)(nfound-1)/(double)(ngood-1);
- }
- if (gmtdefs.verbose) fprintf (stderr, "grd2cpt: z = %.8lg and CDF(z) = %.8lg\n",
- cdf_cpt[j].z, cdf_cpt[j].f);
- }
-
- /* Now the cdf function has been found. We get hsv and then covert to rgb as needed */
- if (monochrome) {
- if (gmtdefs.color_model) {
- /* Make a monochrome HSV file. */
- for (j = 1; j < ncdf; j++) {
- printf("%.6lg\t0\t0\t%.6lg\t%.6lg\t0\t0\t%.6lg\n",
- cdf_cpt[j-1].z, min_gray + (max_gray - min_gray) * cdf_cpt[j-1].f,
- cdf_cpt[j].z, min_gray + (max_gray - min_gray) * cdf_cpt[j].f);
- }
- }
- else {
- /* Make an r,g,b gray file */
- lasthue = min_gray + (max_gray - min_gray) * cdf_cpt[0].f;
- lastr = floor(255.0 * lasthue);
- for (j = 1; j < ncdf; j++) {
- thishue = min_gray + (max_gray - min_gray) * cdf_cpt[j].f;
- thisr = floor(255.0 * thishue);
- printf("%.6lg\t%d\t%d\t%d\t%.6lg\t%d\t%d\t%d\n",
- cdf_cpt[j-1].z, lastr, lastr, lastr, cdf_cpt[j].z, thisr, thisr, thisr);
- lasthue = thishue;
- lastr = thisr;
- }
- }
- }
- else {
- if (gmtdefs.color_model) {
- sat = gmtdefs.hsv_min_saturation;
- val = gmtdefs.hsv_max_value;
- }
- else {
- sat = val = 1.0;
- }
- lasthue = min_hue;
- if (!gmtdefs.color_model) gmt_hsv_to_rgb (&lastr, &lastg, &lastb, lasthue, sat, val);
-
- for (j = 1; j < ncdf; j++) {
- thishue = min_hue + (max_hue - min_hue) * cdf_cpt[j].f;
- if (gmtdefs.color_model) {
- printf("%.6lg\t%.6lg\t%.6lg\t%.6lg\t%.6lg\t%.6lg\t%.6lg\t%.6lg\n",
- cdf_cpt[j-1].z, lasthue, sat, val, cdf_cpt[j].z, thishue, sat, val);
- }
- else {
- gmt_hsv_to_rgb (&thisr, &thisg, &thisb, thishue, sat, val);
- printf("%.6lg\t%d\t%d\t%d\t%.6lg\t%d\t%d\t%d\n",
- cdf_cpt[j-1].z, lastr, lastg, lastb, cdf_cpt[j].z, thisr, thisg, thisb);
- lastr = thisr;
- lastg = thisg;
- lastb = thisb;
- }
- lasthue = thishue;
- }
- }
-
- free ((char *)cdf_cpt);
- free ((char *)zdata);
-
- gmt_end (argc, argv);
- }
-