/* 2DtoHPGL.c  -  convert 2-D list to HPGL plotter commands */

/* Oscar Garcia <garciao@mof.govt.nz>, May 1992 */

/* uses getopt */
int getopt(int argc, char *argv[], char *options);
extern  int optind;
extern char *optarg;

#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <ctype.h>
#include <string.h>

#define USAGE "usage: 2DtoHPGL [/s] [/xn] [/yn] [/wn] [/hn] [/pn]\
 [input_file [output_file]]\n\
\tIf file names are omitted, the standard i/o streams are used.\n\
\tOptions (with defaults, numbers in plotter units):\n\
\t\t/s       -  Fit full (-1,-1) to (1,1) square\n\
\t\t            (default is maximum magnification)\n\
\t\t/x5450   -  Center x coordinate\n\
\t\t/y3825   -  Center y coordinate\n\
\t\t/w10000  -  Maximum width\n\
\t\t/h7200   -  Maximum height\n\
\t\t/p123456781234567  -  Mapping colours to pens\n"

#define ERROR(msg) {fputs(msg,stderr),exit(1);}
#define PERROR(msg) {perror(msg),exit(1);}

#define RECLEN 81

void main(int argc, char* argv[])
{
	int i, c, n, currpen = 0, pen[] = {0,1,2,3,4,5,6,7,8,1,2,3,4,5,6,7};
	int cenx=5450, ceny=3825, width=5000, height=3600, square=0;
				/* HALF of width and height, actually */
	double x, y, xmin=-1, xmax=1, ymin=-1, ymax=1;	/* if square */
	char comment[RECLEN + 1], *s;
	char options[] = "x:y:w:h:sp:";
	FILE *infile = stdin, *outfile = stdout;


	/* get options */
	while ((c = getopt(argc, argv, options)) != EOF)
		if (c == '?')
			ERROR(USAGE)
		else
			switch (c)
			{	case 'x':	cenx = atoi(optarg); break;
				case 'y':	ceny = atoi(optarg); break;
				case 'w':	width = atoi(optarg) / 2; break;
				case 'h':	height = atoi(optarg) / 2; break;
				case 's':	square = 1; break;
				case 'p':
					i = 0;
					while (isdigit(n = *(optarg + i)))
						pen[++i] = n;
					break;
			}

	/* open files */
	if (optind < argc - 2)
		ERROR(USAGE);	/* too many */
	if (optind < argc)
	{	infile = fopen(argv[optind], "rt");
		if (infile == NULL)
			ERROR("Can't open input file");
		if (++optind < argc)
		{	outfile = fopen(argv[optind], "wt");
			if (outfile == NULL)
				ERROR("Can't open output file");
		}
	}

	/* get bounds, if necessary */
	if (!square)
	{	fgets(comment, RECLEN, infile);
		s = strstr(comment, "x_range");
		if (s == NULL || sscanf(s, "x_range=[%lf:%lf]", &xmin, &xmax) != 2)
			ERROR("Bad or invalid x_range");
		s = strstr(comment, "y_range");
		if (s == NULL || sscanf(s, "y_range=[%lf:%lf]", &ymin, &ymax) != 2)
			ERROR("Bad or invalid y_range");
	}

	/* adjust aspect-ratio */
	if (height * (xmax - xmin) > width * (ymax - ymin))
		height = width * (ymax - ymin) / (xmax - xmin);
	else
		width = height * (xmax - xmin) / (ymax - ymin);

	/* set defaults, and plotter P1 and P2 */
	fprintf(outfile, "DF;\nIP %d,%d,%d,%d;\n",
		cenx - width, ceny - height, cenx + width, ceny + height);

	/* set scale */
	fprintf(outfile, "SC %.4f,%.4f,%.4f,%.4f;\n",
			100 * xmin, 100 * xmax, 100 * ymin, 100 * ymax);
					/* (scale by 100 for better precision) */

	/* skip comments */
	while ((c = getc(infile)) == '#')
		fgets(comment, RECLEN, infile);
	if (ferror(infile))
		PERROR("Bad input");
	ungetc(c, outfile);

	/* do it */
	while (3 == fscanf(infile, "%lf %lf %d", &x, &y, &c))
		if (c == 0)
			/* move */
			fprintf(outfile, "PU %.4f,%.4f;\n", 100 * x, 100 * y);
		else
		{	/* draw */
			if (currpen != pen[c])
			{	/* new pen */
				currpen = pen[c];
				fprintf(outfile, "SP %d;\n", currpen);
			}
			fprintf(outfile, "PD %.4f,%.4f;\n", 100 * x, 100 * y);
		}
	fputs("PU;SP;", outfile);	/* put pen away when finished */

	if (ferror(infile))
		PERROR("Error on input");
	fclose(infile);

	if (ferror(outfile))
		PERROR("Error on output");
	fclose(outfile);
}
