home *** CD-ROM | disk | FTP | other *** search
Wrap
/*-------------------------------------------------------------------- * The GMT-system: @(#)grdcontour.c 2.46 22 Jun 1995 * * Copyright (c) 1991-1995 by P. Wessel and W. H. F. Smith * See README file for copying and redistribution conditions. *--------------------------------------------------------------------*/ /* * grdcontour reads a 2-D grd file and contours it. This algoritm handles * cases where the old contourm failed, e.g. when a contour line passes * exactly through a data point. This is achieved by adding a tiny * number to those data points that would have a contour line going * through them. This is cheating, but the human eye cannot tell the * difference, so who cares? * A multitude of options exist and are explained in the usage message. * The 2-D grd file format is outlined in the routines read_grd/write_grd. * * Author: Paul Wessel * Date: 6-JAN-1991-1995 * Version: 2.0 Based on old v1.x by Paul Wessel & Walter Smith * */ #include "gmt.h" #define MIN_LENGTH 0.01 float *grd; int *edge; double *x, *y; /* Arrays holding the contour xy values */ struct LABEL { double x, y; double angle; char label[32]; struct LABEL *next_label, *prev_label; } *anchor, *old_label; struct SAVE { double *x, *y; double cval; int n, pen; BOOLEAN do_it, high; } *save; main (argc, argv) int argc; char **argv; { int i, j, n, nm, c, n_edges, label_font_size = 9, br, bg, bb, n_alloc; int section, n_contours, smooth_factor = 0, side, id, box = 1, bad; int dummy[4], off, nx, ny, half = 5, n_save = 0, got, ncut = 0; BOOLEAN error = FALSE, first = TRUE, dump = FALSE, anot = FALSE, interior, begin; BOOLEAN fix_angle = FALSE, do_ticks = FALSE, multi_segments = FALSE; BOOLEAN tick_high = FALSE, tick_low = FALSE, cpt_given = FALSE, tick_label = FALSE; char *grdfile = 0, dfile[512], line[512], *cont_type, *cont_do_tick, EOL_flag = '>'; char *cpt_file, *labels; double c_int = 0.0, c_low, c_high, take_out, aval, a_int = 0.0, tick_gap = 0.2; double anot_dist, west = 0.0, east = 0.0, south = 0.0, north = 0.0, tick_length = 0.05; double *contour, cval, mult = 1.0, min, max, small, label_angle = 0.0; double small_x, small_y, data_west, data_east, data_south, data_north, tmp, *cont_angle; FILE *fpc = NULL; struct GRD_HEADER header; struct PEN pen[2]; argc = gmt_begin (argc, argv); gmt_init_pen (&pen[0], 1); gmt_init_pen (&pen[1], 3); c_low = -MAXDOUBLE; c_high = MAXDOUBLE; dfile[0] = 0; anot_dist = 4.0; /* Distance in inches between anotations */ if (!gmtdefs.measure_unit) { /* change to cm */ anot_dist = 10.0; tick_gap = 0.5; tick_length = 0.1; } br = gmtdefs.page_rgb[0]; /* Default box color is page color */ bg = gmtdefs.page_rgb[1]; bb = gmtdefs.page_rgb[2]; dummy[0] = dummy[1] = dummy[2] = dummy[3] = 0; for (i = 1; i < argc; i++) { if (argv[i][0] == '-') { switch (argv[i][1]) { /* Common parameters */ case 'B': case 'J': case 'K': case 'O': case 'P': case 'R': case 'U': case 'V': case 'X': case 'x': case 'Y': case 'y': case 'c': case '\0': error += get_common_args (argv[i], &west, &east, &south, &north); break; /* Supplemental parameters */ case 'A': n = sscanf (&argv[i][2], "%lf", &a_int); for (j = 2, bad = 0; argv[i][j] && argv[i][j] != 'f'; j++); if (argv[i][j]) { /* Found font size option */ label_font_size = atoi (&argv[i][j+1]); if (label_font_size <= 0) bad++; } for (j = 2; argv[i][j] && argv[i][j] != 'a'; j++); if (argv[i][j]) { /* Found fixed angle option */ label_angle = atof (&argv[i][j+1]); fix_angle = TRUE; if (label_angle <= -90.0 || label_angle > 180.0) bad++; } for (j = 2; argv[i][j] && argv[i][j] != '/'; j++); if (argv[i][j] && gmt_getrgb (&argv[i][j+1], &br, &bg, &bb)) bad++; anot = TRUE; if (strchr (argv[i], 'o')) box = 2; if (bad) { fprintf (stderr, "%s: GMT SYNTAX ERROR -A option. Correct syntax:\n", gmt_program); fprintf (stderr, "\t-A[aint][f<fontsize>][a<fixedangle>][/<r/g/b>][o]\n"); error += bad; } break; case 'C': if ((fpc = fopen (&argv[i][2], "r")) == NULL) c_int = atof (&argv[i][2]); else { c_int = 1.0; cpt_given = (int) strstr (&argv[i][2], ".cpt"); cpt_file = &argv[i][2]; } break; case 'D': dump = TRUE; strcpy (dfile, &argv[i][2]); break; case 'E': sscanf (&argv[i][2], "%lf/%lf", &z_project.view_azimuth, &z_project.view_elevation); break; case 'F': if (gmt_getrgb (&argv[i][2], &gmtdefs.basemap_frame_rgb[0], &gmtdefs.basemap_frame_rgb[1], &gmtdefs.basemap_frame_rgb[2])) { gmt_pen_syntax ('F'); error++; } break; case 'G': sscanf (&argv[i][2], "%lf/%d", &anot_dist, &half); half /= 2; break; case 'L': sscanf (&argv[i][2], "%lf/%lf", &c_low, &c_high); break; case 'M': /* with -D, create one multiple line segments */ multi_segments = 2; if (argv[i][2]) EOL_flag = argv[i][2]; break; case 'S': smooth_factor = atoi (&argv[i][2]); break; case 'Q': ncut = atoi (&argv[i][2]); break; case 'T': if (argv[i][2]) { if (argv[i][2] == '+') tick_high = TRUE, j = 1; else if (argv[i][2] == '-') tick_low = TRUE, j = 1; else tick_high = tick_low = TRUE, j = 0; n = sscanf (&argv[i][2+j], "%lf/%lf", &tick_gap, &tick_length); if (n != 2 || tick_gap <= 0.0 || tick_length == 0.0) { fprintf (stderr, "%s: GMT SYNTAX ERROR -T option. Correct syntax:\n", gmt_program); fprintf (stderr, "\t-T[+|-]<tick_gap>/<tick_length>[:LH], <tick_gap> must be > 0\n"); error = TRUE; } do_ticks = TRUE; for (j = 2; argv[i][j] && argv[i][j] != ':'; j++); if (argv[i][j]) { j++; tick_label = TRUE; labels = &argv[i][j]; } } break; case 'W': j = (argv[i][2] == 'a' || argv[i][2] == 'c') ? 3 : 2; if (j == 2) { /* Set both */ if (gmt_getpen (&argv[i][j], &pen[0])) { gmt_pen_syntax ('W'); error++; } else pen[1] = pen[0]; } else { id = (argv[i][2] == 'a') ? 1 : 0; if (gmt_getpen (&argv[i][j], &pen[id])) { gmt_pen_syntax ('W'); error++; } } break; case 'Z': mult = atof (&argv[i][2]); break; default: error++; gmt_default_error (argv[i][1]); break; } } else grdfile = argv[i]; } if (argc == 1 || gmt_quick) { fprintf (stderr,"grdcontour %s - Contouring of 2-D gridded data sets\n\n", GMT_VERSION); fprintf (stderr, "usage: grdcontour <grdfile> -C<cont_int> -J<params> [-A[<anot_int>][f<fontsize>][/r/g/b][a<angle>][o]]\n"); fprintf (stderr, " [-B<tickinfo>] [-D<dumpfile>] [-Eaz/el] [-F<r/g/b>] [-G<gap>/<npoints>] [-K] [-L<Low/high>]\n"); fprintf (stderr, " [-M[<flag>]] [-O] [-P] [-Q<cut>] [-R<west/east/south/north>] [-S<smooth>] [-T[+|-][<gap/length>][:LH]] [-U[<label>]] [-V]\n"); fprintf (stderr, " [-W<type><pen>] [-X<x_shift>] [-Y<y_shift>] [-Z<fact>] [-c<ncopies>]\n\n"); if (gmt_quick) exit (-1); fprintf (stderr, " <grdfile> is 2-D netCDF grdfile to be contoured\n"); fprintf (stderr, " -C Contours to be drawn can be specified in one of three ways:\n"); fprintf (stderr, " -Fixed contour interval\n"); fprintf (stderr, " -Name of file with contour levels in col 1 and C(ont) or A(not) in col 2\n"); fprintf (stderr, " [and optionally an individual annotation angle in col 3.]\n"); fprintf (stderr, " -Name of cpt-file\n"); fprintf (stderr, " If -T is used, only contours with upper case C or A is ticked\n"); fprintf (stderr, " [cpt-file contours are set to C unless last column has flags; Use -A to force all to A]\n"); explain_option ('j'); fprintf (stderr, "\n\tOPTIONS:\n"); fprintf (stderr, " -A Annotation information. [Default is no annotation].\n"); fprintf (stderr, " Append f followed by desired font size in points [Default is 9].\n"); fprintf (stderr, " Append /r/g/b to change color of text box [Default is %d/%d/%d]\n", br, bg, bb); fprintf (stderr, " Append o to draw outline of text box [Default is no outline]\n"); fprintf (stderr, " Append a<angle> to force anotations at this fixed angle [Default follows contour]\n"); explain_option ('b'); fprintf (stderr, " -D to Dump contour lines to individual files (but see -M)\n"); fprintf (stderr, " -E set azimuth and elevation of viewpoint for 3-D perspective [180/90]\n"); fprintf (stderr, " -F Set color used for Frame and anotation [%d/%d/%d]\n", gmtdefs.basemap_frame_rgb[0], gmtdefs.basemap_frame_rgb[1], gmtdefs.basemap_frame_rgb[2]); fprintf (stderr, " -G Gap between anotations in %s and number of (x,y) values used to find L2 label angle [Default = %lg/10]\n", gmt_unit_names[gmtdefs.measure_unit], anot_dist); explain_option ('K'); fprintf (stderr, " -L only contour inside this range\n"); fprintf (stderr, " -M Used with -D. Create a single multiple segment file where contours are separated by a record\n"); fprintf (stderr, " whose first character is <flag> ['>']. This header also has the contour level value\n"); explain_option ('O'); explain_option ('P'); fprintf (stderr, " -Q Do not draw contours with less than <cut> points [Draw all contours]\n"); explain_option ('R'); fprintf (stderr, " [Default is extent of grdfile]\n"); fprintf (stderr, " -S will Smooth contours by splining and resampling\n"); fprintf (stderr, " at approximately gridsize/<smooth> intervals\n"); fprintf (stderr, " -T will embellish innermost, closed contours with ticks pointing in the downward direction\n"); fprintf (stderr, " User may specify to tick only highs (-T+) or lows (-T-) [-T means both]\n"); fprintf (stderr, " Append spacing/ticklength (in %s) to change defaults [%lg/%lg]\n", gmt_unit_names[gmtdefs.measure_unit], tick_gap, tick_length); fprintf (stderr, " Append :LH to plot the characters L and H in the center of closed contours\n"); fprintf (stderr, " for local Lows and Highs (e.g, give :-+ to plot - and + signs)\n"); explain_option ('U'); explain_option ('V'); fprintf (stderr, " -W sets pen attributes. <type> can be 'a' for anotated contours and\n"); fprintf (stderr, " 'c' for regular contours. The default settings are\n"); fprintf (stderr, " Contour pen: width = %d, color = (%d/%d/%d), texture = solid\n", pen[0].width, pen[0].r, pen[0].g, pen[0].b); fprintf (stderr, " Annotate pen: width = %d, color = (%d/%d/%d), texture = solid\n", pen[1].width, pen[1].r, pen[1].g, pen[1].b); explain_option ('X'); fprintf (stderr, " -Z to multiply data by <fact> before contouring.\n"); explain_option ('c'); exit(-1); } if (a_int > 0.0 && (!fpc && c_int == 0.0)) c_int = a_int; if (!fpc && c_int <= 0.0) { fprintf (stderr, "%s: GMT SYNTAX ERROR -C option: Must specify contour interval, file name with levels, or cpt-file\n", gmt_program); error++; } if (c_low >= c_high) { fprintf (stderr, "%s: GMT SYNTAX ERROR -L option: lower limit >= upper!\n", gmt_program); error++; } if (smooth_factor < 0) { fprintf (stderr, "%s: GMT SYNTAX ERROR -S option: Smooth_factor must be > 0\n", gmt_program); error++; } if (z_project.view_azimuth > 360.0 || z_project.view_elevation <= 0.0 || z_project.view_elevation > 90.0) { fprintf (stderr, "%s: GMT SYNTAX ERROR -E option: Enter azimuth in 0-360 range, elevation in 0-90 range\n", gmt_program); error++; } if (!grdfile) { fprintf (stderr, "%s: GMT SYNTAX ERROR: Must specify input file\n", gmt_program); error++; } if (anot_dist <= 0.0 || half <= 0) { fprintf (stderr, "%s: GMT SYNTAX ERROR -G option. Correct syntax:\n", gmt_program); fprintf (stderr, "\t-G<anot_dist>/<npoints>, both values must be > 0\n"); error++; } if (mult == 0.0) { fprintf (stderr, "%s: GMT SYNTAX ERROR -Z option: factor must be nonzero\n", gmt_program); error++; } if (error) exit (-1); if (dump && dfile[0] == 0) strcpy (dfile,"contour"); if (gmtdefs.verbose) fprintf (stderr, "grdcontour: Allocate memory and read data file\n"); if (!strcmp (grdfile, "=")) { fprintf (stderr, "grdcontour: Piping of grdfile not supported!\n"); exit (-1); } if (read_grd_info (grdfile, &header)) { fprintf (stderr, "grdcontour: Error opening file %s\n", grdfile); exit (-1); } off = (header.node_offset) ? 0 : 1; /* Determine what wesn to pass to map_setup */ if (west == east && south == north) { west = header.x_min; east = header.x_max; south = header.y_min; north = header.y_max; } map_setup (west, east, south, north); /* Determine the wesn to be used to read the grdfile */ grd_setregion (&header, &data_west, &data_east, &data_south, &data_north); /* Read data */ nx = rint ( (data_east - data_west) / header.x_inc) + off; ny = rint ( (data_north - data_south) / header.y_inc) + off; nm = nx * ny; grd = (float *) memory (CNULL, nm, sizeof (float), "grdcontour"); if (read_grd (grdfile, &header, grd, data_west, data_east, data_south, data_north, dummy, FALSE)) { fprintf (stderr, "grdcontour: Error reading file %s\n", grdfile); exit (-1); } anchor = old_label = (struct LABEL *) memory (CNULL, 1, sizeof (struct LABEL), "grdcontour"); n_edges = header.ny * (int )ceil (header.nx / 16.0); edge = (int *) memory (CNULL, n_edges, sizeof (int), "grdcontour"); if (mult != 1.0) { if (gmtdefs.verbose) fprintf (stderr, "grdcontour: Multiplying grid by %lg\n", mult); for (i = 1; i < nm; i++) grd[i] *= mult; header.z_min *= mult; header.z_max *= mult; if (mult < 0.0) d_swap (header.z_min, header.z_max); } if (c_low > header.z_min) header.z_min = c_low; if (c_high < header.z_max) header.z_max = c_high; small = c_int * 1.0e-6; if (a_int == 0.0) a_int = c_int; small_x = 0.01 * header.x_inc; small_y = 0.01 * header.y_inc; ps_plotinit (CNULL, gmtdefs.overlay, gmtdefs.page_orientation, gmtdefs.x_origin, gmtdefs.y_origin, gmtdefs.global_x_scale, gmtdefs.global_y_scale, gmtdefs.n_copies, gmtdefs.dpi, gmtdefs.measure_unit, gmtdefs.paper_width, gmtdefs.page_rgb, gmt_epsinfo (argv[0])); echo_command (argc, argv); if (gmtdefs.unix_time) timestamp (argc, argv); if (project_info.three_D) ps_transrotate (-z_project.xmin, -z_project.ymin, 0.0); if (anot) { /* Wants anotated contours */ aval = floor (header.z_min / a_int) * a_int; if (aval < header.z_min) aval += a_int; } else aval = header.z_max + 1.0; n_alloc = GMT_CHUNK; contour = (double *) memory (CNULL, n_alloc, sizeof (double), "grdcontour"); cont_type = memory (CNULL, n_alloc, sizeof (char), "grdcontour"); cont_do_tick = memory (CNULL, n_alloc, sizeof (char), "grdcontour"); cont_angle = (double *) memory (CNULL, n_alloc, sizeof (double), "grdcontour"); if (cpt_given) { /* Presumably got a cpt-file */ read_cpt (cpt_file); n_contours = gmt_n_colors + 1; if (n_contours > n_alloc) { contour = (double *) memory ((char *)contour, n_contours, sizeof (double), "grdcontour"); cont_type = memory (cont_type, n_contours, sizeof (char), "grdcontour"); cont_do_tick = memory (cont_do_tick, n_contours, sizeof (char), "grdcontour"); cont_angle = (double *) memory ((char *)cont_angle, n_contours, sizeof (double), "grdcontour"); } for (i = 0; i < gmt_n_colors; i++) { contour[i] = gmt_lut[i].z_low; if (gmt_lut[i].anot) cont_type[i] = 'A'; else cont_type[i] = (anot) ? 'A' : 'C'; cont_angle[i] = (fix_angle) ? label_angle : gmt_NaN; cont_do_tick[i] = do_ticks; } contour[gmt_n_colors] = gmt_lut[gmt_n_colors-1].z_high; if (gmt_lut[gmt_n_colors-1].anot & 2) cont_type[gmt_n_colors] = 'A'; else cont_type[gmt_n_colors] = (anot) ? 'A' : 'C'; cont_angle[gmt_n_colors] = (fix_angle) ? label_angle : gmt_NaN; cont_do_tick[gmt_n_colors] = do_ticks; } else if (fpc != NULL) { /* read contour info from file */ n_contours = 0; while (fgets (line, 512, fpc)) { if (line[0] == '#') continue; got = sscanf (line, "%lf %c %lf", &contour[n_contours], &cont_type[n_contours], &tmp); if (cont_type[n_contours] == 0) cont_type[n_contours] = 'C'; cont_do_tick[n_contours] = (do_ticks && ((cont_type[n_contours] == 'C') || (cont_type[n_contours] == 'A'))) ? 1 : 0; cont_angle[n_contours] = (got == 3) ? tmp : gmt_NaN; n_contours++; if (n_contours == n_alloc) { n_alloc += GMT_CHUNK; contour = (double *) memory ((char *)contour, n_alloc, sizeof (double), "grdcontour"); cont_type = memory (cont_type, n_alloc, sizeof (char), "grdcontour"); cont_do_tick = memory (cont_do_tick, n_alloc, sizeof (char), "grdcontour"); cont_angle = (double *) memory ((char *)cont_angle, n_alloc, sizeof (double), "grdcontour"); } } fclose (fpc); } else { /* Set up contour intervals automatically from c_int and a_int */ min = floor (header.z_min / c_int) * c_int; if (min < header.z_min) min += c_int; max = ceil (header.z_max / c_int) * c_int; if (max > header.z_max) max -= c_int; for (c = rint(min/c_int), n_contours = 0; c <= rint(max/c_int); c++, n_contours++) { if (n_contours == n_alloc) { n_alloc += GMT_CHUNK; contour = (double *) memory ((char *)contour, n_alloc, sizeof (double), "grdcontour"); cont_type = memory (cont_type, n_alloc, sizeof (char), "grdcontour"); cont_angle = (double *) memory ((char *)cont_angle, n_alloc, sizeof (double), "grdcontour"); } contour[n_contours] = c * c_int; if (anot && (contour[n_contours] - aval) > SMALL) aval += a_int; cont_type[n_contours] = (fabs (contour[n_contours] - aval) < SMALL) ? 'A' : 'C'; cont_angle[n_contours] = (fix_angle) ? label_angle : gmt_NaN; cont_do_tick[n_contours] = do_ticks; } } contour = (double *) memory ((char *)contour, n_contours, sizeof (double), "grdcontour"); cont_type = memory (cont_type, n_contours, sizeof (char), "grdcontour"); cont_do_tick = memory (cont_do_tick, n_contours, sizeof (char), "grdcontour"); cont_angle = (double *) memory ((char *)cont_angle, n_contours, sizeof (double), "grdcontour"); if (do_ticks) save = (struct SAVE *) memory (CNULL, n_alloc, sizeof (struct SAVE), "grdcontour"); for (c = 0; c < n_contours; c++) { /* For each contour value cval */ /* Reset markers and set up new zero-contour*/ cval = contour[c]; if (gmtdefs.verbose) fprintf (stderr, "grdcontour: Tracing the %lg contour\n", cval); take_out = (first) ? cval : contour[c] - contour[c-1]; for (i = 0; i < nm; i++) { grd[i] -= take_out; if (grd[i] == 0.0) grd[i] += small; } section = 0; first = FALSE; id = (cont_type[c] == 'A' || cont_type[c] == 'a') ? 1 : 0; ps_setline (pen[id].width); ps_setpaint (pen[id].r, pen[id].g, pen[id].b); if (pen[id].texture) ps_setdash (pen[id].texture, pen[id].offset); side = 0; begin = TRUE; while (side < 5) { while ((n = contours (grd, &header, smooth_factor, gmtdefs.interpolant, &side, edge, begin, &x, &y)) > 0) { if (fabs (x[0] - x[n-1]) < small_x && fabs (y[0] - y[n-1]) < small_y) { interior = TRUE; x[n-1] = x[0]; y[n-1] = y[0]; } else interior = FALSE; if (dump) dump_contour (x, y, n, cval, section, interior, dfile, &multi_segments, EOL_flag); if (n >= ncut) draw_contour (x, y, n, cval, cont_type[c], cont_angle[c], interior, anot_dist, half); if (cont_do_tick[c] && interior && n >= ncut) { save[n_save].x = (double *) memory (CNULL, n, sizeof (double), "grdcontour"); save[n_save].y = (double *) memory (CNULL, n, sizeof (double), "grdcontour"); memcpy ((char *)save[n_save].x, (char *)x, n * sizeof (double)); memcpy ((char *)save[n_save].y, (char *)y, n * sizeof (double)); save[n_save].n = n; save[n_save].pen = pen[id].width; save[n_save].do_it = TRUE; save[n_save].cval = cval; n_save++; if (n_save == n_alloc) { save = (struct SAVE *) memory ((char *)save, n_alloc, sizeof (struct SAVE), "grdcontour"); n_alloc += GMT_CHUNK; } } if (n >= ncut) section++; begin = FALSE; free ((char *)x); free ((char *)y); } begin = FALSE; } } if (pen[0].texture || pen[1].texture) ps_setdash (CNULL, 0); if (do_ticks && n_save) { save = (struct SAVE *) memory ((char *)save, n_save, sizeof (struct SAVE), "grdcontour"); read_grd_info (grdfile, &header); read_grd (grdfile, &header, grd, data_west, data_east, data_south, data_north, dummy, FALSE); if (mult != 1.0) { for (i = 1; i < nm; i++) grd[i] *= mult; header.z_min *= mult; header.z_max *= mult; if (mult < 0.0) d_swap (header.z_min, header.z_max); } sort_and_plot_ticks (save, n_save, &header, grd, tick_gap, tick_length, tick_low, tick_high, tick_label, labels); for (i = 0; i < n_save; i++) { free ((char *)save[i].x); free ((char *)save[i].y); } free ((char *)save); } plot_labels (label_font_size, box, br, bg, bb); if (frame_info.plot) { ps_setpaint (gmtdefs.basemap_frame_rgb[0], gmtdefs.basemap_frame_rgb[1], gmtdefs.basemap_frame_rgb[2]); map_basemap (); } ps_setpaint (gmtdefs.background_rgb[0], gmtdefs.background_rgb[1], gmtdefs.background_rgb[2]); if (project_info.three_D) ps_rotatetrans (z_project.xmin, z_project.ymin, 0.0); ps_plotend (gmtdefs.last_page); free ((char *)grd); free ((char *)edge); free ((char *)contour); free (cont_type); free ((char *)cont_angle); free (cont_do_tick); if (gmtdefs.verbose) fprintf (stderr, "grdcontour: Done!\n"); gmt_end (argc, argv); } int dump_contour (xx, yy, nn, cval, id, interior, file, m_segment, flag) double *xx, *yy, cval; char *file, flag; int nn, id; BOOLEAN interior, *m_segment; { int i; char fname[512], format[80]; FILE *fp; if (nn < 2) return; sprintf (format, "%s\t%s\t%s\n\0", gmtdefs.d_format, gmtdefs.d_format, gmtdefs.d_format); if (*m_segment) { if (*m_segment == 2) { /* Must create file the first time around */ fp = fopen (file, "w"); *m_segment = TRUE; } else /* Later we append to it */ fp = fopen (file, "a+"); fprintf (fp, "%c %lg contour\n", flag, cval); } else { if (interior) sprintf (fname, "%s_%lg_%d_i.xyz\0", file, cval, id); else sprintf (fname, "%s_%lg_%d.xyz\0", file, cval, id); fp = fopen (fname, "w"); } for (i = 0; i < nn; i++) fprintf (fp, format, xx[i], yy[i], cval); fclose (fp); } int draw_contour (xx, yy, nn, cval, ctype, cangle, closed, gap, half_width) double *xx, *yy, cval, cangle, gap; char ctype; int nn, closed, half_width; { int i, j; double dist, angle, dx, dy, width, sum_x2, sum_xy, one = 1.0; char label[100], format[50]; struct LABEL *new_label; if (nn < 2) return; sprintf (format, "%lg contour\0", cval); ps_comment (format); gmt_n_plot = geo_to_xy_line (xx, yy, nn); gmt_plot_line (gmt_x_plot, gmt_y_plot, gmt_pen, gmt_n_plot); if (ctype == 'A' || ctype == 'a') { /* Annotated contours */ if (!gmtdefs.measure_unit) one = 2.5; get_format (cval, format); sprintf (label, format, cval); dist = (closed) ? gap - one : 0.0; /* Label closed contours longer than 1 inch */ for (i = 1; i < gmt_n_plot; i++) { if (gmt_pen[i] == 3) continue; dx = gmt_x_plot[i] - gmt_x_plot[i-1]; if (fabs (dx) > (width = gmt_half_map_width (gmt_y_plot[i-1]))) { width *= 2.0; dx = copysign (width - fabs (dx), -dx); if (gmt_x_plot[i] < width) gmt_x_plot[i-1] -= width; else gmt_x_plot[i-1] += width; } dy = gmt_y_plot[i] - gmt_y_plot[i-1]; dist += hypot (dx, dy); if (dist > gap) { /* Time for label */ new_label = (struct LABEL *) memory (CNULL, 1, sizeof (struct LABEL), "grdcontour"); new_label->x = 0.5 * (gmt_x_plot[i-1] + gmt_x_plot[i]); new_label->y = 0.5 * (gmt_y_plot[i-1] + gmt_y_plot[i]); strcpy (new_label->label, label); sum_x2 = sum_xy = 0.0; for (j = i - half_width; j <= i + half_width; j++) { /* L2 fit for slope */ if (j < 0 || j >= gmt_n_plot) continue; dx = gmt_x_plot[j] - new_label->x; dy = gmt_y_plot[j] - new_label->y; sum_x2 += dx * dx; sum_xy += dx * dy; } if (bad_float (cangle)) { /* Must calculate label angle */ angle = d_atan2 (sum_xy, sum_x2) * R2D; if (angle < 0.0) angle += 360.0; if (angle > 90.0 && angle < 270) angle -= 180.0; } else angle = cangle; new_label->angle = angle; new_label->prev_label = old_label; dist = 0.0; old_label->next_label = new_label; old_label = new_label; } gmt_x_plot[i-1] = gmt_x_plot[i]; gmt_y_plot[i-1] = gmt_y_plot[i]; } } } int plot_labels (size, box, r, g, b) int size, box, r, g, b; { /* box = 1: white box only, box = 2: white box + draw outline */ double dx, dy; struct LABEL *this, *old; dx = 0.5 * gmtdefs.anot_offset; dy = 0.05 * gmtdefs.anot_offset; box--; ps_comment ("Contour annotations:"); ps_setpaint (gmtdefs.basemap_frame_rgb[0], gmtdefs.basemap_frame_rgb[1], gmtdefs.basemap_frame_rgb[2]); for (old = anchor; old->next_label; old = old->next_label) { /* First draw boxes if not 3-D*/ this = old->next_label; gmt_textbox3d (this->x, this->y, project_info.z_level, size, gmtdefs.anot_font, this->label, this->angle, 6, box, dx, dy, r, g, b); } for (old = anchor; old->next_label; old = old->next_label) { /* Then labels */ this = old->next_label; gmt_text3d (this->x, this->y, project_info.z_level, size, gmtdefs.anot_font, this->label, this->angle, 6, 0); } ps_setpaint (gmtdefs.background_rgb[0], gmtdefs.background_rgb[1], gmtdefs.background_rgb[2]); this = anchor; while (this) { /* Free memory */ old = this; this = old->next_label; free ((char *)old); } } int sort_and_plot_ticks (save, n, h, grd, tick_gap, tick_length, tick_low, tick_high, tick_label, labels) struct SAVE save[]; int n; struct GRD_HEADER *h; float grd[]; double tick_gap, tick_length; BOOLEAN tick_low, tick_high, tick_label; char *labels; { int np, i, j, inside, ix, iy, done, n_ticks; double x0, y0, add, sign, dx, dy, x_back, y_back, x_front, y_front; double xmin, xmax, ymin, ymax, x_mean, y_mean, inc, dist, a, small, *s; char txt[2][2]; small = 0.1 * project_info.xmax / h->nx; if (tick_label) { txt[0][0] = labels[0]; txt[0][1] = 0; txt[1][0] = labels[1]; txt[1][1] = 0; } for (i = 0; i < n; i++) { np = save[i].n; for (j = 0; save[i].do_it && j < n; j++) { inside = non_zero_winding (save[j].x[0], save[j].y[0], save[i].x, save[i].y, np); if (inside == 2) save[i].do_it = FALSE; } } for (i = 0; i < n; i++) { if (!save[i].do_it) continue; np = save[i].n; s = (double *) memory (CNULL, np, sizeof (double), "grdcontour"); xmin = xmax = save[i].x[0]; ymin = ymax = save[i].y[0]; for (j = 1; j < np; j++) { xmin = MIN (xmin, save[i].x[j]); xmax = MAX (xmax, save[i].x[j]); ymin = MIN (ymin, save[i].y[j]); ymax = MAX (ymax, save[i].y[j]); } ix = rint ((0.5 * (xmin + xmax) - h->x_min) / h->x_inc) + 1; iy = rint ((h->y_max - ymax) / h->y_inc) + 1; x0 = h->x_min + ix * h->x_inc; done = FALSE; while (!done && iy < h->ny) { y0 = h->y_max - iy * h->y_inc; inside = non_zero_winding (x0, y0, save[i].x, save[i].y, np); if (inside == 2) done = TRUE; else iy++; } save[i].high = (grd[iy*h->nx+ix] > save[i].cval); if (save[i].high && !tick_high) continue; /* Dont tick highs */ if (!save[i].high && !tick_low) continue; /* Dont tick lows */ geo_to_xy (save[i].x[0], save[i].y[0], &save[i].x[0], &save[i].y[0]); if (tick_label) { x_mean = save[i].x[0]; y_mean = save[i].y[0]; } for (j = 1, s[0] = 0.0; j < np; j++) { geo_to_xy (save[i].x[j], save[i].y[j], &save[i].x[j], &save[i].y[j]); s[j] = s[j-1] + hypot (save[i].x[j]-save[i].x[j-1], save[i].y[j]-save[i].y[j-1]); if (tick_label) { x_mean += save[i].x[j]; y_mean += save[i].y[j]; } } if (s[np-1] < MIN_LENGTH) { free ((char *)s); continue; } dx = save[i].x[1] - save[i].x[0]; dy = save[i].y[1] - save[i].y[0]; a = atan2 (dy, dx) + M_PI_2; x0 = 0.5 * (save[i].x[0] + save[i].x[1]) + small * cos (a); y0 = 0.5 * (save[i].y[0] + save[i].y[1]) + small * sin (a); inside = non_zero_winding (x0, y0, save[i].x, save[i].y, np); sign = (inside == 2) ? 1.0 : -1.0; n_ticks = s[np-1] / tick_gap; if (n_ticks == 0) { free ((char *)s); continue; } inc = s[np-1] / n_ticks; if (tick_label) { x_mean /= np; y_mean /= np; gmt_text3d (x_mean, y_mean, project_info.z_level, gmtdefs.anot_font_size, gmtdefs.anot_font, txt[save[i].high], 0.0, 6, 0); } x_back = save[i].x[np-1]; y_back = save[i].y[np-1]; dist = 0.0; j = 0; add = sign * ((save[i].high) ? -1.0 : 1.0); ps_setline (save[i].pen); while (j < np-1) { x_front = save[i].x[j+1]; y_front = save[i].y[j+1]; if (s[j] >= dist) { /* Time for tick */ dx = x_front - x_back; dy = y_front - y_back; a = atan2 (dy, dx) + add * M_PI_2; if (project_info.three_D) { xy_do_z_to_xy (save[i].x[j], save[i].y[j], project_info.z_level, &x0, &y0); ps_plot (x0, y0, 3); xy_do_z_to_xy (save[i].x[j] + tick_length * cos (a), save[i].y[j] + tick_length * sin (a), project_info.z_level, &x0, &y0); ps_plot (x0, y0, 2); } else { ps_plot (save[i].x[j], save[i].y[j], 3); ps_plotr (tick_length * cos (a), tick_length * sin (a), 2); } dist += inc; } x_back = x_front; y_back = y_front; j++; } free ((char *)s); } }