home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: Science / Science.zip / gmt_os2.zip / src / pswiggle.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-06-30  |  16.5 KB  |  482 lines

  1. /*--------------------------------------------------------------------
  2.  *    The GMT-system:    @(#)pswiggle.c    2.24  30 Jun 1995
  3.  *
  4.  *    Copyright (c) 1991-1995 by P. Wessel and W. H. F. Smith
  5.  *    See README file for copying and redistribution conditions.
  6.  *--------------------------------------------------------------------*/
  7. /*
  8.  * pswiggle reads x,y,z from stdin and plots a wiggleplot using the
  9.  * specified map projection. If the distance between 2 consecutive points
  10.  * exceeds the value of dist_gap, a data gap is assumed.  The user may
  11.  * select a preferred direction where s/he wants the positive anomalies
  12.  * to be pointing towards.  Positive normal vectors to the trackline
  13.  * will then always be withing +- 90 degrees of this direction.
  14.  * Separate colors may be specified for positive anomaly, outline of
  15.  * anomaly, and trackline.  Plotting of the outline and track is optional.
  16.  *
  17.  * Author:    Paul Wessel
  18.  * Date:    24-JAN-1995
  19.  * Version:    3.0, based on old v2.x
  20.  *
  21.  */
  22.  
  23. #include "gmt.h"
  24.  
  25. #define MAX_POINTS 400
  26.  
  27. double *xx, *yy, *zz, *lon, *lat, *z;
  28. double start_az, stop_az;
  29.  
  30. main (argc, argv)
  31. int argc;
  32. char **argv; {
  33.     int i, j, n, k, ix, iy, n_files = 0, fno, n_alloc = GMT_CHUNK, n_args;
  34.     
  35.     BOOLEAN error = FALSE, nofile = TRUE, outline = FALSE, track = FALSE, paint_wiggle, draw_scale = FALSE;
  36.     BOOLEAN multi_segments = FALSE, do_fill = FALSE, negative = FALSE, fix = FALSE, done, gave_xy = FALSE;
  37.     
  38.     double west = 0.0, east = 360.0, south = 0.0, north = 0.0, x_2, y_2, bias = 0.0, fix_az;
  39.     double zscale = 0.0, dx, dy, dz, ds, x0, y0, length, dist_gap = MAXDOUBLE, xy[2], pref_dir = 0.0;
  40.     
  41.     char line[512], *more, EOF_flag = '>', *units, txt_a[32], txt_b[32];
  42.     
  43.     FILE *fp = NULL;
  44.     
  45.     struct FILL fill;
  46.     struct PEN pen_o, pen_t;
  47.     
  48.     argc = gmt_begin (argc, argv);
  49.     
  50.     gmt_init_pen (&pen_o, 1);
  51.     gmt_init_pen (&pen_t, 1);
  52.     gmt_init_fill (&fill, gmtdefs.basemap_frame_rgb[0], gmtdefs.basemap_frame_rgb[1], gmtdefs.basemap_frame_rgb[2]);
  53.     
  54.     for (i = 1; i < argc; i++) {
  55.         if (argv[i][0] == '-') {
  56.             switch(argv[i][1]) {
  57.         
  58.                 /* Common parameters */
  59.             
  60.                 case 'B':
  61.                 case 'H':
  62.                 case 'J':
  63.                 case 'K':
  64.                 case 'O':
  65.                 case 'P':
  66.                 case 'R':
  67.                 case 'U':
  68.                 case 'V':
  69.                 case 'X':
  70.                 case 'x':
  71.                 case 'Y':
  72.                 case 'y':
  73.                 case 'c':
  74.                 case ':':
  75.                 case '\0':
  76.                     error += get_common_args (argv[i], &west, &east, &south, &north);
  77.                     break;
  78.                 
  79.                 /* Supplemental parameters */
  80.             
  81.                 case 'A':
  82.                     pref_dir = atof (&argv[i][2]);
  83.                     break;
  84.                 case 'D':
  85.                     dist_gap = atof (&argv[i][2]) * 1000.0;
  86.                     break;
  87.                 case 'E':
  88.                     sscanf (&argv[i][2], "%lf/%lf", &z_project.view_azimuth, &z_project.view_elevation);
  89.                     break;
  90.                 case 'F':
  91.                     if (gmt_getrgb (&argv[i][2], &gmtdefs.basemap_frame_rgb[0], &gmtdefs.basemap_frame_rgb[1], &gmtdefs.basemap_frame_rgb[2])) {
  92.                         gmt_pen_syntax ('F');
  93.                         error++;
  94.                     }
  95.                     break;
  96.                 case 'G':
  97.                     if (gmt_getfill (&argv[i][2], &fill)) {
  98.                         gmt_fill_syntax ('G');
  99.                         error++;
  100.                     }
  101.                     do_fill = TRUE;
  102.                     break;
  103.                 case 'I':
  104.                     fix_az = atof (&argv[i][2]) * D2R;
  105.                     fix = TRUE;
  106.                     break;
  107.                 case 'M':
  108.                     if (argv[i][2]) EOF_flag = argv[i][2];
  109.                     multi_segments = TRUE;
  110.                     break;
  111.                 case 'N':
  112.                     negative = TRUE;
  113.                     break;
  114.                 case 'C':
  115.                     bias = atof (&argv[i][2]);
  116.                     break;
  117.                 case 'T':
  118.                     if (gmt_getpen (&argv[i][2], &pen_t)) {
  119.                         gmt_pen_syntax ('T');
  120.                         error++;
  121.                     }
  122.                     track = TRUE;
  123.                     break;
  124.                 case 'W':
  125.                     if (gmt_getpen (&argv[i][2], &pen_o)) {
  126.                         gmt_pen_syntax ('W');
  127.                         error++;
  128.                     }
  129.                     outline = TRUE;
  130.                     break;
  131.                 case 'S':
  132.                     j = 0;
  133.                     if (argv[i][2] == 'x') gave_xy = TRUE, j = 1;
  134.                     k = sscanf (&argv[i][2+j], "%[^/]/%[^/]/%lf", txt_a, txt_b, &length);
  135.                     x0 = ddmmss_to_degree (txt_a);
  136.                     y0 = ddmmss_to_degree (txt_b);
  137.                     units = strrchr (argv[i], '/');    units++;
  138.                     if (k != 3) {
  139.                         fprintf (stderr, "%s: GMT SYNTAX ERROR -S option:  Correct syntax\n", gmt_program);
  140.                         fprintf (stderr, "    -S[x]<x0>/<y0>/<length>[/<units>]\n");
  141.                         error++;
  142.                     }
  143.                     draw_scale = TRUE;
  144.                     break;
  145.                     
  146.                 case 'Z':
  147.                     zscale = atof (&argv[i][2]);
  148.                     break;
  149.                     
  150.                 /* Illegal options */
  151.             
  152.                 default:
  153.                     error = TRUE;
  154.                     gmt_default_error (argv[i][1]);
  155.                     break;
  156.             }
  157.         }
  158.         else
  159.             n_files++;
  160.     }
  161.     
  162.     if (argc == 1 || gmt_quick) {
  163.         fprintf (stderr,"pswiggle %s - Plot xyz-series along tracks\n\n", GMT_VERSION);
  164.         fprintf (stderr, "usage: pswiggle <xyz-files> -J<params> -R<west/east/south/north> -Z<scale>\n");
  165.         fprintf (stderr, "    [-A<direction>] [-B<tickinfo>] [-C<center>] [-D<gap>] [-Eaz/el] [-F<r/g/b>] [-G<fill>] [-H]\n");
  166.         fprintf (stderr, "    [-I<az>] [-K] [-M[<flag>]] [-N] [-O] [-P] [-S[x]<lon0>/<lat0>/<length>/<units>] [-T<trackpen>]\n");
  167.         fprintf (stderr, "    [-U] [-V] [-W<outlinepen>] [-X<x_shift>] [-Y<y_shift>] [-c<ncopies>] [-:]\n");
  168.  
  169.         if (gmt_quick) exit (-1);
  170.         
  171.         fprintf (stderr, "    <xyz_files> is one or more files.  If none, read standard input\n");
  172.         explain_option ('j');
  173.         explain_option ('R');
  174.         fprintf (stderr, "\n\tOPTIONS:\n");
  175.         fprintf (stderr, "    -A set azimuth for preferred positive wiggle direction [0.0]\n");
  176.         explain_option ('b');
  177.         fprintf (stderr, "    -C sets center value to be removed from z before plotting. [0]\n");
  178.         fprintf (stderr, "    -D means there is a datagap if 2 points are more than <gap> distance units apart\n");
  179.         fprintf (stderr, "       gap is in km for map projections, user-units otherwise\n");
  180.         fprintf (stderr, "    -E set azimuth and elevation of viewpoint for 3-D perspective [180/90]\n");
  181.         fprintf (stderr, "      -F Set color used for Frame and anotation [%d/%d/%d]\n",
  182.             gmtdefs.basemap_frame_rgb[0], gmtdefs.basemap_frame_rgb[1], gmtdefs.basemap_frame_rgb[2]);
  183.         fprintf (stderr, "    -G Specify color or pattern for positive areas. fill can be either\n");
  184.         fprintf (stderr, "       1) <r/g/b> (each 0-255) for color or <gray> (0-255) for gray-shade [0]\n");
  185.         fprintf (stderr, "       2) p[or P]<iconsize>/<pattern> for predefined patterns (0-31).\n");
  186.         explain_option ('H');
  187.         fprintf (stderr, "    -I set fixed projection angle for wiggles\n");
  188.         explain_option ('K');
  189.         fprintf (stderr, "    -M Input files each consist of multiple segments separated by one record\n");
  190.         fprintf (stderr, "       whose first character is <flag> [>]\n");
  191.         fprintf (stderr, "    -N Fill negative wiggles instead [Default is positive]\n");
  192.         explain_option ('O');
  193.         explain_option ('P');
  194.         fprintf (stderr, "      -S draws a simple vertical scale centered on <lon0>/<lat0>.  Use -Sx to specify cartesian coordinates instead.\n");
  195.         fprintf (stderr, "         <length> is in z-units, append unit name for labeling\n");
  196.         fprintf (stderr, "    -T specifies track pen attributes. [Default is no track]\n");
  197.         explain_option ('U');
  198.         explain_option ('V');
  199.         fprintf (stderr, "    -W specifies outline pen attributes. [Default is no outline]\n");
  200.         explain_option ('X');
  201.         fprintf (stderr, "    -Z gives the wiggle scale in data-units per %s\n", gmt_unit_names[gmtdefs.measure_unit]);
  202.         explain_option ('c');
  203.         explain_option (':');
  204.         explain_option ('.');
  205.         exit (-1);
  206.     }
  207.     
  208.     if (!project_info.region_supplied) {
  209.         fprintf (stderr, "%s: GMT SYNTAX ERROR:  Must specify -R option\n", gmt_program);
  210.         error++;
  211.     }
  212.     if (!(outline || do_fill)) {
  213.         fprintf (stderr, "%s: GMT SYNTAX ERROR:  Must specify at least one of -G, -W\n", gmt_program);
  214.         error++;
  215.     }
  216.     if (z_project.view_azimuth > 360.0 || z_project.view_elevation <= 0.0 || z_project.view_elevation > 90.0) {
  217.         fprintf (stderr, "%s: GMT SYNTAX ERROR -E option:  Enter azimuth in 0-360 range, elevation in 0-90 range\n", gmt_program);
  218.         error++;
  219.     }
  220.     if (zscale == 0.0) {
  221.         fprintf (stderr, "%s: GMT SYNTAX ERROR -Z option:  scale must be nonzero\n", gmt_program);
  222.         error++;
  223.     }
  224.           
  225.     if (error) exit (-1);
  226.  
  227.     map_setup (west, east, south, north);
  228.  
  229.     ps_plotinit (CNULL, gmtdefs.overlay, gmtdefs.page_orientation, gmtdefs.x_origin, gmtdefs.y_origin,
  230.         gmtdefs.global_x_scale, gmtdefs.global_y_scale, gmtdefs.n_copies,
  231.         gmtdefs.dpi, gmtdefs.measure_unit, gmtdefs.paper_width, gmtdefs.page_rgb, gmt_epsinfo (argv[0]));
  232.     echo_command (argc, argv);
  233.     if (gmtdefs.unix_time) timestamp (argc, argv);
  234.     if (project_info.three_D) ps_transrotate (-z_project.xmin, -z_project.ymin, 0.0);
  235.  
  236.     zscale = 1.0 / zscale;
  237.     start_az = pref_dir - 90.0;
  238.     stop_az = pref_dir + 90.0;
  239.     map_clip_on (-1, -1, -1, 3);
  240.     
  241.     /* Allocate memory */
  242.         
  243.     lon = (double *) memory (CNULL, n_alloc, sizeof (double), "psxy");
  244.     lat = (double *) memory (CNULL, n_alloc, sizeof (double), "psxy");
  245.     z = (double *) memory (CNULL, n_alloc, sizeof (double), "psxy");
  246.     xx = (double *) memory (CNULL, n_alloc, sizeof (double), "psxy");
  247.     yy = (double *) memory (CNULL, n_alloc, sizeof (double), "psxy");
  248.     zz = (double *) memory (CNULL, n_alloc, sizeof (double), "psxy");
  249.     
  250.     if (n_files != 0) nofile = FALSE;
  251.     done = FALSE;
  252.     n_args = (argc > 1) ? argc : 2;
  253.     
  254.     for (fno = 1; !done && fno < n_args; fno++) {    /* Loop over all the files */
  255.         if (!nofile && argv[fno][0] == '-') continue;
  256.         if (nofile) {
  257.             fp = stdin;
  258.             done = TRUE;
  259.             if (gmtdefs.verbose) fprintf (stderr, "pswiggle: Reading data from standard input\n");
  260.         }
  261.         else if ((fp = fopen (argv[fno], "r")) == NULL) {
  262.             fprintf (stderr, "pswiggle: Cannot open file %s\n", argv[fno]);
  263.             continue;
  264.         }
  265.         
  266.         if (!nofile && gmtdefs.verbose) {
  267.             fprintf (stderr, "pswiggle: Working on file %s\n", argv[fno]);
  268.             printf ("%% file %s\n", argv[fno]);
  269.         }
  270.         
  271.         ix = (gmtdefs.xy_toggle);    iy = 1 - ix;
  272.         
  273.         
  274.         if (gmtdefs.io_header) for (i = 0; i < gmtdefs.n_header_recs; i++) fgets (line, 512, fp);
  275.         if (multi_segments) {
  276.             fgets (line, 512, fp);
  277.             if (gmtdefs.verbose) ps_comment (line);
  278.         }
  279.         more = fgets (line, 512, fp);
  280.         while (more) {
  281.             n = 0;
  282.             while ((more && !multi_segments) || (more && multi_segments && line[0] != EOF_flag)) {
  283.                 sscanf (line, "%lf %lf %lf", &xy[ix], &xy[iy], &z[n]);
  284.                 lon[n] = xy[0];    lat[n] = xy[1];
  285.                 z[n] -= bias;
  286.                 n++;
  287.                 if (n >= n_alloc) {
  288.                     n_alloc += GMT_CHUNK;
  289.                     lon = (double *) memory ((char *)lon, n_alloc, sizeof (double), "psxy");
  290.                     lat = (double *) memory ((char *)lat, n_alloc, sizeof (double), "psxy");
  291.                     z = (double *) memory ((char *)z, n_alloc, sizeof (double), "psxy");
  292.                     xx = (double *) memory ((char *)xx, n_alloc, sizeof (double), "psxy");
  293.                     yy = (double *) memory ((char *)yy, n_alloc, sizeof (double), "psxy");
  294.                     zz = (double *) memory ((char *)zz, n_alloc, sizeof (double), "psxy");
  295.                 }
  296.                 more = fgets (line, 512, fp);
  297.             }
  298.                     
  299.             geo_to_xy (lon[0], lat[0], &xx[0], &yy[0]);
  300.             zz[0] = z[0];
  301.             paint_wiggle = (do_fill && ((negative && z[0] <= 0.0) || (!negative && z[0] >= 0.0)));
  302.             j = 1;
  303.             for (i = 1; i < n; i++) {    /* Convert to inches/cm and get distance increments */
  304.                 dx = lon[i] - lon[i-1];
  305.                 dy = lat[i] - lat[i-1];
  306.                 if (project_info.projection > 5) {
  307.                     dx *= cos (0.5 * (lat[i] + lat[i-1]) * D2R);
  308.                     ds = hypot (dx, dy) * M_PR_DEG;
  309.                 }
  310.                 else
  311.                     ds = hypot (dx, dy);
  312.                     
  313.                 geo_to_xy (lon[i], lat[i], &x_2, &y_2);
  314.  
  315.                 if (j > 0 && (ds > dist_gap || bad_float (z[i]))) {    /* Data gap, plot what we have */
  316.                     paint_wiggle = (do_fill && ((negative && zz[j-1] <= 0.0) || (!negative && zz[j-1] >= 0.0)));
  317.                     plot_wiggle (xx, yy, zz, j, zscale, fix, fix_az, &fill, &pen_o, &pen_t, paint_wiggle, outline, track);
  318.                     j = 0;
  319.                 }
  320.                 else if (j >= MAX_POINTS) {
  321.                     paint_wiggle = (do_fill && ((negative && zz[j-1] <= 0.0) || (!negative && zz[j-1] >= 0.0)));
  322.                     plot_wiggle (xx, yy, zz, j, zscale, fix, fix_az, &fill, &pen_o, &pen_t, paint_wiggle, outline, track);
  323.                     xx[0] = xx[j-1];
  324.                     yy[0] = yy[j-1];
  325.                     zz[0] = zz[j-1];
  326.                     j = 1;
  327.                 }
  328.                 else if (!bad_float (z[i-1]) && (z[i]*z[i-1] < 0.0 || z[i] == 0.0)) {    /* Crossed 0, add new point and plot */
  329.                     dz = z[i] - z[i-1];
  330.                     xx[j] = (dz == 0.0) ? xx[j-1] : xx[j-1] + fabs (z[i-1] / dz) * (x_2 - xx[j-1]);
  331.                     yy[j] = (dz == 0.0) ? yy[j-1] : yy[j-1] + fabs (z[i-1] / dz) * (y_2 - yy[j-1]);
  332.                     zz[j] = 0.0;
  333.                     j++;
  334.                     paint_wiggle = (do_fill && ((negative && zz[j-2] <= 0.0) || (!negative && zz[j-2] >= 0.0)));
  335.                     plot_wiggle (xx, yy, zz, j, zscale, fix, fix_az, &fill, &pen_o, &pen_t, paint_wiggle, outline, track);
  336.                     xx[0] = xx[j-1];
  337.                     yy[0] = yy[j-1];
  338.                     zz[0] = zz[j-1];
  339.                     j = 1;
  340.                 }
  341.                 xx[j] = x_2;
  342.                 yy[j] = y_2;
  343.                 zz[j] = z[i];
  344.                 if (!bad_float (z[i])) j++;
  345.             }
  346.             
  347.             if (j > 1) {
  348.                 paint_wiggle = (do_fill && ((negative && zz[j-1] <= 0.0) || (!negative && zz[j-1] >= 0.0)));
  349.                 plot_wiggle (xx, yy, zz, j, zscale, fix, fix_az, &fill, &pen_o, &pen_t, paint_wiggle, outline, track);
  350.             }
  351.             more = fgets (line, 512, fp);
  352.         }
  353.         if (fp != stdin) fclose (fp);
  354.     }
  355.             
  356.     map_clip_off();
  357.     if (frame_info.plot) {
  358.         ps_setpaint (gmtdefs.basemap_frame_rgb[0], gmtdefs.basemap_frame_rgb[1], gmtdefs.basemap_frame_rgb[2]);
  359.         map_basemap ();
  360.     }
  361.     if (draw_scale) draw_z_scale (x0, y0, length, zscale, gave_xy, units);
  362.     ps_setpaint (gmtdefs.background_rgb[0], gmtdefs.background_rgb[1], gmtdefs.background_rgb[2]);
  363.     
  364.     if (project_info.three_D) ps_rotatetrans (z_project.xmin, z_project.ymin, 0.0);
  365.     ps_plotend (gmtdefs.last_page);
  366.     
  367.     free ((char *)lon);
  368.     free ((char *)lat);
  369.     free ((char *)z);
  370.     free ((char *)xx);
  371.     free ((char *)yy);
  372.     free ((char *)zz);
  373.     
  374.     gmt_end (argc, argv);
  375. }
  376.     
  377. int plot_wiggle (x, y, z, np, zscale, fixed, fix_az, fill, pen_o, pen_t, paint_wiggle, outline, track)
  378. double x[], y[], z[], zscale, fix_az;
  379. int np;
  380. struct FILL *fill;
  381. struct PEN *pen_o, *pen_t;
  382. BOOLEAN fixed, paint_wiggle, outline, track; {
  383.     double dx, dy, az = 0.0, x_inc, y_inc;
  384.     int n, i;
  385.     
  386.     if (fixed) az = fix_az;
  387.  
  388.     if (paint_wiggle || outline) {
  389.         if (!gmt_n_alloc) get_plot_array ();
  390.         gmt_x_plot[0] = x[0];
  391.         gmt_y_plot[0] = y[0];
  392.         n = 1;
  393.         for (i = 0; i < np; i++) {
  394.             if (!fixed && i < np-1) {
  395.                 dx = x[i+1] - x[i];
  396.                 dy = y[i+1] - y[i];
  397.                 if (!(dx == 0.0 && dy == 0.0)) az = d_atan2 (dy, dx) * R2D - 360.0;
  398.                 while (az < start_az) az += 360.0;
  399.                 if (az > stop_az) az -= 180.0;
  400.                 az *= D2R;
  401.             }
  402.             if (fabs (z[i]) > 0.0) {
  403.                 x_inc = -zscale * z[i] * sin (az);
  404.                 y_inc = zscale * z[i]* cos (az);
  405.             }
  406.             else
  407.                 x_inc = y_inc = 0.0;
  408.                 
  409.             gmt_x_plot[n] = x[i] + x_inc;
  410.             gmt_y_plot[n] = y[i] + y_inc;
  411.             n++;
  412.             if (n == gmt_n_alloc) get_plot_array ();
  413.         }
  414.         gmt_x_plot[n] = x[np-1];
  415.         gmt_y_plot[n] = y[np-1];
  416.         n++;
  417.         
  418.         if (paint_wiggle) {
  419.             for (i = np - 2; i >= 0; i--, n++) {    /* Go back to 1st point along track */
  420.                 if (n == gmt_n_alloc) get_plot_array ();
  421.                 gmt_x_plot[n] = x[i];
  422.                 gmt_y_plot[n] = y[i];
  423.             }
  424.         }
  425.         if (project_info.three_D) two_d_to_three_d (gmt_x_plot, gmt_y_plot, n);
  426.     }
  427.     
  428.     
  429.     if (paint_wiggle) { /* First shade wiggles */
  430.         printf ("%% Positive wiggle\n");
  431.         if (fill->use_pattern)
  432.             ps_imagefill (gmt_x_plot, gmt_y_plot, n, fill->pattern_no, fill->pattern, fill->inverse, fill->icon_size, FALSE);
  433.         else
  434.             ps_polygon (gmt_x_plot, gmt_y_plot, n, fill->r, fill->g, fill->b, FALSE);
  435.     }
  436.     
  437.     if (outline) { /* Then draw wiggle outline */
  438.         printf ("%% Wiggle line\n");
  439.         ps_setpaint (pen_o->r, pen_o->g, pen_o->b);
  440.         ps_setline (pen_o->width);
  441.         if (pen_o->texture) ps_setdash (pen_o->texture, pen_o->offset);
  442.         ps_line (&gmt_x_plot[1], &gmt_y_plot[1], np, 3, FALSE, TRUE);
  443.         if (pen_o->texture) ps_setdash (CNULL, 0);
  444.     }
  445.     
  446.     if (track) {    /* Finally draw track line */
  447.         if (project_info.three_D) two_d_to_three_d (x, y, np);
  448.         printf ("%% Track line\n");
  449.         ps_setline (pen_t->width);
  450.         ps_setpaint (pen_t->r, pen_t->g, pen_t->b);
  451.         if (pen_t->texture) ps_setdash (pen_t->texture, pen_t->offset);
  452.         ps_line (x, y, np, 3, FALSE, TRUE);
  453.         if (pen_t->texture) ps_setdash (CNULL, 0);
  454.     }
  455. }
  456.  
  457. int draw_z_scale (x0, y0, length, zscale, gave_xy, units)
  458. double x0, y0, length, zscale;
  459. BOOLEAN gave_xy;
  460. char *units; {
  461.     double dy, a, b, off;
  462.     char txt[80];
  463.     
  464.     if (!gave_xy) geo_to_xy (x0, y0, &x0, &y0);
  465.         
  466.     if (units)
  467.         sprintf (txt, "%lg %s\0", length, units);
  468.     else
  469.         sprintf (txt, "%lg\0", length);
  470.     dy = 0.5 * length * zscale;    
  471.     xyz_to_xy (x0 + gmtdefs.tick_length, y0 - dy, 0.0, &a, &b);
  472.     ps_plot (a, b, 3);
  473.     xyz_to_xy (x0, y0 - dy, 0.0, &a, &b);
  474.     ps_plot (a, b, 2);
  475.     xyz_to_xy (x0, y0 + dy, 0.0, &a, &b);
  476.     ps_plot (a, b, 2);
  477.     xyz_to_xy (x0 + gmtdefs.tick_length, y0 + dy, 0.0, &a, &b);
  478.     ps_plot (a, b, 2);
  479.     off = ((gmtdefs.tick_length > 0.0) ? gmtdefs.tick_length : 0.0) + gmtdefs.anot_offset;
  480.     gmt_text3d (x0 + off, y0, project_info.z_level, gmtdefs.anot_font_size, gmtdefs.anot_font, txt, 0.0, 5, 0);
  481. }
  482.