home *** CD-ROM | disk | FTP | other *** search
- /*--------------------------------------------------------------------
- * The GMT-system: @(#)gmt_support.c 2.49 28 Jul 1995
- *
- * Copyright (c) 1991-1995 by P. Wessel and W. H. F. Smith
- * See README file for copying and redistribution conditions.
- *--------------------------------------------------------------------*/
- /*
- *
- * G M T _ S U P P O R T . C
- *
- *- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- * gmt_support.c contains code used by most GMT programs
- *
- * Author: Paul Wessel
- * Date: 27-JUL-1992
- * Version: 2.1
- *
- * Modules in this file:
- *
- * akima Akima's 1-D spline
- * check_rgb Check rgb for valid range
- * check_region Check region in -R for valid range
- * comp_double_asc Used when sorting doubles into ascending order [checks for NaN]
- * comp_float_asc Used when sorting floats into ascending order [checks for NaN]
- * contours Subroutine for contouring
- * cspline/csplint Natural cubic 1-D spline
- * bcr_init Initialize structure for bicubic interpolation
- * delaunay Performs a Delaunay triangulation
- * get_bcr_z Get bicubic interpolated value
- * get_bcr_nodal_values Supports -"-
- * get_bcr_cardinals "
- * get_bcr_ij "
- * get_bcr_xy "
- * get_index Return color table entry for given z
- * get_format : Find # of decimals and create format string
- * get_rgb24 Return rgb for given z
- * get_plot_array Allocate memory for plotting arrays
- * free_plot_array Free such memory
- * gmt_getfill Decipher and check fill argument
- * gmt_getinc Decipher and check increment argument
- * gmt_getpen Decipher and check pen argument
- * gmt_getrgb Dechipher and check color argument
- * gmt_init_fill Initialize fill attributes
- * gmt_init_pen Initialize pen attributes
- * grd_init : Initialize grd header structure
- * grd_shift : Rotates grdfiles in x-direction
- * grd_setregion : Determines subset coordinates for grdfiles
- * gmt_hsv_to_rgb Convert HSV to RGB
- * illuminate Add illumination effects to rgb
- * intpol 1-D interpolation
- * memory Memory allocation/reallocation
- * median Finds the median without sorting
- * non_zero_winding Finds if a point is inside/outside a polygon
- * plane Find best-fitting plane to grd matrix
- * read_cpt Read color palette file
- * gmt_rgb_to_hsv Convert RGB to HSV
- * set_bcr_boundaries Sets natural boundary conditions at grid edges
- * smooth_contour Use Akima's spline to smooth contour
- * start_trace Subfunction used by trace_contour
- * trace_contour Function that trace the contours in contours
- */
-
- #include "gmt.h"
- #include "gmt_bcr.h"
-
- #define I_255 (1.0 / 255.0)
-
- int check_rgb (r, g, b)
- int r, g, b; {
- return (( (r < 0 || r > 255) || (g < 0 || g > 255) || (b < 0 || b > 255) ));
- }
-
- int check_region (w, e, s, n)
- double w, e, s, n; { /* If region is given then we must have w < e and s < n */
- return ((w >= e || s >= n) && project_info.region);
- }
-
- int gmt_init_fill (fill, r, g, b)
- struct FILL *fill;
- int r, g, b; { /* Initialize FILL structure */
- fill->use_pattern = fill->inverse = FALSE;
- fill->pattern[0] = 0;
- fill->pattern_no = 0;
- fill->icon_size = 0.0;
- fill->r = r; fill->g = g; fill->b = b;
- }
-
- int gmt_getfill (line, fill)
- char *line;
- struct FILL *fill; {
- int n, count, error = FALSE, slash_count();
-
- if (line[0] == 'p' || line[0] == 'P') { /* Pattern specified */
- n = sscanf (&line[1], "%lf/%s", &fill->icon_size, fill->pattern);
- if (n != 2) error = TRUE;
- fill->pattern_no = atoi (fill->pattern);
- if (fill->pattern_no == 0) fill->pattern_no = -1;
- fill->inverse = !(line[0] == 'P');
- fill->use_pattern = TRUE;
- }
- else { /* Plain color or shade */
- if ((count = slash_count (line)) == 2)
- n = sscanf (line, "%d/%d/%d", &fill->r, &fill->g, &fill->b);
- else if (count == 0) {
- n = sscanf (line, "%d", &fill->r);
- fill->g = fill->b = fill->r;
- }
- else
- n = 0;
- fill->use_pattern = FALSE;
- error = (n < 1 || n > 3) ? TRUE : check_rgb (fill->g, fill->b, fill->r);
- }
- return (error);
- }
-
- int slash_count (txt)
- char *txt; {
- int i = 0, n = 0;
- while (txt[i]) if (txt[i++] == '/') n++;
- return (n);
- }
-
- int gmt_getrgb (line, r, g, b)
- char *line;
- int *r, *g, *b; {
- int n, count, slash_count();
-
- if ((count = slash_count (line)) == 2)
- n = sscanf (line, "%d/%d/%d", r, g, b);
- else if (count == 0) {
- n = sscanf (line, "%d", r);
- *g = *b = *r;
- }
- else
- n = 0;
- return (n < 1 || n > 3 || check_rgb (*r, *g, *b));
- }
-
- int gmt_init_pen (pen, width)
- struct PEN *pen;
- int width; {
- pen->width = width;
- pen->r = gmtdefs.basemap_frame_rgb[0];
- pen->g = gmtdefs.basemap_frame_rgb[1];
- pen->b = gmtdefs.basemap_frame_rgb[2];
- pen->texture[0] = 0;
- pen->offset = 0;
- }
-
- int gmt_getpen (line, pen)
- char *line;
- struct PEN *pen; {
- int i, n_slash, t_pos, c_pos, s_pos, width;
- BOOLEAN get_pen, points = FALSE;
- double val = 0.0;
-
- /* Check for p which means pen thickness is given in points */
-
- points = (BOOLEAN) strchr (line, 'p');
-
- /* First check if a pen thickness has been entered */
-
- get_pen = ((line[0] == '-' && (line[1] >= '0' && line[1] <= '9')) || (line[0] >= '0' && line[0] <= '9'));
-
- /* Then look for slash which indicate start of color information */
-
- for (i = n_slash = 0, s_pos = -1; line[i]; i++) if (line[i] == '/') {
- n_slash++;
- if (s_pos < 0) s_pos = i; /* First slash position */
- }
-
- /* Finally see if a texture is given */
-
- for (i = 0, t_pos = -1; line[i] && t_pos == -1; i++) if (line[i] == 't') t_pos = i;
-
- /* Now decode values */
-
- if (get_pen) { /* Decode pen width */
- val = atof (line);
- pen->width = (points) ? rint (val * gmtdefs.dpi / gmt_ppu[gmtdefs.measure_unit]) : rint (val);
- }
- if (s_pos >= 0) { /* Get color of pen */
- s_pos++;
- if (n_slash == 1) { /* Gray shade is given */
- sscanf (&line[s_pos], "%d", &pen->r);
- pen->g = pen->b = pen->r;
- }
- else if (n_slash == 3) /* Color is given */
- sscanf (&line[s_pos], "%d/%d/%d", &pen->r, &pen->g, &pen->b);
- }
-
- if (t_pos >= 0) { /* Get texture */
- t_pos++;
- if (line[t_pos] == 'o') { /* Dotted */
- width = (pen->width == 0) ? 1 : pen->width;
- sprintf (pen->texture, "%d %d\0", width, 4 * width);
- pen->offset = 0;
- }
- else if (line[t_pos] == 'a') { /* Dashed */
- width = (pen->width == 0) ? 1 : pen->width;
- sprintf (pen->texture, "%d %d\0", 8 * width, 8 * width);
- pen->offset = 4 * width;
- }
- else { /* Specified pattern */
- for (i = t_pos+1, c_pos = 0; line[i] && c_pos == 0; i++) if (line[i] == ':') c_pos = i;
- if (c_pos == 0) return (pen->width < 0 || check_rgb (pen->r, pen->g, pen->b));
- line[c_pos] = ' ';
- sscanf (&line[t_pos], "%s %d", pen->texture, &pen->offset);
- line[c_pos] = ':';
- for (i = 0; pen->texture[i]; i++) if (pen->texture[i] == '_') pen->texture[i] = ' ';
- if (points) { /* Must convert points to current dpi */
- char tmp[10], string[BUFSIZ], *ptr;
-
- ptr = strtok (pen->texture, " ");
- memset (string, 0, BUFSIZ);
- while (ptr) {
- sprintf (tmp, "%d \0", (int) rint (atof (ptr) * gmtdefs.dpi / gmt_ppu[gmtdefs.measure_unit]));
- strcat (string, tmp);
- ptr = strtok (CNULL, " ");
- }
- string[strlen (string) - 1] = 0;
- strcpy (pen->texture, string);
- pen->offset = rint (pen->offset * gmtdefs.dpi / gmt_ppu[gmtdefs.measure_unit]);
- }
-
- }
- }
- return (pen->width < 0 || check_rgb (pen->r, pen->g, pen->b));
- }
-
- int gmt_getinc (line, dx, dy)
- char *line;
- double *dx, *dy; {
- int t_pos, i;
- char xstring[80], ystring[80];
-
- for (t_pos = -1, i = 0; line[i] && t_pos < 0; i++) if (line[i] == '/') t_pos = i;
-
- if (t_pos != -1) {
- strcpy (xstring, line);
- xstring[t_pos] = 0;
- if (t_pos > 0 && (xstring[t_pos-1] == 'm' || xstring[t_pos-1] == 'M') ) {
- xstring[t_pos-1] = 0;
- if ( (sscanf(xstring, "%lf", dx)) != 1) return(1);
- (*dx) /= 60.0;
- }
- else if (t_pos > 0 && (xstring[t_pos-1] == 'c' || xstring[t_pos-1] == 'C') ) {
- xstring[t_pos-1] = 0;
- if ( (sscanf(xstring, "%lf", dx)) != 1) return(1);
- (*dx) /= 3600.0;
- }
- else {
- if ( (sscanf(xstring, "%lf", dx)) != 1) return(1);
- }
-
- strcpy (ystring, &line[t_pos+1]);
- t_pos = strlen(ystring);
- if (t_pos > 0 && (ystring[t_pos-1] == 'm' || ystring[t_pos-1] == 'M') ) {
- ystring[t_pos-1] = 0;
- if ( (sscanf(ystring, "%lf", dy)) != 1) return(1);
- (*dy) /= 60.0;
- }
- else if (t_pos > 0 && (ystring[t_pos-1] == 'c' || ystring[t_pos-1] == 'C') ) {
- ystring[t_pos-1] = 0;
- if ( (sscanf(ystring, "%lf", dy)) != 1) return(1);
- (*dy) /= 3600.0;
- }
- else {
- if ( (sscanf(ystring, "%lf", dy)) != 1) return(1);
- }
- }
- else {
- t_pos = strlen(line);
- if (t_pos > 0 && (line[t_pos-1] == 'm' || line[t_pos-1] == 'M') ) {
- line[t_pos-1] = 0;
- if ( (sscanf(line, "%lf", dx)) != 1) return(1);
- (*dx) /= 60.0;
- }
- else if (t_pos > 0 && (line[t_pos-1] == 'c' || line[t_pos-1] == 'C') ) {
- line[t_pos-1] = 0;
- if ( (sscanf(line, "%lf", dx)) != 1) return(1);
- (*dx) /= 3600.0;
- }
- else {
- if ( (sscanf(line, "%lf", dx)) != 1) return(1);
- }
- *dy = (*dx);
- }
- return(0);
- }
-
- int read_cpt (cpt_file)
- char *cpt_file; {
- /* Opens and reads a color palette file in RGB or HSV of arbitrary length */
-
- int n = 0, i, nread, n_alloc = GMT_SMALL_CHUNK;
- double r0, r1, g0, g1, b0, b1;
- BOOLEAN gap, error = FALSE;
- char line[512], c;
- FILE *fp = NULL;
-
- if ((fp = fopen (cpt_file, "r")) == NULL) {
- fprintf (stderr, "GMT Fatal Error: Cannot open color palette table %s\n", cpt_file);
- exit (-1);
- }
-
- gmt_lut = (struct GMT_LUT *) memory (CNULL, n_alloc, sizeof (struct GMT_LUT), "read_cpt");
-
- gmt_b_and_w = gmt_gray = TRUE;
- gmt_continuous = FALSE;
-
- while (!error && fgets (line, 512, fp)) {
-
- if (line[0] == '#') continue; /* Comment */
-
- if (line[0] == 'F' || line[0] == 'f') { /* Foreground color */
- nread = sscanf (&line[1], "%lf %lf %lf", &r0, &g0, &b0);
- if (!(nread == 1 || nread == 3)) error = TRUE;
- if (nread == 1 || gmtdefs.color_model == 0) { /* Read r,g,b or gray */
- if (nread == 1) /* Grayshades given */
- gmtdefs.foreground_rgb[0] = gmtdefs.foreground_rgb[1] = gmtdefs.foreground_rgb[2] = r0;
- else {
- gmtdefs.foreground_rgb[0] = r0;
- gmtdefs.foreground_rgb[1] = g0;
- gmtdefs.foreground_rgb[2] = b0;
- }
- }
- else
- gmt_hsv_to_rgb (&gmtdefs.foreground_rgb[0], &gmtdefs.foreground_rgb[1], &gmtdefs.foreground_rgb[2], r0, g0, b0);
- if (!(gmtdefs.foreground_rgb[0] == gmtdefs.foreground_rgb[1] && gmtdefs.foreground_rgb[0] == gmtdefs.foreground_rgb[2])) gmt_gray = FALSE;
- if (gmt_gray && !(gmtdefs.foreground_rgb[0] == 0 || gmtdefs.foreground_rgb[0] == 255)) gmt_b_and_w = FALSE;
- continue;
- }
- else if (line[0] == 'B' || line[0] == 'b') { /* Background color */
- nread = sscanf (&line[1], "%lf %lf %lf", &r0, &g0, &b0);
- if (!(nread == 1 || nread == 3)) error = TRUE;
- if (nread == 1 || gmtdefs.color_model == 0) { /* Read r,g,b or gray*/
- if (nread == 1) /* Grayshades given */
- gmtdefs.background_rgb[0] = gmtdefs.background_rgb[1] = gmtdefs.background_rgb[2] = r0;
- else {
- gmtdefs.background_rgb[0] = r0;
- gmtdefs.background_rgb[1] = g0;
- gmtdefs.background_rgb[2] = b0;
- }
- }
- else
- gmt_hsv_to_rgb (&gmtdefs.background_rgb[0], &gmtdefs.background_rgb[1], &gmtdefs.background_rgb[2], r0, g0, b0);
- if (!(gmtdefs.background_rgb[0] == gmtdefs.background_rgb[1] && gmtdefs.background_rgb[0] == gmtdefs.background_rgb[2])) gmt_gray = FALSE;
- if (gmt_gray && !(gmtdefs.background_rgb[0] == 0 || gmtdefs.background_rgb[0] == 255)) gmt_b_and_w = FALSE;
- continue;
- }
- else if (line[0] == 'N' || line[0] == 'n') { /* NaN color */
- nread = sscanf (&line[1], "%lf %lf %lf", &r0, &g0, &b0);
- if (!(nread == 1 || nread == 3)) error = TRUE;
- if (nread == 1 || gmtdefs.color_model == 0) { /* Read r,g,b */
- if (nread == 1) /* Grayshades given */
- gmtdefs.nan_rgb[0] = gmtdefs.nan_rgb[1] = gmtdefs.nan_rgb[2] = r0;
- else {
- gmtdefs.nan_rgb[0] = r0;
- gmtdefs.nan_rgb[1] = g0;
- gmtdefs.nan_rgb[2] = b0;
- }
- }
- else
- gmt_hsv_to_rgb (&gmtdefs.nan_rgb[0], &gmtdefs.nan_rgb[1], &gmtdefs.nan_rgb[2], r0, g0, b0);
- if (!(gmtdefs.nan_rgb[0] == gmtdefs.nan_rgb[1] && gmtdefs.nan_rgb[0] == gmtdefs.nan_rgb[2])) gmt_gray = FALSE;
- if (gmt_gray && !(gmtdefs.nan_rgb[0] == 0 || gmtdefs.nan_rgb[0] == 255)) gmt_b_and_w = FALSE;
- continue;
- }
-
- nread = sscanf (line, "%lf %lf %lf %lf %lf %lf %lf %lf",
- &gmt_lut[n].z_low, &r0, &g0, &b0, &gmt_lut[n].z_high, &r1, &g1, &b1);
- if (!(nread == 4 || nread == 8)) error = TRUE;
-
- if (nread == 4 || gmtdefs.color_model == 0) { /* Read r,b,g or gray */
- if (nread == 4) { /* Grayshades given */
- gmt_lut[n].z_high = g0;
- r1 = b0;
- gmt_lut[n].rgb_low[0] = gmt_lut[n].rgb_low[1] = gmt_lut[n].rgb_low[2] = r0;
- gmt_lut[n].rgb_high[0] = gmt_lut[n].rgb_high[1] = gmt_lut[n].rgb_high[2] = r1;
- }
- else {
- gmt_lut[n].rgb_low[0] = r0;
- gmt_lut[n].rgb_low[1] = g0;
- gmt_lut[n].rgb_low[2] = b0;
- gmt_lut[n].rgb_high[0] = r1;
- gmt_lut[n].rgb_high[1] = g1;
- gmt_lut[n].rgb_high[2] = b1;
- }
- }
- else { /* Read hue, saturation, value */
- gmt_hsv_to_rgb (&gmt_lut[n].rgb_low[0], &gmt_lut[n].rgb_low[1], &gmt_lut[n].rgb_low[2], r0, g0, b0);
- gmt_hsv_to_rgb (&gmt_lut[n].rgb_high[0], &gmt_lut[n].rgb_high[1], &gmt_lut[n].rgb_high[2], r1, g1, b1);
- }
-
- if (gmt_lut[n].rgb_low[0] != -1) { /* Ok to check these colors */
- gmt_lut[n].skip = FALSE;
- if (!(gmt_lut[n].rgb_low[0] == gmt_lut[n].rgb_low[1] &&
- gmt_lut[n].rgb_low[0] == gmt_lut[n].rgb_low[2])) gmt_gray = FALSE;
- if (!(gmt_lut[n].rgb_high[0] == gmt_lut[n].rgb_high[1] &&
- gmt_lut[n].rgb_high[0] == gmt_lut[n].rgb_high[2])) gmt_gray = FALSE;
- if (gmt_gray && !(gmt_lut[n].rgb_low[0] == 0 || gmt_lut[n].rgb_low[0] == 255)) gmt_b_and_w = FALSE;
- if (gmt_gray && !(gmt_lut[n].rgb_high[0] == 0 || gmt_lut[n].rgb_high[0] == 255)) gmt_b_and_w = FALSE;
- for (i = 0; !gmt_continuous && i < 3; i++)
- if (gmt_lut[n].rgb_low[i] != gmt_lut[n].rgb_high[i]) gmt_continuous = TRUE;
- }
- else {
- gmt_lut[n].skip = TRUE; /* Dont paint this slice */
- for (i = 0; i < 3; i++) gmt_lut[n].rgb_low[i] = gmt_lut[n].rgb_high[i] = gmtdefs.page_rgb[i];
- }
-
- /* Determine if psscale need to label these steps */
-
- c = line[strlen(line)-2];
- if (c == 'L' || c == 'l')
- gmt_lut[n].anot = 1;
- else if (c == 'U' || c == 'u')
- gmt_lut[n].anot = 2;
- else if (c == 'B' || c == 'b')
- gmt_lut[n].anot = 3;
- n++;
- if (n == n_alloc) {
- n_alloc += GMT_SMALL_CHUNK;
- gmt_lut = (struct GMT_LUT *) memory ((char *)gmt_lut, n_alloc, sizeof (struct GMT_LUT), "read_cpt");
- }
- }
-
- if (error) {
- fprintf (stderr, "GMT Fatal Error: Error when decoding %s - aborts!\n", cpt_file);
- exit (-1);
- }
- gmt_lut = (struct GMT_LUT *) memory ((char *)gmt_lut, n, sizeof (struct GMT_LUT), "read_cpt");
- gmt_n_colors = n;
- for (i = 0, gap = FALSE; !gap && i < gmt_n_colors - 1; i++) if (gmt_lut[i].z_high != gmt_lut[i+1].z_low) gap = TRUE;
- if (gap) {
- fprintf (stderr, "GMT Fatal Error: Color palette table %s has gaps - aborts!\n", cpt_file);
- exit (-1);
- }
- if (!gmt_gray) gmt_b_and_w = FALSE;
- }
-
-
- int get_index (value)
- double value; {
- int index;
-
- if (bad_float (value)) /* Set to NaN color */
- return (-1);
- if (value < gmt_lut[0].z_low) /* Set to background color */
- return (-2);
- if (value > gmt_lut[gmt_n_colors-1].z_high) /* Set to foreground color */
- return (-3);
-
- /* Must search for correct index */
-
- index = 0;
- while (index < gmt_n_colors && ! (value >= gmt_lut[index].z_low && value < gmt_lut[index].z_high) ) index++;
- if (index == gmt_n_colors) index--; /* Because we use <= for last range */
- return (index);
- }
-
- int get_rgb24 (value, r, g, b)
- double value;
- int *r, *g, *b; {
- int index;
- double rel;
-
- index = get_index (value);
-
- if (index == -1) {
- *r = gmtdefs.nan_rgb[0];
- *g = gmtdefs.nan_rgb[1];
- *b = gmtdefs.nan_rgb[2];
- }
- else if (index == -2) {
- *r = gmtdefs.background_rgb[0];
- *g = gmtdefs.background_rgb[1];
- *b = gmtdefs.background_rgb[2];
- }
- else if (index == -3) {
- *r = gmtdefs.foreground_rgb[0];
- *g = gmtdefs.foreground_rgb[1];
- *b = gmtdefs.foreground_rgb[2];
- }
- else if (gmt_lut[index].skip) { /* Set to page color for now */
- *r = gmtdefs.page_rgb[0];
- *g = gmtdefs.page_rgb[1];
- *b = gmtdefs.page_rgb[2];
- }
- else {
- rel = (value - gmt_lut[index].z_low) / (gmt_lut[index].z_high - gmt_lut[index].z_low);
- *r = gmt_lut[index].rgb_low[0] + rint (rel * (gmt_lut[index].rgb_high[0] - gmt_lut[index].rgb_low[0]));
- *g = gmt_lut[index].rgb_low[1] + rint (rel * (gmt_lut[index].rgb_high[1] - gmt_lut[index].rgb_low[1]));
- *b = gmt_lut[index].rgb_low[2] + rint (rel * (gmt_lut[index].rgb_high[2] - gmt_lut[index].rgb_low[2]));
- }
- return (index);
- }
-
- int gmt_rgb_to_hsv (r, g, b, h, s, v)
- int r, g, b;
- double *h, *s, *v; {
- double xr, xg, xb, r_dist, g_dist, b_dist, max_v, min_v, diff, idiff;
-
- xr = r * I_255;
- xg = g * I_255;
- xb = b * I_255;
- max_v = MAX (MAX (xr, xg), xb);
- min_v = MIN (MIN (xr, xg), xb);
- diff = max_v - min_v;
- *v = max_v;
- *s = (max_v == 0.0) ? 0.0 : diff / max_v;
- *h = 0.0;
- if ((*s) == 0.0) return; /* Hue is undefined */
- idiff = 1.0 / diff;
- r_dist = (max_v - xr) * idiff;
- g_dist = (max_v - xg) * idiff;
- b_dist = (max_v - xb) * idiff;
- if (xr == max_v)
- *h = b_dist - g_dist;
- else if (xg == max_v)
- *h = 2.0 + r_dist - b_dist;
- else
- *h = 4.0 + g_dist - r_dist;
- (*h) *= 60.0;
- if ((*h) < 0.0) (*h) += 360.0;
- }
-
- int gmt_hsv_to_rgb (r, g, b, h, s, v)
- int *r, *g, *b;
- double h, s, v; {
- int i;
- double f, p, q, t, rr, gg, bb;
-
- if (s == 0.0)
- *r = *g = *b = floor (255.999 * v);
- else {
- while (h >= 360.0) h -= 360.0;
- h /= 60.0;
- i = h;
- f = h - i;
- p = v * (1.0 - s);
- q = v * (1.0 - (s * f));
- t = v * (1.0 - (s * (1.0 - f)));
- switch (i) {
- case 0:
- rr = v; gg = t; bb = p;
- break;
- case 1:
- rr = q; gg = v; bb = p;
- break;
- case 2:
- rr = p; gg = v; bb = t;
- break;
- case 3:
- rr = p; gg = q; bb = v;
- break;
- case 4:
- rr = t; gg = p; bb = v;
- break;
- case 5:
- rr = v; gg = p; bb = q;
- break;
- }
-
- *r = floor (rr * 255.999);
- *g = floor (gg * 255.999);
- *b = floor (bb * 255.999);
- }
- }
-
- int illuminate (intensity, r, g, b)
- double intensity;
- int *r, *g, *b; {
- double h, s, v;
-
- if (bad_float (intensity)) return;
- if (intensity == 0.0) return;
- if (fabs (intensity) > 1.0) intensity = copysign (1.0, intensity);
-
- gmt_rgb_to_hsv (*r, *g, *b, &h, &s, &v);
- if (intensity > 0) {
- if (s != 0.0) s = (1.0 - intensity) * s + intensity * gmtdefs.hsv_max_saturation;
- v = (1.0 - intensity) * v + intensity * gmtdefs.hsv_max_value;
- }
- else {
- if (s != 0.0) s = (1.0 + intensity) * s - intensity * gmtdefs.hsv_min_saturation;
- v = (1.0 + intensity) * v - intensity * gmtdefs.hsv_min_value;
- }
- if (v < 0.0) v = 0.0;
- if (s < 0.0) s = 0.0;
- if (v > 1.0) v = 1.0;
- if (s > 1.0) s = 1.0;
- gmt_hsv_to_rgb (r, g, b, h, s, v);
- }
-
- /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- * AKIMA computes the coefficients for a quasi-cubic hermite spline.
- * Same algorithm as in the IMSL library.
- * Programmer: Paul Wessel
- * Date: 16-JAN-1987
- * Ver: v.1-pc
- * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- */
-
- int akima (x,y,nx,c)
- int nx;
- double x[], y[], c[]; {
- int i, no;
- double t1, t2, b, rm1, rm2, rm3, rm4;
-
- if (nx < 4) return (-1);
- for (i = 1; i < nx; i++) if (x[i] <= x[i-1]) return (-2);
-
- rm3 = (y[1] - y[0])/(x[1] - x[0]);
- t1 = rm3 - (y[1] - y[2])/(x[1] - x[2]);
- rm2 = rm3 + t1;
- rm1 = rm2 + t1;
-
- /* get slopes */
-
- no = nx - 2;
- for (i = 0; i < nx; i++) {
- if (i >= no)
- rm4 = rm3 - rm2 + rm3;
- else
- rm4 = (y[i+2] - y[i+1])/(x[i+2] - x[i+1]);
- t1 = fabs(rm4 - rm3);
- t2 = fabs(rm2 - rm1);
- b = t1 + t2;
- c[3*i] = (b != 0.0) ? (t1*rm2 + t2*rm3) / b : 0.5*(rm2 + rm3);
- rm1 = rm2;
- rm2 = rm3;
- rm3 = rm4;
- }
- no = nx - 1;
-
- /* compute the coefficients for the nx-1 intervals */
-
- for (i = 0; i < no; i++) {
- t1 = 1.0 / (x[i+1] - x[i]);
- t2 = (y[i+1] - y[i])*t1;
- b = (c[3*i] + c[3*i+3] - t2 - t2)*t1;
- c[3*i+2] = b*t1;
- c[3*i+1] = -b + (t2 - c[3*i])*t1;
- }
- return (0);
- }
-
- /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- * CSPLINE computes the coefficients for a natural cubic spline.
- * To evaluate, call csplint
- * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- */
-
- int cspline (x, y, n, c)
- double x[], y[], c[];
- int n;
- {
- int i, k;
- double p, s, *u;
-
- u = (double *) memory (CNULL, n, sizeof (double), "cspline");
- c[1] = c[n] = u[1] = 0.0;
- for (i = 1; i < n-1; i++) {
- s = (x[i] - x[i-1]) / (x[i+1] - x[i-1]);
- p = s * c[i-1] + 2.0;
- c[i] = (s - 1.0) / p;
- u[i] = (y[i+1] - y[i]) / (x[i+1] - x[i]) - (y[i] - y[i-1]) / (x[i] - x[i-1]);
- u[i] = (6.0 * u[i] / (x[i+1] - x[i-1]) - s * u[i-1]) / p;
- }
- for (k = n-2; k >= 0; k--) c[k] = c[k] * c[k+1] + u[k];
- free ((char *)u);
-
- return (0);
- }
-
- double csplint (x, y, c, n, xp, klo)
- double x[], y[], c[], xp;
- int n, klo;
- {
- int khi;
- double h, ih, b, a, yp;
-
- khi = klo + 1;
- h = x[khi] - x[klo];
- ih = 1.0 / h;
- a = (x[khi] - xp) * ih;
- b = (xp - x[klo]) * ih;
- yp = a * y[klo] + b * y[khi] + ((a*a*a - a) * c[klo] + (b*b*b - b) * c[khi]) * (h*h) / 6.0;
-
- return (yp);
- }
-
- /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- * INTPOL will interpolate from the dataset <x,y> onto a new set <u,v>
- * where <x,y> and <u> is supplied by the user. <v> is returned. The
- * parameter mode governs what interpolation scheme that will be used.
- * If u[i] is outside the range of x, then v[i] will contain NaN.
- *
- * input: x = x-values of input data
- * y = y-values " " "
- * n = number of data pairs
- * m = number of desired interpolated values
- * u = x-values of these points
- * mode = type of interpolation
- * mode = 0 : Linear interpolation
- * mode = 1 : Quasi-cubic hermite spline (akima)
- * mode = 2 : Natural cubic spline (cubspl)
- * output: v = y-values at interpolated points
- *
- * Programmer: Paul Wessel
- * Date: 16-JAN-1987
- * Ver: v.2
- * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- */
-
- int intpol (x,y,n,m,u,v,mode)
- double x[], y[], u[], v[];
- int n, m, mode; {
- int i, j, err_flag = 0;
- double dx, *c, csplint ();
-
- if (n < 4) mode = 0;
- if (mode > 0) c = (double *) memory (CNULL, 3*n, sizeof(double), "intpol");
-
- if (mode == 0) { /* Linear interpolation */
- for (i = 1; i < n; i++) if (x[i] <= x[i-1]) return (-1);
- }
- else if (mode == 1) /* Akimas spline */
- err_flag = akima (x,y,n,c);
- else if (mode == 2) /* Natural cubic spline */
- err_flag = cspline (x,y,n,c);
- else
- err_flag = -4;
- if (err_flag != 0) {
- free ((char *)c);
- return (err_flag);
- }
-
- /* Compute the interpolated values from the coefficients */
-
- j = 0;
- for (i = 0; i < m; i++) {
- if (u[i] < x[0] || u[i] > x[n-1]) { /* Desired point outside data range */
- v[i] = gmt_NaN;
- continue;
- }
- while (x[j] > u[i] && j > 0) j--; /* In case u is not sorted */
- while (j < n && x[j] <= u[i]) j++;
- if (j == n) j--;
- if (j > 0) j--;
- switch (mode) {
- case 0:
- dx = u[i] - x[j];
- v[i] = (y[j+1]-y[j])*dx/(x[j+1]-x[j]) + y[j];
- break;
- case 1:
- dx = u[i] - x[j];
- v[i] = ((c[3*j+2]*dx + c[3*j+1])*dx + c[3*j])*dx + y[j];
- break;
- case 2:
- v[i] = csplint (x, y, c, n, u[i], j);
- break;
- }
- }
- if (mode > 0) free ((char *)c);
- return (0);
- }
-
- char *memory (prev_addr, n, size, progname)
- char *prev_addr, *progname;
- int n, size; {
- char *tmp;
-
- if (n == 0) return((char *) NULL); /* Take care of n = 0 */
-
- if (prev_addr) {
- if ((tmp = realloc ((char *) prev_addr, (unsigned) (n * size))) == CNULL) {
- fprintf (stderr, "GMT Fatal Error: %s could not reallocate more memory, n = %d\n", progname, n);
- exit (-1);
- }
- }
- else {
- if ((tmp = calloc ((unsigned) n, (unsigned) size)) == CNULL) {
- fprintf (stderr, "GMT Fatal Error: %s could not allocate memory, n = %d\n", progname, n);
- exit (-1);
- }
- }
- return (tmp);
- }
-
- #define CONTOUR_IJ(i,j) ((i) + (j) * nx)
-
- int contours (grd, header, smooth_factor, int_scheme, side, edge, first, x_array, y_array)
- float grd[];
- struct GRD_HEADER *header;
- int smooth_factor, int_scheme, *side, first;
- int edge[];
- double *x_array[], *y_array[]; {
- /* The routine finds the zero-contour in the grd dataset. it assumes that
- * no node has a value exactly == 0.0. If more than max points are found
- * trace_contour will try to allocate more memory in blocks of GMT_CHUNK points
- */
-
- static int i0, j0;
- int i, j, ij, n = 0, n2, n_edges, edge_word, edge_bit, nx, ny, nans = 0;
- BOOLEAN go_on = TRUE;
- double x0, y0, r, west, east, south, north, dx, dy, xinc2, yinc2, *x, *y, *x2, *y2;
- int p[5], i_off[5], j_off[5], k_off[5], offset;
- unsigned int bit[32];
-
- nx = header->nx; ny = header->ny;
- west = header->x_min; east = header->x_max;
- south = header->y_min; north = header->y_max;
- dx = header->x_inc; dy = header->y_inc;
- xinc2 = (header->node_offset) ? 0.5 * dx : 0.0;
- yinc2 = (header->node_offset) ? 0.5 * dy : 0.0;
- x = *x_array; y = *y_array;
-
- n_edges = ny * (int) ceil (nx / 16.0);
- offset = n_edges / 2;
-
- /* Reset edge-flags to zero, if necessary */
- if (first) { /* Set i0,j0 for southern boundary */
- memset ((char *)edge, 0, n_edges * sizeof (int));
- i0 = 0;
- j0 = ny - 1;
- }
- p[0] = p[4] = 0; p[1] = 1; p[2] = 1 - nx; p[3] = -nx;
- i_off[0] = i_off[2] = i_off[3] = i_off[4] = 0; i_off[1] = 1;
- j_off[0] = j_off[1] = j_off[3] = j_off[4] = 0; j_off[2] = -1;
- k_off[0] = k_off[2] = k_off[4] = 0; k_off[1] = k_off[3] = 1;
- for (i = 1, bit[0] = 1; i < 32; i++) bit[i] = bit[i-1] << 1;
-
- switch (*side) {
- case 0: /* Southern boundary */
- for (i = i0, j = j0, ij = (ny - 1) * nx + i0; go_on && i < nx-1; i++, ij++) {
- edge_word = ij / 32;
- edge_bit = ij % 32;
- if (start_trace (grd[ij+1], grd[ij], edge, edge_word, edge_bit, bit)) { /* Start tracing countour */
- r = grd[ij+1] - grd[ij];
- x0 = west + (i - grd[ij]/r)*dx + xinc2;
- y0 = south + yinc2;
- edge[edge_word] |= bit[edge_bit];
- n = trace_contour (grd, header, x0, y0, edge, smooth_factor, &x, &y, i, j, 0, offset, i_off, j_off, k_off, p, bit, &nans);
- n = smooth_contour (&x, &y, n, smooth_factor, int_scheme);
- go_on = FALSE;
- i0 = i + 1; j0 = j;
- }
- }
- if (n == 0) {
- i0 = nx - 2;
- j0 = ny - 1;
- (*side)++;
- }
- break;
-
- case 1: /* Eastern boundary */
-
- for (j = j0, ij = nx * (j0 + 1) - 1, i = i0; go_on && j > 0; j--, ij -= nx) {
- edge_word = ij / 32 + offset;
- edge_bit = ij % 32;
- if (start_trace (grd[ij-nx], grd[ij], edge, edge_word, edge_bit, bit)) { /* Start tracing countour */
- r = grd[ij] - grd[ij-nx];
- x0 = east - xinc2;
- y0 = north - (j - grd[ij]/r) * dy - yinc2;
- edge[edge_word] |= bit[edge_bit];
- n = trace_contour (grd, header, x0, y0, edge, smooth_factor, &x, &y, i, j, 1, offset, i_off, j_off, k_off, p, bit, &nans);
- n = smooth_contour (&x, &y, n, smooth_factor, int_scheme);
- go_on = FALSE;
- i0 = i; j0 = j - 1;
- }
- }
- if (n == 0) {
- i0 = nx - 2;
- j0 = 1;
- (*side)++;
- }
- break;
-
- case 2: /* Northern boundary */
-
- for (i = i0, j = j0, ij = i0; go_on && i >= 0; i--, ij--) {
- edge_word = ij / 32;
- edge_bit = ij % 32;
- if (start_trace (grd[ij], grd[ij+1], edge, edge_word, edge_bit, bit)) { /* Start tracing countour */
- r = grd[ij+1] - grd[ij];
- x0 = west + (i - grd[ij]/r)*dx + xinc2;
- y0 = north - yinc2;
- edge[edge_word] |= bit[edge_bit];
- n = trace_contour (grd, header, x0, y0, edge, smooth_factor, &x, &y, i, j, 2, offset, i_off, j_off, k_off, p, bit, &nans);
- n = smooth_contour (&x, &y, n, smooth_factor, int_scheme);
- go_on = FALSE;
- i0 = i - 1; j0 = j;
- }
- }
- if (n == 0) {
- i0 = 0;
- j0 = 1;
- (*side)++;
- }
- break;
-
- case 3: /* Western boundary */
-
- for (j = j0, ij = j * nx, i = i0; go_on && j < ny; j++, ij += nx) {
- edge_word = ij / 32 + offset;
- edge_bit = ij % 32;
- if (start_trace (grd[ij], grd[ij-nx], edge, edge_word, edge_bit, bit)) { /* Start tracing countour */
- r = grd[ij] - grd[ij-nx];
- x0 = west + xinc2;
- y0 = north - (j - grd[ij] / r) * dy - yinc2;
- edge[edge_word] |= bit[edge_bit];
- n = trace_contour (grd, header, x0, y0, edge, smooth_factor, &x, &y, i, j, 3, offset, i_off, j_off, k_off, p, bit, &nans);
- n = smooth_contour (&x, &y, n, smooth_factor, int_scheme);
- go_on = FALSE;
- i0 = i; j0 = j + 1;
- }
- }
- if (n == 0) {
- i0 = 1;
- j0 = 1;
- (*side)++;
- }
- break;
-
- case 4: /* Then loop over interior boxes */
-
- for (j = j0; go_on && j < ny; j++) {
- ij = i0 + j * nx;
- for (i = i0; go_on && i < nx-1; i++, ij++) {
- edge_word = ij / 32 + offset;
- edge_bit = ij % 32;
- if (start_trace (grd[ij], grd[ij-nx], edge, edge_word, edge_bit, bit)) { /* Start tracing countour */
- r = grd[ij] - grd[ij-nx];
- x0 = west + i*dx + xinc2;
- y0 = north - (j - grd[ij] / r) * dy - yinc2;
- /* edge[edge_word] |= bit[edge_bit]; */
- nans = 0;
- n = trace_contour (grd, header, x0, y0, edge, smooth_factor, &x, &y, i, j, 3, offset, i_off, j_off, k_off, p, bit, &nans);
- if (nans) { /* Must trace in other direction, then splice */
- n2 = trace_contour (grd, header, x0, y0, edge, smooth_factor, &x2, &y2, i-1, j, 1, offset, i_off, j_off, k_off, p, bit, &nans);
- n = splice_contour (&x, &y, n, &x2, &y2, n2);
- free ((char *)x2);
- free ((char *)y2);
-
- n = smooth_contour (&x, &y, n, smooth_factor, int_scheme);
- }
- i0 = i + 1;
- go_on = FALSE;
- j0 = j;
- }
- }
- if (go_on) i0 = 1;
- }
- if (n == 0) (*side)++;
- break;
- default:
- break;
- }
- *x_array = x; *y_array = y;
- return (n);
- }
-
- int start_trace (first, second, edge, edge_word, edge_bit, bit)
- float first, second;
- int edge[], edge_word,edge_bit;
- unsigned int bit[]; {
- /* First make sure we havent been here before */
-
- if ( (edge[edge_word] & bit[edge_bit]) ) return (FALSE);
-
- /* Then make sure both points are real numbers */
-
- if (bad_float ((double)first) ) return (FALSE);
- if (bad_float ((double)second) ) return (FALSE);
-
- /* Finally return TRUE if values of opposite sign */
-
- return ( first * second < 0.0);
- }
-
- int splice_contour (x, y, n, x2, y2, n2)
- double *x[], *y[], *x2[], *y2[];
- int n, n2; { /* Basically does a "tail -r" on the array x,y and append arrays x2/y2 */
-
- int i, j, m;
- double *xtmp, *ytmp, *xa, *ya, *xb, *yb;
-
- xa = *x; ya = *y;
- xb = *x2; yb = *y2;
-
- m = n + n2 - 1; /* Total length since one point is shared */
-
- /* First copy and reverse first contour piece */
-
- xtmp = (double *) memory (CNULL, n , sizeof (double), "splice_contour");
- ytmp = (double *) memory (CNULL, n, sizeof (double), "splice_contour");
-
- memcpy ((char *)xtmp, (char *)xa, n * sizeof (double));
- memcpy ((char *)ytmp, (char *)ya, n * sizeof (double));
-
- xa = (double *) memory ((char *)xa, m, sizeof (double), "splice_contour");
- ya = (double *) memory ((char *)ya, m, sizeof (double), "splice_contour");
-
- for (i = 0; i < n; i++) xa[i] = xtmp[n-i-1];
- for (i = 0; i < n; i++) ya[i] = ytmp[n-i-1];
-
- /* Then append second piece */
-
- for (j = 1, i = n; j < n2; j++, i++) xa[i] = xb[j];
- for (j = 1, i = n; j < n2; j++, i++) ya[i] = yb[j];
-
- free ((char *)xtmp);
- free ((char *)ytmp);
-
- *x = xa;
- *y = ya;
-
- return (m);
- }
-
- int trace_contour (grd, header, x0, y0, edge, smooth_factor, x_array, y_array, i, j, kk, offset, i_off, j_off, k_off, p, bit, nan_flag)
- float grd[];
- struct GRD_HEADER *header;
- int edge[], smooth_factor, i, j, kk, offset, i_off[], j_off[], k_off[], p[];
- unsigned int bit[];
- double x0, y0, *x_array[], *y_array[];
- int *nan_flag; {
- int side = 0, n = 1, k, k0, ij, ij0, n_cuts, k_index[2], kk_opposite, more;
- int edge_word, edge_bit, m, n_nan, nx, ny, n_alloc, ij_in;
- double xk[4], yk[4], r, dr[2];
- double west, north, dx, dy, xinc2, yinc2, *xx, *yy;
-
- west = header->x_min; north = header->y_max;
- dx = header->x_inc; dy = header->y_inc;
- nx = header->nx; ny = header->ny;
- xinc2 = (header->node_offset) ? 0.5 * dx : 0.0;
- yinc2 = (header->node_offset) ? 0.5 * dy : 0.0;
-
- n_alloc = GMT_CHUNK;
- m = n_alloc - 2;
-
- xx = (double *) memory (CNULL, n_alloc, sizeof (double), "trace_contour");
- yy = (double *) memory (CNULL, n_alloc, sizeof (double), "trace_contour");
-
- xx[0] = x0; yy[0] = y0;
- ij_in = j * nx + i - 1;
-
- more = TRUE;
- do {
- ij = i + j * nx;
- x0 = west + i * dx + xinc2;
- y0 = north - j * dy - yinc2;
- n_cuts = 0;
- k0 = kk;
-
- for (k = n_nan = 0; k < 4; k++) { /* Loop over box sides */
-
- /* Skip where we already have a cut (k == k0) */
-
- if (k == k0) continue;
-
- /* Skip if NAN encountered */
-
- if (bad_float ((double)grd[ij+p[k+1]]) || bad_float ( (double)grd[ij+p[k]])) {
- n_nan++;
- continue;
- }
-
- /* Skip edge already has been used */
-
- ij0 = CONTOUR_IJ (i + i_off[k], j + j_off[k]);
- edge_word = ij0 / 32 + k_off[k] * offset;
- edge_bit = ij0 % 32;
- if (edge[edge_word] & bit[edge_bit]) continue;
-
- /* Skip if no zero-crossing on this edge */
-
- if (grd[ij+p[k+1]] * grd[ij+p[k]] > 0.0) continue;
-
- /* Here we have a crossing */
-
- r = grd[ij+p[k+1]] - grd[ij+p[k]];
-
- if (k%2) { /* Cutting a S-N line */
- if (k == 1) {
- xk[1] = x0 + dx;
- yk[1] = y0 - grd[ij+p[k]]*dy/r;
- }
- else {
- xk[3] = x0;
- yk[3] = y0 + (1.+grd[ij+p[k]]/r)*dy;
- }
- }
- else { /* Cutting a E-W line */
- if (k == 0) {
- xk[0] = x0 - grd[ij+p[k]]*dx/r;
- yk[0] = y0;
- }
- else {
- xk[2] = x0 + (1.+grd[ij+p[k]]/r)*dx;
- yk[2] = y0 + dy;
- }
- }
- kk = k;
- n_cuts++;
- }
-
- if (n > m) { /* Must try to allocate more memory */
- n_alloc += GMT_CHUNK;
- m += GMT_CHUNK;
- xx = (double *) memory ((char *)xx, n_alloc, sizeof (double), "trace_contour");
- yy = (double *) memory ((char *)yy, n_alloc, sizeof (double), "trace_contour");
- }
- if (n_cuts == 0) { /* Close interior contour and return */
- /* if (n_nan == 0 && (n > 0 && fabs (xx[n-1] - xx[0]) <= dx && fabs (yy[n-1] - yy[0]) <= dy)) { */
- if (ij == ij_in) { /* Close iterior contour */
- xx[n] = xx[0];
- yy[n] = yy[0];
- n++;
- }
- more = FALSE;
- *nan_flag = n_nan;
- }
- else if (n_cuts == 1) { /* Draw a line to this point and keep tracing */
- xx[n] = xk[kk];
- yy[n] = yk[kk];
- n++;
- }
- else { /* Saddle point, we decide to connect to the point nearest previous point */
- kk_opposite = (k0 + 2) % 4; /* But it cannot be on opposite side */
- for (k = side = 0; k < 4; k++) {
- if (k == k0 || k == kk_opposite) continue;
- dr[side] = (xx[n-1]-xk[k])*(xx[n-1]-xk[k]) + (yy[n-1]-yk[k])*(yy[n-1]-yk[k]);
- k_index[side++] = k;
- }
- kk = (dr[0] < dr[1]) ? k_index[0] : k_index[1];
- xx[n] = xk[kk];
- yy[n] = yk[kk];
- n++;
- }
- if (more) { /* Mark this edge as used */
- ij0 = CONTOUR_IJ (i + i_off[kk], j + j_off[kk]);
- edge_word = ij0 / 32 + k_off[kk] * offset;
- edge_bit = ij0 % 32;
- edge[edge_word] |= bit[edge_bit];
- }
-
- if ((kk == 0 && j == ny - 1) || (kk == 1 && i == nx - 2) ||
- (kk == 2 && j == 1) || (kk == 3 && i == 0)) /* Going out of grid */
- more = FALSE;
-
- /* Get next box (i,j,kk) */
-
- i -= (kk-2)%2;
- j -= (kk-1)%2;
- kk = (kk+2)%4;
-
- } while (more);
-
- xx = (double *) memory ((char *)xx, n, sizeof (double), "trace_contour");
- yy = (double *) memory ((char *)yy, n, sizeof (double), "trace_contour");
-
- *x_array = xx; *y_array = yy;
- return (n);
- }
-
- int smooth_contour (x_in, y_in, n, sfactor, stype)
- double *x_in[], *y_in[]; /* Input (x,y) points */
- int n; /* Number of input points */
- int sfactor; /* n_out = sfactor * n -1 */
- int stype; { /* Interpolation scheme used (0 = linear, 1 = Akima, 2 = Cubic spline */
- int i, j, k, n_out;
- double ds, t_next, *x, *y;
- double *t_in, *t_out, *x_tmp, *y_tmp, x0, x1, y0, y1;
- char *flag;
-
- if (sfactor == 0 || n < 4) return (n); /* Need at least 4 points to call Akima */
-
- x = *x_in; y = *y_in;
-
- n_out = sfactor * n - 1; /* Number of new points */
-
- t_in = (double *) memory (CNULL, n, sizeof (double), "smooth_contour");
- t_out = (double *) memory (CNULL, n_out + n, sizeof (double), "smooth_contour");
- x_tmp = (double *) memory (CNULL, n_out + n, sizeof (double), "smooth_contour");
- y_tmp = (double *) memory (CNULL, n_out + n, sizeof (double), "smooth_contour");
- flag = memory (CNULL, n_out + n, sizeof (char), "smooth_contour");
-
- /* Create dummy distance values for input points */
-
- t_in[0] = 0.0;
- for (i = 1; i < n; i++) t_in[i] = t_in[i-1] + hypot ((x[i]-x[i-1]), (y[i]-y[i-1]));
-
- /* Create equidistance output points */
-
- ds = t_in[n-1] / (n_out-1);
- t_next = ds;
- t_out[0] = 0.0;
- flag[0] = TRUE;
- for (i = j = 1; i < n_out; i++) {
- if (j < n && t_in[j] < t_next) {
- t_out[i] = t_in[j];
- flag[i] = TRUE;
- j++;
- n_out++;
- }
- else {
- t_out[i] = t_next;
- t_next += ds;
- }
- }
- t_out[n_out-1] = t_in[n-1];
- if (t_out[n_out-1] == t_out[n_out-2]) n_out--;
- flag[n_out-1] = TRUE;
-
- intpol (t_in, x, n, n_out, t_out, x_tmp, stype);
- intpol (t_in, y, n, n_out, t_out, y_tmp, stype);
-
- /* Make sure interpolated function is bounded on each segment interval */
-
- i = 0;
- while (i < (n_out - 1)) {
- j = i + 1;
- while (j < n_out && !flag[j]) j++;
- x0 = x_tmp[i]; x1 = x_tmp[j];
- if (x0 > x1) d_swap (x0, x1);
- y0 = y_tmp[i]; y1 = y_tmp[j];
- if (y0 > y1) d_swap (y0, y1);
- for (k = i + 1; k < j; k++) {
- if (x_tmp[k] < x0)
- x_tmp[k] = x0 + 1.0e-10;
- else if (x_tmp[k] > x1)
- x_tmp[k] = x1 - 1.0e-10;
- if (y_tmp[k] < y0)
- y_tmp[k] = y0 + 1.0e-10;
- else if (y_tmp[k] > y1)
- y_tmp[k] = y1 - 1.0e-10;
- }
- i = j;
- }
-
- free ((char *)x);
- free ((char *)y);
-
- *x_in = x_tmp;
- *y_in = y_tmp;
-
- free ((char *) t_in);
- free ((char *) t_out);
- free (flag);
-
- return (n_out);
- }
-
- int get_plot_array () { /* Allocate more space for plot arrays */
-
- gmt_n_alloc += GMT_CHUNK;
- gmt_x_plot = (double *) memory ((char *)gmt_x_plot, gmt_n_alloc, sizeof (double), "gmt");
- gmt_y_plot = (double *) memory ((char *)gmt_y_plot, gmt_n_alloc, sizeof (double), "gmt");
- gmt_pen = (int *) memory ((char *)gmt_pen, gmt_n_alloc, sizeof (int), "gmt");
- }
-
- int free_plot_array () {
- if (gmt_n_alloc) {
- free ((char *)gmt_x_plot);
- free ((char *)gmt_y_plot);
- free ((char *)gmt_pen);
- }
- }
-
- int comp_double_asc (point_1, point_2)
- double *point_1, *point_2;
- {
- /* Returns -1 if point_1 is < that point_2,
- +1 if point_2 > point_1, and 0 if they are equal
- */
- int bad_1, bad_2;
-
- bad_1 = bad_float ((*point_1));
- bad_2 = bad_float ((*point_2));
-
- if (bad_1 && bad_2) return (0);
- if (bad_1) return (1);
- if (bad_2) return (-1);
-
- if ( (*point_1) < (*point_2) )
- return (-1);
- else if ( (*point_1) > (*point_2) )
- return (1);
- else
- return (0);
- }
-
- int comp_float_asc (point_1, point_2)
- float *point_1, *point_2;
- {
- /* Returns -1 if point_1 is < that point_2,
- +1 if point_2 > point_1, and 0 if they are equal
- */
- int bad_1, bad_2;
-
- bad_1 = bad_float ((double)(*point_1));
- bad_2 = bad_float ((double)(*point_2));
-
- if (bad_1 && bad_2) return (0);
- if (bad_1) return (1);
- if (bad_2) return (-1);
-
- if ( (*point_1) < (*point_2) )
- return (-1);
- else if ( (*point_1) > (*point_2) )
- return (1);
- else
- return (0);
- }
-
- int comp_int_asc (point_1, point_2)
- int *point_1, *point_2;
- {
- /* Returns -1 if point_1 is < that point_2,
- +1 if point_2 > point_1, and 0 if they are equal
- */
-
- if ( (*point_1) < (*point_2) )
- return (-1);
- else if ( (*point_1) > (*point_2) )
- return (1);
- else
- return (0);
- }
-
- struct EPS *gmt_epsinfo (program)
- char *program;
- {
- /* Supply info about the EPS file that will be created */
-
- int fno[5], id, i, n, n_fonts, last, move_up = FALSE;
-
- double y, dy;
-
- char title[512];
-
- struct passwd *pw;
- struct EPS *new;
- #ifdef NeXT
- uid_t getuid();
- #endif
- new = (struct EPS *) memory (CNULL, 1, sizeof (struct EPS), "gmt_epsinfo");
-
- /* First estimate the boundingbox coordinates */
-
- new->x0 = new->y0 = 0;
- new->x1 = rint (gmt_ppu[gmtdefs.measure_unit] * (z_project.xmax - z_project.xmin + 2.0 * ((gmtdefs.overlay) ? 1.0 : gmtdefs.x_origin)));
- y = z_project.ymax - z_project.ymin + 2.0 * ((gmtdefs.overlay) ? 1.0 : gmtdefs.y_origin);
-
- if (frame_info.header[0]) { /* Make space for header text */
- move_up = (MAPPING || frame_info.side[2] == 2);
- dy = ((gmtdefs.tick_length > 0.0) ? gmtdefs.tick_length : 0.0) + 2.5 * gmtdefs.anot_offset;
- dy += ((move_up) ? (gmtdefs.anot_font_size + gmtdefs.label_font_size) / gmt_ppu[gmtdefs.measure_unit] : 0.0) + 2.5 * gmtdefs.anot_offset;
- y += dy;
- }
- new->y1 = rint (gmt_ppu[gmtdefs.measure_unit] * y);
-
- /* Get font names used */
-
- id = 0;
- if (gmtdefs.unix_time) {
- fno[0] = 0;
- fno[1] = 1;
- id = 2;
- }
-
- if (frame_info.header[0]) fno[id++] = gmtdefs.header_font;
-
- if (frame_info.label[0][0] || frame_info.label[1][0] || frame_info.label[2][0]) fno[id++] = gmtdefs.label_font;
-
- fno[id++] = gmtdefs.anot_font;
-
- qsort ((char *)fno, id, sizeof (int), comp_int_asc);
-
- last = -1;
- for (i = n_fonts = 0; i < id; i++) {
- if (fno[i] != last) {
- new->font[n_fonts++] = font_name[fno[i]];
- last = fno[i];
- }
- }
- new->font[n_fonts] = CNULL;
-
- /* Get user name and date */
- #ifdef NeXT
- pw = getpwuid ( ( (int)getuid () ) );
- #elif sony
- pw = getpwuid ( ( (int)getuid () ) );
- #else
- pw = getpwnam ( cuserid ( CNULL));
- #endif
-
- n = strlen (pw->pw_gecos) + 1;
- new->name = memory (CNULL, n, 1, "gmt_epsinfo");
- strcpy (new->name, pw->pw_gecos);
-
- sprintf (title, "GMT v%s Document from %s\0", GMT_VERSION, program);
- new->title = memory (CNULL, strlen (title) + 1, 1, "gmt_epsinfo");
- strcpy (new->title, title);
-
- return (new);
- }
-
- int median(x, n, xmin, xmax, m_initial, med)
-
- double *x, xmin, xmax, m_initial, *med;
- int n;
-
- {
- double lower_bound, upper_bound, m_guess, t_0, t_1, t_middle;
- double lub, glb, xx, temp;
- int i, n_above, n_below, n_equal, n_lub, n_glb;
- int finished = FALSE;
- int iteration = 0;
-
- m_guess = m_initial;
- lower_bound = xmin;
- upper_bound = xmax;
- t_0 = 0;
- t_1 = n - 1;
- t_middle = 0.5 * (n - 1);
-
- do {
-
- n_above = n_below = n_equal = n_lub = n_glb = 0;
- lub = xmax;
- glb = xmin;
-
- for (i = 0; i < n; i++) {
-
- xx = x[i];
- if (xx == m_guess) {
- n_equal++;
- }
- else if (xx > m_guess) {
- n_above++;
- if (xx < lub) {
- lub = xx;
- n_lub = 1;
- }
- else if (xx == lub) {
- n_lub++;
- }
- }
- else {
- n_below++;
- if (xx > glb) {
- glb = xx;
- n_glb = 1;
- }
- else if (xx == glb) {
- n_glb++;
- }
- }
- }
-
- iteration++;
-
- /* Now test counts, watch multiple roots, think even/odd: */
-
- if ( (abs(n_above - n_below)) <= n_equal) {
-
- if (n_equal) {
- *med = m_guess;
- }
- else {
- *med = 0.5 * (lub + glb);
- }
- finished = TRUE;
- }
- else if ( (abs( (n_above - n_lub) - (n_below + n_equal) ) ) < n_lub) {
-
- *med = lub;
- finished = TRUE;
- }
- else if ( (abs( (n_below - n_glb) - (n_above + n_equal) ) ) < n_glb) {
-
- *med = glb;
- finished = TRUE;
- }
- /* Those cases found the median; the next two will forecast a new guess: */
-
- else if ( n_above > (n_below + n_equal) ) { /* Guess is too low */
-
- lower_bound = m_guess;
- t_0 = n_below + n_equal - 1;
- temp = lower_bound + (upper_bound - lower_bound) * (t_middle - t_0) / (t_1 - t_0);
- m_guess = (temp > lub) ? temp : lub; /* Move guess at least to lub */
- }
- else if ( n_below > (n_above + n_equal) ) { /* Guess is too high */
-
- upper_bound = m_guess;
- t_1 = n_below + n_equal - 1;
- temp = lower_bound + (upper_bound - lower_bound) * (t_middle - t_0) / (t_1 - t_0);
- m_guess = (temp < glb) ? temp : glb; /* Move guess at least to glb */
- }
- else { /* If we get here, I made a mistake! */
- fprintf (stderr,"GMT Fatal Error: Internal goof - please report to developers!\n");
- exit (-1);
- }
-
- } while (!finished);
-
- /* That's all, folks! */
- return (iteration);
- }
-
- int mode(x, n, j, sort, mode_est)
-
- double *x, *mode_est;
- int n, j, sort;
-
- {
- int i, istop, multiplicity = 0;
- double mid_point_sum = 0.0, length, short_length = 1.0e+30;
-
- if (sort) qsort((char *)x, n, sizeof(double), comp_double_asc);
-
- istop = n - j;
-
- for (i = 0; i < istop; i++) {
- length = x[i + j] - x[i];
- if (length < 0.0) {
- fprintf(stderr,"mode: Array not sorted in non-decreasing order.\n");
- return (-1);
- }
- else if (length == short_length) {
- multiplicity++;
- mid_point_sum += (0.5 * (x[i + j] + x[i]));
- }
- else if (length < short_length) {
- multiplicity = 1;
- mid_point_sum = (0.5 * (x[i + j] + x[i]));
- short_length = length;
- }
- }
-
- if (multiplicity - 1) mid_point_sum /= multiplicity;
-
- *mode_est = mid_point_sum;
- return (0);
- }
-
- int get_format (interval, format)
- double interval;
- char *format; {
- int i, j, ndec = 0;
- char text[80];
-
- /* Find number of decimals needed, if any, and create suitable format statement */
-
- sprintf (text, "%lg\0", interval);
- for (i = 0; text[i] && text[i] != '.'; i++);
- if (text[i]) { /* Found a decimal point */
- for (j = i + 1; text[j]; j++);
- ndec = j - i - 1;
- }
- if (ndec > 0)
- sprintf (format, "%%.%dlf\0", ndec);
- else
- strcpy (format, "%lg");
- return (ndec);
- }
-
- int get_label_parameters (side, line_angle, text_angle, justify)
- int side, *justify;
- double line_angle, *text_angle; {
- int ok;
-
- *text_angle = line_angle;
- if (*text_angle < -90.0) *text_angle += 360.0;
- if (frame_info.horizontal && !(side%2)) *text_angle += 90.0;
- if (*text_angle >= 270.0 ) *text_angle -= 360.0;
- else if (*text_angle >= 90.0) *text_angle -= 180.0;
-
- switch (side) {
- case 0: /* S */
- if (frame_info.horizontal)
- *justify = 10;
- else
- *justify = ((*text_angle) < 0.0) ? 5 : 7;
- break;
- case 1: /* E */
- *justify = 5;
- break;
- case 2: /* N */
- if (frame_info.horizontal)
- *justify = 2;
- else
- *justify = ((*text_angle) < 0.0) ? 7 : 5;
- break;
- case 3: /* W */
- *justify = 7;
- break;
- }
-
- if (frame_info.horizontal) return (TRUE);
-
-
- switch (side) {
- case 0: /* S */
- case 2: /* N */
- ok = (fabs ((*text_angle)) >= gmtdefs.anot_min_angle);
- break;
- case 1: /* E */
- case 3: /* W */
- ok = (fabs ((*text_angle)) <= (90.0 - gmtdefs.anot_min_angle));
- break;
- }
- return (ok);
- }
-
- int non_zero_winding(xp, yp, x, y, n_path)
- double xp, yp, *x, *y;
- int n_path;
- {
- /* Routine returns (2) if (xp,yp) is inside the
- polygon x[n_path], y[n_path], (0) if outside,
- and (1) if exactly on the path edge.
- Uses non-zero winding rule in Adobe PostScript
- Language reference manual, section 4.6 on Painting.
- Path should have been closed first, so that
- x[n_path-1] = x[0], and y[n_path-1] = y[0].
-
- This is version 2, trying to kill a bug
- in above routine: If point is on X edge,
- fails to discover that it is on edge.
-
- We are imagining a ray extending "up" from the
- point (xp,yp); the ray has equation x = xp, y >= yp.
- Starting with crossing_count = 0, we add 1 each time
- the path crosses the ray in the +x direction, and
- subtract 1 each time the ray crosses in the -x direction.
- After traversing the entire polygon, if (crossing_count)
- then point is inside. We also watch for edge conditions.
-
- If two or more points on the path have x[i] == xp, then
- we have an ambiguous case, and we have to find the points
- in the path before and after this section, and check them.
- */
-
- int i, j, k, jend, crossing_count, above;
- double y_sect;
-
- above = FALSE;
- crossing_count = 0;
-
- /* First make sure first point in path is not a special case: */
- j = jend = n_path - 1;
- if (x[j] == xp) {
- /* Trouble already. We might get lucky: */
- if (y[j] == yp) return(1);
-
- /* Go backward down the polygon until x[i] != xp: */
- if (y[j] > yp) above = TRUE;
- i = j - 1;
- while (x[i] == xp && i > 0) {
- if (y[i] == yp) return (1);
- if (!(above) && y[i] > yp) above = TRUE;
- i--;
- }
-
- /* Now if i == 0 polygon is degenerate line x=xp;
- since we know xp,yp is inside bounding box,
- it must be on edge: */
- if (i == 0) return(1);
-
- /* Now we want to mark this as the end, for later: */
- jend = i;
-
- /* Now if (j-i)>1 there are some segments the point could be exactly on: */
- for (k = i+1; k < j; k++) {
- if ( (y[k] <= yp && y[k+1] >= yp) || (y[k] >= yp && y[k+1] <= yp) ) return (1);
- }
-
-
- /* Now we have arrived where i is > 0 and < n_path-1, and x[i] != xp.
- We have been using j = n_path-1. Now we need to move j forward
- from the origin: */
- j = 1;
- while (x[j] == xp) {
- if (y[j] == yp) return (1);
- if (!(above) && y[j] > yp) above = TRUE;
- j++;
- }
-
- /* Now at the worst, j == jstop, and we have a polygon with only 1 vertex
- not at x = xp. But now it doesn't matter, that would end us at
- the main while below. Again, if j>=2 there are some segments to check: */
- for (k = 0; k < j-1; k++) {
- if ( (y[k] <= yp && y[k+1] >= yp) || (y[k] >= yp && y[k+1] <= yp) ) return (1);
- }
-
-
- /* Finally, we have found an i and j with points != xp. If (above) we may have crossed the ray: */
- if (above && x[i] < xp && x[j] > xp)
- crossing_count++;
- else if (above && x[i] > xp && x[j] < xp)
- crossing_count--;
-
- /* End nightmare scenario for x[0] == xp. */
- }
-
- else {
- /* Get here when x[0] != xp: */
- i = 0;
- j = 1;
- while (x[j] == xp && j < jend) {
- if (y[j] == yp) return (1);
- if (!(above) && y[j] > yp) above = TRUE;
- j++;
- }
- /* Again, if j==jend, (i.e., 0) then we have a polygon with only 1 vertex
- not on xp and we will branch out below. */
-
- /* if ((j-i)>2) the point could be on intermediate segments: */
- for (k = i+1; k < j-1; k++) {
- if ( (y[k] <= yp && y[k+1] >= yp) || (y[k] >= yp && y[k+1] <= yp) ) return (1);
- }
-
- /* Now we have x[i] != xp and x[j] != xp.
- If (above) and x[i] and x[j] on opposite sides, we are certain to have crossed the ray.
- If not (above) and (j-i)>1, then we have not crossed it.
- If not (above) and j-i == 1, then we have to check the intersection point. */
-
- if (x[i] < xp && x[j] > xp) {
- if (above)
- crossing_count++;
- else if ( (j-i) == 1) {
- y_sect = y[i] + (y[j] - y[i]) * ( (xp - x[i]) / (x[j] - x[i]) );
- if (y_sect == yp) return (1);
- if (y_sect > yp) crossing_count++;
- }
- }
- if (x[i] > xp && x[j] < xp) {
- if (above)
- crossing_count--;
- else if ( (j-i) == 1) {
- y_sect = y[i] + (y[j] - y[i]) * ( (xp - x[i]) / (x[j] - x[i]) );
- if (y_sect == yp) return (1);
- if (y_sect > yp) crossing_count--;
- }
- }
-
- /* End easier case for x[0] != xp */
- }
-
- /* Now MAIN WHILE LOOP begins:
- Set i = j, and search for a new j, and do as before. */
-
- i = j;
- while (i < jend) {
- above = FALSE;
- j = i+1;
- while (x[j] == xp) {
- if (y[j] == yp) return (1);
- if (!(above) && y[j] > yp) above = TRUE;
- j++;
- }
- /* if ((j-i)>2) the point could be on intermediate segments: */
- for (k = i+1; k < j-1; k++) {
- if ( (y[k] <= yp && y[k+1] >= yp) || (y[k] >= yp && y[k+1] <= yp) ) return (1);
- }
-
- /* Now we have x[i] != xp and x[j] != xp.
- If (above) and x[i] and x[j] on opposite sides, we are certain to have crossed the ray.
- If not (above) and (j-i)>1, then we have not crossed it.
- If not (above) and j-i == 1, then we have to check the intersection point. */
-
- if (x[i] < xp && x[j] > xp) {
- if (above)
- crossing_count++;
- else if ( (j-i) == 1) {
- y_sect = y[i] + (y[j] - y[i]) * ( (xp - x[i]) / (x[j] - x[i]) );
- if (y_sect == yp) return (1);
- if (y_sect > yp) crossing_count++;
- }
- }
- if (x[i] > xp && x[j] < xp) {
- if (above)
- crossing_count--;
- else if ( (j-i) == 1) {
- y_sect = y[i] + (y[j] - y[i]) * ( (xp - x[i]) / (x[j] - x[i]) );
- if (y_sect == yp) return (1);
- if (y_sect > yp) crossing_count--;
- }
- }
-
- /* That's it for this piece. Advance i: */
-
- i = j;
- }
-
- /* End of MAIN WHILE. Get here when we have gone all around without landing on edge. */
-
- if (crossing_count)
- return(2);
- else
- return(0);
- }
-
- /*
- * delaunay performs a Delaunay triangulation on the input data
- * and returns a list of indeces of the points for each triangle
- * found. Algorithm translated from
- * Watson, D. F., ACORD: Automatic contouring of raw data,
- * Computers & Geosciences, 8, 97-101, 1982.
- */
-
- int delaunay (x_in, y_in, n, link)
- double x_in[]; /* Input point x coordinates */
- double y_in[]; /* Input point y coordinates */
- int n; /* Number of input poins */
- int *link[]; /* pointer to List of point ids per triangle. Vertices for triangle no i
- is in link[i*3], link[i*3+1], link[i*3+2] */
- {
- int ix[3], iy[3];
- int i, j, ij, nuc, jt, km, id, isp, l1, l2, k, k1, jz, i2, kmt, kt, done, size;
- int *index, *istack, *x_tmp, *y_tmp;
- double det[2][3], *x_circum, *y_circum, *r2_circum, *x, *y;
- double xmin, xmax, ymin, ymax, datax, dx, dy, dsq, dd;
-
- size = 2 * n + 1;
- n += 3;
-
- index = (int *) memory (CNULL, 3 * size, sizeof (int), "delaunay");
- istack = (int *) memory (CNULL, size, sizeof (int), "delaunay");
- x_tmp = (int *) memory (CNULL, size, sizeof (int), "delaunay");
- y_tmp = (int *) memory (CNULL, size, sizeof (int), "delaunay");
- x_circum = (double *) memory (CNULL, size, sizeof (double), "delaunay");
- y_circum = (double *) memory (CNULL, size, sizeof (double), "delaunay");
- r2_circum = (double *) memory (CNULL, size, sizeof (double), "delaunay");
- x = (double *) memory (CNULL, n, sizeof (double), "delaunay");
- y = (double *) memory (CNULL, n, sizeof (double), "delaunay");
-
- x[0] = x[1] = -1.0; x[2] = 5.0;
- y[0] = y[2] = -1.0; y[1] = 5.0;
- x_circum[0] = y_circum[0] = 2.0; r2_circum[0] = 18.0;
-
- ix[0] = ix[1] = 0; ix[2] = 1;
- iy[0] = 1; iy[1] = iy[2] = 2;
-
- for (i = 0; i < 3; i++) index[i] = i;
- for (i = 0; i < size; i++) istack[i] = i;
-
- xmin = ymin = 1.0e100; xmax = ymax = -1.0e100;
-
- for (i = 3, j = 0; i < n; i++, j++) { /* Copy data and get extremas */
- x[i] = x_in[j];
- y[i] = y_in[j];
- if (x[i] > xmax) xmax = x[i];
- if (x[i] < xmin) xmin = x[i];
- if (y[i] > ymax) ymax = y[i];
- if (y[i] < ymin) ymin = y[i];
- }
-
- /* Normalize data */
-
- datax = 1.0 / MAX (xmax - xmin, ymax - ymin);
-
- for (i = 3; i < n; i++) {
- x[i] = (x[i] - xmin) * datax;
- y[i] = (y[i] - ymin) * datax;
- }
-
- isp = id = 1;
- for (nuc = 3; nuc < n; nuc++) {
-
- km = 0;
-
- for (jt = 0; jt < isp; jt++) { /* loop through established 3-tuples */
-
- ij = 3 * jt;
-
- /* Test if new data is within the jt circumcircle */
-
- dx = x[nuc] - x_circum[jt];
- if ((dsq = r2_circum[jt] - dx * dx) < 0.0) continue;
- dy = y[nuc] - y_circum[jt];
- if ((dsq -= dy * dy) < 0.0) continue;
-
- /* Delete this 3-tuple but save its edges */
-
- id--;
- istack[id] = jt;
-
- /* Add edges to x/y_tmp but delete if already listed */
-
- for (i = 0; i < 3; i++) {
- l1 = ix[i];
- l2 = iy[i];
- if (km > 0) {
- kmt = km;
- for (j = 0, done = FALSE; !done && j < kmt; j++) {
- if (index[ij+l1] != x_tmp[j]) continue;
- if (index[ij+l2] != y_tmp[j]) continue;
- km--;
- if (j >= km) {
- done = TRUE;
- continue;
- }
- for (k = j; k < km; k++) {
- k1 = k + 1;
- x_tmp[k] = x_tmp[k1];
- y_tmp[k] = y_tmp[k1];
- done = TRUE;
- }
- }
- }
- else
- done = FALSE;
- if (!done) {
- x_tmp[km] = index[ij+l1];
- y_tmp[km] = index[ij+l2];
- km++;
- }
- }
- }
-
- /* Form new 3-tuples */
-
- for (i = 0; i < km; i++) {
- kt = istack[id];
- ij = 3 * kt;
- id++;
-
- /* Calculate the circumcircle center and radius
- * squared of points ktetr[i,*] and place in tetr[kt,*] */
-
- for (jz = 0; jz < 2; jz++) {
- i2 = (jz == 0) ? x_tmp[i] : y_tmp[i];
- det[jz][0] = x[i2] - x[nuc];
- det[jz][1] = y[i2] - y[nuc];
- det[jz][2] = 0.5 * (det[jz][0] * (x[i2] + x[nuc]) + det[jz][1] * (y[i2] + y[nuc]));
- }
- dd = 1.0 / (det[0][0] * det[1][1] - det[0][1] * det[1][0]);
- x_circum[kt] = (det[0][2] * det[1][1] - det[1][2] * det[0][1]) * dd;
- y_circum[kt] = (det[0][0] * det[1][2] - det[1][0] * det[0][2]) * dd;
- dx = x[nuc] - x_circum[kt];
- dy = y[nuc] - y_circum[kt];
- r2_circum[kt] = dx * dx + dy * dy;
- index[ij++] = x_tmp[i];
- index[ij++] = y_tmp[i];
- index[ij] = nuc;
- }
- isp += 2;
- }
-
- for (jt = i = 0; jt < isp; jt++) {
- ij = 3 * jt;
- if (index[ij] < 3 || r2_circum[jt] > 1.0) continue;
- index[i++] = index[ij++] - 3;
- index[i++] = index[ij++] - 3;
- index[i++] = index[ij++] - 3;
- }
-
- index = (int *) memory ((char *)index, i, sizeof (int), "delaunay");
- *link = index;
-
- free ((char *)istack);
- free ((char *)x_tmp);
- free ((char *)y_tmp);
- free ((char *)x_circum);
- free ((char *)y_circum);
- free ((char *)r2_circum);
- free ((char *)x);
- free ((char *)y);
-
- return (i/3);
- }
-
- /*
- * grd_init initializes a grd header to default values and copies the
- * command line to the header variable command
- */
-
- int grd_init (header, argc, argv, update)
- struct GRD_HEADER *header;
- int argc;
- char **argv;
- BOOLEAN update; { /* TRUE if we only want to update command line */
- int i, len;
-
- /* Always update command line history */
-
- memset (header->command, 0, 320);
- if (argc > 0) {
- strcpy (header->command, argv[0]);
- len = strlen (header->command);
- for (i = 1; len < 320 && i < argc; i++) {
- len += strlen (argv[i]) + 1;
- if (len > 320) continue;
- strcat (header->command, " ");
- strcat (header->command, argv[i]);
- }
- header->command[len] = 0;
- }
-
- if (update) return; /* Leave other variables unchanged */
-
- /* Here we initialize the variables to default settings */
-
- header->x_min = header->x_max = 0.0;
- header->y_min = header->y_max = 0.0;
- header->z_min = header->z_max = 0.0;
- header->x_inc = header->y_inc = 0.0;
- header->z_scale_factor = 1.0;
- header->z_add_offset = 0.0;
- header->nx = header->ny = 0;
- header->node_offset = FALSE;
-
- memset (header->x_units, 0, 80);
- memset (header->y_units, 0, 80);
- memset (header->z_units, 0, 80);
- strcpy (header->x_units, "user_x_unit");
- strcpy (header->y_units, "user_y_unit");
- strcpy (header->z_units, "user_z_unit");
- memset (header->title, 0, 80);
- memset (header->remark, 0, 160);
- }
-
- int grd_shift (header, grd, shift)
- struct GRD_HEADER *header;
- float grd[];
- double shift; /* Rotate geographical, global grid in e-w direction */
- {
- /* This function will shift a grid by shift degrees */
-
- int i, j, k, ij, nc, n_shift, width;
- float *tmp;
-
- tmp = (float *) memory (CNULL, header->nx, sizeof (float), "grd_shift");
-
- n_shift = rint (shift / header->x_inc);
- width = (header->node_offset) ? header->nx : header->nx - 1;
- nc = header->nx * sizeof (float);
-
- for (j = ij = 0; j < header->ny; j++, ij += header->nx) {
- for (i = 0; i < width; i++) {
- k = (i - n_shift) % width;
- if (k < 0) k += header->nx;
- tmp[k] = grd[ij+i];
- }
- if (!header->node_offset) tmp[width] = tmp[0];
- memcpy ((char *)&grd[ij], (char *)tmp, nc);
- }
-
- /* Shift boundaries */
-
- header->x_min += shift;
- header->x_max += shift;
- if (header->x_max < 0.0) {
- header->x_min += 360.0;
- header->x_max += 360.0;
- }
- else if (header->x_max > 360.0) {
- header->x_min -= 360.0;
- header->x_max -= 360.0;
- }
-
- free ((char *) tmp);
- }
-
- /* grd_setregion determines what wesn should be passed to grd_read. It
- does so by using project_info.w,e,s,n which have been set correctly
- by map_setup. */
-
- int grd_setregion (h, xmin, xmax, ymin, ymax)
- struct GRD_HEADER *h;
- double *xmin, *xmax, *ymin, *ymax; {
-
- /* Round off to nearest multiple of the grid spacing. This should
- only affect the numbers when oblique projections or -R...r has been used */
-
- *xmin = floor (project_info.w / h->x_inc) * h->x_inc;
- *xmax = ceil (project_info.e / h->x_inc) * h->x_inc;
- if (fabs (h->x_max - h->x_min - 360.0) > SMALL) { /* Not a periodic grid */
- if (*xmin < h->x_min) *xmin = h->x_min;
- if (*xmax > h->x_max) *xmax = h->x_max;
- }
- *ymin = floor (project_info.s / h->y_inc) * h->y_inc;
- if (*ymin < h->y_min) *ymin = h->y_min;
- *ymax = ceil (project_info.n / h->y_inc) * h->y_inc;
- if (*ymax > h->y_max) *ymax = h->y_max;
- }
-
- /* code for bicubic rectangle and bilinear interpolation of grd files
- *
- * Author: Walter H F Smith
- * Date: 23 September 1993
- */
-
-
- void bcr_init(grd, pad, bilinear)
- struct GRD_HEADER *grd;
- int pad[]; /* padding on grid, as given to read_grd2 */
- int bilinear; /* T/F we only want bilinear */
- {
- /* Initialize i,j so that they cannot look like they have been used: */
- bcr.i = -10;
- bcr.j = -10;
-
- /* Initialize bilinear: */
- bcr.bilinear = bilinear;
-
- /* Initialize ioff, joff, mx, my according to grd and pad: */
- bcr.ioff = pad[0];
- bcr.joff = pad[3];
- bcr.mx = grd->nx + pad[0] + pad[1];
- bcr.my = grd->ny + pad[2] + pad[3];
-
- /* Initialize rx_inc, ry_inc, and offset: */
- bcr.rx_inc = 1.0 / grd->x_inc;
- bcr.ry_inc = 1.0 / grd->y_inc;
- bcr.offset = (grd->node_offset) ? 0.5 : 0.0;
-
- /* Initialize ij_move: */
- bcr.ij_move[0] = 0;
- bcr.ij_move[1] = 1;
- bcr.ij_move[2] = -bcr.mx;
- bcr.ij_move[3] = 1 - bcr.mx;
-
- return;
- }
-
- int set_bcr_boundaries (grd, f)
- struct GRD_HEADER *grd;
- float f[];
- {
- int i, j, ne, nw, se, sw;
-
- /* Get inside corner indeces */
-
- nw = bcr.joff * bcr.mx + bcr.ioff;
- ne = nw + grd->nx - 1;
- sw = (grd->ny + bcr.joff - 1) * bcr.mx + bcr.ioff;
- se = sw + grd->nx - 1;
-
- /* Set Natural spline boundary conditions */
-
- for (i = 0; i < grd->nx; i++) {
- j = nw - bcr.mx + i; /* Set top row */
- f[j] = f[j+bcr.mx] + (f[j+bcr.mx] - f[j+bcr.mx+bcr.mx]);
- j = sw + bcr.mx + i; /* Bottom row */
- f[j] = f[j-bcr.mx] + (f[j-bcr.mx] - f[j-bcr.mx-bcr.mx]);
- }
- for (i = 0; i < grd->ny; i++) {
- j = nw - 1 + i * bcr.mx; /* Left column */
- f[j] = f[j+1] + (f[j+1] - f[j+2]);
- j += (grd->nx + 1); /* Right column */
- f[j] = f[j-1] + (f[j-1] - f[j-2]);
- }
-
- f[nw-bcr.mx-1] = f[nw-bcr.mx] - (f[nw] - f[nw-1]); /* NW corner */
- f[ne-bcr.mx+1] = f[ne-bcr.mx] + (f[nw+1] - f[nw]); /* NE corner */
- f[sw+bcr.mx-1] = f[sw+bcr.mx] - (f[sw] - f[sw-1]); /* SW corner */
- f[se+bcr.mx+1] = f[se+1] - (f[se] - f[se+bcr.mx]); /* SE corner: */
- }
-
- void get_bcr_cardinals(x, y)
- double x;
- double y;
- {
- /* Given x,y compute the cardinal functions. Note x,y should be in
- * normalized range, usually [0,1) but sometimes a little outside this. */
-
- double xcf[2][2], ycf[2][2], tsq, tm1, tm1sq;
- int vertex, verx, very, value, valx, valy;
-
- if (bcr.bilinear) {
- bcr.bl_basis[0] = (1.0 - x)*(1.0 - y);
- bcr.bl_basis[1] = x*(1.0 - y);
- bcr.bl_basis[2] = y*(1.0 - x);
- bcr.bl_basis[3] = x*y;
-
- return;
- }
-
- /* Get here when we need to do bicubic functions: */
- tsq = x*x;
- tm1 = x - 1.0;
- tm1sq = tm1 * tm1;
- xcf[0][0] = (2.0*x + 1.0) * tm1sq;
- xcf[0][1] = x * tm1sq;
- xcf[1][0] = tsq * (3.0 - 2.0*x);
- xcf[1][1] = tsq * tm1;
-
- tsq = y*y;
- tm1 = y - 1.0;
- tm1sq = tm1 * tm1;
- ycf[0][0] = (2.0*y + 1.0) * tm1sq;
- ycf[0][1] = y * tm1sq;
- ycf[1][0] = tsq * (3.0 - 2.0*y);
- ycf[1][1] = tsq * tm1;
-
- for (vertex = 0; vertex < 4; vertex++) {
- verx = vertex%2;
- very = vertex/2;
- for (value = 0; value < 4; value++) {
- valx = value%2;
- valy = value/2;
-
- bcr.bcr_basis[vertex][value] = xcf[verx][valx] * ycf[very][valy];
- }
- }
- return;
- }
-
- void get_bcr_ij(grd, xx, yy, ii, jj)
- struct GRD_HEADER *grd;
- double xx, yy;
- int *ii, *jj;
- {
- /* Given xx, yy in user's grdfile x and y units (not normalized),
- set ii,jj to the point to be used for the bqr origin. This
- should have jj in the range 1 grd->ny-1 and ii in the range 0 to
- grd->nx-2, so that the north and east edges will not have the
- origin on them.
- This function should NOT be called unless xx,yy are within the
- valid range of the grid. */
-
- int i, j;
-
- i = floor((xx-grd->x_min)*bcr.rx_inc - bcr.offset);
- if (i < 0 ) i = 0;
- if (i > grd->nx-2) i = grd->nx-2;
- j = ceil ((grd->y_max-yy)*bcr.ry_inc - bcr.offset);
- if (j < 1) j = 1;
- if (j > grd->ny-1) j = grd->ny-1;
-
- *ii = i;
- *jj = j;
-
- return;
- }
-
- void get_bcr_xy(grd, xx, yy, x, y)
- struct GRD_HEADER *grd;
- double xx, yy;
- double *x, *y;
- {
- /* Given xx, yy in user's grdfile x and y units (not normalized),
- use the bcr.i and bcr.j to find x,y (normalized) which are the
- coordinates of xx,yy in the bcr rectangle. */
-
- double xorigin, yorigin;
-
- xorigin = (bcr.i + bcr.offset)*grd->x_inc + grd->x_min;
- yorigin = grd->y_max - (bcr.j + bcr.offset)*grd->y_inc;
-
- *x = (xx - xorigin) * bcr.rx_inc;
- *y = (yy - yorigin) * bcr.ry_inc;
-
- return;
- }
-
- void get_bcr_nodal_values(z, ii, jj)
- float z[];
- int ii, jj;
- {
- /* ii, jj is the point we want to use now, which is different from
- the bcr.i, bcr.j point we used last time this function was called.
- If (nan_condition == FALSE) && abs(ii-bcr.i) < 2 && abs(jj-bcr.j)
- < 2 then we can reuse some previous results. */
-
- int i, valstop, vertex, ij, ij_origin, k0, k1, k2, k3, dontneed[4];
-
- /* whattodo[vertex] says which vertices are previously known. */
- for (i = 0; i < 4; i++) dontneed[i] = FALSE;
-
- valstop = (bcr.bilinear) ? 1 : 4;
-
- if (!(bcr.nan_condition) && (abs(ii-bcr.i) < 2 && abs(jj-bcr.j) < 2) ) {
- /* There was no nan-condition last time and we can use some
- previously computed results. */
- switch (ii-bcr.i) {
- case 1:
- /* We have moved to the right ... */
- switch (jj-bcr.j) {
- case -1:
- /* ... and up. New 0 == old 3 */
- dontneed[0] = TRUE;
- for (i = 0; i < valstop; i++)
- bcr.nodal_value[0][i] = bcr.nodal_value[3][i];
- break;
- case 0:
- /* ... horizontally. New 0 == old 1; New 2 == old 3 */
- dontneed[0] = dontneed[2] = TRUE;
- for (i = 0; i < valstop; i++) {
- bcr.nodal_value[0][i] = bcr.nodal_value[1][i];
- bcr.nodal_value[2][i] = bcr.nodal_value[3][i];
- }
- break;
- case 1:
- /* ... and down. New 2 == old 1 */
- dontneed[2] = TRUE;
- for (i = 0; i < valstop; i++)
- bcr.nodal_value[2][i] = bcr.nodal_value[1][i];
- break;
- }
- break;
- case 0:
- /* We have moved only ... */
- switch (jj-bcr.j) {
- case -1:
- /* ... up. New 0 == old 2; New 1 == old 3 */
- dontneed[0] = dontneed[1] = TRUE;
- for (i = 0; i < valstop; i++) {
- bcr.nodal_value[0][i] = bcr.nodal_value[2][i];
- bcr.nodal_value[1][i] = bcr.nodal_value[3][i];
- }
- break;
- case 0:
- /* ... not at all. This shouldn't happen */
- return;
- break;
- case 1:
- /* ... down. New 2 == old 0; New 3 == old 1 */
- dontneed[2] = dontneed[3] = TRUE;
- for (i = 0; i < valstop; i++) {
- bcr.nodal_value[2][i] = bcr.nodal_value[0][i];
- bcr.nodal_value[3][i] = bcr.nodal_value[1][i];
- }
- break;
- }
- break;
- case -1:
- /* We have moved to the left ... */
- switch (jj-bcr.j) {
- case -1:
- /* ... and up. New 1 == old 2 */
- dontneed[1] = TRUE;
- for (i = 0; i < valstop; i++)
- bcr.nodal_value[1][i] = bcr.nodal_value[2][i];
- break;
- case 0:
- /* ... horizontally. New 1 == old 0; New 3 == old 2 */
- dontneed[1] = dontneed[3] = TRUE;
- for (i = 0; i < valstop; i++) {
- bcr.nodal_value[1][i] = bcr.nodal_value[0][i];
- bcr.nodal_value[3][i] = bcr.nodal_value[2][i];
- }
- break;
- case 1:
- /* ... and down. New 3 == old 0 */
- dontneed[3] = TRUE;
- for (i = 0; i < valstop; i++)
- bcr.nodal_value[3][i] = bcr.nodal_value[0][i];
- break;
- }
- break;
- }
- }
-
- /* When we get here, we are ready to look for new values (and possibly derivatives) */
-
- ij_origin = (jj + bcr.joff) * bcr.mx + (ii + bcr.ioff);
- bcr.i = ii;
- bcr.j = jj;
-
- for (vertex = 0; vertex < 4; vertex++) {
-
- if (dontneed[vertex]) continue;
-
- ij = ij_origin + bcr.ij_move[vertex];
- if (bad_float ((double)z[ij])) {
- bcr.nan_condition = TRUE;
- return;
- }
- bcr.nodal_value[vertex][0] = (double)z[ij];
-
- if (bcr.bilinear) continue;
-
- /* Get dz/dx: */
- if (bad_float ((double)z[ij+1]) || bad_float((double)z[ij-1]) ){
- bcr.nan_condition = TRUE;
- return;
- }
- bcr.nodal_value[vertex][1] = 0.5 * (z[ij+1] - z[ij-1]);
-
- /* Get dz/dy: */
- if (bad_float ((double)z[ij+bcr.mx]) || bad_float((double)z[ij-bcr.mx]) ){
- bcr.nan_condition = TRUE;
- return;
- }
- bcr.nodal_value[vertex][2] = 0.5 * (z[ij-bcr.mx] - z[ij+bcr.mx]);
-
- /* Get d2z/dxdy: */
- k0 = ij + bcr.mx - 1;
- if (bad_float ((double)z[k0])) {
- bcr.nan_condition = TRUE;
- return;
- }
- k1 = k0 + 2;
- if (bad_float ((double)z[k1])) {
- bcr.nan_condition = TRUE;
- return;
- }
- k2 = ij - bcr.mx - 1;
- if (bad_float ((double)z[k2])) {
- bcr.nan_condition = TRUE;
- return;
- }
- k3 = k2 + 2;
- if (bad_float ((double)z[k3])) {
- bcr.nan_condition = TRUE;
- return;
- }
- bcr.nodal_value[vertex][3] = 0.25 * ( (z[k3] - z[k2]) - (z[k1] - z[k0]) );
- }
-
- /* If we get here, we have not found any NaNs that would screw us up. */
- bcr.nan_condition = FALSE;
- return;
- }
-
- double get_bcr_z(grd, xx, yy, data)
- struct GRD_HEADER *grd;
- double xx, yy;
- float data[];
- {
- /* Given xx, yy in user's grdfile x and y units (not normalized),
- this routine returns the desired interpolated value (bilinear
- or bicubic) at xx, yy. */
-
- int i, j, vertex, value;
- double x, y, retval;
-
- if (xx < grd->x_min || xx > grd->x_max) return(gmt_NaN);
- if (yy < grd->y_min || yy > grd->y_max) return(gmt_NaN);
-
- if (fmod (xx, grd->x_inc) == 0.0 && fmod (yy, grd->y_inc) == 0.0) { /* Special case, simply return this node value */
- i = floor((xx-grd->x_min)*bcr.rx_inc - bcr.offset);
- j = ceil ((grd->y_max-yy)*bcr.ry_inc - bcr.offset);
- return ((double)data[(j+bcr.joff)*bcr.mx+i+bcr.ioff]);
- }
-
- get_bcr_ij(grd, xx, yy, &i, &j);
-
- if (i != bcr.i || j != bcr.j)
- get_bcr_nodal_values(data, i, j);
-
- if (bcr.nan_condition) return(gmt_NaN);
-
- get_bcr_xy(grd, xx, yy, &x, &y);
-
- if (x == 0.0) {
- if (y == 0.0)
- return(bcr.nodal_value[0][0]);
- if (y == 1.0)
- return(bcr.nodal_value[2][0]);
- }
- if (x == 1.0) {
- if (y == 0.0)
- return(bcr.nodal_value[1][0]);
- if (y == 1.0)
- return(bcr.nodal_value[3][0]);
- }
-
- get_bcr_cardinals(x, y);
-
- retval = 0.0;
- if (bcr.bilinear) {
- for (vertex = 0; vertex < 4; vertex++) {
- retval += (bcr.nodal_value[vertex][0] * bcr.bl_basis[vertex]);
- }
- return(retval);
- }
- for (vertex = 0; vertex < 4; vertex++) {
- for (value = 0; value < 4; value++) {
- retval += (bcr.nodal_value[vertex][value]*bcr.bcr_basis[vertex][value]);
- }
- }
- return(retval);
- }
-
- /* Table I/O routines for ascii and binary io */
-
- int ascii_input (fp, n, ptr)
- FILE *fp;
- int n;
- double **ptr;
- {
- char line[BUFSIZ], *p;
- int i = 0;
- double val;
-
- p = fgets (line, BUFSIZ, fp);
- if (!p) return (-1);
-
- p = strtok(line, " \t,");
- while (p && i < n) {
- gmt_data[i] = (sscanf (p, "%lf", &val) == 1) ? val : gmt_NaN;
- p = strtok(CNULL, " \t,");
- i++;
- }
-
- *ptr = gmt_data;
- return (i);
- }
-
- int bin_double_input (fp, n, ptr)
- FILE *fp;
- int n;
- double **ptr;
-
- {
- if (fread((char *) gmt_data, sizeof (double), n, fp) != n) return (EOF);
- *ptr = gmt_data;
- return (n);
- }
-
-
- int bin_float_input (fp, n, ptr)
- FILE *fp;
- int n;
- double **ptr;
- {
- int i;
- static float gmt_f[BUFSIZ];
-
- if (fread((char *) gmt_f, sizeof (float), n, fp) != n) return (EOF);
- for (i = 0; i < n; i++) gmt_data[i] = (double)gmt_f[i];
- *ptr = gmt_data;
- return (n);
- }
-
- int ascii_output (fp, n, ptr)
- FILE *fp;
- int n;
- double *ptr;
- {
- int i;
-
- n--;
- for (i = 0; i < n; i++) {
- (bad_float (ptr[i])) ? fprintf (fp, "NaN\t") : (fprintf (fp, gmtdefs.d_format, ptr[i]), putc ('\t', fp));
- }
- (bad_float (ptr[n])) ? fprintf (fp, "NaN\n") : (fprintf (fp, gmtdefs.d_format, ptr[n]), putc ('\n', fp));
- }
-
- int bin_double_output (fp, n, ptr)
- FILE *fp;
- int n;
- double *ptr;
-
- {
- fwrite((char *) ptr, sizeof (double), n, fp);
- }
-
- int bin_float_output (fp, n, ptr)
- FILE *fp;
- int n;
- double *ptr;
- {
- int i;
- static float gmt_f[BUFSIZ];
-
- for (i = 0; i < n; i++) gmt_f[i] = (float)ptr[i];
- fwrite((char *) gmt_f, sizeof (float), n, fp);
- }
-
-