/*--------------------------------------------------------------------
 *	$Id: mgd77track.c,v 1.9 2004/09/17 21:50:56 pwessel Exp $
 *
 *    Copyright (c) 2004 by P. Wessel
 *    See README file for copying and redistribution conditions.
 *--------------------------------------------------------------------*/
/*
 * mgd77track will read *.mgd77-files and and write PostScript code
 * that will create a navigation plot on a basemap using the
 * projection specified by the user. WESN must be specified on the 
 * command line along with other options for scaling, annotation etc.
*
 * To select a sub-section of the track, specify the start/endpoints by:
 *	1) Start-time (yyyy-mm-ddT[hh:mm:ss]) OR start-distance (km)
 *	2) Stop-time  (yyyy-mm-ddT[hh:mm:ss]) OR stop-distance (km)
 *
 * Author:	Paul Wessel
 * Date:	19-AUG-2004
 * Version:	1.0 Based alot on the old gmttrack.c
 *
 *
 */
 
#include "mgd77.h"

#define ANSIZE 0.125
#define MARK_NEWDAY	0
#define MARK_SAMEDAY	1
#define MARK_DIST	2

struct ANNOT {
	double annot_int_dist;
	double tick_int_dist;
	double annot_int_time;
	double tick_int_time;
} info;

struct LEG_ANNOT {	/* Structure used to annotate legs after clipping is terminated */
	double x, y;
	double lon, lat;
	double angle;
	char text[16];
};

struct TRACK {
	double dist, time;
};

struct GMT_PEN pen;

struct MARKER {
	double marker_size, font_size;
	struct GMT_FILL f, s;	/* Font and symbol colors */
	int font_no;
};

int get_annotinfo (char *args, struct ANNOT *info);
void annot_legname (double x, double y, double lon, double lat, double angle, char *text, double size);
double heading (int rec, double *lon, double *lat, int n_records);

main (int argc, char **argv)
{
	int i, j, rec, last_rec, n_out = 0, argno, n_cruises = 0, n_alloc = GMT_CHUNK;
	int n_id = 0, mrk, annot_name = 0, n_records, pen_type = 0;
	int this_julian, last_julian, n_alloc_c = GMT_SMALL_CHUNK;
	
	BOOLEAN error = FALSE, exact = FALSE, nautical = FALSE, string_output = FALSE;
	BOOLEAN first, both = FALSE, no_clip = FALSE;
	BOOLEAN  annot_tick = FALSE, draw_tick = FALSE;
	
	char *start_date = CNULL, *stop_date = CNULL, file[BUFSIZ];
       	char label[128], date[64], clock[64], comment[BUFSIZ];
	char ms[64], mc[64], mfs[64], mf[64], mfc[64], name[64];

	double west, east, south, north, start_time, stop_time, start_dist;
	double stop_dist, dist_scale, dx, dy, x, y, annot_dist, tick_dist, annot_time, tick_time;
	double dlon, ds, angle, plot_x, plot_y, *lon, *lat;

	double annotsize = ANSIZE, factor = 0.001, scale = 1.0, c_angle;
	
	struct MGD77_CONTROL M;
	struct MGD77_HEADER_RECORD H;
	struct MGD77_DATA_RECORD D;
	
	struct LEG_ANNOT *cruise_id;
	
	struct TRACK *record;
	struct GMT_gcal calendar;
	struct MARKER marker[3];	/* Time (2) and distance marker information */

	FILE *fp;
	
	argc = GMT_begin (argc, argv);		/* Initialize GMT Machinery */
	
	GMT_init_pen (&pen, GMT_PENWIDTH);
	GMT_init_fill (&marker[MARK_NEWDAY].s, 0, 0, 0);	/* Black color for new Julian day marker */
	GMT_init_fill (&marker[MARK_SAMEDAY].s, 255, 255, 255);	/* White color for other time markers in same day */
	GMT_init_fill (&marker[MARK_DIST].s, 0, 0, 0);		/* Black color for distance markers */
	GMT_init_fill (&marker[MARK_NEWDAY].f, 0, 0, 0);	/* Black color for all text */
	GMT_init_fill (&marker[MARK_SAMEDAY].f, 0, 0, 0);	/* Black color for all text */
	GMT_init_fill (&marker[MARK_DIST].f, 0, 0, 0);		/* Black color for all text */
	if (gmtdefs.measure_unit == GMT_CM) {
		marker[MARK_NEWDAY].marker_size = marker[MARK_SAMEDAY].marker_size = 0.1 / 2.54;	/* 1 mm */
		marker[MARK_DIST].marker_size = 0.15 / 2.54;	/* 1.5 mm */
	}
	else {	/* Assume we think in inches */
		marker[MARK_NEWDAY].marker_size = marker[MARK_SAMEDAY].marker_size = 0.04;
		marker[MARK_DIST].marker_size = 0.06;
	}
	marker[MARK_NEWDAY].font_size = marker[MARK_SAMEDAY].font_size = marker[MARK_DIST].font_size = gmtdefs.annot_font_size[0] * GMT_u2u[GMT_PT][GMT_INCH];
	marker[MARK_NEWDAY].font_no = GMT_font_lookup ("Times-BoldItalic", GMT_font, N_FONTS);
	marker[MARK_SAMEDAY].font_no = GMT_font_lookup ("Times-Italic", GMT_font, N_FONTS);
	marker[MARK_DIST].font_no = GMT_font_lookup ("Times-Roman", GMT_font, N_FONTS);

	/* Initialize MGD77 output order and other parameters*/
	
	MGD77_Init (&M, TRUE);			/* Initialize MGD77 Machinery */
	west = 0.0;	east = 360.0;	south = -90.0;	north = 90.0;
	start_time = start_dist = 0.0;
	stop_time = stop_dist = DBL_MAX;

	for (i = 1; !error && i < argc; i++) {	/* Process input options */
		if (argv[i][0] == '-') {
			switch(argv[i][1]) {
			
				case 'B':
				case 'P':
				case 'O':
				case 'K':
				case 'R':
				case 'J':
				case 'U':
				case 'V':
				case 'X':
				case 'x':
				case 'Y':
				case 'y':
				case 'c':
				case '\0':
					error += GMT_get_common_args (argv[i], &west, &east, &south, &north);
					break;
										
				case 'A':
					annot_name = 1;
					j = 2;
					if (argv[i][2] == 'c') j = 3, annot_name = 2;
					if (argv[i][j]) annotsize = atof (&argv[i][j]) * GMT_u2u[GMT_PT][GMT_INCH];
					break;

				case 'D':		/* Assign start/stop times for sub-section */
					if (argv[i][2] == 'a') {		/* Start date */
						start_date = &argv[i][3];
					}
					else if (argv[i][2] == 'b')	 {	/* Stop date */
						stop_date = &argv[i][3];
					}
					else
						error = TRUE;
					break;

				case 'M':
					error += get_annotinfo (&argv[i][2], &info);
					break;
					
				case 'N':
					no_clip = TRUE;
					break;
					
				case 'S':		/* Assign start/stop position for sub-section (in meters) */
					if (argv[i][2] == 'a') {		/* Start position */
						MGD77_set_unit (&argv[i][3], &scale);
						start_dist = atof (&argv[i][3]) * scale;
					}
					else if (argv[i][2] == 'b') {		/* Stop position */
						MGD77_set_unit (&argv[i][3], &scale);
						stop_dist = atof (&argv[i][3]) * scale;
					}
					else
						error = TRUE;
					break;
					
				case 'T':	/* Marker attributes */
					switch (argv[i][2]) {
						case 'T':	/* New day marker */
							mrk = MARK_NEWDAY;
							break;
						case 't':	/* Same day marker */
							mrk = MARK_SAMEDAY;
							break;
						case 'd':	/* Distance marker */
							mrk = MARK_DIST;
							break;
						default:
							error = TRUE;
							break;
					}
					if (error) {
						fprintf(stderr, "%s: ERROR: Unrecognized modifier %c given to -T\n", GMT_program, argv[i][2]);
						exit (EXIT_FAILURE);
					}
					strcpy (comment, &argv[i][3]);
					for (j = 0; j < (int)strlen (comment); j++) if (comment[j] == ',') comment[j] = ' ';	/* Replace commas with spaces */
					j = sscanf (comment, "%s %s %s %s %s", ms, mc, mfs, mf, mfc);
					if (j != 5) {
						fprintf(stderr, "%s: ERROR: -TT|t|d takes 5 arguments\n", GMT_program);
						exit (EXIT_FAILURE);
					}
					marker[mrk].marker_size = GMT_convert_units (ms, GMT_INCH);
					GMT_getfill (mc, &marker[mrk].s);
					marker[mrk].font_size = atof (mfs) * GMT_u2u[GMT_PT][GMT_INCH];
					marker[mrk].font_no = (mf[0] >= '0' && mf[0] <= '9') ? atoi (mf) : GMT_font_lookup (mf, GMT_font, N_FONTS);;
					GMT_getfill (mfc, &marker[mrk].f);
					break;
							
				case 'W':
					GMT_getpen (&argv[i][2], &pen);
					break;
					
				default:		/* Options not recognized */
					error = TRUE;
					break;
			}
		}
		else
			n_cruises++;
	}
	
	/* Check that the options selected are mutually consistent */
	
	if (start_date && start_dist > 0.0) {
		fprintf(stderr, "%s: ERROR: Cannot specify both start time AND start distance\n", GMT_program);
		exit (EXIT_FAILURE);
	}
	if (stop_date && stop_dist < DBL_MAX) {
		fprintf(stderr, "%s: ERROR: Cannot specify both stop time AND stop distance\n", GMT_program);
		exit (EXIT_FAILURE);
	}
	if (east < west || south > north) {
		fprintf(stderr, "%s: ERROR: Region set incorrectly\n", GMT_program);
		exit (EXIT_FAILURE);
	}
	if (start_date) GMT_atoft (start_date, &start_time);
	if (stop_date)  GMT_atoft (stop_date,  &stop_time);
	if (start_time > stop_time) {
		fprintf(stderr, "%s: ERROR: Start time exceeds stop time!\n", GMT_program);
		exit (EXIT_FAILURE);
	}
	if (start_dist > stop_dist) {
		fprintf(stderr, "%s: ERROR: Start distance exceeds stop distance!\n", GMT_program);
		exit (EXIT_FAILURE);
	}
	
	if (GMT_quick || argc == 1) {	/* Display usage */
		fprintf(stderr,"usage: mgd77track cruise(s) -R<west>/<east>/<south>/<north> -J<params> [-A[c][size]] [-B<tickinfo>]\n");
		fprintf(stderr,"	[-Da<startdate>] [-Db<stopdate>] [-K] [-M<trackticks>] [-N] [-O] [-P] [-Sa<startdist>[unit]]\n");
		fprintf(stderr,"	[-Sb<stopdist>[unit]] [-TT|t|d<ms,mc,mfs,mf,mfc>] [-U[dx/dy/][label]] [-V] [-W<pen>] [-X<x_shift>]\n");
		fprintf(stderr,"	[-Y<y_shift>] [-c<ncopies>]\n\n");
      
		if (GMT_quick) exit (EXIT_FAILURE);
              
		fprintf(stderr,"	<cruises> is one or more MGD77 legnames, e.g., 01010083 etc.\n");
		GMT_explain_option ('J');
		GMT_explain_option ('R');
		fprintf(stderr,"	OPTIONS:\n\n");
		fprintf(stderr, "	-A will Annotate legs when they enter the grid. Append c for cruise ID [Default is file prefix]\n");
		fprintf(stderr, "	   <size> is optional text size in points [9].  The font used is controlled by LABEL_FONT\n");
		GMT_explain_option ('B');
		fprintf(stderr,"	-Da plots from <startdate> (given as yyyy-mm-ddT[hh:mm:ss]) [Start of cruise]\n");
		fprintf(stderr,"	-Db plots up to <stopdate> (given as yyyy-mm-ddT[hh:mm:ss]) [End of cruise]\n");
		GMT_explain_option ('K');
		fprintf (stderr, "	-M puts time/distance Marks on the track. E.g. a500ka24ht6h means (a)nnotate\n");
		fprintf (stderr, "	   every 500 km (k) and 24 h(ours), with (t)ickmarks every 500 km and 6 (h)ours\n");
		fprintf (stderr, "	   Units of n(autical miles) and d(ays) are also recognized.\n");
		fprintf (stderr, "	-N Do Not clip leg name annotation that fall outside map border [Default will clip]\n");
		GMT_explain_option ('O');
		GMT_explain_option ('P');
		fprintf(stderr,"	-Sa plots from <startdist> (in m; append k, m, or n) [Start of the cruise]\n");
		fprintf(stderr,"	-Sb plots up to <stopdist> (in m; append k, m, or n) [End of the cruise]\n");
		fprintf(stderr,"	-T sets attributes of marker items. Append T for new day marker, t for same\n");
		fprintf(stderr,"	   day marker, and d for distance marker.  Then, append 5 comma-separated items:\n");
		fprintf(stderr,"	   <markersize>[unit],<markercolor>,<markerfontsize,<markerfont>,<markerfontcolor>\n");
		fprintf(stderr,"	   Default settings for the three marker types are:\n");
		fprintf(stderr,"	     -TT%lg,black,%lg,%d,black\n", marker[MARK_NEWDAY].marker_size, marker[MARK_NEWDAY].font_size, marker[MARK_NEWDAY].font_no);
		fprintf(stderr,"	     -Tt%lg,white,%lg,%d,black\n", marker[MARK_SAMEDAY].marker_size, marker[MARK_SAMEDAY].font_size, marker[MARK_SAMEDAY].font_no);
		fprintf(stderr,"	     -Td%lg,black,%lg,%d,black\n", marker[MARK_DIST].marker_size, marker[MARK_DIST].font_size, marker[MARK_DIST].font_no);
		GMT_explain_option ('U');
		GMT_explain_option ('V');
		fprintf (stderr, "	-W sets track pen attributes [width = %lgp, color = (%d/%d/%d), texture = solid line].\n", 
			pen.width, pen.rgb[0], pen.rgb[1], pen.rgb[2]);
		GMT_explain_option ('X');
		GMT_explain_option ('c');
		GMT_explain_option ('.');
		exit(EXIT_FAILURE);
	}

	if (n_cruises == 0) {
		fprintf(stderr, "%s: ERROR: No cruises given\n", GMT_program);
		exit (EXIT_FAILURE);
	}

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

	dist_scale = 1000.0 * DEG2KM;	/* Work internally in meters */

	if (east < west) west -= 360.0;
		
	GMT_map_setup (west, east, south, north);
	
	ps_plotinit (NULL, gmtdefs.overlay, gmtdefs.page_orientation, gmtdefs.x_origin, gmtdefs.y_origin,
		gmtdefs.global_x_scale, gmtdefs.global_y_scale, gmtdefs.n_copies,
		gmtdefs.dpi, GMT_INCH, gmtdefs.paper_width, gmtdefs.page_rgb,
		     gmtdefs.encoding.name, GMT_epsinfo (argv[0]));
		
	GMT_echo_command (argc, argv);
	if (gmtdefs.unix_time) GMT_timestamp (argc, argv);
	
	record = (struct TRACK *) GMT_memory (VNULL, (size_t)n_alloc, sizeof (struct TRACK), "mgd77track");
	lon = (double *) GMT_memory (VNULL, (size_t)n_alloc, sizeof (double), "mgd77track");
	lat = (double *) GMT_memory (VNULL, (size_t)n_alloc, sizeof (double), "mgd77track");
	
	GMT_map_clip_on (GMT_no_rgb, 3);
	GMT_setpen (&pen);
	both = (info.annot_int_time && info.annot_int_dist);
	
	if (no_clip) {
		cruise_id = (struct LEG_ANNOT *) GMT_memory (VNULL, (size_t)n_alloc_c, sizeof (struct LEG_ANNOT), "mgd77track");
	}

	for (argno = 1; argno < argc; argno++) {	/* Loop over all the files */
	
		if (argv[argno][0] == '-') continue;
  		if (MGD77_Get_Path (file, argv[argno], &M)) {
   			fprintf (stderr, "%s : Cannot find leg %s\n", argv[argno], GMT_program);
     			continue;
  		}
		if ((fp = GMT_fopen (file, "r")) == NULL) {
			fprintf (stderr, "%s: Could not open %s\n", file, GMT_program);
			continue;
		}

		if (gmtdefs.verbose) fprintf (stderr, "%s: Now processing cruise %s\n", GMT_program, argv[argno]);
		
		if (!MGD77_Read_Header_Record (fp, &H)) {
			fprintf (stderr, "%s: Error reading header sequence for cruise %s\n", GMT_program, argv[argno]);
			exit (EXIT_FAILURE);
		}
		if (GMT_io.multi_segments) {	/* Write multisegment header between each cruise */
			sprintf (GMT_io.segment_header, "%c %s\n", GMT_io.EOF_flag, argv[argno]);
			GMT_write_segmentheader (GMT_stdout, M.n_out_columns);
		}
		rec = 0;
		last_julian = -1;
		
		if (annot_name == 2) {	/* Use MGD77 cruise ID */
			strcpy (name, H.Cruise_Identifier);
		}
		else {			/* Use file name prefix */
			strcpy (name, argv[argno]);
			for (i = 0; i < (int)strlen (name); i++) if (name[i] == '.') name[i] = '\0';
		}
	
		/* Start reading data from file */
	
		while (MGD77_Read_Data_Record (fp, &D)) {		/* While able to read a data record */
		
			/* Check if time falls outside specified range */
		
			if (D.time < start_time || D.time > stop_time) continue;
		
			/* Compute accumulated distance along track (Flat Earth) */
		
			lon[rec] = D.number[MGD77_LONGITUDE];
			lat[rec] = D.number[MGD77_LATITUDE];
			record[rec].time = D.time;
			if (rec > 0) {	/* Need a previous point to calculate distance */
				dlon = lon[rec] - lon[last_rec];
				if (fabs (dlon) > 180.0) dlon = copysign ((360.0 - fabs (dlon)), dlon);
				dx = dlon * cosd (0.5 * (lat[rec] + lat[last_rec]));
				dy = lat[rec] - lat[last_rec];
				ds = dist_scale * hypot (dx, dy);
				record[rec].dist = record[last_rec].dist + ds;
			}
			
			/* Check if this_dist falls outside specified range */
		
			if (record[rec].dist < start_dist || record[rec].dist > stop_dist) continue;
		
			last_rec = rec;
			rec++;
			if (rec == n_alloc) {
				n_alloc += GMT_CHUNK;
				record = (struct TRACK *) GMT_memory ((void *)record, (size_t)n_alloc, sizeof (struct TRACK), "mgd77track");
				lon = (double *) GMT_memory ((void *)lon, (size_t)n_alloc, sizeof (double), "mgd77track");
				lat = (double *) GMT_memory ((void *)lat, (size_t)n_alloc, sizeof (double), "mgd77track");
			}
		}
		GMT_fclose (fp);
		n_records = rec;
		
		if (gmtdefs.verbose) fprintf (stderr, "mgd77track: Plotting %s [%s]\n", argv[argno], H.Cruise_Identifier);
		sprintf (comment, "Tracking %s\0", argv[argno]);
		ps_comment (comment);
		
		/* First draw the track line, clip segments outside the area */
		
		GMT_n_plot = GMT_geo_to_xy_line (lon, lat, n_records);
		GMT_plot_line (GMT_x_plot, GMT_y_plot, GMT_pen, GMT_n_plot);

		first = TRUE;
		for (rec = 0; rec < n_records; rec++) {
			if (GMT_outside (lon[rec], lat[rec])) {
				first = TRUE;
				continue;
			}
			GMT_geo_to_xy (lon[rec], lat[rec], &x, &y);
			if (first) {
				if (annot_name) {
					c_angle = heading (rec, lon, lat, n_records);
					if (no_clip) {	/* Keep these in a list to plot after clipping is turned off */
						cruise_id[n_id].x = x;
						cruise_id[n_id].y = y;
						cruise_id[n_id].lon = lon[rec];
						cruise_id[n_id].lat = lat[rec];
						cruise_id[n_id].angle = c_angle;

						strcpy (cruise_id[n_id].text, name);
						n_id++;
						if (n_id == n_alloc_c) {
							n_alloc_c += GMT_SMALL_CHUNK;
							cruise_id = (struct LEG_ANNOT *) GMT_memory ((void *)cruise_id, (size_t)n_alloc_c, sizeof (struct LEG_ANNOT), "mgd77track");
						}
					}
					else
						annot_legname (x, y, lon[rec], lat[rec], c_angle, name, GMT_u2u[GMT_INCH][GMT_PT] * 1.25 * annotsize);
				}
				first = FALSE;
				if (info.annot_int_dist > 0) annot_dist = (record[rec].dist / info.annot_int_dist + 1) * info.annot_int_dist;
				if (info.tick_int_dist > 0) tick_dist = (record[rec].dist / info.tick_int_dist + 1) * info.tick_int_dist;
				if (info.annot_int_time > 0) annot_time = ceil (record[rec].time / info.annot_int_time) * info.annot_int_time;
				if (info.tick_int_time > 0) tick_time = ceil (record[rec].time / info.tick_int_time) * info.tick_int_time;
			}
			
			/* See if we need to annotate/tick the trackline for time/km marks */
			
			if (info.annot_int_time && (record[rec].time >= annot_time)) {
				annot_time += info.annot_int_time;
				annot_tick = 1;
			}
			if (info.annot_int_dist && (record[rec].dist >= annot_dist)) {
				annot_dist += info.annot_int_dist;
				annot_tick += 2;
			}
			if (info.tick_int_time && (record[rec].time >= tick_time)) {
				tick_time += info.tick_int_time;
				draw_tick = 1;
			}
			if (info.tick_int_dist && (record[rec].dist >= tick_dist)) {
				tick_dist += info.tick_int_dist;
				draw_tick += 2;
			}
			if (annot_tick) {
				angle = heading (rec, lon, lat, n_records);
				if (angle < 0.0)
					angle += 90.0;
				else
					angle -= 90.0;
				if (annot_tick & 1) {	/* Time mark */
					GMT_gcal_from_dt (annot_time, &calendar);			/* Convert t to a complete calendar structure */
					GMT_format_calendar (date, clock, &GMT_plot_calclock.date, &GMT_plot_calclock.clock, FALSE, 1, annot_time);
					this_julian = calendar.day_y;
					if (this_julian != last_julian) {
						mrk = MARK_NEWDAY;
						sprintf (label, "%s+%s", date, clock);
						ps_circle (x, y, marker[mrk].marker_size, marker[mrk].s.rgb, TRUE);
					}
					else {
						mrk = MARK_SAMEDAY;
						sprintf (label, "+%s", clock);
						ps_circle (x, y, marker[mrk].marker_size, marker[mrk].s.rgb, TRUE);
					}
					ps_setfont (marker[mrk].font_no);
					ps_setpaint (marker[mrk].f.rgb);
					plot_x = x;	plot_y = y;
					GMT_smart_justify (5, angle, 0.5 * marker[mrk].font_size, 0.5 * marker[mrk].font_size, &plot_x, &plot_y);
					ps_text (plot_x, plot_y, GMT_u2u[GMT_INCH][GMT_PT] * marker[mrk].font_size, label, angle, 5, 0);
					last_julian = calendar.day_y;
				}
				if (annot_tick & 2) {	/* Distance mark */
					mrk = MARK_DIST;
					sprintf (label, "%d km  \0", (int)((annot_dist - info.annot_int_dist) * factor));
					ps_square (x, y, marker[mrk].marker_size, marker[mrk].s.rgb, TRUE);
					ps_setpaint (marker[mrk].f.rgb);
					plot_x = x;	plot_y = y;
					GMT_smart_justify (7, angle, 0.5 * marker[mrk].font_size, 0.5 * marker[mrk].font_size, &plot_x, &plot_y);
					ps_text (plot_x, plot_y, GMT_u2u[GMT_INCH][GMT_PT] * marker[mrk].font_size, label, angle, 7, 0);
				}
			}
			if (both && !(annot_tick & 1) && (draw_tick & 1)) {
				mrk = (this_julian != last_julian) ? MARK_NEWDAY : MARK_SAMEDAY;
				ps_circle (x, y, marker[mrk].marker_size, marker[mrk].s.rgb, TRUE);
			}
			if (both && !(annot_tick & 2) && (draw_tick & 2)) {
				mrk = (this_julian != last_julian) ? MARK_NEWDAY : MARK_SAMEDAY;
				ps_square (x, y, marker[mrk].marker_size, marker[mrk].s.rgb, TRUE);
			}
			if (draw_tick) {
				mrk = MARK_DIST;
				ps_setpaint (marker[mrk].s.rgb);
				ps_cross (x, y, marker[mrk].marker_size);
			}
			if (annot_tick || draw_tick) annot_tick = draw_tick = FALSE;
		}
		
	}
		
	GMT_map_clip_off();

	GMT_map_basemap ();
	
	if (annot_name && no_clip) {	/* Plot leg names after clipping is terminated ( see -N) */
		int id;
		double size;
		size = GMT_u2u[GMT_INCH][GMT_PT] * 1.25 * annotsize;
		for (id = 0; id < n_id; id++) annot_legname (cruise_id[id].x, cruise_id[id].y, cruise_id[id].lon, cruise_id[id].lat, cruise_id[id].angle, cruise_id[id].text, size);
		GMT_free ((void *)cruise_id);
	}

	ps_plotend (gmtdefs.last_page);
	GMT_free ((void *)record);
	GMT_free ((void *)lon);
	GMT_free ((void *)lat);

	exit (EXIT_SUCCESS);
}

double heading (int rec, double *lon, double *lat, int n_records)
{
	int i1, i2, j;
	double angle, x1, x0, y1, y0;
	double sum_x2 = 0.0, sum_xy = 0.0, sum_y2 = 0.0, dx, dy;
	
	i1 = rec - 10;
	if (i1 < 0) i1 = 0;
	i2 = i1 + 10;
	if (i2 > (n_records-1)) i2 = n_records - 1;
	GMT_geo_to_xy (lon[rec], lat[rec], &x0, &y0);
	for (j = i1; j <= i2; j++) {	/* L2 fit for slope over this range of points */
		GMT_geo_to_xy (lon[j], lat[j], &x1, &y1);
		dx = x1 - x0;
		dy = y1 - y0;
		sum_x2 += dx * dx;
		sum_y2 += dy * dy;
		sum_xy += dx * dy;
	}
	if (sum_y2 < GMT_CONV_LIMIT)	/* Line is horizontal */
		angle = 0.0;
	else if (sum_x2 < GMT_CONV_LIMIT)	/* Line is vertical */
		angle = 90.0;
	else
		angle = (fabs(sum_xy) < GMT_CONV_LIMIT) ? 90.0 : d_atan2 (sum_xy, sum_x2) * R2D;
	if (angle > 90.0)
		angle -= 180;
	else if (angle < -90.0)
		angle += 180.0;
	return (angle);
}

int get_annotinfo (char *args, struct ANNOT *info)
{
	int i1, i2, error = FALSE;
	int flag1, flag2, type;
	double value;
	
	info->annot_int_dist = info->tick_int_dist = 0;
	info->annot_int_time = info->tick_int_time = 0;

	i1 = 0;
	while (args[i1]) {
		flag1 = 'a';
		if (isalpha (args[i1])) {
			flag1 = args[i1];
			if (isupper(flag1)) flag1 = tolower (flag1);
			i1++;
		}
		i2 = i1;
		while (args[i2] && strchr ("athkmnd", (int)args[i2]) == NULL) i2++;
		value = atof (&args[i1]);
		flag2 = args[i2];
		if (isupper(flag2)) flag2 = tolower (flag2);
		if (flag2 == 'd') {		/* Days */
			value *= GMT_DAY2SEC_F;
			type = 't';
		}
		else if (flag2 == 'h') {		/* Hours */
			value *= GMT_HR2SEC_F;
			type = 't';
		}
		else if (flag2 == 'k') {	/* kilometers */
			value *= 1000;
			type = 'd';
		}
		else if (flag2 == 'n') {	/* Nautical miles */
			value *= MGD77_METERS_PER_NM;
			type = 'd';
		}
		else if (flag2 == 'm') {	/* Minutes */
			value *= GMT_MIN2SEC_F;
			type = 't';
		}
		else				/* Default is seconds */
			type = 't';
		i2++;
		if (flag1 == 'a') {	/* Annotation interval */
			if (type == 'd')	/* Distance */
				info->annot_int_dist = (int)value;
			else
				info->annot_int_time = (int)value;
		}
		else {			/* Tickmark interval */
			if (type == 'd')	/* Distance */
				info->tick_int_dist = (int)value;
			else
				info->tick_int_time = (int)value;
		}
		i1 = i2;
	}
	if (info->annot_int_dist <= 0 && info->tick_int_dist <= 0 && info->annot_int_time <= 0 && info->tick_int_time <= 0)
		error = TRUE;
	if (info->annot_int_dist <= 0)
		info->annot_int_dist = info->tick_int_dist;
	else if (info->tick_int_dist <= 0)
		info->tick_int_dist = info->annot_int_dist;
	if (info->annot_int_time <= 0)
		info->annot_int_time = info->tick_int_time;
	else if (info->tick_int_time <= 0)
		info->tick_int_time = info->annot_int_time;
	return (error);
}

void annot_legname (double x, double y, double lon, double lat, double angle, char *text, double size)
{
	int just;
	
	if (lat < project_info.s)
		just = (angle >= 0.0) ? 1 : 3;
	else if (lat > project_info.n)
		just = (angle >= 0.0) ? 11 : 9;
	else if (lon < project_info.w)
		just = (angle >= 0.0) ? 9 : 1;
	else
		just = (angle >= 0.0) ? 3 : 11;
	ps_setfont (gmtdefs.label_font);
	ps_setpaint (gmtdefs.basemap_frame_rgb);
	GMT_smart_justify (just, angle, GMT_u2u[GMT_PT][GMT_INCH] * 0.15 * size, GMT_u2u[GMT_PT][GMT_INCH] * 0.15 * size, &x, &y);
	ps_text (x, y, size, text, angle, just, 0);
}
