home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: Science / Science.zip / gmt_os2.zip / src / psxy.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-07-05  |  27.5 KB  |  832 lines

  1. /*--------------------------------------------------------------------
  2.  *    The GMT-system:    @(#)psxy.c    2.39  05 Jul 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.  * psxy will read <x,y> pairs (or <lon,lat>) from stdin and plot
  9.  * the lines, polygons, or symbols on a map. A variety of symbols
  10.  * may be specified, some of which require additional columns of
  11.  * data, like symbol-size etc.  Only one symbol may be plotted
  12.  * at the time.  PostScript code is written to stdout.
  13.  *
  14.  * Author:    Paul Wessel
  15.  * Date:    5-JAN-1995
  16.  * Version:    3.0, based on old v2.1
  17.  *
  18.  */
  19.  
  20. #include "gmt.h"
  21.  
  22. #define NONE        99
  23. #define LINE        0
  24. #define BAR        1
  25. #define CROSS        2
  26. #define POINT        3
  27. #define CIRCLE        4
  28. #define SQUARE        5
  29. #define TRIANGLE    6
  30. #define DIAMOND        7
  31. #define ELLIPSE        8
  32. #define STAR        9
  33. #define HEXAGON        10
  34. #define ITRIANGLE    11
  35. #define VECTOR        12    
  36. #define VECTOR2        13
  37. #define TEXT        14
  38. #define FAULT        -15
  39.  
  40. #define POINTSIZE 0.005
  41.  
  42. double *xx, *yy, *xp, *yp;
  43. int *plot_pen;
  44.  
  45. main (argc, argv)
  46. int argc;
  47. char **argv; {
  48.  
  49.     int     i, j, symbol = 0, n, ix = 0, iy = 1, n_files = 0, fno, xy_errors[2], two, three, four;
  50.     int    n_alloc = GMT_CHUNK, plot_n, n_use, start, n_args, slash, f_sense = 0, n_got, n_expected = 2;
  51.     int     font_size;
  52.     
  53.     BOOLEAN    error = FALSE, nofile = TRUE, error_bars = FALSE, polygon = FALSE, user_unit = FALSE;
  54.     BOOLEAN    read_size = FALSE, outline = FALSE, multi_segments = FALSE, draw_arc = TRUE, f_triangle = FALSE;
  55.     BOOLEAN done, read_vector = FALSE, read_ellipse = FALSE, get_rgb = FALSE, greenwich, check;
  56.     BOOLEAN convert_angles = FALSE, pen_set = FALSE, old_gmt_world_map, skip_if_outside = TRUE;
  57.     
  58.     double xy[2], west = 0.0, east = 0.0, south = 0.0, north = 0.0, delta_x, delta_y;
  59.     double plot_x, plot_y, symbol_size = 0.0, x_1, x_2, y_1, y_2, y0;
  60.     double direction, length1, length2, x2, y2, error_width2, f_gap = 0.0, f_len = 0.05;
  61.     double v_width = 0.03, h_length = 0.12, h_width = 0.1, error_width = 0.1;
  62.     double v_w, h_l, h_w, v_shrink, v_norm = 0.0, base = 0.0, z, tmp, step = 1.0;
  63.     
  64.     char line[512], header[512], symbol_type, col[6][100], *cpt, *more, EOL_flag = '>', *string = 0;
  65.     
  66.     FILE *fp = NULL;
  67.     
  68.     struct PEN pen, epen;
  69.     struct FILL fill;
  70.     
  71.     xy_errors[0] = xy_errors[1] = 0;
  72.     
  73.     argc = gmt_begin (argc, argv);
  74.     
  75.     gmt_init_pen (&pen, 1);
  76.     gmt_init_pen (&epen, 1);
  77.     gmt_init_fill (&fill, -1, -1, -1);    /* Default is no fill */
  78.     
  79.     if (gmtdefs.measure_unit) {
  80.         v_width = 0.075;    h_length = 0.3;    h_width = 0.25; error_width = 0.25;
  81.     }
  82.     
  83.     /* Check and interpret the command line arguments */
  84.     
  85.     for (i = 1; i < argc; i++) {
  86.         if (argv[i][0] == '-') {
  87.             switch(argv[i][1]) {
  88.         
  89.                 /* Common parameters */
  90.             
  91.                 case 'B':
  92.                 case 'H':
  93.                 case 'J':
  94.                 case 'K':
  95.                 case 'O':
  96.                 case 'P':
  97.                 case 'R':
  98.                 case 'U':
  99.                 case 'V':
  100.                 case 'X':
  101.                 case 'x':
  102.                 case 'Y':
  103.                 case 'y':
  104.                 case 'c':
  105.                 case ':':
  106.                 case '\0':
  107.                     error += get_common_args (argv[i], &west, &east, &south, &north);
  108.                     break;
  109.                 
  110.                 /* Supplemental parameters */
  111.             
  112.                 case 'A':    /* Turn off draw_arc mode */
  113.                     if (argv[i][2])
  114.                         step = atof (&argv[i][2]);    /* Undocumented test feature */
  115.                     else
  116.                         draw_arc = FALSE;
  117.                     break;
  118.                     
  119.                 case 'C':    /* Vary symbol color with z */
  120.                     cpt = &argv[i][2];
  121.                     get_rgb = TRUE;
  122.                     break;
  123.                 case 'E':    /* Get info for error bars */
  124.                     for (j = 2; argv[i][j] && argv[i][j] != '/'; j++) {
  125.                         if (argv[i][j] == 'x')
  126.                             xy_errors[0] = j;
  127.                         else if (argv[i][j] == 'y')
  128.                             xy_errors[1] = j;
  129.                         else {    /* Get error 'cap' width */
  130.                             error_width = atof (&argv[i][j]);
  131.                             while (argv[i][j] && argv[i][j] != '/') j++;
  132.                             j--;
  133.                         }
  134.                     }
  135.                     error_bars = TRUE;
  136.                     if (argv[i][j] == '/') gmt_getpen (&argv[i][j+1], &epen);
  137.                     break;
  138.                 case 'F':
  139.                     if (gmt_getrgb (&argv[i][2], &gmtdefs.basemap_frame_rgb[0], &gmtdefs.basemap_frame_rgb[1], &gmtdefs.basemap_frame_rgb[2])) {
  140.                         gmt_pen_syntax ('F');
  141.                         error++;
  142.                     }
  143.                     break;
  144.                 case 'G':        /* Set Gray shade for polygon */
  145.                     if (gmt_getfill (&argv[i][2], &fill)) {
  146.                         gmt_fill_syntax ('G');
  147.                         error++;
  148.                     }
  149.                     polygon = TRUE;
  150.                     break;
  151.                 case 'L':        /* Draw the outline */
  152.                     outline = TRUE;
  153.                     break;
  154.                 case 'M':        /* Multiple line segments */
  155.                     multi_segments = TRUE;
  156.                     if (argv[i][2]) EOL_flag = argv[i][2];
  157.                     break;
  158.                 case 'N':        /* Do not skip points outside border */
  159.                     skip_if_outside = FALSE;
  160.                     break;
  161.                 case 'S':        /* Get symbol [and size] */
  162.                     n = sscanf (&argv[i][2], "%c%lf", &symbol_type, &symbol_size);
  163.                     check = TRUE;
  164.                     switch (symbol_type) {
  165.                         case 'a':
  166.                             symbol = STAR;
  167.                             break;
  168.                         case 'b':
  169.                             symbol = BAR;
  170.                             symbol_size *= 0.5;
  171.                             for (j = 3, slash = -1; argv[i][j] && slash < 0; j++) if (argv[i][j] == '/') slash = j;
  172.                             if (slash > 0) base = atof (&argv[i][j]);
  173.                             if (argv[i][strlen(argv[i])-1] == 'u') user_unit = TRUE;
  174.                             break;
  175.                         case 'c':
  176.                             symbol = CIRCLE;
  177.                             symbol_size *= 0.5;
  178.                             break;
  179.                         case 'd':
  180.                             symbol = DIAMOND;
  181.                             break;
  182.                         case 'e':
  183.                             symbol = ELLIPSE;
  184.                             read_ellipse = TRUE;
  185.                             n_expected += 3;
  186.                             check = FALSE;
  187.                             break;
  188.                         case 'f':
  189.                             symbol = FAULT;
  190.                             sscanf (&argv[i][3], "%lf/%lf", &f_gap, &f_len);
  191.                             switch (argv[i][strlen(argv[i])-1]) {
  192.                                 case 'L':
  193.                                     f_triangle = TRUE;
  194.                                 case 'l':
  195.                                     f_sense = 1;
  196.                                     break;
  197.                                 case 'R':
  198.                                     f_triangle = TRUE;
  199.                                 case 'r':
  200.                                     f_sense = -1;
  201.                                     break;
  202.                                 default:
  203.                                     f_sense = 0;
  204.                                     break;
  205.                             }
  206.                             break;
  207.                         case 'h':
  208.                             symbol = HEXAGON;
  209.                             break;
  210.                         case 'i':
  211.                             symbol = ITRIANGLE;
  212.                             break;
  213.                         case 'l':
  214.                             symbol = TEXT;
  215.                             for (j = 3, slash = 0; argv[i][j] && !slash; j++) if (argv[i][j] == '/') slash = j;
  216.                             if (slash && argv[i][slash+1])
  217.                                 string = &argv[i][slash+1];
  218.                             else if (!slash && argv[i][3] && symbol_size == 0.0)
  219.                                 string = &argv[i][3];
  220.                             else {
  221.                                 fprintf (stderr, "%s: GMT SYNTAX ERROR -Sl option:  No string given\n", gmt_program);
  222.                                 error++;
  223.                             }
  224.                             break;
  225.                         case 'p':
  226.                             symbol = POINT;
  227.                             check = FALSE;
  228.                             break;
  229.                         case 's':
  230.                             symbol = SQUARE;
  231.                             break;
  232.                         case 't':
  233.                             symbol = TRIANGLE;
  234.                             break;
  235.                         case 'V':
  236.                             convert_angles = TRUE;
  237.                         case 'v':
  238.                             symbol = VECTOR;
  239.                             if (argv[i][3]) sscanf (&argv[i][3], "%lf/%lf/%lf", &v_width, &h_length, &h_width);
  240.                             for (j = 3; argv[i][j] && argv[i][j] != 'n'; j++);
  241.                             if (argv[i][j]) {    /* Normalize option used */
  242.                                 v_norm = atof (&argv[i][j+1]);
  243.                                 if (v_norm > 0.0) {
  244.                                     v_shrink = 1.0 / v_norm;
  245.                                     symbol = VECTOR2;
  246.                                 }
  247.                             }
  248.                             read_vector = TRUE;
  249.                             n_expected += 2;
  250.                             check = FALSE;
  251.                             break;
  252.                         case 'x':
  253.                             symbol = CROSS;
  254.                             break;
  255.                         default:
  256.                             error = TRUE;
  257.                             fprintf (stderr, "%s: GMT SYNTAX ERROR -S option:  Unrecognized symbol type %c\n", gmt_program, symbol_type);
  258.                             break;
  259.                     }
  260.                     if (symbol_size == 0.0 && check) {
  261.                         read_size = TRUE;
  262.                         n_expected++;
  263.                     }
  264.                     break;
  265.                 case 'W':        /* Set line attributes */
  266.                     if (gmt_getpen (&argv[i][2], &pen)) {
  267.                         gmt_pen_syntax ('W');
  268.                         error++;
  269.                     }
  270.                     pen_set = TRUE;
  271.                     break;
  272.                     
  273.                 /* Illegal options */
  274.             
  275.                 default:        /* Options not recognized */
  276.                     error = TRUE;
  277.                     gmt_default_error (argv[i][1]);
  278.                     break;
  279.             }
  280.         }
  281.         else
  282.             n_files++;
  283.     }
  284.     
  285.     if (argc == 1 || gmt_quick) {    /* Display usage */
  286.         fprintf (stderr,"psxy %s - Plot lines, polygons, and symbols on maps\n\n", GMT_VERSION);
  287.         fprintf (stderr,"usage: psxy <infiles> -J<params> -R<west/east/south/north> [-A] [-B<tickinfo>]\n");
  288.         fprintf (stderr, "    [-C<cpt>] [-E[x][y][cap][/<pen>]] [-F<r/g/b>] [-G<fill>] [-H] [-K] [-L] [-M<flag>] [-N]\n");
  289.         fprintf (stderr, "    [-O] [-P] [-S<symbol><size>] [-U[<label>]] [-V] [-W<pen>] [-c<ncopies>]\n");
  290.         fprintf (stderr, "    [-X<x_shift>] [-Y<y_shift>] [-:]\n\n");
  291.         
  292.         if (gmt_quick) exit(-1);
  293.         
  294.         fprintf (stderr, "    <infiles> is one or more files.  If no, read standard input\n");
  295.         explain_option ('j');
  296.         explain_option ('R');
  297.         fprintf (stderr, "\n\tOPTIONS:\n");
  298.         explain_option ('b');
  299.         fprintf (stderr, "    -A Suppress drawing line segments as great circle arcs\n");
  300.         fprintf (stderr, "    -C Use cpt-file to assign colors based on z-value in 3rd column\n");
  301.         fprintf (stderr, "       Must be used with -S\n");
  302.         fprintf (stderr, "    -E means draw error bars for x [and/or y].  Add cap-width [%lg]. Append pen attributes.\n", error_width);
  303.         fprintf (stderr, "      -F Set color used for Frame and anotation [%d/%d/%d]\n",
  304.             gmtdefs.basemap_frame_rgb[0], gmtdefs.basemap_frame_rgb[1], gmtdefs.basemap_frame_rgb[2]);
  305.         fprintf (stderr, "    -G Specify color (for symbols/polygons) or pattern (for polygons). fill can be either\n");
  306.         fprintf (stderr, "       1) <r/g/b> (each 0-255) for color or <gray> (0-255) for gray-shade [0].\n");
  307.         fprintf (stderr, "       2) p[or P]<iconsize>/<pattern> for predefined patterns (0-31).\n");
  308.         fprintf (stderr, "       Default is no fill (transparent symbols or polygons)\n");
  309.         explain_option ('H');
  310.         explain_option ('K');
  311.         fprintf (stderr, "    -L close polygon OR draw symbol outline with current pen (see -W).\n");
  312.         fprintf (stderr, "    -M Input files each consist of multiple segments separated by one record.\n");
  313.         fprintf (stderr, "       whose first character is <flag> [>].\n");
  314.         fprintf (stderr, "    -N Do Not skip/clip symbols that fall outside map border [Default will ignore those outside]\n");
  315.         explain_option ('O');
  316.         explain_option ('P');
  317.         fprintf (stderr, "    -S to select symbol type and symbol size (in %s).  Choose between\n", gmt_unit_names[gmtdefs.measure_unit]);
  318.         fprintf (stderr, "       st(a)r, (b)ar, (c)ircle, (d)iamond, (e)llipse, (f)ault, (h)exagon,\n");
  319.         fprintf (stderr, "       (i)nvtriangle, (l)etter, (p)oint, (s)quare, (t)riangle, (v)ector, (x)cross\n");
  320.         fprintf (stderr, "       If no size is specified, psxy expects the 3rd column to have sizes.\n");
  321.         fprintf (stderr, "       [Note: if -C is selected then 3rd means 4th column, etc.]\n");
  322.         fprintf (stderr, "       Bars: Append /base to give the y-value of the base [Default = 0]\n");
  323.         fprintf (stderr, "          Append u if width is in x-input units [Default is %s]\n", gmt_unit_names[gmtdefs.measure_unit]);
  324.         fprintf (stderr, "       Ellipses: the direction, major, and minor axis must be in input columns 3, 4 and 5.\n");
  325.         fprintf (stderr, "       Faults: Give tickgap/ticklen[type], where type is:\n");
  326.         fprintf (stderr, "         l - draw tick to left, r - draw tick to right [Default is centered]\n");
  327.         fprintf (stderr, "         Upper case L or R gives filled triangle\n");
  328.         fprintf (stderr, "       Letter: append /<string> after symbol size\n");
  329.         fprintf (stderr, "       Vectors: the direction and length must be in input columns 3 and 4.\n");
  330.         fprintf (stderr, "         Furthermore, <size> means arrowwidth/headlength/headwith [Default is %lg/%lg/%lg]\n", v_width, h_length, h_width);
  331.         fprintf (stderr, "         If -SV rather than -Sv is selected, psxy will expect aximuth and length\n");
  332.         fprintf (stderr, "         and convert azimuths based on the chosen map projection\n");
  333.         explain_option ('U');
  334.         explain_option ('V');
  335.         fprintf (stderr, "    -W sets pen attributes [width = %d, color = (%d/%d/%d), texture = solid line].\n", 
  336.             pen.width, pen.r, pen.g, pen.b);
  337.         explain_option ('X');
  338.         explain_option ('c');
  339.         explain_option (':');
  340.         explain_option ('.');
  341.         exit(-1);
  342.     }
  343.  
  344.     /* Check that the options selected are mutually consistant */
  345.     
  346.     if (error_bars && (read_vector || read_ellipse || symbol == FAULT)) {
  347.         fprintf (stderr, "%s: GMT SYNTAX ERROR -E option: Incompatible with -Se, -Sf, -Sv\n", gmt_program);
  348.         error++;
  349.     }
  350.     if (fill.use_pattern && symbol != LINE) {    /* fill-pattern only for polygons */
  351.         error++;
  352.         fprintf (stderr, "%s: GMT SYNTAX ERROR -G option: Fill-pattern only used with polygons\n", gmt_program);
  353.     }
  354.     if (get_rgb && symbol == 0) {
  355.         error++;
  356.         fprintf (stderr, "%s: GMT SYNTAX ERROR -C option: Must also specify a symbol (see -S)\n", gmt_program);
  357.     }
  358.     if (!project_info.region_supplied) {
  359.         fprintf (stderr, "%s: GMT SYNTAX ERROR:  Must specify -R option\n", gmt_program);
  360.         error++;
  361.     }
  362.     if (error) exit (-1);
  363.     
  364.     if (error_bars && symbol == 0)    /* Assume user only wants error bars */
  365.         symbol = NONE;
  366.         
  367.     if (symbol == 0 && outline) polygon = TRUE;
  368.     if (symbol != LINE && pen_set) outline = TRUE;
  369.     
  370.     if (get_rgb) read_cpt (cpt);
  371.         
  372.     if (n_files > 0)
  373.         nofile = FALSE;
  374.     else
  375.         n_files = 1;
  376.     n_args = (argc > 1) ? argc : 2;
  377.     
  378.     if (xy_errors[0] == 0 && xy_errors[1] == 0) error_bars = FALSE;    /* Must specify x and/or y */
  379.     if (error_bars) {
  380.         if (xy_errors[0]) n_expected++;
  381.         if (xy_errors[1]) n_expected++;
  382.         xy_errors[0] += read_size;    /* Move 1 column over */
  383.         xy_errors[1] += read_size;
  384.         error_width2 = 0.5 * error_width;
  385.     }
  386.     two   = (get_rgb) ? 3 : 2;
  387.     three = (get_rgb) ? 4 : 3;
  388.     four  = (get_rgb) ? 5 : 4;
  389.  
  390.     greenwich = (west < 0.0 || east <= 0.0);
  391.     
  392.     map_setup (west, east, south, north);
  393.  
  394.     ps_plotinit (CNULL, gmtdefs.overlay, gmtdefs.page_orientation, gmtdefs.x_origin, gmtdefs.y_origin,
  395.         gmtdefs.global_x_scale, gmtdefs.global_y_scale, gmtdefs.n_copies,
  396.         gmtdefs.dpi, gmtdefs.measure_unit, gmtdefs.paper_width, gmtdefs.page_rgb, gmt_epsinfo (argv[0]));
  397.     echo_command (argc, argv);
  398.     if (gmtdefs.unix_time) timestamp (argc, argv);
  399.     
  400.     ps_setline (pen.width);
  401.     if (pen.texture) ps_setdash (pen.texture, pen.offset);
  402.     if (symbol == TEXT && polygon && !outline)
  403.         ps_setpaint (fill.r, fill.g, fill.b);
  404.     else
  405.         ps_setpaint (pen.r, pen.g, pen.b);
  406.     
  407.     if (symbol == TEXT) {
  408.         font_size = rint (symbol_size * 72.0);    /* To get points */
  409.         ps_setfont (gmtdefs.anot_font);
  410.     }
  411.     if (symbol > 0 && skip_if_outside) map_clip_on (-1, -1, -1, 3);
  412.     
  413.     geo_to_xy (west, base, &plot_x, &y0);    /* Zero level for bars */
  414.     old_gmt_world_map = gmt_world_map;
  415.     
  416.     ix = (gmtdefs.xy_toggle);    iy = 1 - ix;
  417.     if (symbol <= 0) {
  418.         xx = (double *) memory (CNULL, n_alloc, sizeof (double), "psxy");
  419.         yy = (double *) memory (CNULL, n_alloc, sizeof (double), "psxy");
  420.     }
  421.     done = FALSE;
  422.     for (fno = 1; !done && fno < n_args; fno++) {    /* Loop over all input files */
  423.         if (!nofile && argv[fno][0] == '-') continue;
  424.         if (nofile) {
  425.             fp = stdin;
  426.             done = TRUE;
  427.         }
  428.         else if ((fp = fopen (argv[fno], "r")) == NULL) {
  429.             fprintf (stderr, "psxy: Cannot open file %s\n", argv[fno]);
  430.             continue;
  431.         }
  432.  
  433.         if (!nofile && gmtdefs.verbose) {
  434.             fprintf (stderr, "psxy: Working on file %s\n", argv[fno]);
  435.             sprintf (line, "File: %s\0", argv[fno]);
  436.             ps_comment (line);
  437.         }
  438.         if (gmtdefs.io_header) for (i = 0; i < gmtdefs.n_header_recs; i++) fgets (line, 512, fp);
  439.         
  440.         if (multi_segments) fgets (header, 512, fp);
  441.  
  442.         if (symbol > 0) {    /* symbol part */
  443.         
  444.             gmt_world_map = TRUE;
  445.             
  446.             if (multi_segments && gmtdefs.verbose) ps_comment (header);
  447.             while (fgets (line, 512, fp)) {
  448.                 n_got = sscanf (line, "%s %s %s %s %s %s", col[0], col[1], col[2], col[3], col[4], col[5]);
  449.             
  450.                 if (col[0][0] == EOL_flag) {
  451.                     ps_comment (line);
  452.                     continue;
  453.                 }
  454.             
  455.                 if (n_got < n_expected) {
  456.                     fprintf (stderr, "psxy: Mismatch between expected (%d) and actual (%d) columns!\n", n_expected, n_got);
  457.                     fprintf (stderr, "--> %s\n", line);
  458.                     exit (-1);
  459.                 }
  460.                 
  461.                 xy[ix] = atof (col[0]);
  462.                 xy[iy] = atof (col[1]);
  463.             
  464.                 if (get_rgb) {
  465.                     z = atof (col[2]);
  466.                     get_rgb24 (z, &fill.r, &fill.g, &fill.b);
  467.                     if (symbol == CROSS || symbol == POINT || symbol == TEXT) ps_setpaint (fill.r, fill.g, fill.b);
  468.                 }
  469.                 if (read_size) {
  470.                     symbol_size = atof (col[two]);
  471.                     if (symbol == BAR || symbol == CIRCLE)
  472.                         symbol_size *= 0.5;
  473.                     else
  474.                         font_size = rint (symbol_size * 72.0);
  475.                 }
  476.                 else if (read_vector) {
  477.                     direction = atof (col[two]);
  478.                     length1 = atof (col[three]);
  479.                 }
  480.                 else if (read_ellipse) {
  481.                     direction = atof (col[two]);
  482.                     length1 = atof (col[three]);
  483.                     length2 = atof (col[four]);
  484.                 }
  485.                 
  486.                 /* Skip zero-size symbols */
  487.                 
  488.                 if (symbol != POINT && symbol < VECTOR && symbol_size <= 0.0) continue;
  489.                 if (read_vector && length1 <= 0.0) continue;
  490.                 if (read_ellipse && (length1 <= 0.0 || length2 <= 0.0)) continue;
  491.                 
  492.                 if (xy_errors[0]) delta_x = atof (col[xy_errors[0]]);
  493.                 if (xy_errors[1]) delta_y = atof (col[xy_errors[1]]);
  494.                 
  495.                 if (skip_if_outside) {
  496.                     map_outside (xy[0], xy[1]);
  497.                     if ( abs (gmt_x_status_new) > 1 || abs (gmt_y_status_new) > 1) continue;
  498.                 }
  499.  
  500.                 geo_to_xy (xy[0], xy[1], &plot_x, &plot_y);
  501.             
  502.                 if (error_bars) {
  503.                     ps_setline (epen.width);
  504.                     ps_setpaint (epen.r, epen.g, epen.b);
  505.                     if (xy_errors[0]) {
  506.                         geo_to_xy (xy[0] - delta_x, xy[1], &x_1, &y_1);
  507.                         geo_to_xy (xy[0] + delta_x, xy[1], &x_2, &y_2);
  508.                         ps_plot (x_1, y_1, 3);
  509.                         ps_plot (x_2, y_2, 2);
  510.                         if (error_width > 0.0) {
  511.                             ps_plot (x_1, y_1 - error_width2, 3);
  512.                             ps_plotr (0.0, error_width, 2);
  513.                             ps_plot (x_2, y_2 - error_width2, 3);
  514.                             ps_plotr (0.0, error_width, 2);
  515.                         }
  516.                     }
  517.                     if (xy_errors[1]) {
  518.                         geo_to_xy (xy[0], xy[1] - delta_y, &x_1, &y_1);
  519.                         geo_to_xy (xy[0], xy[1] + delta_y, &x_2, &y_2);
  520.                         ps_plot (x_1, y_1, 3);
  521.                         ps_plot (x_2, y_2, 2);
  522.                         if (error_width > 0.0) {
  523.                             ps_plot (x_1 - error_width2, y_1, 3);
  524.                             ps_plotr (error_width, 0.0, 2);
  525.                             ps_plot (x_2 - error_width2, y_2, 3);
  526.                             ps_plotr (error_width, 0.0, 2);
  527.                         }
  528.                     }
  529.                     ps_setline (pen.width);
  530.                     ps_setpaint (pen.r, pen.g, pen.b);
  531.                 }
  532.                 
  533.                 switch (symbol) {
  534.                     case NONE:
  535.                         break;
  536.                     case STAR:
  537.                         ps_star (plot_x, plot_y, symbol_size, fill.r, fill.g, fill.b, outline);
  538.                         break;
  539.                     case BAR:
  540.                         if (user_unit) {    /* Width measured in x units */
  541.                             geo_to_xy (xy[0]-symbol_size, base, &x_1, &y_1);
  542.                             geo_to_xy (xy[0]+symbol_size, xy[1], &x_2, &y_2);
  543.                     
  544.                             ps_rect (x_1, y_1, x_2, y_2, fill.r, fill.g, fill.b, outline);
  545.                         }
  546.                         else
  547.                             ps_rect (plot_x-symbol_size, y0, plot_x+symbol_size, plot_y, fill.r, fill.g, fill.b, outline);
  548.                         break;
  549.                     case CROSS:
  550.                         ps_cross (plot_x, plot_y, symbol_size);
  551.                         break;
  552.                     case POINT:
  553.                         ps_cross (plot_x, plot_y, POINTSIZE);
  554.                         break;
  555.                     case CIRCLE:
  556.                         ps_circle (plot_x, plot_y, symbol_size, fill.r, fill.g, fill.b, outline);
  557.                         break;
  558.                     case SQUARE:
  559.                         ps_square (plot_x, plot_y, symbol_size, fill.r, fill.g, fill.b, outline);
  560.                         break;
  561.                     case HEXAGON:
  562.                         ps_hexagon (plot_x, plot_y, symbol_size, fill.r, fill.g, fill.b, outline);
  563.                         break;
  564.                     case TRIANGLE:
  565.                         ps_triangle (plot_x, plot_y, symbol_size, fill.r, fill.g, fill.b, outline);
  566.                         break;
  567.                     case ITRIANGLE:
  568.                         ps_itriangle (plot_x, plot_y, symbol_size, fill.r, fill.g, fill.b, outline);
  569.                         break;
  570.                     case DIAMOND:
  571.                         ps_diamond (plot_x, plot_y, symbol_size, fill.r, fill.g, fill.b, outline);
  572.                         break;
  573.                     case TEXT:
  574.                         if (outline && polygon) {
  575.                             ps_setpaint (fill.r, fill.g, fill.b);
  576.                             ps_text (plot_x, plot_y, font_size, string, 0.0, 6, FALSE);
  577.                             ps_setpaint (pen.r, pen.g, pen.b);
  578.                             ps_text (plot_x, plot_y, font_size, string, 0.0, 6, TRUE);
  579.                         }
  580.                         else if (polygon)
  581.                             ps_text (plot_x, plot_y, font_size, string, 0.0, 6, FALSE);
  582.                         else
  583.                             ps_text (plot_x, plot_y, font_size, string, 0.0, 6, TRUE);
  584.                         break;
  585.                     case ELLIPSE:
  586.                         ps_ellipse (plot_x, plot_y, direction, length1, length2, fill.r, fill.g, fill.b, outline);
  587.                         break;
  588.                     case VECTOR:
  589.                         if (length1 == 0.0) continue;
  590.                         if (convert_angles) {
  591.                             azim_2_angle (xy[0], xy[1], 0.1, direction, &tmp);
  592.                             direction = tmp;
  593.                         }
  594.                         x2 = plot_x + length1 * cos (direction * D2R);
  595.                         y2 = plot_y + length1 * sin (direction * D2R);
  596.                         ps_vector (plot_x, plot_y, x2, y2, v_width, h_length, h_width, gmtdefs.vector_shape, fill.r, fill.g, fill.b, outline);
  597.                         break;
  598.                     case VECTOR2:
  599.                         if (length1 == 0.0) continue;
  600.                         if (convert_angles) {
  601.                             azim_2_angle (xy[0], xy[1], 1.0, direction, &tmp);
  602.                             direction = tmp;
  603.                         }
  604.                         x2 = plot_x + length1 * cos (direction * D2R);
  605.                         y2 = plot_y + length1 * sin (direction * D2R);
  606.                         if (length1 < v_norm) {    /* Scale arrow attributes down with length */
  607.                             v_w = v_width * length1 * v_shrink;
  608.                             h_l = h_length * length1 * v_shrink;
  609.                             h_w = h_width * length1 * v_shrink;
  610.                             ps_vector (plot_x, plot_y, x2, y2, v_w, h_l, h_w, gmtdefs.vector_shape, fill.r, fill.g, fill.b, outline);
  611.                         }
  612.                         else    /* Leave as specified */
  613.                             ps_vector (plot_x, plot_y, x2, y2, v_width, h_length, h_width, gmtdefs.vector_shape, fill.r, fill.g, fill.b, outline);
  614.                         break;
  615.                 }
  616.             }
  617.         }
  618.         else {    /* Line/polygon part */
  619.             
  620.             more = fgets (line, 512, fp);
  621.             while (more) {
  622.                 if (multi_segments && gmtdefs.verbose) ps_comment (header);
  623.                 n = 0;
  624.                 while ((more && !multi_segments) || (more && multi_segments && line[0] != EOL_flag)) {
  625.                     if (line[0] == EOL_flag) {
  626.                         more = fgets (line, 512, fp);
  627.                         continue;
  628.                     }
  629.  
  630.                     sscanf (line, "%lf %lf", &xy[ix], &xy[iy]);
  631.                     xx[n] = xy[0];    yy[n] = xy[1];
  632.                     n++;
  633.                     if (n == n_alloc) {
  634.                         n_alloc += GMT_CHUNK;
  635.                         xx = (double *) memory ((char *)xx, n_alloc, sizeof (double), "psxy");
  636.                         yy = (double *) memory ((char *)yy, n_alloc, sizeof (double), "psxy");
  637.                     }
  638.                     more = fgets (line, 512, fp);
  639.                 }
  640.                 if (polygon && !(xx[0] == xx[n-1] && yy[0] == yy[n-1])) {    /* Explicitly close polygon so that arc will work */
  641.                     xx[n] = xx[0];
  642.                     yy[n] = yy[0];
  643.                     n++;
  644.                     if (n == n_alloc) {
  645.                         n_alloc += GMT_CHUNK;
  646.                         xx = (double *) memory ((char *)xx, n_alloc, sizeof (double), "psxy");
  647.                         yy = (double *) memory ((char *)yy, n_alloc, sizeof (double), "psxy");
  648.                     }
  649.                 }
  650.                 if (multi_segments && gmtdefs.verbose) strcpy (header, line);
  651.         
  652.                 xx = (double *) memory ((char *)xx, n, sizeof (double), "psxy");
  653.                 yy = (double *) memory ((char *)yy, n, sizeof (double), "psxy");
  654.                 n_alloc = n;
  655.                 
  656.                 if (draw_arc && project_info.projection > 5) n = fix_up_path (&xx, &yy, n, greenwich, step);
  657.  
  658.                 if (polygon) {
  659.                     if ((plot_n = clip_to_map (xx, yy, n, &xp, &yp)) == 0) {
  660.                         if (more) more = fgets (line, 512, fp);
  661.                         continue;
  662.                     }
  663.                     while (plot_n > gmt_n_alloc) get_plot_array ();
  664.                     memcpy ((char *)gmt_x_plot, (char *)xp, plot_n * sizeof (double));
  665.                     memcpy ((char *)gmt_y_plot, (char *)yp, plot_n * sizeof (double));
  666.                 }
  667.                 else {
  668.                     plot_n = geo_to_xy_line (xx, yy, n);
  669.                     xp = (double *) memory (CNULL, plot_n, sizeof (double), "psxy");
  670.                     yp = (double *) memory (CNULL, plot_n, sizeof (double), "psxy");
  671.                     plot_pen = (int *) memory (CNULL, plot_n, sizeof (int), "psxy");
  672.                     memcpy ((char *)xp, (char *)gmt_x_plot, plot_n * sizeof (double));
  673.                     memcpy ((char *)yp, (char *)gmt_y_plot, plot_n * sizeof (double));
  674.                     memcpy ((char *)plot_pen, (char *)gmt_pen, plot_n * sizeof (int));
  675.                 }
  676.         
  677.                 if (polygon) {
  678.                     
  679.                     if (will_it_wrap (xp, yp, plot_n, &start)) {    /* Polygon wraps */
  680.                     
  681.                         /* First truncate agains left border */
  682.                         
  683.                         gmt_n_plot = truncate_left (xp, yp, plot_n, start);
  684.                         n_use = compact_line (gmt_x_plot, gmt_y_plot, gmt_n_plot, FALSE, 0);
  685.                         if (fill.use_pattern)
  686.                             ps_imagefill (gmt_x_plot, gmt_y_plot, n_use, fill.pattern_no, fill.pattern, fill.inverse, fill.icon_size, outline);
  687.                         else
  688.                             ps_polygon (gmt_x_plot, gmt_y_plot, n_use, fill.r, fill.g, fill.b, outline);
  689.                                 
  690.                         /* Then truncate agains right border */
  691.                         
  692.                         gmt_n_plot = truncate_right (xp, yp, plot_n, start);
  693.                         n_use = compact_line (gmt_x_plot, gmt_y_plot, gmt_n_plot, FALSE, 0);
  694.                         if (fill.use_pattern)
  695.                             ps_imagefill (gmt_x_plot, gmt_y_plot, n_use, fill.pattern_no, fill.pattern, fill.inverse, fill.icon_size, outline);
  696.                         else
  697.                             ps_polygon (gmt_x_plot, gmt_y_plot, n_use, fill.r, fill.g, fill.b, outline);
  698.                         
  699.                     }
  700.                     else {
  701.                         if (fill.use_pattern)
  702.                             ps_imagefill (xp, yp, plot_n, fill.pattern_no, fill.pattern, fill.inverse, fill.icon_size, outline);
  703.                         else
  704.                             ps_polygon (xp, yp, plot_n, fill.r, fill.g, fill.b, outline);
  705.                     }
  706.                 }
  707.                 else
  708.                     gmt_plot_line (xp, yp, plot_pen, plot_n);
  709.  
  710.                 if (symbol == FAULT) draw_fence (xp, yp, plot_n, f_gap, f_len, f_sense, f_triangle, &fill, outline);     /* Must draw crossbars */
  711.                                         
  712.                 free ((char *)xp);
  713.                 free ((char *)yp);
  714.                 if (!polygon) free ((char *)plot_pen);
  715.             
  716.                 if (more) more = fgets (line, 512, fp);
  717.             }
  718.         }
  719.         if (fp != stdin) fclose (fp);
  720.     }
  721.     
  722.     if (symbol > 0 && skip_if_outside) map_clip_off ();
  723.  
  724.     gmt_world_map = old_gmt_world_map;
  725.     
  726.     if (pen.texture) ps_setdash (CNULL, 0);
  727.     if (frame_info.plot) {
  728.         ps_setpaint (gmtdefs.basemap_frame_rgb[0], gmtdefs.basemap_frame_rgb[1], gmtdefs.basemap_frame_rgb[2]);
  729.         map_basemap ();
  730.         ps_setpaint (gmtdefs.background_rgb[0], gmtdefs.background_rgb[1], gmtdefs.background_rgb[2]);
  731.     }
  732.     ps_plotend (gmtdefs.last_page);
  733.     
  734.     if (symbol == 0) {
  735.         free ((char *)xx);
  736.         free ((char *)yy);
  737.     }
  738.     
  739.     gmt_end (argc, argv);
  740. }
  741.  
  742. int draw_fence (x, y, n, gap, len, sense, triangle, fill, outline)
  743. double x[], y[];
  744. int n;
  745. double gap, len;
  746. int sense, triangle;
  747. struct FILL *fill;
  748. BOOLEAN outline; {
  749.     int i, ngap;
  750.     double *s, xx[3], yy[3], dist = 0.0, frac, dx, dy, angle;
  751.     double x0, y0, len2, len3, cosa, sina;
  752.     
  753.     s = (double *) memory (CNULL, n, sizeof (double), "psxy");
  754.     for (i = 1, s[0] = 0.0; i < n; i++)
  755.         s[i] = s[i-1] + hypot (x[i] - x[i-1], y[i] - y[i-1]);
  756.         
  757.     if (gap > 0.0) {
  758.         ngap = rint (s[n-1] / gap);
  759.         gap = s[n-1] / ngap;
  760.         ngap++;
  761.     }
  762.     else {
  763.         ngap = (int) fabs (gap);
  764.         gap = s[n-1] / (ngap - 1);
  765.         if (ngap == 1) dist = 0.5 * s[n-1];
  766.     }
  767.     
  768.     len2 = 0.5 * len;
  769.     len3 = 0.866025404 * len;            
  770.     i = 0;
  771.     while (i < n) {
  772.         while ((s[i] - dist) > -SMALL) {    /* Time for tick */
  773.             if (i > 0) {
  774.                 dx = x[i] - x[i-1];
  775.                 dy = y[i] - y[i-1];
  776.             }
  777.             else {
  778.                 dx = x[1] - x[0];
  779.                 dy = y[1] - y[0];
  780.             }
  781.             if (fabs (dist - s[i]) < SMALL) {
  782.                 x0 = x[i];
  783.                 y0 = y[i];
  784.             }
  785.             else {
  786.                 frac = (s[i] - dist) / (s[i] - s[i-1]);
  787.                 x0 = x[i] - dx * frac;
  788.                 y0 = y[i] - dy * frac;
  789.             }
  790.             angle = atan2 (dy, dx);
  791.                         
  792.             if (triangle) {
  793.                 if (sense == -1) angle += M_PI;
  794.                 cosa = cos (angle);
  795.                 sina = sin (angle);
  796.                 xx[0] = x0 + len2 * cosa;
  797.                 yy[0] = y0 + len2 * sina;
  798.                 xx[1] = x0 - len3 * sina;
  799.                 yy[1] = y0 + len3 * cosa;
  800.                 xx[2] = x0 - len2 * cosa;
  801.                 yy[2] = y0 - len2 * sina;
  802.                 if (project_info.three_D) two_d_to_three_d (xx, yy, 3);
  803.                 ps_patch (xx, yy, 3, fill->r, fill->g, fill->b, outline);
  804.             }
  805.             else {
  806.                 xx[0] = xx[1] = x0;    yy[0] = yy[1] = y0;
  807.                 if (sense == 0) {
  808.                     angle -= M_PI_2;
  809.                     cosa = cos (angle);
  810.                     sina = sin (angle);
  811.                     xx[0] += len2 * cosa;
  812.                     yy[0] += len2 * sina;
  813.                     xx[1] -= len2 * cosa;
  814.                     yy[1] -= len2 * sina;
  815.                 }
  816.                 else {
  817.                     angle += (sense * M_PI_2);
  818.                     xx[1] += len * cos (angle);
  819.                     yy[1] += len * sin (angle);
  820.                 }
  821.                 if (project_info.three_D) two_d_to_three_d (xx, yy, 2);
  822.                 ps_plot (xx[0], yy[0], 3);
  823.                 ps_plot (xx[1], yy[1], 2);
  824.             }
  825.             dist += gap;
  826.         }
  827.         i++;
  828.     }
  829.     free ((char *)s);
  830. }
  831.                 
  832.