/*--------------------------------------------------------------------
 *	$Id: psxy.c,v 1.99 2006/04/12 21:55:46 pwessel Exp $
 *
 *	Copyright (c) 1991-2006 by P. Wessel and W. H. F. Smith
 *	See COPYING file for copying and redistribution conditions.
 *
 *	This program is free software; you can redistribute it and/or modify
 *	it under the terms of the GNU General Public License as published by
 *	the Free Software Foundation; version 2 of the License.
 *
 *	This program is distributed in the hope that it will be useful,
 *	but WITHOUT ANY WARRANTY; without even the implied warranty of
 *	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *	GNU General Public License for more details.
 *
 *	Contact info: gmt.soest.hawaii.edu
 *--------------------------------------------------------------------*/
/*
 * psxy will read <x,y> pairs (or <lon,lat>) from GMT_stdin and plot
 * the lines, polygons, or symbols on a map. A variety of symbols
 * may be specified, some of which require additional columns of
 * data, like symbol-size etc.  Only one symbol may be plotted
 * at the time.  PostScript code is written to GMT_stdout.
 *
 * Author:	Paul Wessel
 * Date:	15-SEP-2001
 * Version:	4
 *
 */

#include "gmt.h"
#include "pslib.h"

struct PSXY_CTRL {
	struct A {	/* -A[step] */
		BOOLEAN active;
		double step;
	} A;
	struct C {	/* -C<cpt> */
		BOOLEAN active;
		char *file;
	} C;
	struct D {	/* -D<dx>/<dy> */
		BOOLEAN active;
		double dx, dy;
	} D;
	struct E {	/* -E[x|X][y|Y][cap][/<pen>] */
		BOOLEAN active;
		int xbar, ybar;
		double size;
		struct GMT_PEN pen;
	} E;
	struct G {	/* -G<fill> */
		BOOLEAN active;
		struct GMT_FILL fill;
	} G;
	struct L {	/* -L */
		BOOLEAN active;
	} L;
	struct N {	/* -N */
		BOOLEAN active;
	} N;
	struct S {	/* -S */
		BOOLEAN active;
		char *arg;
	} S;
	struct W {	/* -W<pen> */
		BOOLEAN active;
		struct GMT_PEN pen;
	} W;
};

int main (int argc, char **argv)
{
	BOOLEAN	error = FALSE, nofile = TRUE, polygon = FALSE, read_symbol = FALSE, penset_OK = TRUE;
	BOOLEAN	default_outline = FALSE, done, get_rgb = FALSE, greenwich, default_polygon = FALSE, resample;
	BOOLEAN old_GMT_world_map, error_x = FALSE, error_y = FALSE, def_err_xy = FALSE, clip_set = FALSE;

	char line[BUFSIZ], *p, txt_a[GMT_LONG_TEXT], txt_b[GMT_LONG_TEXT];

	int i, j, n, j0, n_files = 0, fno, xy_errors[2], two, three, four, error_type[2] = {0,0};
	int n_alloc = GMT_CHUNK, plot_n, n_args, n_fields, n_cols_start = 2, this_outline;
	int n_required, n_total_read = 0, n_expected = 0, reset_cap = 0, error_cols[2] = {1,4};

	double west = 0.0, east = 0.0, south = 0.0, north = 0.0, s, c;
	double plot_x, plot_y, x_1, x_2, y_1, y_2, y0, *xx, *yy, *xp, *yp;
	double direction = 0.0, length = 0.0, major = 0.0, minor = 0.0, x2, y2, z;
	double dir1 = 0.0, dir2 = 0.0, x_len = 0.0, y_len = 0.0, dx, dy, size;
	double v_w, h_l, h_w, tmp, *in, font_size;

	FILE *fp = NULL;

	struct GMT_PEN default_pen;
	struct GMT_FILL default_fill, test_fill;
	struct GMT_SYMBOL S;
	struct PSXY_CTRL *Ctrl;

	void plot_x_errorbar (double x, double y, double delta_x, double error_width2, int line);
	void plot_y_errorbar (double x, double y, double delta_y, double error_width2, int line);
	void plot_x_whiskerbar (double x, double y, double hinge[], double error_width2, int rgb[], int line);
	void plot_y_whiskerbar (double x, double y, double hinge[], double error_width2, int rgb[], int line);
	void *New_Psxy_Ctrl (), Free_Psxy_Ctrl (struct PSXY_CTRL *C);
	
	argc = GMT_begin (argc, argv);

	Ctrl = (struct PSXY_CTRL *)New_Psxy_Ctrl ();	/* Allocate and initialize a new control structure */

	xy_errors[0] = xy_errors[1] = 0;	/* These will be col # of where to find this info in data */

	/* Initialize GMT_SYMBOL structure */

	memset ((void *)&S, 0, sizeof (struct GMT_SYMBOL));
	GMT_contlabel_init (&S.G, 0);
	
	S.v_width = 0.03;
	S.h_length = 0.12;
	S.h_width = 0.1;
	S.font_no = gmtdefs.annot_font[0];

	if ((S.u = gmtdefs.measure_unit) == GMT_CM) {
		S.v_width = 0.075 / 2.54;	S.h_length = 0.3 / 2.54;
		S.h_width = 0.25 / 2.54; Ctrl->E.size = 0.25 / 2.54;
	}

	/* Check and interpret the command line arguments */

	for (i = 1; i < argc; i++) {
		if (argv[i][0] == '-') {
			switch(argv[i][1]) {

				/* Common parameters */
	
				case 'B':
				case 'H':
				case 'J':
				case 'K':
				case 'O':
				case 'P':
				case 'R':
				case 'U':
				case 'V':
				case 'X':
				case 'x':
				case 'Y':
				case 'y':
				case 'b':
				case 'c':
				case 'f':
				case ':':
				case '\0':
					error += GMT_parse_common_options (argv[i], &west, &east, &south, &north);
					break;
		
				/* Supplemental parameters */
	
				case 'A':	/* Turn off draw_arc mode */
					if (argv[i][2])
						Ctrl->A.step = atof (&argv[i][2]);	/* Undocumented test feature */
					else
						Ctrl->A.active = TRUE;
					break;
			
				case 'C':	/* Vary symbol color with z */
					Ctrl->C.file = strdup (&argv[i][2]);
					Ctrl->C.active = TRUE;
					break;
				case 'D':
					if (sscanf (&argv[i][2], "%[^/]/%s", txt_a, txt_b) != 2) {
						fprintf (stderr, "%s: GMT SYNTAX ERROR -D option: Give x and y offsets\n", GMT_program);
						error++;
					}
					else {
						Ctrl->D.dx = GMT_convert_units (txt_a, GMT_INCH);
						Ctrl->D.dy = GMT_convert_units (txt_b, GMT_INCH);
						Ctrl->D.active = TRUE;
					}
					break;
				case 'E':	/* Get info for error bars and bow-whisker bars */
					Ctrl->E.active = TRUE;
					for (j = 2; argv[i][j] && argv[i][j] != '/'; j++) {
						if (argv[i][j] == 'x')		/* Error bar for x */
							Ctrl->E.xbar = 1;
						else if (argv[i][j] == 'X')	/* Box-whisker instead */
							Ctrl->E.xbar = 2;
						else if (argv[i][j] == 'y')	/* Error bar for y */
							Ctrl->E.ybar = 1;
						else if (argv[i][j] == 'Y')	/* Box-whisker instead */
							Ctrl->E.ybar = 2;
						else {	/* Get error 'cap' width */
							strcpy (txt_a, &argv[i][j]);
							j0 = 0;
							while (txt_a[j0] && txt_a[j0] != '/') j0++;
							txt_a[j0] = 0;
							Ctrl->E.size = GMT_convert_units (txt_a, GMT_INCH);
							while (argv[i][j] && argv[i][j] != '/') j++;
							j--;
						}
					}
					if (argv[i][j] == '/') GMT_getpen (&argv[i][j+1], &Ctrl->E.pen);
					break;
				case 'G':		/* Set fill for symbols or polygon */
					Ctrl->G.active = TRUE;
					if (!argv[i][2] || (argv[i][2] && GMT_getfill (&argv[i][2], &Ctrl->G.fill))) {
						GMT_fill_syntax ('G');
						error++;
					}
					break;
				case 'L':		/* Close line segments */
					Ctrl->L.active = TRUE;
					break;
				case 'M':		/* Multiple line segments */
					GMT_multisegment (&argv[i][2]);
					break;
				case 'N':		/* Do not skip points outside border */
					Ctrl->N.active = TRUE;
					break;
				case 'S':		/* Get symbol [and size] */
					Ctrl->S.active = TRUE;
					Ctrl->S.arg = &argv[i][2];
					break;
				case 'W':		/* Set line attributes */
					Ctrl->W.active = TRUE;
					if (argv[i][2] && GMT_getpen (&argv[i][2], &Ctrl->W.pen)) {
						GMT_pen_syntax ('W');
						error++;
					}
					break;
			
				/* Illegal options */
	
				default:		/* Options not recognized */
					error = TRUE;
					GMT_default_error (argv[i][1]);
					break;
			}
		}
		else
			n_files++;
	}

	if (argc == 1 || GMT_give_synopsis_and_exit) {	/* Display usage */
		fprintf (stderr,"psxy %s - Plot lines, polygons, and symbols on maps\n\n", GMT_VERSION);
		fprintf (stderr,"usage: psxy <infiles> %s %s [-A] [%s] [-C<cpt>]\n", GMT_J_OPT, GMT_Rgeo_OPT, GMT_B_OPT);
		fprintf (stderr, "\t[-D<dx>/<dy>] [-E[x|y|X|Y][cap][/<pen>]] [-G<fill>] [%s] [-K] [-L] [%s]\n", GMT_H_OPT, GMT_Mo_OPT);
		fprintf (stderr, "\t[-N] [-O] [-P] [-S[<symbol>][<size>]] [%s] [-V] [-W[<pen>]] [%s]\n", GMT_U_OPT, GMT_X_OPT);
		fprintf (stderr, "\t[%s] [%s] [%s] [%s] [%s]\n\n", GMT_Y_OPT, GMT_c_OPT, GMT_t_OPT, GMT_bi_OPT, GMT_f_OPT);

		if (GMT_give_synopsis_and_exit) exit (EXIT_FAILURE);

		fprintf (stderr, "\t<infiles> is one or more files.  If no, read standard input\n");
		GMT_explain_option ('j');
		GMT_explain_option ('R');
		fprintf (stderr, "\n\tOPTIONS:\n");
		GMT_explain_option ('b');
		fprintf (stderr, "\t-A Suppress drawing line segments as great circle arcs\n");
		fprintf (stderr, "\t-C Use cpt-file to assign symbol colors based on z-value in 3rd column (requires -S)\n");
		fprintf (stderr, "\t   Without -S, psxy excepts -M lines/polygons and looks for -Z<val> options in each multiheader\n");
		fprintf (stderr, "\t-D Offset symbol positions by <dx>/<dy> [no offset].. Requires -S.\n");
		fprintf (stderr, "\t-E means draw error bars for x, y, or both.  Add cap-width [%g]. Append pen attributes.\n", Ctrl->E.size);
		fprintf (stderr, "\t   If X or Y is used instead a box-and-whisker diagram is drawn instead, using data from 4\n");
		fprintf (stderr, "\t   extra columns to get the 0 %%, 25 %%, 75 %% ,and 100%% quartiles (point value is assumed to be 50%%)\n");
		fprintf (stderr, "\t   Then, use -W, -G to control the appearance of the 25-75%% box.\n");
		fprintf (stderr, "\t-G Specify color (for symbols/polygons) or pattern (for polygons). Fill can be either\n");
		fprintf (stderr, "\t   1) <gray> (0-255) for gray-shade [0].\n");
		fprintf (stderr, "\t   2) <r/g/b> (each 0-255), <h/s/v> (0-360,0-1,0-1), or <c/m/y/k> (each 0-100) for color.\n");
		fprintf (stderr, "\t   3) black, white or [light|dark]{red, orange, yellow, green, cyan, blue, magenta, brown, gray}.\n");
		fprintf (stderr, "\t   4) p[or P]<dpi>/<pattern> for predefined patterns (1-90).\n");
		fprintf (stderr, "\t   5) not given; -G option is present in all subheader (requires -M and no -S)\n");
		fprintf (stderr, "\t   Default is no fill (transparent symbols or polygons)\n");
		GMT_explain_option ('H');
		GMT_explain_option ('K');
		fprintf (stderr, "\t-L Force closed polygons.\n");
		GMT_explain_option ('M');
		fprintf (stderr, "\t-N Do Not skip/clip symbols that fall outside map border [Default will ignore those outside]\n");
		GMT_explain_option ('O');
		GMT_explain_option ('P');
		fprintf (stderr, "\t-S to select symbol type and symbol size (in %s).  Choose between\n", GMT_unit_names[gmtdefs.measure_unit]);
		fprintf (stderr, "\t   -(xdash), st(a)r, (b)ar, (c)ircle, (d)iamond, (e)llipse, (f)ront, octa(g)on, (h)exagon, (i)nvtriangle,\n");
		fprintf (stderr, "\t   (k)ustom, (l)etter, pe(n)tagon, (p)oint, (q)uoted line, (r)ect, (s)quare, (t)riangle, (v)ector, (w)edge, (x)cross, (y)dash\n");
		fprintf (stderr, "\t   If no size is specified, psxy expects the 3rd column to have sizes.\n");
		fprintf (stderr, "\t   If no symbol is specified, psxy expects the last column to have symbol code.\n");
		fprintf (stderr, "\t   [Note: if -C is selected then 3rd means 4th column, etc.]\n");
		fprintf (stderr, "\t   Symbols A, C, D, G, H, I, N, S, T are adjusted to have same area as a circle of given size\n");
		fprintf (stderr, "\t   Bars: Append b<base> to give the y-value of the base [Default = 0]\n");
		fprintf (stderr, "\t      Append u if width is in x-input units [Default is %s]\n", GMT_unit_names[gmtdefs.measure_unit]);
		fprintf (stderr, "\t   Ellipses: the direction, major, and minor axis must be in input columns 3, 4 and 5.\n");
		fprintf (stderr, "\t     If -SE rather than -Se is selected, psxy will expect azimuth, and axes in km\n");
		fprintf (stderr, "\t     and convert azimuths based on the chosen map projection.  If projection is linear then\n");
		fprintf (stderr, "\t     we scale the minor/major axes by the map scale.\n");
		fprintf (stderr, "\t   Fronts: Give tickgap/ticklen[dir][type][:offset], where\n");
		fprintf (stderr, "\t     dir    = Plot symbol to the l(eft) or r(ight) of front [Default is centered]\n");
		fprintf (stderr, "\t     type   =  b(ox), c(ircle), f(ault), s(lip), t(riangle) [Default is f]\n");
		fprintf (stderr, "\t       box      : square when centered, half-square otherwise.\n"); 
		fprintf (stderr, "\t       circle   : full when centered, half-circle otherwise.\n"); 
		fprintf (stderr, "\t       fault    : centered cross-tick or tick only in the <dir> direction.\n"); 
		fprintf (stderr, "\t       slip     : left-lateral or right-lateral strike-slip arrows (centered is not defined).\n"); 
		fprintf (stderr, "\t       triangle : diagonal square when centered, directed triangle otherwise.\n"); 
		fprintf (stderr, "\t     offset = start plotting symbols when along-track distance equals offset [0].\n"); 
		fprintf (stderr, "\t   Kustom: append <symbolname> immediately after 'k'; this will look for <symbolname>.def in\n");
		fprintf (stderr, "\t     the current directory or in $GMTHOME/share/custom.\n");
		GMT_list_custom_symbols ();
		fprintf (stderr, "\t   Letter: append /<string> after symbol size, and optionally %%<font>\n");
		fprintf (stderr, "\t   Quoted line: Give [d|f|n|l|x]<info>[:<labelinfo>]\n");
		fprintf (stderr, "\t     <code><info> controls placement of labels along lines.  Choose among five algorithms:\n");
		GMT_cont_syntax (7, 1);
		fprintf (stderr, "\t     <labelinfo> controls the specifics of the labels.  Append what you need:\n");
		GMT_label_syntax (7, 1);
		fprintf (stderr, "\t   Rectangles: the x- and y-dimension must be in input columns 3 and 4.\n");
		fprintf (stderr, "\t   Vectors: the direction and length must be in input columns 3 and 4.\n");
		fprintf (stderr, "\t     Furthermore, <size> means arrowwidth/headlength/headwith [Default is %g/%g/%g]\n", S.v_width, S.h_length, S.h_width);
		fprintf (stderr, "\t     If -SV rather than -Sv is selected, psxy will expect azimuth and length\n");
		fprintf (stderr, "\t     and convert azimuths based on the chosen map projection\n");
		fprintf (stderr, "\t     Insert h(head), b(balance point), or t(ail) after -Sv|V to justify vector w.r.t. input (x,y).\n");
		fprintf (stderr, "\t     Insert s(egment) if (x,y) is tail and columns 3 and 4 holds head (x,y).\n");
		fprintf (stderr, "\t     Upper case H, B, T, S will give double-headed vector [Default is t]\n");
		fprintf (stderr, "\t   Wedges: the start and stop directions of pie wedge must be in input columns 3, 4.\n");
		fprintf (stderr, "\t     If -SW rather than -Sw is selected, psxy will expect two azimuths instead.\n");
		GMT_explain_option ('U');
		GMT_explain_option ('V');
		fprintf (stderr, "\t-W sets pen attributes [width = %gp, color = black, texture = solid line].\n", Ctrl->W.pen.width);
		fprintf (stderr, "\t   Implicitly draws symbol outline with this pen.\n");
		fprintf (stderr, "\t   OR -W:<width>:<color>:<texture>: (leave empty to obtain the default values [:thinnest:black::]\n");
		fprintf (stderr, "\t   <width> = faint or {thin, thick, fat}[er|est].\n");
		fprintf (stderr, "\t   <color> = black, white or [light|dark]{red, orange, yellow, green, cyan, blue, magenta, brown, gray}.\n");
		fprintf (stderr, "\t   <texture> = pattern of dashes (-) and dots (.) which will be scaled by pen width.\n");
		GMT_explain_option ('X');
		GMT_explain_option ('c');
		GMT_explain_option (':');
		GMT_explain_option ('i');
		GMT_explain_option ('n');
		fprintf (stderr, "\t   Default is the required number of columns\n");
		GMT_explain_option ('f');
		GMT_explain_option ('.');
		exit (EXIT_FAILURE);
	}

	/* Check that the options selected are mutually consistent */

	if (Ctrl->S.active && GMT_decode_symbol_option (Ctrl->S.arg, &S, 0, TRUE)) {
		fprintf (stderr, "%s: GMT SYNTAX ERROR -S option\n", GMT_program);
		error++;
	}
	if (S.symbol > 0 && Ctrl->C.active) get_rgb = TRUE;	/* Need to read z-vales from input data file */
	if (Ctrl->E.active && (S.read_vector || S.symbol == GMT_SYMBOL_ELLIPSE || S.symbol == GMT_SYMBOL_FRONT || S.symbol == GMT_SYMBOL_QUOTED_LINE)) {
		fprintf (stderr, "%s: GMT SYNTAX ERROR -E option: Incompatible with -Se, -Sf, -Sq, -Sv\n", GMT_program);
		error++;
	}
	if (Ctrl->G.fill.use_pattern && !(S.symbol == GMT_SYMBOL_LINE || S.symbol == GMT_SYMBOL_CUSTOM)) {	/* fill-pattern only for polygons */
		error++;
		fprintf (stderr, "%s: GMT SYNTAX ERROR -G option: Fill-pattern only used with polygons\n", GMT_program);
	}
	if (Ctrl->C.active && S.symbol == 0 && !GMT_io.multi_segments[GMT_IN]) {
		error++;
		fprintf (stderr, "%s: GMT SYNTAX ERROR -C option: Must also specify a symbol (see -S) or give polygon file with -M\n", GMT_program);
	}
	if (!project_info.region_supplied) {
		fprintf (stderr, "%s: GMT SYNTAX ERROR:  Must specify -R option\n", GMT_program);
		error++;
	}
	if (GMT_io.binary[GMT_IN] && GMT_io.io_header[GMT_IN]) {
		fprintf (stderr, "%s: GMT SYNTAX ERROR.  Binary input data cannot have header -H\n", GMT_program);
		error++;
	}
	if (GMT_io.binary[GMT_IN] && S.symbol == GMT_SYMBOL_NOT_SET) {
		fprintf (stderr, "%s: GMT SYNTAX ERROR.  Binary input data cannot have symbol information\n", GMT_program);
		error++;
	}
	if (S.symbol == 0 && Ctrl->D.active) {
		fprintf (stderr, "%s: GMT SYNTAX ERROR.  -D option only applies to symbols, not lines\n", GMT_program);
		error++;
	}

	if (error) exit (EXIT_FAILURE);

	if (Ctrl->E.active) {	/* Set error bar parameters */
		j = 2;	/* Normally, error bar related columns start in position 2 */
		if (Ctrl->E.xbar == 1) {
			xy_errors[0] = j++;
			error_type[0] = 0;
		}
		else if (Ctrl->E.xbar == 2) {	/* Box-whisker instead */
			xy_errors[0] = j++;
			error_type[0] = 1;
		}
		if (Ctrl->E.ybar == 1) {
			xy_errors[1] = j++;
			error_type[1] = 0;
		}
		else if (Ctrl->E.ybar == 2) {	/* Box-whisker instead */
			xy_errors[1] = j++;
			error_type[1] = 1;
		}
		if (!(xy_errors[0] || xy_errors[1])) {	/* Default is plain error bars for both */
			def_err_xy = TRUE;
			xy_errors[0] = 2;	/* Assumes xy input, later check for -: */
			xy_errors[1] = 3;
			error_type[0] = error_type[1] = 1;
		}
	}

	read_symbol = (S.symbol == GMT_SYMBOL_NOT_SET);	/* Only for ASCII input */

	if (S.symbol == 0 && (Ctrl->G.active || Ctrl->L.active)) polygon = TRUE;
	if (S.symbol == GMT_SYMBOL_FRONT || S.symbol == GMT_SYMBOL_QUOTED_LINE) polygon = FALSE;

	if (S.symbol && !(Ctrl->G.active || Ctrl->C.active)) Ctrl->W.active = TRUE;	/* User wants symbol but no fill - implicitly set outline */

	default_pen = Ctrl->W.pen;
	default_fill = Ctrl->G.fill;
	default_outline = Ctrl->W.active;
	default_polygon = polygon;

	Ctrl->E.size *= 0.5;	/* Since we draw half-way in either direction */

	if (Ctrl->E.active && S.symbol == 0)	/* Assume user only wants error bars */
		S.symbol = GMT_SYMBOL_NONE;

	if (Ctrl->C.active) {
		GMT_read_cpt (Ctrl->C.file);
		if (get_rgb) n_cols_start++;
	}

	if (n_files > 0)
		nofile = FALSE;
	else
		n_files = 1;
	n_args = (argc > 1) ? argc : 2;

	if (Ctrl->E.active) {
		if (xy_errors[0] && xy_errors[1] && error_type[0] == 1) xy_errors[1] += 3;	/* Need 4 columns for whisker bars */
		if (def_err_xy && gmtdefs.xy_toggle[0]) {	/* -E should be -Eyx */
			i_swap (xy_errors[0], xy_errors[1]);
			i_swap (error_type[0], error_type[1]);
		}
		if (xy_errors[0]) n_cols_start += error_cols[error_type[0]], error_x = TRUE;
		if (xy_errors[1]) n_cols_start += error_cols[error_type[1]], error_y = TRUE;
		xy_errors[0] += (S.read_size + get_rgb);	/* Move 0-2 columns over */
		xy_errors[1] += (S.read_size + get_rgb);
	}
	two   = (get_rgb) ? 3 : 2;
	three = (get_rgb) ? 4 : 3;
	four  = (get_rgb) ? 5 : 4;
	n_required = n_cols_start + S.n_required;

	if (GMT_io.binary[GMT_IN] && GMT_io.ncol[GMT_IN] == 0) GMT_io.ncol[GMT_IN] = n_required;
	n_expected = (GMT_io.binary[GMT_IN]) ? GMT_io.ncol[GMT_IN] : n_required;
	if (n_expected < n_required) {
		fprintf (stderr, "%s: GMT SYNTAX ERROR.  Binary input data must have at least %d columns\n", GMT_program, n_required);
		error++;
	}

	GMT_put_history (argc, argv);	/* Update .gmtcommands4 */

	if (GMT_io.binary[GMT_IN] && gmtdefs.verbose) {
		char *type[2] = {"double", "single"};
		fprintf (stderr, "%s: Expects %d-column %s-precision binary data\n", GMT_program, GMT_io.ncol[GMT_IN], type[GMT_io.single_precision[GMT_IN]]);
	}

	GMT_map_setup (west, east, south, north);

	if (S.symbol == GMT_SYMBOL_QUOTED_LINE) {
		if (GMT_contlabel_prep (&S.G, NULL)) exit (EXIT_FAILURE);
		penset_OK = FALSE;	/* Since it is set in PSL */
	}

	resample = (!Ctrl->A.active && GMT_IS_MAPPING);
	greenwich = (project_info.w <= 0.0 || project_info.e <= 0.0);

	GMT_plotinit (argc, argv);

	if (penset_OK) GMT_setpen (&Ctrl->W.pen);
	if (S.symbol == GMT_SYMBOL_TEXT && Ctrl->G.active && !Ctrl->W.active) ps_setpaint (Ctrl->G.fill.rgb);

	if (S.symbol == GMT_SYMBOL_TEXT) {
		ps_setfont (S.font_no);			/* Set the required font */
	}
	if (S.symbol == GMT_SYMBOL_FRONT || S.symbol == GMT_SYMBOL_QUOTED_LINE || (S.symbol > 0 && !Ctrl->N.active)) {
		GMT_map_clip_on (GMT_no_rgb, 3);
		clip_set = TRUE;
	}
	if (S.symbol == GMT_SYMBOL_ELLIPSE) Ctrl->N.active = TRUE;	/* So we can see ellipses that have centers outside -R */
	if (S.symbol == GMT_SYMBOL_POINT && !Ctrl->E.active) {	/* Temporarily change linecap to round (1)*/
		ps_setlinecap (1);
		reset_cap = 1;
	}
	else if ((read_symbol || Ctrl->E.active) && gmtdefs.ps_line_cap != 1) {	/* Must set/rest cap around each ps_point call */
		reset_cap = 2;
	}
	old_GMT_world_map = GMT_world_map;
	if (S.convert_angles && GMT_IS_MAPPING) S.convert_angles = 2;

	if (S.symbol <= 0) {
		xx = (double *) GMT_memory (VNULL, (size_t)n_alloc, sizeof (double), GMT_program);
		yy = (double *) GMT_memory (VNULL, (size_t)n_alloc, sizeof (double), GMT_program);
	}
	done = FALSE;
	for (fno = 1; !done && fno < n_args; fno++) {	/* Loop over all input files */
		if (!nofile && argv[fno][0] == '-') continue;
		if (nofile) {
			fp = GMT_stdin;
			done = TRUE;
#ifdef SET_IO_MODE
			GMT_setmode (GMT_IN);
#endif
		}
		else if ((fp = GMT_fopen (argv[fno], GMT_io.r_mode)) == NULL) {
			fprintf (stderr, "%s: Cannot open file %s\n", GMT_program, argv[fno]);
			continue;
		}

		GMT_io.file_no++;
		GMT_io.seg_no = -1;
		if (!nofile && gmtdefs.verbose) {
			fprintf (stderr, "%s: Working on file %s\n", GMT_program, argv[fno]);
			sprintf (line, "File: %s", argv[fno]);
			ps_comment (line);
		}
		if (GMT_io.io_header[GMT_IN]) {
			for (i = 0; i < GMT_io.n_header_recs; i++) {
				GMT_fgets (line, BUFSIZ, fp);
				if (i == 0 && S.G.label_type == 2) GMT_extract_label (&line[1], S.G.label);	/* Set initial header as potential label */
			}
		}
		if (S.symbol > 0) {	/* symbol part (not counting GMT_SYMBOL_FRONT and GMT_SYMBOL_QUOTED_LINE) */

			GMT_world_map = (S.symbol == GMT_SYMBOL_ELLIPSE && S.convert_angles) ? FALSE : TRUE;
			if (read_symbol) n_expected = BUFSIZ;
			while ((n_fields = GMT_input (fp, &n_expected, &in)) >= 0 && !(GMT_io.status & GMT_IO_EOF)) {

				while ((GMT_io.status & GMT_IO_SEGMENT_HEADER) && !(GMT_io.status & GMT_IO_EOF)) {	/* Skip segment headers */
					if (gmtdefs.verbose) ps_comment (GMT_io.segment_header);
					if ((p = strstr (GMT_io.segment_header, " -G")) || (p = strstr (GMT_io.segment_header, "	-G"))) {
						strcpy (line, &p[3]);
						for (i = 0; line[i]; i++) if (line[i] == ' ') line[i] = '\0';
						if (!GMT_getfill (line, &test_fill)) Ctrl->G.fill = test_fill;	/* Failure is OK since -G may appear in text strings */
					}
					else if (Ctrl->C.active && ((p = strstr (GMT_io.segment_header, " -Z")) || (p = strstr (GMT_io.segment_header, "	-Z")))) {	/* Set symbol r/g/b via cpt-lookup */
						if(!strncmp (&p[3], "NaN", 3))	/* Got -ZNaN */
							GMT_get_rgb24 (GMT_d_NaN, Ctrl->G.fill.rgb);
						else {
							if (sscanf (&p[3], "%lg", &z) == 1) GMT_get_rgb24 (z, Ctrl->G.fill.rgb);
						}
					}
					else
						Ctrl->G.fill = default_fill;
					if ((p = strstr (GMT_io.segment_header, " -W")) || (p = strstr (GMT_io.segment_header, "	-W"))) {
						strcpy (line, &p[3]);
						for (i = 0; line[i]; i++) if (line[i] == ' ') line[i] = '\0';
						if (!GMT_getpen (line, &Ctrl->W.pen)) {	/* Failure is OK since -W may appear in text strings */
							GMT_setpen (&Ctrl->W.pen);
							Ctrl->W.active = TRUE;
						}
					}
					else {
						GMT_setpen (&default_pen);
						Ctrl->W.active = default_outline;
					}
					if (read_symbol) n_expected = BUFSIZ;
					n_fields = GMT_input (fp, &n_expected, &in);
				}
				if ((GMT_io.status & GMT_IO_EOF)) continue;	/* At EOF */

				if (GMT_io.status & GMT_IO_MISMATCH && !read_symbol) {
					fprintf (stderr, "%s: Mismatch between actual (%d) and expected (%d) fields near line %d\n", GMT_program, n_fields, n_expected, n_total_read);
					exit (EXIT_FAILURE);
				}
				n_total_read++;
	
				if (S.read_size) {
					S.size_x = in[two] * GMT_u2u[S.u][GMT_INCH];
				}
				if (read_symbol) {
					i = strlen (GMT_io.current_record) - 1;
					GMT_io.current_record[i--] = 0;	/* Chop off the \n */
					while (GMT_io.current_record[i] && !strchr (" ,\t", (int)GMT_io.current_record[i])) i--;
					(void ) GMT_decode_symbol_option (&GMT_io.current_record[i+1], &S, 0, FALSE);
					n_required = n_cols_start + S.n_required;
				}

				if (S.symbol == GMT_SYMBOL_BAR) GMT_geo_to_xy (west, S.base, &plot_x, &y0);	/* Zero level for bars */
				if (get_rgb) {
					GMT_get_rgb24 (in[2], Ctrl->G.fill.rgb);
					if (S.symbol == GMT_SYMBOL_CROSS || S.symbol == GMT_SYMBOL_POINT || S.symbol == GMT_SYMBOL_TEXT) ps_setpaint (Ctrl->G.fill.rgb);
				}
				if (GMT_cpt_skip) continue;	/* Chosen cpt file indicates skip for this z */
		
				if (S.read_vector) {
					direction = in[two];
					length = in[three] * GMT_u2u[S.u][GMT_INCH];
				}
				else if (S.symbol == GMT_SYMBOL_ELLIPSE && S.convert_angles == 2) {	/* Leave axes in km */
					direction = in[two];
					major = in[three];
					minor = in[four];
				}
				else if (S.symbol == GMT_SYMBOL_ELLIPSE && S.convert_angles) {	/* Scale lengths by given scale */
					direction = 90.0 - in[two];	/* Cartesian azimuth */
					major = in[three] * project_info.x_scale;
					minor = in[four] * project_info.x_scale;
				}
				else if (S.symbol == GMT_SYMBOL_ELLIPSE) {
					direction = in[two];
					major = in[three] * GMT_u2u[S.u][GMT_INCH];
					minor = in[four] * GMT_u2u[S.u][GMT_INCH];
				}
				else if (S.symbol == GMT_SYMBOL_PIE && S.convert_angles) {
					dir1 = 90.0 - in[two+S.read_size];
					dir2 = 90.0 - in[three+S.read_size];
				}
				else if (S.symbol == GMT_SYMBOL_PIE) {
					dir1 = in[two+S.read_size];
					dir2 = in[three+S.read_size];
				}
				else if (S.symbol == GMT_SYMBOL_RECT) {
					x_len = 0.5 * in[two+S.read_size];
					y_len = 0.5 * in[three+S.read_size];
				}
		
				/* Skip zero-size symbols */
		
				if (!(S.symbol == GMT_SYMBOL_BAR) && S.symbol < GMT_SYMBOL_ELLIPSE && S.size_x <= 0.0) {
					if (gmtdefs.verbose) fprintf (stderr, "%s: Warning: Symbol size <= 0.0 near line %d (skipped)\n", GMT_program, n_total_read);
					continue;
				}
		
				if (S.read_vector && S.v_just < 3 && length <= 0.0) {
					if (gmtdefs.verbose) fprintf (stderr, "%s: Warning: Vector length <= 0.0 near line %d (skipped)\n", GMT_program, n_total_read);
					continue;
				}
				if (S.symbol == GMT_SYMBOL_ELLIPSE && (major <= 0.0 || minor <= 0.0)) {
					if (gmtdefs.verbose) fprintf (stderr, "%s: Warning: Ellipse axes <= 0.0 near line %d (skipped)\n", GMT_program, n_total_read);
					continue;
				}

				if (!Ctrl->N.active) {
					GMT_map_outside (in[0], in[1]);
					if ( abs (GMT_x_status_new) > 1 || abs (GMT_y_status_new) > 1) continue;
				}

				GMT_geo_to_xy (in[0], in[1], &plot_x, &plot_y);
				if (GMT_is_dnan (plot_x)) {
					fprintf (stderr, "%s: Data point with x = NaN near line %d\n", GMT_program, n_total_read);
					continue;
				}
				if (GMT_is_dnan (plot_y)) {
					if (gmtdefs.verbose) fprintf (stderr, "%s: Warning: Data point with y = NaN near line %d\n", GMT_program, n_total_read);
					continue;
				}
				if (Ctrl->D.active) {
					plot_x += Ctrl->D.dx;
					plot_y += Ctrl->D.dy;
				}
				if (Ctrl->E.active) {
					GMT_setpen (&Ctrl->E.pen);
					if (error_x) {
						if (error_type[0] == 0)
							plot_x_errorbar (in[0], in[1], in[xy_errors[0]], Ctrl->E.size, n_total_read);
						else
							plot_x_whiskerbar (plot_x, in[1], &in[xy_errors[0]], Ctrl->E.size, Ctrl->G.fill.rgb, n_total_read);
					}
					if (error_y) {
						if (error_type[1] == 0)
							plot_y_errorbar (in[0], in[1], in[xy_errors[1]], Ctrl->E.size, n_total_read);
						else
							plot_y_whiskerbar (in[0], plot_y, &in[xy_errors[1]], Ctrl->E.size, Ctrl->G.fill.rgb, n_total_read);
					}
					GMT_setpen (&Ctrl->W.pen);
				}

				switch (S.symbol) {
					case GMT_SYMBOL_NONE:
						break;
					case GMT_SYMBOL_STAR:
						size = (S.equal_area) ? 1.67289326141 * S.size_x : S.size_x;
						ps_star (plot_x, plot_y, size, Ctrl->G.fill.rgb, Ctrl->W.active);
						break;
					case GMT_SYMBOL_BAR:
						if (S.user_unit) {	/* Width measured in x units */
							GMT_geo_to_xy (in[0]-S.size_x, S.base, &x_1, &y_1);
							GMT_geo_to_xy (in[0]+S.size_x, in[1], &x_2, &y_2);
			
							ps_rect (x_1, y_1, x_2, y_2, Ctrl->G.fill.rgb, Ctrl->W.active);
						}
						else
							ps_rect (plot_x-S.size_x, y0, plot_x+S.size_x, plot_y, Ctrl->G.fill.rgb, Ctrl->W.active);
						break;
					case GMT_SYMBOL_CROSS:
						ps_cross (plot_x, plot_y, S.size_x);
						break;
					case GMT_SYMBOL_POINT:
						if (reset_cap == 2) ps_setlinecap (1);
						ps_point (plot_x, plot_y, S.size_x);
						if (reset_cap == 2) ps_setlinecap (gmtdefs.ps_line_cap);
						break;
					case GMT_SYMBOL_CIRCLE:
						ps_circle (plot_x, plot_y, S.size_x, Ctrl->G.fill.rgb, Ctrl->W.active);
						break;
					case GMT_SYMBOL_SQUARE:
						size = (S.equal_area) ? 1.25331413732 * S.size_x : S.size_x;
						ps_square (plot_x, plot_y, size, Ctrl->G.fill.rgb, Ctrl->W.active);
						break;
					case GMT_SYMBOL_HEXAGON:
						size = (S.equal_area) ? 1.09963611079 * S.size_x : S.size_x;
						ps_hexagon (plot_x, plot_y, size, Ctrl->G.fill.rgb, Ctrl->W.active);
						break;
					case GMT_SYMBOL_PENTAGON:
						size = (S.equal_area) ? 1.14948092619 * S.size_x : S.size_x;
						ps_pentagon (plot_x, plot_y, size, Ctrl->G.fill.rgb, Ctrl->W.active);
						break;
					case GMT_SYMBOL_OCTAGON:
						size = (S.equal_area) ? 1.05390736526 * S.size_x : S.size_x;
						ps_octagon (plot_x, plot_y, size, Ctrl->G.fill.rgb, Ctrl->W.active);
						break;
					case GMT_SYMBOL_TRIANGLE:
						size = (S.equal_area) ? 1.55512030156 * S.size_x : S.size_x;
						ps_triangle (plot_x, plot_y, size, Ctrl->G.fill.rgb, Ctrl->W.active);
						break;
					case GMT_SYMBOL_ITRIANGLE:
						size = (S.equal_area) ? 1.55512030156 * S.size_x : S.size_x;
						ps_itriangle (plot_x, plot_y, size, Ctrl->G.fill.rgb, Ctrl->W.active);
						break;
					case GMT_SYMBOL_DIAMOND:
						size = (S.equal_area) ? 1.25331413732 * S.size_x : S.size_x;
						ps_diamond (plot_x, plot_y, size, Ctrl->G.fill.rgb, Ctrl->W.active);
						break;
					case GMT_SYMBOL_TEXT:
						font_size = S.size_x * 72.0;
						if (Ctrl->W.active && Ctrl->G.active) {
							ps_setpaint (Ctrl->G.fill.rgb);
							ps_text (plot_x, plot_y, font_size, S.string, 0.0, 6, FALSE);
							ps_setpaint (Ctrl->W.pen.rgb);
							ps_text (plot_x, plot_y, font_size, S.string, 0.0, 6, TRUE);
						}
						else if (Ctrl->G.active)
							ps_text (plot_x, plot_y, font_size, S.string, 0.0, 6, FALSE);
						else
							ps_text (plot_x, plot_y, font_size, S.string, 0.0, 6, TRUE);
						break;
					case GMT_SYMBOL_ELLIPSE:
						if (S.convert_angles == 2)
							GMT_plot_ellipse (in[0], in[1], 0.0, major, minor, direction, Ctrl->G.fill, Ctrl->W.active);
						else
							ps_ellipse (plot_x, plot_y, direction, major, minor, Ctrl->G.fill.rgb, Ctrl->W.active);
						break;
					case GMT_SYMBOL_VECTOR:
						if (S.convert_angles == 2) {
							GMT_azim_to_angle (in[0], in[1], 0.1, direction, &tmp);
							direction = tmp;
						}
						else if (S.convert_angles == 1)	/* Cartesian azimuth */
							direction = 90.0 - direction;
						if (S.v_just == 3) {
							GMT_geo_to_xy (in[2], in[3], &x2, &y2);
							if (GMT_is_dnan (x2) || GMT_is_dnan (y2)) {
								fprintf (stderr, "%s: Warning: Vector head coordinates contain NaNs near line %d. Skipped\n", GMT_program, n_total_read);
								continue;
							}
						}
						else {
							sincos (direction * D2R, &s, &c);
							x2 = plot_x + length * c;
							y2 = plot_y + length * s;
							if (S.v_just) {
								dx = S.v_just * 0.5 * (x2 - plot_x);	dy = S.v_just * 0.5 * (y2 - plot_y);
								plot_x -= dx;		plot_y -= dy;
								x2 -= dx;		y2 -= dy;
							}
						}
						this_outline = (S.v_double_heads) ? Ctrl->W.active + 8 : Ctrl->W.active;
						ps_vector (plot_x, plot_y, x2, y2, S.v_width, S.h_length, S.h_width, gmtdefs.vector_shape, Ctrl->G.fill.rgb, this_outline);
						break;
					case GMT_SYMBOL_VECTOR2:
						if (S.convert_angles == 2) {
							GMT_azim_to_angle (in[0], in[1], 1.0, direction, &tmp);
							direction = tmp;
						}
						else if (S.convert_angles == 1)	/* Cartesian azimuth */
							direction = 90.0 - direction;
						if (S.v_just == 3) {
							GMT_geo_to_xy (in[2], in[3], &x2, &y2);
							if (GMT_is_dnan (x2) || GMT_is_dnan (y2)) {
								fprintf (stderr, "%s: Warning: Vector head coordinates contain NaNs near line %d. Skipped\n", GMT_program, n_total_read);
								continue;
							}
						}
						else {
							sincos (direction * D2R, &s, &c);
							x2 = plot_x + length * c;
							y2 = plot_y + length * s;
							if (S.v_just) {
								dx = S.v_just * 0.5 * (x2 - plot_x);	dy = S.v_just * 0.5 * (y2 - plot_y);
								plot_x -= dx;		plot_y -= dy;
								x2 -= dx;		y2 -= dy;
							}
						}
						this_outline = (S.v_double_heads) ? Ctrl->W.active + 8 : Ctrl->W.active;
						if (length < S.v_norm) {	/* Scale arrow attributes down with length */
							v_w = S.v_width * length * S.v_shrink;
							h_l = S.h_length * length * S.v_shrink;
							h_w = S.h_width * length * S.v_shrink;
							ps_vector (plot_x, plot_y, x2, y2, v_w, h_l, h_w, gmtdefs.vector_shape, Ctrl->G.fill.rgb, this_outline);
						}
						else	/* Leave as specified */
							ps_vector (plot_x, plot_y, x2, y2, S.v_width, S.h_length, S.h_width, gmtdefs.vector_shape, Ctrl->G.fill.rgb, this_outline);
						break;
					case GMT_SYMBOL_PIE:
						if (S.convert_angles == 2) {
							GMT_azim_to_angle (in[0], in[1], 1.0, dir1, &tmp);
							dir1 = tmp;
							GMT_azim_to_angle (in[0], in[1], 1.0, dir2, &tmp);
							dir2 = tmp;
						}
						ps_pie (plot_x, plot_y, S.size_x, dir1, dir2, Ctrl->G.fill.rgb, Ctrl->W.active);
						break;
					case GMT_SYMBOL_XDASH:
						ps_segment (plot_x - S.size_x, plot_y, plot_x + S.size_x, plot_y);
						break;
					case GMT_SYMBOL_YDASH:
						ps_segment (plot_x, plot_y - S.size_x, plot_x, plot_y + S.size_x);
						break;
					case GMT_SYMBOL_RECT:
						ps_rect (plot_x - x_len, plot_y - y_len, plot_x + x_len, plot_y + y_len, Ctrl->G.fill.rgb, Ctrl->W.active);
						break;
					case GMT_SYMBOL_CUSTOM:
						GMT_draw_custom_symbol (plot_x, plot_y, 0.0, S.size_x, S.custom, &Ctrl->W.pen, &Ctrl->G.fill, Ctrl->W.active);
						break;
				}
				if (read_symbol) n_expected = BUFSIZ;
			}
		}
		else {	/* Line/polygon part */

			n_required = 2;
			n_fields = GMT_input (fp, &n_expected, &in);
			while (! (GMT_io.status & GMT_IO_EOF)) {	/* Not yet EOF */

				while (GMT_io.status & GMT_IO_SEGMENT_HEADER) {
					if (gmtdefs.verbose) ps_comment (GMT_io.segment_header);
					if ((p = strstr (GMT_io.segment_header, " -W")) || (p = strstr (GMT_io.segment_header, "	-W"))) {
						strcpy (line, &p[3]);
						for (i = 0; line[i]; i++) if (line[i] == ' ') line[i] = '\0';
						if (!GMT_getpen (line, &Ctrl->W.pen)) {	/* Failure is OK since -W may appear in text strings */
							if (penset_OK) GMT_setpen (&Ctrl->W.pen);
							Ctrl->W.active = TRUE;
						}
					}
					else {
						if (penset_OK) GMT_setpen (&default_pen);
						Ctrl->W.active = default_outline;
						Ctrl->W.pen = default_pen;
					}
					if ((p = strstr (GMT_io.segment_header, " -G")) || (p = strstr (GMT_io.segment_header, "	-G"))) {	/* Set polygon fill */
						strcpy (line, &p[3]);
						for (i = 0; line[i]; i++) if (line[i] == ' ') line[i] = '\0';
						if (!GMT_getfill (line, &test_fill)) {	/* Failure is OK since -G may appear in text strings */
							Ctrl->G.fill = test_fill;
							polygon = TRUE;
						}
					}
					else if (Ctrl->C.active && ((p = strstr (GMT_io.segment_header, " -Z")) || (p = strstr (GMT_io.segment_header, "	-Z")))) {	/* Set polygon or pen r/g/b via cpt-lookup */
						if(!strncmp (&p[3], "NaN", 3)) {	/* Got -ZNaN */
							GMT_get_rgb24 (GMT_d_NaN, Ctrl->G.fill.rgb);
							Ctrl->G.fill.use_pattern = FALSE;
							polygon = TRUE;
						}
						else {
							if (sscanf (&p[3], "%lg", &z) == 1) {
								GMT_get_rgb24 (z, Ctrl->G.fill.rgb);
								Ctrl->G.fill.use_pattern = FALSE;
								polygon = TRUE;
							}
						}
						if (!Ctrl->L.active) {	/* Use -Zz -Ccpt to set pen color instead */
							polygon = FALSE;
							ps_setpaint (Ctrl->G.fill.rgb);
						}
					}
					else {
						polygon = default_polygon;
						Ctrl->G.fill = default_fill;
					}
					if (S.G.label_type == 2) {	/* Update segment header */
						GMT_extract_label (&GMT_io.segment_header[1], S.G.label);
					}
			
					n_fields = GMT_input (fp, &n_expected, &in);
					n_total_read++;
				}
				if ((GMT_io.status & GMT_IO_EOF)) continue;	/* At EOF */

				n = 0;
				while (! (GMT_io.status & (GMT_IO_SEGMENT_HEADER | GMT_IO_EOF))) {	/* Keep going until FALSE or = 2 segment header */
					if (GMT_io.status & GMT_IO_MISMATCH) {
						fprintf (stderr, "%s: Mismatch between actual (%d) and expected (%d) fields near line %d\n", GMT_program, n_fields, n_expected, n_total_read);
						exit (EXIT_FAILURE);
					}

					xx[n] = in[0];	yy[n] = in[1];
					n++;
					if (n == n_alloc) {
						n_alloc += GMT_CHUNK;
						xx = (double *) GMT_memory ((void *)xx, (size_t)n_alloc, sizeof (double), GMT_program);
						yy = (double *) GMT_memory ((void *)yy, (size_t)n_alloc, sizeof (double), GMT_program);
					}
					n_fields = GMT_input (fp, &n_expected, &in);
				}
				if (polygon && GMT_polygon_is_open (xx, yy, n)) {	/* Explicitly close polygon so that arc will work */
					xx[n] = xx[0];
					yy[n] = yy[0];
					n++;
					if (n == n_alloc) {
						n_alloc += GMT_CHUNK;
						xx = (double *) GMT_memory ((void *)xx, (size_t)n_alloc, sizeof (double), GMT_program);
						yy = (double *) GMT_memory ((void *)yy, (size_t)n_alloc, sizeof (double), GMT_program);
					}
				}

				xx = (double *) GMT_memory ((void *)xx, (size_t)n, sizeof (double), GMT_program);
				yy = (double *) GMT_memory ((void *)yy, (size_t)n, sizeof (double), GMT_program);
				n_alloc = n;
		
				if (GMT_cpt_skip) continue;	/* CPT says skip this polygon */
				
				if (resample) n = GMT_fix_up_path (&xx, &yy, n, greenwich, Ctrl->A.step);	/* Resample if spacing is too coarse */

				if (polygon) {	/* Want a filled polygon */
					GMT_fill_polygon (xx, yy, 0.0, n, &Ctrl->G.fill, Ctrl->W.active);
				}
				else {		/* Want a line of some sort */
					if ((plot_n = GMT_geo_to_xy_line (xx, yy, n)) == 0) continue;		/* Nothing there there */
					if (S.symbol == GMT_SYMBOL_QUOTED_LINE) {	/* Labelled lines are dealt with by the contour machinery */
						int start = 0, stop;
						S.G.line_pen = Ctrl->W.pen;
						/* Since the line might exit and enter the region we must isolate the segments before calling GMT_hold_contour */
						while (start < plot_n) {	/* More segments to register */
							while (GMT_pen[start+1] == 3 && start < (plot_n-1)) start++;	/* Skip multiple start points */
							stop = start + 1;
							while (GMT_pen[stop] == 2 && stop < plot_n) stop++;	/* Find the end of this segment */
							n = stop - start;
							xp = (double *) GMT_memory (VNULL, (size_t)n, sizeof (double), GMT_program);
							yp = (double *) GMT_memory (VNULL, (size_t)n, sizeof (double), GMT_program);
							memcpy ((void *)xp, (void *)&GMT_x_plot[start], (size_t)(n*sizeof (double)));
							memcpy ((void *)yp, (void *)&GMT_y_plot[start], (size_t)(n*sizeof (double)));
							GMT_hold_contour (&xp, &yp, n, 0.0, "N/A", 'A', S.G.label_angle, Ctrl->L.active, &S.G);
							start = stop;
							GMT_free ((void *)xp);
							GMT_free ((void *)yp);
						}
					}
					else {
						GMT_plot_line (GMT_x_plot, GMT_y_plot, GMT_pen, plot_n);
						if (S.symbol == GMT_SYMBOL_FRONT) GMT_draw_fence (GMT_x_plot, GMT_y_plot, 0.0, plot_n, &S.f, &Ctrl->G.fill, Ctrl->W.active); 	/* Must draw front crossbars */
					}
				}
			}
		}
		if (fp != GMT_stdin) GMT_fclose (fp);
	}

	if (reset_cap == 1) ps_setlinecap (gmtdefs.ps_line_cap);	/* Reset linecap to default */

	if (S.symbol == GMT_SYMBOL_QUOTED_LINE) GMT_contlabel_plot (&S.G);

	if (clip_set) GMT_map_clip_off ();

	GMT_world_map = old_GMT_world_map;

	GMT_map_basemap ();

	GMT_plotend ();

	if (S.symbol == 0) {
		GMT_free ((void *)xx);
		GMT_free ((void *)yy);
	}

	Free_Psxy_Ctrl (Ctrl);	/* Deallocate control structure */

	GMT_end (argc, argv);

	exit (EXIT_SUCCESS);
}

void plot_x_errorbar (double x, double y, double delta_x, double error_width2, int line) {
	double x_1, x_2, y_1, y_2;

	GMT_geo_to_xy (x - delta_x, y, &x_1, &y_1);
	GMT_geo_to_xy (x + delta_x, y, &x_2, &y_2);
	if (GMT_is_dnan (x_1)) {
		fprintf (stderr, "%s: Warning: X error bar exceeded domain near line %d. Set to x_min\n", GMT_program, line);
		x_1 = project_info.xmin;
	}
	if (GMT_is_dnan (x_2)) {
		fprintf (stderr, "%s: Warning: X error bar exceeded domain near line %d. Set to x_max\n", GMT_program, line);
		x_2 = project_info.xmax;
	}
	ps_segment (x_1, y_1, x_2, y_2);
	if (error_width2 > 0.0) {
		ps_segment (x_1, y_1 - error_width2, x_1, y_1 + error_width2);
		ps_segment (x_2, y_2 - error_width2, x_2, y_2 + error_width2);
	}
}

void plot_y_errorbar (double x, double y, double delta_y, double error_width2, int line) {
	double x_1, x_2, y_1, y_2;

	GMT_geo_to_xy (x, y - delta_y, &x_1, &y_1);
	GMT_geo_to_xy (x, y + delta_y, &x_2, &y_2);
	if (GMT_is_dnan (y_1)) {
		fprintf (stderr, "%s: Warning: Y error bar exceeded domain near line %d. Set to y_min\n", GMT_program, line);
		y_1 = project_info.ymin;
	}
	if (GMT_is_dnan (y_2)) {
		fprintf (stderr, "%s: Warning: Y error bar exceeded domain near line %d. Set to y_max\n", GMT_program, line);
		y_2 = project_info.ymax;
	}
	ps_segment (x_1, y_1, x_2, y_2);
	if (error_width2 > 0.0) {
		ps_segment (x_1 - error_width2, y_1, x_1 + error_width2, y_1);
		ps_segment (x_2 - error_width2, y_2, x_2 + error_width2, y_2);
	}
}

void plot_x_whiskerbar (double x, double y, double hinge[], double error_width2, int rgb[], int line) {
	int i;
	static int q[4] = {0, 25, 75, 100};
	double xx[4], yy[4];

	for (i = 0; i < 4; i++) {	/* for 0, 25, 75, 100% hinges */
		GMT_geo_to_xy (hinge[i], y, &xx[i], &yy[i]);
		if (GMT_is_dnan (xx[i])) {
			fprintf (stderr, "%s: Warning: X %d %% hinge exceeded domain near line %d\n", GMT_program, q[i], line);
			xx[i] = (i <2 ) ? project_info.xmin :  project_info.xmax;
		}
	}
	yy[1] -= error_width2;
	yy[2] += error_width2;

	ps_segment (xx[0], yy[1], xx[0], yy[2]);		/* Left whisker */
	ps_segment (xx[0], yy[0], xx[1], yy[0]);

	ps_segment (xx[3], yy[1], xx[3], yy[2]);		/* Right whisker */
	ps_segment (xx[3], yy[0], xx[2], yy[0]);

	ps_rect (xx[1], yy[1], xx[2], yy[2], rgb, TRUE);	/* Main box */

	ps_segment (x, yy[1], x, yy[2]);			/* Median line */
}

void plot_y_whiskerbar (double x, double y, double hinge[], double error_width2, int rgb[], int line) {
	int i;
	static int q[4] = {0, 25, 75, 100};
	double xx[4], yy[4];

	for (i = 0; i < 4; i++) {	/* for 0, 25, 75, 100% hinges */
		GMT_geo_to_xy (x, hinge[i], &xx[i], &yy[i]);
		if (GMT_is_dnan (yy[i])) {
			fprintf (stderr, "%s: Warning: Y %d %% hinge exceeded domain near line %d\n", GMT_program, q[i], line);
			yy[i] = (i <2 ) ? project_info.ymin :  project_info.ymax;
		}
	}
	xx[1] -= error_width2;
	xx[2] += error_width2;

	ps_segment (xx[1], yy[0], xx[2], yy[0]);		/* bottom whisker */
	ps_segment (xx[0], yy[0], xx[0], yy[1]);

	ps_segment (xx[1], yy[3], xx[2], yy[3]);		/* Top whisker */
	ps_segment (xx[0], yy[3], xx[0], yy[2]);

	ps_rect (xx[2], yy[2], xx[1], yy[1], rgb, TRUE);	/* Main box */

	ps_segment (xx[1], y, xx[2], y);			/* Median line */
}

void *New_Psxy_Ctrl () {	/* Allocate and initialize a new control structure */
	struct PSXY_CTRL *C;
	
	C = (struct PSXY_CTRL *) GMT_memory (VNULL, 1, sizeof (struct PSXY_CTRL), "New_Psxy_Ctrl");
	
	/* Initialize values whose defaults are not 0/FALSE/NULL */
		
	GMT_init_pen (&C->W.pen, GMT_PENWIDTH);
	GMT_init_pen (&C->E.pen, GMT_PENWIDTH);
	GMT_init_fill (&C->G.fill, -1, -1, -1);	/* Default is no fill */
	C->A.step = gmtdefs.line_step;
	C->E.size = 0.1;
	return ((void *)C);
}

void Free_Psxy_Ctrl (struct PSXY_CTRL *C) {	/* Deallocate control structure */
	if (C->C.file) GMT_free ((void *)C->C.file);	
	GMT_free ((void *)C);	
}
