summaryrefslogtreecommitdiff
path: root/graphics/fig2mfpic
diff options
context:
space:
mode:
Diffstat (limited to 'graphics/fig2mfpic')
-rw-r--r--graphics/fig2mfpic/Makefile13
-rw-r--r--graphics/fig2mfpic/README76
-rw-r--r--graphics/fig2mfpic/TODO8
-rw-r--r--graphics/fig2mfpic/fig2mfpic.c2411
-rw-r--r--graphics/fig2mfpic/graphbase.mf1228
-rw-r--r--graphics/fig2mfpic/mfpic.tex422
-rw-r--r--graphics/fig2mfpic/tidied.fig31
-rw-r--r--graphics/fig2mfpic/various.fig40
8 files changed, 4229 insertions, 0 deletions
diff --git a/graphics/fig2mfpic/Makefile b/graphics/fig2mfpic/Makefile
new file mode 100644
index 0000000000..c3eb4f10ce
--- /dev/null
+++ b/graphics/fig2mfpic/Makefile
@@ -0,0 +1,13 @@
+# Makefile for fig2mfpic. 22:34 GMT +10 Fri 10 June 1994.
+
+DBN = Makefile README TODO fig2mfpic.c graphbase.mf mfpic.tex \
+ tidied.fig various.fig
+
+fig2mfpic: fig2mfpic.c
+ cc -g fig2mfpic.c -o fig2mfpic -lm
+
+lint: fig2mfpic.c
+ lint fig2mfpic.c > f2m.lint
+
+zip: $(DBN)
+ zip fig2mfpic $(DBN)
diff --git a/graphics/fig2mfpic/README b/graphics/fig2mfpic/README
new file mode 100644
index 0000000000..9b1c30ff5d
--- /dev/null
+++ b/graphics/fig2mfpic/README
@@ -0,0 +1,76 @@
+README for fig2mfpic 0.24 alpha version, Thu 16 June 1994.
+----------------------------------------------------------
+Author: Geoffrey Tobin.
+Email: G.Tobin@ee.latrobe.edu.au
+Address: Department of Electronic Engineering,
+ La Trobe University,
+ Bundoora VIC 3083,
+ Australia.
+
+Purpose:
+
+fig2mfpic is a program for converting Fig 2.1 graphics language into
+an approximate equivalent in MFpic. MFpic is a set of TeX and METAFONT
+macros for drawings.
+
+Current version:
+
+fig2mfpic 0.24 alpha is designed for mfpic.tex version 0.2.5 (as at CTAN)
+and graphbase 0.2 fig 2a. The graphbase (0.1.13.1) of mfpic 0.2.5 does
+NOT work with fig2mfpic.
+
+
+Manifest: eight (8) files:
+
+ 296 Jun 10 22:34 Makefile A make file for the "cc" C compiler.
+ 2896 Jun 16 13:35 README This introductory file.
+ 386 Jun 15 20:03 TODO What I'd like fig2mfpic to do, in future.
+52714 Jun 16 13:30 fig2mfpic.c ANSI/traditional C source for fig2mfpic.
+23444 Jun 16 13:33 graphbase.mf Modified graphbase.mf, version 0.2 fig 2a.
+11511 Oct 12 1993 mfpic.tex mfpic.tex 0.2.5, from mfpic distribution.
+ 2233 Jun 2 22:42 tidied.fig Sample Fig file, every major Fig object type.
+ 2689 Jun 1 22:08 various.fig Like tidied.fig, plus unknown object types.
+
+Usage:
+
+After making fig2mfpic, if you type just the command `fig2mfpic', as:
+
+ fig2mfpic
+
+then fig2mfpic will issue a usage summary to stderr, as follows:
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+usage: fig2mfpic [infile] [... infile] [> outfile]
+ [-?] Help request
+ [-d] List input file, with line numbers
+ [-code=<integer>] First character's code : not effective
+ [-pen=<real>] Default pen width (pt)
+ [-u=<none>] Output unit name
+ [-xscale=<real>] X unit (in output units)
+ [-yscale=<real>] Y unit (in output units)
+ [-xneg=<real>] Most negative X value (X units)
+ [-xpos=<real>] Most positive X value (X units)
+ [-yneg=<real>] Most negative Y value (Y units)
+ [-ypos=<real>] Most positive Y value (Y units)
+ [-top=<real>] Top of drawing (Y units)
+ [-mf=<string>] Output METAFONT file
+ [-tex=<string>] mfpic TeX drawing macros file
+ [-log=<string>] fig2mfpic log file
+If an "infile" is "-", then standard input is read.
+The mfpic TeX drawing file goes to standard output.
+Messages, such as this, go to standard error.
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+Typical use of fig2mfpic is exemplified by:
+
+ fig2mfpic various.fig > various.tex
+
+Error messages are recorded in the log file, which is called
+`fig2mfpic.log' unless you give it another name by the -log= option.
+If there are no error messages, then the log file has a size of zero
+bytes (at least on unix).
+
+Impressions and advice are of course welcome.
+
+Best wishes!
+Geoffrey Tobin
diff --git a/graphics/fig2mfpic/TODO b/graphics/fig2mfpic/TODO
new file mode 100644
index 0000000000..04a9549e90
--- /dev/null
+++ b/graphics/fig2mfpic/TODO
@@ -0,0 +1,8 @@
+TODO for fig2mfpic.c of Wed 15 June 1994, by Geoffrey Tobin (gt@ee.latrobe.edu.au).
+----------------------------------------------------------------------------------
+
+1. Catch empty lists of points in paths, such as curves and cyclic curves.
+2. Arc boxes.
+3. B-splines.
+4. Scale text to Fig's specified font size. (How?)
+5. Cause TeX code to use PostScript fonts, when Fig does.
diff --git a/graphics/fig2mfpic/fig2mfpic.c b/graphics/fig2mfpic/fig2mfpic.c
new file mode 100644
index 0000000000..7104c14b0c
--- /dev/null
+++ b/graphics/fig2mfpic/fig2mfpic.c
@@ -0,0 +1,2411 @@
+/* 13:30 GMT +10 Thu 16 June 1994 - gt@ee.latrobe.edu.au */
+/* fig2mfpic 0.024 in ANSI C and traditional C */
+/*
+ Geoffrey Tobin's attempt at a "fig2mfpic" for mfpic 0.2.5,
+ based on Anthony Starks's Fig2MF 0.04 of Wed 28 Oct 1992,
+ Anthony's letter of Fri 11 Sep 1992, and
+ Uwe Bonnes's investigations for Uwe's transfig driver for mfpic 0.2.5.
+
+ Note: Fig 2.1 is the native (I/O) language of X11 `xfig' GUI drawing program.
+ (An older version of Fig was used in Sunview's `fig'.)
+ Some other programs, e.g. the unix version of gnuplot,
+ can output Fig 2.1 code.
+*/
+
+/* fig2mfpic -- convert Fig 2.1 to mfpic 0.2.5 TeX macros
+ *
+ * Anthony J. Starks and Geoffrey R.D. Tobin
+ * ajs@msdrl.com ecsgrt@luxor.latrobe.edu.au
+ * ajs@merck.com gt@ee.latrobe.edu.au
+ *
+ * Uwe Bonnes
+ * bon@lte.e-technik.u-erlangen.de
+ *
+ * Scaling in inches,
+ * default [x-y]scale is 1/80 inch, which is one Fig unit.
+ * MFpic uses pt, not in, so fig2mfpic must convert.
+ * Pen switching is local.
+ * Supports 3-point arcs.
+ * Token support for text.
+ * Supports interpolated splines.
+ * Output units: in, pt, bp, mm, cm, sp, Fig units.
+ * Many input files.
+ * Output to stdout.
+ * Splines have floating point numbers as coordinates (Fig 2.1 spec).
+ * ANSI C or traditional C.
+ * Count objects, starting from 1.
+ * Log file kept of all error messages.
+ * In polyline, expect EPS line before points line.
+ * For ANSI C, display source file, date and time of compilation.
+ * Fig Object Type information supplied in TeX comments.
+ */
+
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+/* Fig 2.1 signature */
+#define FIG_SIG "#FIG 2.1"
+
+/* A technique for handling both Standard and traditional C compilers, */
+/* borrowed from the Free Software Foundation */
+#ifdef __STDC__
+#define __(X) X
+#define Void void
+#define VOID void
+#else
+#define __(X) ()
+#define Void int
+#define VOID
+#endif
+
+char * type_name __((int code));
+char * diagnostic __((void));
+Void put_msg __((char * msg));
+Void Lwrite __((char * msg));
+Void Lflush __((void));
+double xs __((double x));
+double ys __((double y));
+double xt __((double x));
+double yt __((double y));
+int parse __((char * s));
+Void give_help __((void));
+int process __((char * filename));
+int ellipse __((FILE * figfp));
+int polyline __((FILE * figfp));
+int spline __((FILE * figfp));
+int read_pts __((FILE * figfp));
+int controls __((int npts, FILE * figfp));
+int text __((FILE * figfp));
+int arc __((FILE * figfp));
+int compound __((FILE * figfp));
+char * subtype_name __((int obj, int subobj));
+Void define_polydash __((void));
+Void finit __((void));
+Void cinit __((void));
+Void cfin __((void));
+Void ffin __((void));
+int get_line __((FILE * figfp));
+int next_src_line __((FILE * figfp));
+Void display_line __((void));
+int get_int __((char ** bufpa, int * ya));
+int get_double __((FILE * figfp, char ** bufpa, double * ya));
+int buffer_empty __((char * bp));
+
+#ifndef TRUE
+# define TRUE 1
+# define FALSE 0
+#endif
+
+#define SUCCESS 0
+#define FAILURE 1
+
+#define MIN(a,b) ((a) < (b) ? (a) : (b))
+#define MAX(a,b) ((a) > (b) ? (a) : (b))
+
+#define OUTPUT printf
+
+/* write a log file? */
+int do_log = FALSE;
+
+/* log file pointer */
+FILE * logfp = (FILE *) NULL;
+
+/* error message */
+
+#define MESSAGE_SLEN 255
+typedef char MsgType[MESSAGE_SLEN+1];
+MsgType Message;
+
+/* filling gradation - is "1.2" a `magic' number? */
+#define dofill() 1.2-((double)area_fill/(double)FILL_BLACK)
+
+/* pen size */
+#define do_pen(x) ((x-1)*PEN_INCR)+DEF_PEN
+
+#define VERSION "0.024"
+#define MFPIC_VERSION "0.2.5"
+#define GRAPHBASE_VERSION "0.2 fig 2a"
+
+#define O_ELLIPSE 1
+#define O_POLYLINE 2
+#define O_SPLINE 3
+#define O_TEXT 4
+#define O_ARC 5
+#define O_COMPOUND 6
+#define O_END_COMPOUND (-6)
+
+/* Area fill */
+#define UNFILLED 0
+#define FILL_BLACK 21
+
+#define N_ELLIPSE 19
+#define N_POLYLINE 12
+#define N_SPLINE 11
+#define N_TEXT 14
+#define N_ARC 20
+#define N_COMPOUND 4
+
+/* default pen size in pt */
+#define DEF_PEN 0.5
+#define PEN_INCR 0.1
+
+/* DEFAULT mfpic drawing macros TeX file */
+#define DEF_DFILE "mfpic.tex"
+
+/* DEFAULT output MetaFont file : interpreted by mfpic as "figleaf.mf" */
+#define DEF_MF_OFILE "figleaf"
+
+/* DEFAULT output log file */
+#define DEF_LOG_FILE "fig2mfpic.log"
+
+#define BUF_SIZE 1024
+char buf[BUF_SIZE];
+
+/* Number of TeX points (pt) in an inch (in) */
+#define PT_PER_INCH 72.27
+
+/* Number of actual drawing units per pt */
+#define PIXEL (PT_PER_INCH / ppi)
+
+/* Number of default (Fig) drawing units per inch */
+#define DEF_PPI 80.0
+
+/* Default maxy value (in Y drawing units) */
+#define DEF_MAXY 640.0
+
+/* Pi, from Abramowitz and Stegun */
+#define PI 3.141592653589793238462643
+/* radian in degrees, from Abramowitz and Stegun */
+#define RADIAN 57.295779513082320876798155
+/* degree in radians, from Abramowitz and Stegun */
+#define DEGREE 0.017453292519943295769237
+
+/* First output character's code */
+#define FIRST_CHAR 33
+
+/* "fig2mfpic" program options */
+
+#define None 0
+#define Real 1
+#define Integer 2
+#define String 3
+#define Help 4
+#define Unit 5
+#define Boolean 6
+
+typedef struct
+{
+ char *keyword; /* option's keyword */
+ int type; /* data type of option's value */
+ Void *value; /* generic pointer to option's value */
+ char *description; /* description of keyword & value for option */
+} Options;
+
+/* maximum allowed number of output characters */
+#define MAXNCHAR 256
+
+/* number of characters output so far */
+int nchar = 0;
+
+/* current line number, in current input file */
+int linenum = 0;
+
+/* number of objects counted so far */
+int nobjs = -1;
+
+/* object type */
+int obj_type = -1;
+
+/* object subtype */
+int obj_subtype = -1;
+
+/* whether object types have been listed during this run */
+int listed_types = FALSE;
+
+/* pixels [input units] per inch */
+/* 1 Fig unit = 1 inch / ppi */
+double ppi = DEF_PPI;
+
+/* coordinate system = orientation of Y axis */
+#define Y_UP 1
+#define Y_DOWN 2
+int coord_sys = Y_DOWN; /* usual with Fig */
+
+/* I prefer input and output units to coincide */
+double oupi = DEF_PPI; /* output units per inch */
+double ioc = 1.0; /* input to output unit conversion factor */
+
+/* calculated bounding box of a picture */
+double bxl, bxu, byl, byu;
+int bbbegun = 0; /* no lower bound yet for BB for current picture */
+
+/* options */
+int help; /* help flag */
+int debug; /* debug flag */
+int char_code = 33; /* initial char code */
+double mfpen; /* global pen width (pt) */
+char * o_unit="Fig"; /* output unit (default is 1 Fig unit) */
+double xscale = 1.0; /* 1 X drawing unit = xscale * output unit */
+double yscale = 1.0;
+double xl; /* character bounds, in X and Y drawing units */
+double yl;
+double xu;
+double yu;
+double maxy; /* maximum Y value (Y drawing units) */
+char * mf_ofile=""; /* output MF file name */
+char *draw_macros=""; /* mfpic drawing macros TeX file name */
+char *log_file=""; /* log file name */
+
+char *progname=""; /* command line name of this program */
+char *curfigfile=""; /* current input file */
+
+Options opts[] =
+{
+ {"-?", Help, &help, "Help request"},
+ {"-d", Boolean, &debug, "List input file, with line numbers"},
+ {"-code", Integer, &char_code, "First character's code : not effective"},
+ {"-pen", Real, &mfpen, "Default pen width (pt)"},
+ {"-u", Unit, &o_unit, "Output unit name"},
+ {"-xscale", Real, &xscale, "X unit (in output units)"},
+ {"-yscale", Real, &yscale, "Y unit (in output units)"},
+ {"-xneg", Real, &xl, "Most negative X value (X units)"},
+ {"-xpos", Real, &xu, "Most positive X value (X units)"},
+ {"-yneg", Real, &yl, "Most negative Y value (Y units)"},
+ {"-ypos", Real, &yu, "Most positive Y value (Y units)"},
+ {"-top", Real, &maxy, "Top of drawing (Y units)"},
+ {"-mf", String, &mf_ofile, "Output METAFONT file"},
+ {"-tex", String, &draw_macros, "mfpic TeX drawing macros file"},
+ {"-log", String, &log_file, "fig2mfpic log file"},
+ {NULL, None, NULL, ""}
+}; /* opts[] */
+
+
+/* FUNCTIONS */
+
+
+/* return name of object type from given code */
+char *
+type_name
+#ifdef __STDC__
+ (int code)
+#else
+ (code)
+ int code;
+#endif
+{
+ char * name = "unknown";
+
+ switch (code)
+ {
+ case O_ELLIPSE:
+ name = "ellipse";
+ break;
+ case O_POLYLINE:
+ name = "polyline";
+ break;
+ case O_SPLINE:
+ name = "spline";
+ break;
+ case O_TEXT:
+ name = "text";
+ break;
+ case O_ARC:
+ name = "arc";
+ break;
+ case O_COMPOUND:
+ name = "compound";
+ break;
+ case O_END_COMPOUND:
+ name = "end compound";
+ break;
+ default:
+ name = "unknown";
+ break;
+ }
+ return (name);
+} /* type_name */
+
+
+char *
+diagnostic (VOID)
+{
+ extern char *curfigfile;
+ extern int nobjs;
+ extern int obj_type;
+ extern int linenum;
+ extern MsgType Message;
+ char * Diagnostic = Message;
+
+ sprintf (Diagnostic,
+ " : file \"%s\", object # %d, type %s (%d %d), at line %d\n",
+ curfigfile, nobjs+1,
+ subtype_name (obj_type, obj_subtype), obj_type, obj_subtype,
+ linenum);
+ return (Diagnostic);
+} /* diagnostic */
+
+/* write a diagnostic message to stderr and to logfp */
+Void
+put_msg
+#ifdef __STDC__
+ (char * msg)
+#else
+ (msg)
+ char * msg;
+#endif
+{
+ if (!debug) /* avoid double display */
+ {
+ display_line();
+ }
+ Lwrite ("! ");
+ Lwrite (msg);
+ Lwrite (diagnostic());
+ Lflush ();
+} /* put_msg */
+
+/* write to stderr and to logfp */
+Void
+Lwrite (char * msg)
+{
+ extern int do_log;
+ fprintf (stderr, "%s", msg);
+ if (do_log)
+ {
+ fprintf (logfp, "%s", msg);
+ }
+} /* Lwrite */
+
+/* flush both stderr and logfp */
+Void
+Lflush (void)
+{
+ fflush (stderr);
+ if (do_log)
+ {
+ fflush (logfp);
+ }
+} /* Lflush */
+
+double
+xs
+#ifdef __STDC__
+ (double xr)
+#else
+ (xr)
+ double xr;
+#endif
+{
+ return (ioc * xr);
+} /* xs */
+
+double
+ys
+#ifdef __STDC__
+ (double yr)
+#else
+ (yr)
+ double yr;
+#endif
+{
+ return (ioc * yr);
+} /* ys */
+
+double
+xt
+#ifdef __STDC__
+ (double x)
+#else
+ (x)
+ double x;
+#endif
+{
+ return (ioc * x);
+} /* xt */
+
+double
+yt
+#ifdef __STDC__
+ (double y)
+#else
+ (y)
+ double y;
+#endif
+{
+ return (ioc * (maxy-y));
+} /* yt */
+
+
+int
+main
+#ifdef __STDC__
+ (int argc, char * argv[])
+#else
+ (argc, argv)
+ int argc;
+ char * argv[];
+#endif
+{
+ progname = argv[0]; /* this program */
+ curfigfile = "Standard Input"; /* current input file */
+ linenum=0; /* no line read yet */
+
+ /* initial values of options */
+ help=0; /* no help */
+ char_code=FIRST_CHAR; /* first character has char code FIRST_CHAR */
+ mfpen=DEF_PEN; /* pen diameter (pt) */
+ o_unit = "Fig";
+ xscale=1.0; /* drawing units (in output units) */
+ yscale=1.0;
+ xl=0.0; /* xl, xu, yl, yu : size of picture in drawing units */
+ xu=DEF_MAXY;
+ yl=0.0;
+ yu=DEF_MAXY;
+ maxy=DEF_MAXY;
+ mf_ofile=DEF_MF_OFILE; /* use default MF drawing macros */
+ draw_macros=DEF_DFILE; /* use default TeX drawing macros */
+ log_file=DEF_LOG_FILE; /* write to default log file */
+
+ if ((logfp = fopen (log_file, "w")) == (FILE *) NULL)
+ {
+ do_log = FALSE;
+ }
+ else
+ {
+ do_log = TRUE;
+ }
+
+ if (argc < 2) /* no cmdline arguments, so give help */
+ give_help();
+ else /* treat each argument as an option or an input filename */
+ {
+ int i;
+ for (i=1; i < argc; i++)
+ parse (argv[i]);
+ }
+
+ ffin(); /* close mfpic output, if there was any */
+
+ return (SUCCESS);
+}
+/* main */
+
+
+int
+parse
+#ifdef __STDC__
+ (char * s)
+#else
+ (s)
+ char * s;
+#endif
+{
+ int optnum;
+ char *strchr();
+ double atof();
+ int atoi();
+
+ for (optnum=0; opts[optnum].keyword != NULL; optnum++)
+ {
+ if (strncmp (s, opts[optnum].keyword, strlen (opts[optnum].keyword)) == 0)
+ {
+ switch (opts[optnum].type)
+ {
+ case None:
+ break;
+ case Real:
+ * (double *) opts[optnum].value = atof (strchr (s, '=')+1);
+ break;
+ case Integer:
+ * (int *) opts[optnum].value = atoi (strchr (s, '=')+1);
+ break;
+ case String:
+ * (char * *) opts[optnum].value = strchr (s, '=')+1;
+ break;
+ case Help:
+ give_help();
+ break;
+ case Unit:
+ {
+ char * unit = strchr (s, '=')+1;
+ * (char * *) opts[optnum].value = unit;
+ check_unit (unit);
+ }
+ break;
+ case Boolean: /* FALSE by default */
+ * (int *) opts[optnum].value = TRUE;
+ break;
+ }
+ return (optnum);
+ }
+ }
+ /* this command line argument is not a known option */
+ /* so assume it's a filename */
+ process (s);
+ return (optnum);
+}
+/* parse */
+
+Void
+give_help (VOID)
+{
+ char * typename = "unknown type";
+ int i;
+ MsgType Advice;
+
+ sprintf (Advice, "usage: %s ", progname);
+ Lwrite (Advice);
+ Lwrite ("[infile] [... infile] [> outfile]");
+ Lwrite ("\n");
+ Lflush ();
+
+ for (i=0; opts[i].keyword != NULL; i++)
+ {
+ switch (opts[i].type)
+ {
+ case Real: typename = "real"; break;
+ case Integer: typename = "integer"; break;
+ case String: typename = "string"; break;
+ default: typename = "none"; break;
+ }
+ Lwrite (" ");
+ switch (opts[i].type)
+ {
+ case None:
+ case Help:
+ case Boolean:
+ sprintf (Advice, "[%s]", opts[i].keyword);
+ Lwrite (Advice);
+ break;
+ default:
+ sprintf (Advice, "[%s=<%s>]", opts[i].keyword, typename);
+ Lwrite (Advice);
+ break;
+ }
+ Lwrite (" ");
+ sprintf (Advice, "%s", opts[i].description);
+ Lwrite (Advice);
+ Lwrite ("\n");
+ Lflush ();
+ }
+ Lwrite ("If an \"infile\" is \"-\", then standard input is read.\n");
+ Lwrite ("The mfpic TeX drawing file goes to standard output.\n");
+ Lwrite ("Messages, such as this, go to standard error.\n");
+ Lflush ();
+}
+/* give_help */
+
+typedef struct
+{
+ char * name; /* name of unit */
+ double value; /* value of 1 inch / 1 unit, i.e. the number of units per inch */
+} Units;
+
+Units units[] =
+{
+ {"in", 1.0},
+ {"pt", 72.27},
+ {"bp", 72.0},
+ {"mm", 25.4},
+ {"cm", 2.54},
+ {"sp", 72.27 * 65536},
+ {"Fig", 80.0},
+ {NULL, 0.0},
+}; /* units[] */
+
+int
+check_unit
+#ifdef __STDC__
+ (char * unit)
+#else
+ (unit)
+ char * unit;
+#endif
+{
+ extern MsgType Message;
+ int unum;
+ for (unum=0; units[unum].name != NULL; unum++)
+ {
+ if (strncmp (unit, units[unum].name, strlen (units[unum].name)) == 0)
+ {
+ oupi = units[unum].value;
+ return (unum);
+ }
+ }
+ sprintf (Message, "\"%s\" is an unknown unit!\n", unit);
+ Lwrite (Message);
+ Lflush ();
+ return (unum);
+}
+/* check_unit */
+
+int
+process
+#ifdef __STDC__
+ (char * filename)
+#else
+ (filename)
+ char * filename;
+#endif
+{
+ extern MsgType Message;
+ extern int listed_types;
+ FILE * figfp;
+
+ if (filename[0] == '-')
+ {
+ curfigfile = "Standard Input";
+ figfp = stdin;
+ }
+ else
+ {
+ curfigfile=filename;
+ if ((figfp = fopen (filename, "r")) == NULL)
+ {
+ sprintf (Message,
+ "%s: cannot open the input file \"%s\"\n",
+ progname, filename);
+ Lwrite (Message);
+ Lflush ();
+ return (FAILURE);
+ }
+ }
+
+ linenum = 0;
+ /* The very first line in a Fig file must be a particular comment */
+ get_line (figfp);
+ /* Fig and version identification comment, and its length */
+ if (strncmp (buf, FIG_SIG, strlen (FIG_SIG)) != 0)
+ {
+ put_msg ("Not a Fig 2.1 signature");
+ sprintf (Message, "Expected first line to be \"%s\"\n", FIG_SIG);
+ Lwrite (Message);
+ Lflush ();
+ return (FAILURE);
+ }
+ next_src_line (figfp);
+ if (sscanf (buf, "%lf%d\n", &ppi, &coord_sys) != 2)
+ {
+ put_msg ("ppi or coord_sys missing or not in \"real integer\" format");
+ return (FAILURE);
+ }
+ /* For Fig 2.1, ppi = DEF_PPI = 80.0 pixels per inch, */
+ /* and the coord_sys = Y_DOWN = 2, meaning origin at top left */
+
+ ioc = oupi / ppi; /* current number of output units per input unit */
+
+ {
+ /* First input Fig file */
+ static int once = 0;
+ if (once == 0)
+ {
+ finit(); /* start of the (sole) TeX output file */
+ once = 1;
+ }
+ }
+
+ cinit(); /* One MF character per Fig picture */
+
+ for (nobjs = 0; next_src_line (figfp) > 0; ++ nobjs)
+ {
+ /* object type */
+ if (sscanf (buf, "%d", &obj_type) != 1)
+ {
+ put_msg ("Incorrect object type code (need integer)");
+ return (FAILURE);
+ }
+
+ if (obj_type == O_COMPOUND || obj_type == O_END_COMPOUND)
+ {
+ OUTPUT ("%% %d : %s (%d)\n",
+ nobjs+1,
+ type_name (obj_type), obj_type);
+ }
+ else
+ {
+ /* object subtype */
+ if (sscanf (buf, "%*d %d", &obj_subtype) != 1)
+ {
+ put_msg ("Incorrect object subtype code (need integer)");
+ return (FAILURE);
+ }
+
+ OUTPUT ("%% %d : %s (%d %d)\n",
+ nobjs+1,
+ subtype_name (obj_type, obj_subtype), obj_type, obj_subtype);
+ }
+
+ switch (obj_type)
+ {
+ case O_ELLIPSE:
+ ellipse (figfp);
+ break;
+ case O_POLYLINE:
+ polyline (figfp);
+ break;
+ case O_SPLINE:
+ spline (figfp);
+ break;
+ case O_TEXT:
+ text (figfp);
+ break;
+ case O_ARC:
+ arc (figfp);
+ break;
+ case O_COMPOUND:
+ compound (figfp);
+ break;
+ case O_END_COMPOUND:
+ end_compound (figfp);
+ break;
+ default:
+ sprintf (Message, "Object omitted");
+ put_msg (Message);
+ if (!listed_types)
+ {
+ Lwrite ("Known object types are:\n");
+ sprintf (Message, " ellipse (%d)\n", O_ELLIPSE);
+ Lwrite (Message);
+ sprintf (Message, " polyline (%d)\n", O_POLYLINE);
+ Lwrite (Message);
+ sprintf (Message, " spline (%d)\n", O_SPLINE);
+ Lwrite (Message);
+ sprintf (Message, " text (%d)\n", O_TEXT);
+ Lwrite (Message);
+ sprintf (Message, " arc (%d)\n", O_ARC);
+ Lwrite (Message);
+ sprintf (Message, " compound (%d)\n", O_COMPOUND);
+ Lwrite (Message);
+ sprintf (Message, " end_compound (%d)\n", O_END_COMPOUND);
+ Lwrite (Message);
+ Lflush ();
+ listed_types = TRUE;
+ }
+ break;
+ }
+ }
+
+ cfin();
+
+ if (figfp != stdin)
+ fclose (figfp);
+
+ return (SUCCESS);
+}
+/* process */
+
+
+/* Line styles */
+
+#define SOLID_LINE 0
+#define DASH_LINE 1
+#define DOTTED_LINE 2
+
+/* Dimension of a dot in dotted line style (pt) */
+#define DOT_SIZE 1.0
+
+
+/* Ellipse objects */
+/* Ellipse or circle, described by radius (radii) or diameter(s) */
+/* Subtypes: */
+#define T_ELLIPSE_BY_RAD 1
+#define T_ELLIPSE_BY_DIA 2
+#define T_CIRCLE_BY_RAD 3
+#define T_CIRCLE_BY_DIA 4
+
+int
+ellipse
+#ifdef __STDC__
+ (FILE * figfp)
+#else
+ (figfp)
+ FILE * figfp;
+#endif
+{
+ int n;
+ int type,
+ subtype,
+ line_style,
+ line_thickness, /* pixels */
+ color,
+ depth,
+ pen, /* unused in Fig */
+ area_fill; /* 0: not filled, 1 : white, ..., 21: black */
+ double style_val; /* pixels; for dash lines, length of on/off dashes */
+ /* for dot lines, gap b/w dots */
+ int dir;
+ double angle;
+ int cx, /* cx, cy : centre */
+ cy,
+ rx, /* rx, ry : radii */
+ ry,
+ sx, /* sx, sy, ex, ey : ellipse's bounding box */
+ sy,
+ ex,
+ ey;
+
+ n = sscanf (buf, "%d%d%d%d%d%d%d%d%lf%d%lf%d%d%d%d%d%d%d%d",
+ &type,
+ &subtype,
+ &line_style,
+ &line_thickness,
+ &color,
+ &depth,
+ &pen,
+ &area_fill,
+ &style_val,
+ &dir,
+ &angle,
+ &cx,
+ &cy,
+ &rx,
+ &ry,
+ &sx,
+ &sy,
+ &ex,
+ &ey);
+ if (n != N_ELLIPSE)
+ {
+ put_msg ("Malformed circle or ellipse");
+ return n;
+ }
+
+ {
+ int fx, fy;
+ if (subtype == T_CIRCLE_BY_RAD || subtype == T_ELLIPSE_BY_RAD)
+ {
+ fx = 2 * cx - ex;
+ fy = 2 * cy - ey;
+ }
+ else
+ {
+ fx = sx;
+ fy = sy;
+ }
+ if (bbbegun)
+ {
+ bxl = MIN (bxl, ex); bxl = MIN (bxl, fx);
+ bxu = MAX (bxu, ex); bxu = MAX (bxu, fx);
+ byl = MIN (byl, ey); byl = MIN (byl, fy);
+ byu = MAX (byu, ey); byu = MAX (byu, fy);
+ }
+ else
+ {
+ bxl = MIN (ex, fx);
+ bxu = MAX (ex, fx);
+ byl = MIN (ey, fy);
+ byu = MAX (ey, fy);
+ bbbegun = 1;
+ }
+ }
+
+ if (line_thickness > 1)
+ OUTPUT (" \\pen{%.2lfpt}\n", do_pen (line_thickness));
+
+ if (subtype == T_CIRCLE_BY_RAD || subtype == T_CIRCLE_BY_DIA)
+ {
+ if (area_fill == FILL_BLACK)
+ OUTPUT (" \\cdisk");
+ else if (area_fill < FILL_BLACK && area_fill > UNFILLED)
+ {
+ OUTPUT (" \\shadespace=%lfpt\n", dofill());
+ OUTPUT (" \\circshade");
+ }
+ else
+ OUTPUT (" \\circle");
+
+ OUTPUT ("{(%lf,%lf),%lf}\n", xt(cx), yt(cy), xs(rx));
+ }
+ else if (subtype == T_ELLIPSE_BY_RAD || subtype == T_ELLIPSE_BY_DIA)
+ {
+ if (area_fill == FILL_BLACK)
+ OUTPUT (" \rotatededisk");
+ else if (area_fill < FILL_BLACK && area_fill > UNFILLED)
+ {
+ OUTPUT (" \\shadespace=%lfpt\n", dofill());
+ OUTPUT (" \\rotatedellshade");
+ }
+ else
+ OUTPUT (" \\rotatedellipse");
+
+ OUTPUT ("{(%lf,%lf),%lf,%lf,%lf}\n",
+ xt(cx), yt(cy), xs(rx), ys(ry), angle * RADIAN);
+ }
+
+ if (line_thickness > 1)
+ OUTPUT (" \\pen{%.2lfpt}\n", mfpen);
+
+ return n;
+}
+/* ellipse */
+
+
+/* Polyline objects */
+/* Subtypes: */
+/* Many of these remain unimplemented in fig2mfpic */
+#define T_POLYLINE 1
+#define T_BOX 2
+#define T_POLYGON 3
+#define T_ARC_BOX 4
+#define T_EPS_BOX 5
+
+#define EPS_UPRIGHT 0
+#define EPS_FLIPPED 1
+
+/* Maximum length of name of EPSF file */
+#define EPSF_SLEN 100
+
+int
+polyline
+#ifdef __STDC__
+ (FILE * figfp)
+#else
+ (figfp)
+ FILE * figfp;
+#endif
+{
+ int npts_read;
+ int n;
+ int type,
+ subtype,
+ line_style,
+ line_thickness,
+ color,
+ depth,
+ pen,
+ area_fill;
+
+ double style_val;
+
+ int radius, /* for rounded corners of boxes */
+ fa, /* Forward arrow : not yet interpreted in fig2mfpic */
+ ba, /* Backward arrow : not yet interpreted in fig2mfpic */
+ at,
+ as,
+ eflag;
+
+ double athick,
+ awidth,
+ aht;
+
+ char epsfile[EPSF_SLEN+1];
+
+ npts_read = 0;
+ n = sscanf (buf, "%d%d%d%d%d%d%d%d%lf%d%d%d",
+ &type,
+ &subtype,
+ &line_style,
+ &line_thickness,
+ &color,
+ &depth,
+ &pen,
+ &area_fill,
+ &style_val,
+ &radius,
+ &fa,
+ &ba);
+
+ if (n != N_POLYLINE)
+ {
+ put_msg ("Malformed polyline");
+ return npts_read;
+ }
+
+ if (fa)
+ {
+ next_src_line (figfp);
+ sscanf (buf, "%d%d%lf%lf%lf\n", &at, &as, &athick, &awidth, &aht);
+ }
+ if (ba)
+ {
+ next_src_line (figfp);
+ sscanf (buf, "%d%d%lf%lf%lf\n", &at, &as, &athick, &awidth, &aht);
+ }
+
+ if (line_thickness > 1)
+ OUTPUT (" \\pen{%.2lfpt}%%\n", do_pen (line_thickness));
+
+ /* filling or shading */
+
+ if (area_fill == FILL_BLACK) /* fill with black */
+ {
+ OUTPUT (" \\polyfill");
+ }
+ else if (area_fill < FILL_BLACK && area_fill > UNFILLED) /* shade */
+ {
+ OUTPUT (" \\shadespace=%lfpt%%\n", dofill());
+ OUTPUT (" \\polyshade");
+ }
+ else /* no fill or shade */
+ {
+ if (line_style == SOLID_LINE)
+ OUTPUT (" \\polyline");
+ else if (line_style == DASH_LINE)
+ {
+ OUTPUT (" \\dashlen=%lfpt%%\n", style_val);
+ OUTPUT (" \\dashspace=%lfpt%%\n", style_val);
+ OUTPUT (" \\polydash");
+ }
+ else /* DOTTED_LINE */
+ {
+ OUTPUT (" \\dashlen=%lfpt%%\n", DOT_SIZE);
+ OUTPUT (" \\dashspace=%lfpt%%\n", style_val);
+ OUTPUT (" \\polydash");
+ }
+ }
+
+ /* eps line is before points line, according to transfig source */
+
+ if (subtype == T_EPS_BOX)
+ {
+ next_src_line (figfp);
+ sscanf (buf, "%d%s", &eflag, epsfile);
+ }
+
+ OUTPUT ("{%%\n");
+ npts_read = read_pts (figfp);
+ OUTPUT ("}\n");
+
+ if (line_thickness > 1)
+ OUTPUT (" \\pen{%.2lfpt}%%\n", mfpen);
+
+ return npts_read;
+}
+/* polyline */
+
+
+/* Spline objects */
+/* Subtypes: */
+/* Normal splines (`B-splines') are here incorrectly implemented */
+#define T_OPEN_NORMAL 0
+#define T_CLOSED_NORMAL 1
+#define T_OPEN_INTERPOLATED 2
+#define T_CLOSED_INTERPOLATED 3
+
+int
+spline
+#ifdef __STDC__
+ (FILE * figfp)
+#else
+ (figfp)
+ FILE * figfp;
+#endif
+{
+ int n;
+ int npts_read;
+ int type,
+ line_style,
+ subtype,
+ line_thickness,
+ color,
+ depth,
+ pen,
+ area_fill,
+ fa,
+ ba,
+ at,
+ as;
+
+ double style_val,
+ athick,
+ awidth,
+ aht;
+
+ npts_read = 0;
+ n = sscanf (buf, "%d%d%d%d%d%d%d%d%lf%d%d",
+ &type,
+ &subtype,
+ &line_style,
+ &line_thickness,
+ &color,
+ &depth,
+ &pen,
+ &area_fill,
+ &style_val,
+ &fa,
+ &ba);
+ if (n != N_SPLINE)
+ {
+ put_msg ("Malformed spline");
+ return npts_read;
+ }
+
+ if (fa)
+ {
+ next_src_line (figfp);
+ sscanf (buf, "%d%d%lf%lf%lf\n", &at, &as, &athick, &awidth, &aht);
+ }
+ if (ba)
+ {
+ next_src_line (figfp);
+ sscanf (buf, "%d%d%lf%lf%lf\n", &at, &as, &athick, &awidth, &aht);
+ }
+
+ if (line_thickness > 1)
+ OUTPUT (" \\pen{%.2lfpt}%%\n", do_pen (line_thickness));
+
+ if (subtype == T_OPEN_NORMAL || subtype == T_CLOSED_NORMAL)
+ /* B-spline - very roughly */
+ {
+ if (subtype == T_OPEN_NORMAL) /* open B-spline */
+ {
+ OUTPUT (" \\curve");
+ }
+ else if (subtype == T_CLOSED_NORMAL) /* closed B-spline */
+ {
+ if (area_fill == FILL_BLACK) /* fill with black */
+ {
+ OUTPUT (" \\cyclefill");
+ }
+ else if (area_fill < FILL_BLACK && area_fill > UNFILLED) /* shade */
+ {
+ OUTPUT (" \\shadespace=%lfpt%%\n", dofill());
+ OUTPUT (" \\cycleshade");
+ }
+ else /* neither fill nor shade */
+ {
+ OUTPUT (" \\cyclic");
+ }
+ }
+
+ /* control points - wrongly treated for B-spline */
+ OUTPUT ("{%%\n");
+ npts_read = read_pts (figfp);
+ OUTPUT ("}\n");
+ }
+ else if (subtype == T_OPEN_INTERPOLATED || subtype == T_CLOSED_INTERPOLATED)
+ {
+ OUTPUT (" \\mfcmd {%%\n");
+
+ if (subtype == T_OPEN_INTERPOLATED) /* open I-spline */
+ {
+ OUTPUT (" ispline (false)");
+ }
+ else if (subtype == T_CLOSED_INTERPOLATED) /* closed I-spline */
+ {
+ if (area_fill == FILL_BLACK) /* fill with black */
+ {
+ OUTPUT (" isplineshade (0)");
+ }
+ else if (area_fill < FILL_BLACK && area_fill > UNFILLED) /* shade */
+ {
+ OUTPUT (" isplineshade (%lfpt)", dofill());
+ }
+ else /* neither fill nor shade */
+ {
+ OUTPUT (" ispline (true)");
+ }
+ }
+
+ /* interpolation ("key") points */
+ OUTPUT (" ( \n");
+ npts_read = read_pts (figfp);
+ OUTPUT (" ) \n");
+
+ /* control points */
+ OUTPUT (" ( \n");
+ npts_read = controls (npts_read, figfp);
+ OUTPUT (" ) \n");
+
+ OUTPUT (" }\n"); /* end "\mfcmd" */
+ }
+
+ if (line_thickness > 1)
+ OUTPUT (" \\pen{%.2lfpt}\n", mfpen);
+
+ return npts_read;
+}
+/* spline */
+
+
+/* Sentinel signalling end of coordinate pair list */
+#define END_COORD 9999
+
+int
+read_pts
+#ifdef __STDC__
+ (FILE * figfp)
+#else
+ (figfp)
+ FILE * figfp;
+#endif
+{
+ extern MsgType Message;
+ char * bufp = buf; /* pointer to current buffer position */
+ int more = 1; /* any more coordinates? */
+ int npts_read = 0; /* number of coordinate pairs */
+
+ /* Read key points line from Fig file into buffer */
+ next_src_line (figfp);
+
+ while (more)
+ {
+ int x, y;
+ int n;
+
+ /* read X and Y coordinates of a point */
+ if (!get_int (&bufp, &x))
+ {
+ put_msg ("Missing X coordinate (expect an integer),");
+ sprintf (Message, " point %d anticipated,\n", npts_read+1);
+ Lwrite (Message);
+ sprintf (Message, " coord. after byte %ld in line.\n", bufp - buf);
+ Lwrite (Message);
+ Lflush ();
+ more = 0;
+ }
+ else if (!get_int (&bufp, &y))
+ {
+ put_msg ("Missing Y coordinate (expect an integer),");
+ sprintf (Message, " amidst point %d,\n", npts_read+1);
+ Lwrite (Message);
+ sprintf (Message, " coord. after byte %ld in line.\n", bufp - buf);
+ Lwrite (Message);
+ Lflush ();
+ more = 0;
+ }
+ else if (x == END_COORD)
+ {
+ if (y != END_COORD)
+ {
+ sprintf (Message, "final Y coordinate is not %d", END_COORD);
+ put_msg (Message);
+ }
+ more = 0;
+ }
+ else
+ {
+ if (bbbegun)
+ {
+ bxl = MIN (bxl, x);
+ bxu = MAX (bxu, x);
+ byl = MIN (byl, y);
+ byu = MAX (byu, y);
+ }
+ else
+ {
+ bxl = bxu = x;
+ byl = byu = y;
+ bbbegun = 1;
+ }
+
+ /* write key point coordinates to TeX file */
+
+ if (npts_read > 0)
+ OUTPUT (",\n");
+ OUTPUT (" (%lf, %lf)", xt(x), yt(y));
+ ++ npts_read;
+ more = 1;
+ }
+ }
+
+ if (npts_read < 1)
+ {
+ put_msg ("No key points");
+ }
+
+ return npts_read;
+}
+/* read_pts */
+
+int
+buffer_empty
+#ifdef __STDC__
+ (char * bp)
+#else
+int
+ (bp)
+ char * bp;
+#endif
+{
+ int empty = FALSE;
+ if (bp == NULL)
+ empty = TRUE;
+ else
+ {
+ while (*bp != '\0' && isspace (*bp))
+ ++ bp;
+ empty = (*bp == '\0');
+ }
+ return empty;
+}
+/* buffer_empty */
+
+int
+controls
+#ifdef __STDC__
+ (int npts, FILE * figfp)
+#else
+ (npts, figfp)
+ int npts;
+ FILE * figfp;
+#endif
+/* npts = number of ordinary points */
+{
+ extern MsgType Message;
+ int ncontrols = 0; /* number of control points, should be 2*npts. */
+ int more = TRUE; /* any more coordinates? */
+ int i;
+ char * bufp = buf; /* pointer to current buffer position */
+
+ /* Read control points line from Fig file into buffer */
+ next_src_line (figfp);
+
+ for (i=0; more && i < npts; i++)
+ {
+ double lx, ly, rx, ry; /* control points are floating point */
+ int n;
+
+ /* read X and Y coordinates of left and right control points */
+ if (!get_double (figfp, &bufp, &lx))
+ {
+ put_msg ("Missing Left control X coordinate (expect a number),");
+ sprintf (Message, " for point %d, ", i+1);
+ Lwrite (Message);
+ sprintf (Message, "coord. after byte %ld in line.\n", bufp - buf);
+ Lwrite (Message);
+ Lflush ();
+ more = FALSE;
+ }
+ else if (!get_double (figfp, &bufp, &ly))
+ {
+ put_msg ("Missing Left control Y coordinate (expect a number),");
+ sprintf (Message, " for point %d, ", i+1);
+ Lwrite (Message);
+ sprintf (Message, "coord. after byte %ld in line.\n", bufp - buf);
+ Lwrite (Message);
+ Lflush ();
+ more = FALSE;
+ }
+ else if (!get_double (figfp, &bufp, &rx))
+ {
+ put_msg ("Missing Right control X coordinate (expect a number),");
+ sprintf (Message, " for point %d, ", i+1);
+ Lwrite (Message);
+ sprintf (Message, "coord. after byte %ld in line.\n", bufp - buf);
+ Lwrite (Message);
+ Lflush ();
+ more = FALSE;
+ }
+ else if (!get_double (figfp, &bufp, &ry))
+ {
+ put_msg ("Missing Right control Y coordinate (expect a number),");
+ sprintf (Message, " for point %d, ", i+1);
+ Lwrite (Message);
+ sprintf (Message, "coord. after byte %ld in line.\n", bufp - buf);
+ Lwrite (Message);
+ Lflush ();
+ more = FALSE;
+ }
+ else
+ {
+ if (bbbegun)
+ {
+ bxl = MIN (bxl, lx); bxl = MIN (bxl, rx);
+ bxu = MAX (bxu, lx); bxu = MAX (bxu, rx);
+ byl = MIN (byl, ly); byl = MIN (byl, ry);
+ byu = MAX (byu, ly); byu = MAX (byu, ry);
+ }
+ else
+ {
+ bxl = MIN (lx, rx);
+ bxu = MAX (lx, rx);
+ byl = MIN (ly, ry);
+ byu = MAX (ly, ry);
+ bbbegun = 1;
+ }
+
+ /* write control point coordinates to TeX file */
+
+ if (ncontrols > 0)
+ OUTPUT (",\n");
+ OUTPUT (" (%lf, %lf), (%lf, %lf)",
+ xt(lx), yt(ly), xt(rx), yt(ry));
+ ++ ncontrols;
+ more = TRUE;
+ } /* (outer) fi */
+ } /* end (for) loop */
+
+ if (ncontrols < 1)
+ {
+ put_msg ("No control points");
+ }
+ return ncontrols;
+}
+/* controls */
+
+
+/* Text objects */
+/* Maximum length of text */
+#define TEXT_SLEN 80
+
+/* text justification (text subtypes) */
+
+#define T_LEFT_JUSTIFIED 0
+#define T_CENTER_JUSTIFIED 1
+#define T_RIGHT_JUSTIFIED 2
+
+/* (orthogonal) properties of text, stored as separate bits in text_flags */
+
+#define NO_TEXT 0
+#define RIGID_TEXT 1
+#define SPECIAL_TEXT 2
+#define PSFONT_TEXT 4
+#define HIDDEN_TEXT 8
+
+/* default font values */
+
+#define DEFAULT_FONT_0 0
+#define DEFAULT_FONT_1 (-1)
+
+/* general fonts */
+/* `modern' means `sans serif' */
+
+#define ROMAN 1
+#define BOLD 2
+#define ITALICS 3
+#define MODERN 4
+#define TYPEWRITER 5
+
+/* PostScript fonts (the common 35) */
+
+#define TR 1
+#define TI 2
+#define TB 3
+#define TBI 4
+
+#define AG 5
+#define AGBO 6
+#define AGD 7
+#define AGDO 8
+
+#define BKL 9
+#define BKLI 10
+#define BKD 11
+#define BKDI 12
+
+#define COUR 13
+#define COURO 14
+#define COURB 15
+#define COURBI 16
+
+#define HV 17
+#define HVO 18
+#define HVB 19
+#define HVBO 20
+
+#define HVN 21
+#define HVNO 22
+#define HVNB 23
+#define HVNBO 24
+
+#define NCR 25
+#define NCI 26
+#define NCB 27
+#define NCBI 28
+
+#define PLR 29
+#define PLI 30
+#define PLB 31
+#define PLBI 32
+
+#define SYMBOL 33
+
+#define ZCMI 34
+
+#define ZDING 35
+
+
+int
+text
+#ifdef __STDC__
+ (FILE * figfp)
+#else
+ (figfp)
+ FILE * figfp;
+#endif
+{
+ extern MsgType Message;
+ int type,
+ subtype,
+ font;
+ double font_size;
+ int pen,
+ color,
+ depth;
+ double angle;
+ int text_flags;
+ double ht,
+ len;
+ int x,
+ y;
+ char text[TEXT_SLEN+1];
+
+ /* alignment of text (baseline left is the default) */
+ char * orient = "bl";
+
+ /* Full name of font requested in the Fig file */
+ char * font_name = "DEFAULT FONT";
+
+ /* TeX font used to simulate font requested in the Fig file */
+ char * tex_font = "\\tt";
+
+ /* _estimated_ text bounding box */
+ int txl, txu, tyl, tyu;
+
+ int n;
+
+ /* eat whitespace before text string */
+ n = sscanf (buf, "%d%d%d%lf%d%d%d%lf%d%lf%lf%d%d %[^\1]",
+ &type,
+ &subtype,
+ &font,
+ &font_size,
+ &pen,
+ &color,
+ &depth,
+ &angle,
+ &text_flags,
+ &ht,
+ &len,
+ &x,
+ &y,
+ text);
+ if (n != N_TEXT)
+ {
+ put_msg ("Bad Text");
+ return (0); /* Like a zero length string - a doubtful value? */
+ }
+
+ switch (subtype)
+ {
+ case T_LEFT_JUSTIFIED:
+ orient = "bl";
+ txl = x;
+ break;
+ case T_CENTER_JUSTIFIED:
+ orient = "bc";
+ txl = x - len/2;
+ break;
+ default:
+ sprintf (Message,
+ "\"%d\" is an unknown text justification\n", subtype);
+ put_msg (Message);
+ /* default to right justification */
+ case T_RIGHT_JUSTIFIED:
+ orient = "br";
+ txl = x - len;
+ break;
+ break;
+ }
+
+
+ if (text_flags & PSFONT_TEXT)
+ {
+
+ /* PostScript fonts */
+ switch (font)
+ {
+ case DEFAULT_FONT_0:
+ case DEFAULT_FONT_1:
+ font_name = "DEFAULT PostScript";
+ tex_font = "\\tt";
+ break;
+ case TR:
+ font_name = "Times-Roman";
+ tex_font = "\\rm";
+ break;
+ case TI:
+ font_name = "Times-Italic";
+ tex_font = "\\it";
+ break;
+ case TB:
+ font_name = "Times-Bold";
+ tex_font = "\\bf";
+ break;
+ case TBI:
+ font_name = "Times-Bold-Italic";
+ tex_font = "\\it";
+ break;
+ case AG:
+ font_name = "AvantGarde";
+ tex_font = "\\rm";
+ break;
+ case AGBO:
+ font_name = "AvantGarde-BookOblique";
+ tex_font = "\\sl";
+ break;
+ case AGD:
+ font_name = "AvantGarde-Demi";
+ tex_font = "\\bf";
+ break;
+ case AGDO:
+ font_name = "AvantGarde-DemiOblique";
+ tex_font = "\\sl";
+ break;
+ case BKL:
+ font_name = "Bookman-Light";
+ tex_font = "\\rm";
+ break;
+ case BKLI:
+ font_name = "Bookman-LightItalic";
+ tex_font = "\\it";
+ break;
+ case BKD:
+ font_name = "Bookman-Demi";
+ tex_font = "\\bf";
+ break;
+ case BKDI:
+ font_name = "Bookman-DemiItalic";
+ tex_font = "\\it";
+ break;
+ case COUR:
+ font_name = "Courier";
+ tex_font = "\\tt";
+ break;
+ case COURO:
+ font_name = "Courier-Oblique";
+ tex_font = "\\tt";
+ break;
+ case COURB:
+ font_name = "Courier-Bold";
+ tex_font = "\\tt";
+ break;
+ case COURBI:
+ font_name = "Courier-BoldItalic";
+ tex_font = "\\tt";
+ break;
+ case HV:
+ font_name = "Helvetica";
+ tex_font = "\\sf";
+ break;
+ case HVO:
+ font_name = "Helvetica-Oblique";
+ tex_font = "\\sf";
+ break;
+ case HVB:
+ font_name = "Helvetica-Bold";
+ tex_font = "\\sf";
+ break;
+ case HVBO:
+ font_name = "Helvetica-BoldOblique";
+ tex_font = "\\sf";
+ break;
+ case HVN:
+ font_name = "Helvetica-Narrow";
+ tex_font = "\\sf";
+ break;
+ case HVNO:
+ font_name = "Helvetica-Narrow-Oblique";
+ tex_font = "\\sf";
+ break;
+ case HVNB:
+ font_name = "Helvetica-Narrow-Bold";
+ tex_font = "\\sf";
+ break;
+ case HVNBO:
+ font_name = "Helvetica-Narrow-BoldOblique";
+ tex_font = "\\sf";
+ break;
+ case NCR:
+ font_name = "NewCenturySchlbk-Roman";
+ tex_font = "\\rm";
+ break;
+ case NCI:
+ font_name = "NewCenturySchlbk-Italic";
+ tex_font = "\\it";
+ break;
+ case NCB:
+ font_name = "NewCenturySchlbk-Bold";
+ tex_font = "\\bf";
+ break;
+ case NCBI:
+ font_name = "NewCenturySchlbk-BoldItalic";
+ tex_font = "\\it";
+ break;
+ case PLR:
+ font_name = "Palatino-Roman";
+ tex_font = "\\rm";
+ break;
+ case PLI:
+ font_name = "Palatino-Italic";
+ tex_font = "\\it";
+ break;
+ case PLB:
+ font_name = "Palatino-Bold";
+ tex_font = "\\bf";
+ break;
+ case PLBI:
+ font_name = "Palatino-BoldItalic";
+ tex_font = "\\it";
+ break;
+ case SYMBOL: /* wrong characters, but what to do? */
+ font_name = "Symbol";
+ tex_font = "\\tt";
+ break;
+ case ZCMI: /* wrong characters, but what to do? */
+ font_name = "ZapfChancery-MediumItalic";
+ tex_font = "\\tt";
+ break;
+ case ZDING: /* wrong characters, but what to do? */
+ font_name = "ZapfDingbats";
+ tex_font = "\\tt";
+ break;
+ default: /* fall back to typewriter type */
+ font_name = "INVALID PostScript";
+ tex_font = "\\tt";
+ break;
+ }
+
+ }
+ else
+ {
+
+ /* general fonts */
+ switch (font)
+ {
+ case DEFAULT_FONT_0:
+ case DEFAULT_FONT_1:
+ font_name = "DEFAULT Fig";
+ tex_font = "\\tt";
+ break;
+ case ROMAN:
+ font_name = "Roman";
+ tex_font = "\\rm";
+ break;
+ case BOLD:
+ font_name = "Bold";
+ tex_font = "\\bf";
+ break;
+ case ITALICS:
+ font_name = "Italics";
+ tex_font = "\\it";
+ break;
+ case MODERN:
+ font_name = "Modern (sans serif)";
+ tex_font = "\\sf";
+ break;
+ case TYPEWRITER:
+ font_name = "Typewriter";
+ tex_font = "\\tt";
+ break;
+ default: /* fall back to typewriter type */
+ font_name = "INVALID Fig";
+ tex_font = "\\tt";
+ break;
+ }
+
+ }
+
+ /* completion of calculation of _estimated_ text bounding box */
+ txu = txl + len;
+ tyl = y;
+ tyu = tyl + ht;
+
+ /* _estimated_ Bounding Box for picture, including this text */
+ if (bbbegun)
+ {
+ bxl = MIN (bxl, txl);
+ bxu = MAX (bxu, txu);
+ byl = MIN (byl, tyl);
+ byu = MAX (byu, tyu);
+ }
+ else
+ {
+ bxl = txl;
+ bxu = txu;
+ byl = tyl;
+ byu = tyu;
+ bbbegun = 1;
+ }
+
+ OUTPUT ("%% - %s font at %.3lf pt\n", font_name, font_size);
+
+ /* mfpic label */
+ OUTPUT (" \\label[%s]{%lf}{%lf}{%s %s}\n",
+ orient, xt(x), yt(y), tex_font, text);
+
+ return (strlen (text));
+}
+/* text */
+
+
+/* Arc objects */
+/* The only arc subtype in Fig 2.1 is a three-point arc */
+#define T_3_POINT_ARC 1
+
+int
+arc
+#ifdef __STDC__
+ (FILE * figfp)
+#else
+ (figfp)
+ FILE * figfp;
+#endif
+{
+ int n;
+ int type,
+ subtype,
+ line_style,
+ line_thickness,
+ color,
+ depth,
+ pen,
+ fill;
+ double style_val;
+ int dir,
+ fa,
+ ba;
+ double cx,
+ cy;
+ int x1,
+ y1,
+ x2,
+ y2,
+ x3,
+ y3;
+
+ n = sscanf (buf, "%d%d%d%d%d%d%d%d%lf%d%d%d%lf%lf%d%d%d%d%d%d",
+ &type,
+ &subtype,
+ &line_style,
+ &line_thickness,
+ &color,
+ &depth,
+ &pen,
+ &fill,
+ &style_val,
+ &dir,
+ &fa,
+ &ba,
+ &cx,
+ &cy,
+ &x1,
+ &y1,
+ &x2,
+ &y2,
+ &x3,
+ &y3);
+
+ if (fa) next_src_line (figfp);
+ if (ba) next_src_line (figfp);
+
+ if (n != N_ARC)
+ {
+ put_msg ("Malformed arc");
+ return n;
+ }
+
+ /* arc bounding box */
+ {
+ int cxl, cxu, cyl, cyu;
+ int axl, axu, ayl, ayu;
+
+ int dx1 = x1 - cx;
+ int dy1 = y1 - cy;
+ double r = hypot (dx1, dy1);
+ double cos1 = dx1 / r;
+ double sin1 = dy1 / r;
+ double cos3 = (x3 - cx) / r;
+ double sin3 = (y3 - cy) / r;
+ int ir = (int) ceil (r);
+
+ /* left, right, bottom and top of circle of which arc is part */
+ cxl = cx - ir;
+ cxu = cx + ir;
+ cyl = cy - ir;
+ cyu = cy + ir;
+
+ /* ! temporary, crude estimate, based on including whole circle */
+ axl = cxl;
+ axu = cxu;
+ ayl = cyl;
+ ayu = cyu;
+
+ if (bbbegun)
+ {
+ bxl = MIN (bxl, axl);
+ bxu = MAX (bxu, axu);
+ byl = MIN (byl, ayl);
+ byu = MAX (byu, ayu);
+ }
+ else
+ {
+ bxl = axl;
+ bxu = axu;
+ byl = ayl;
+ byu = ayu;
+ bbbegun = 1;
+ }
+ }
+
+ if (line_thickness > 1)
+ OUTPUT (" \\pen{%.2lfpt}\n", do_pen (line_thickness));
+
+ OUTPUT (" \\mfcmd {arcthree((%lf,%lf), (%lf,%lf), (%lf,%lf))} \n",
+ xt(x1), yt(y1),
+ xt(x2), yt(y2),
+ xt(x3), yt(y3));
+
+ if (line_thickness > 1)
+ OUTPUT (" \\pen{%.2lfpt}\n", mfpen);
+
+ return n;
+}
+/* arc */
+
+
+/* Compound objects */
+/* Write a TeX comment, and, if necessary, extend the bounding box */
+
+int
+compound
+#ifdef __STDC__
+ (FILE * figfp)
+#else
+ (figfp)
+ FILE * figfp;
+#endif
+{
+ int cxl, cxu, cyl, cyu;
+ int n;
+
+ n = sscanf (buf, "%d%d%d%d", &cxl, &cxu, &cyl, &cyu);
+ if (n != N_COMPOUND)
+ {
+ put_msg ("Malformed compound");
+ return n;
+ }
+
+ OUTPUT ("%% Compound.\n");
+
+ if (bbbegun)
+ {
+ bxl = MIN (bxl, cxl);
+ bxu = MAX (bxu, cxu);
+ byl = MIN (byl, cyl);
+ byu = MAX (byu, cyu);
+ }
+ else
+ {
+ bxl = cxl;
+ bxu = cxu;
+ byl = cyl;
+ byu = cyu;
+ bbbegun = 1;
+ }
+
+ return n;
+}
+/* compound */
+
+
+/* End compound objects */
+/* Only write a comment */
+
+int
+end_compound
+#ifdef __STDC__
+ (FILE * figfp)
+#else
+ (figfp)
+ FILE * figfp;
+#endif
+{
+ OUTPUT ("%% End Compound.\n");
+}
+/* end_compound */
+
+
+/* return name of object subtype from given type and subtype codes */
+char *
+subtype_name
+#ifdef __STDC__
+ (int type, int subtype)
+#else
+ (type, subtype)
+ int type, subtype;
+#endif
+{
+ char * sub_name = "unknown";
+
+ switch (type)
+ {
+ case O_ELLIPSE:
+ switch (subtype)
+ {
+ case T_ELLIPSE_BY_RAD:
+ sub_name = "ellipse by radius";
+ break;
+ case T_ELLIPSE_BY_DIA:
+ sub_name = "ellipse by diameter";
+ break;
+ case T_CIRCLE_BY_RAD:
+ sub_name = "circle by radius";
+ break;
+ case T_CIRCLE_BY_DIA:
+ sub_name = "circle by diameter";
+ break;
+ default:
+ sub_name = "unknown ellipse";
+ break;
+ }
+ break;
+ case O_POLYLINE:
+ switch (subtype)
+ {
+ case T_POLYLINE:
+ sub_name = "polyline";
+ break;
+ case T_BOX:
+ sub_name = "box";
+ break;
+ case T_POLYGON:
+ sub_name = "polygon";
+ break;
+ case T_ARC_BOX:
+ sub_name = "arc box";
+ break;
+ case T_EPS_BOX:
+ sub_name = "EPS box";
+ break;
+ default:
+ sub_name = "unknown polyline";
+ break;
+ }
+ break;
+ case O_SPLINE:
+ switch (subtype)
+ {
+ case T_OPEN_NORMAL:
+ sub_name = "open normal spline (open B-spline)";
+ break;
+ case T_CLOSED_NORMAL:
+ sub_name = "closed normal spline (closed B-spline)";
+ break;
+ case T_OPEN_INTERPOLATED:
+ sub_name = "open interpolated spline";
+ break;
+ case T_CLOSED_INTERPOLATED:
+ sub_name = "open interpolated spline";
+ break;
+ default:
+ sub_name = "unknown spline";
+ break;
+ }
+ break;
+ case O_TEXT:
+ switch (subtype)
+ {
+ case T_LEFT_JUSTIFIED:
+ sub_name = "left justified text";
+ break;
+ case T_CENTER_JUSTIFIED:
+ sub_name = "center justified text";
+ break;
+ case T_RIGHT_JUSTIFIED:
+ sub_name = "right justified text";
+ break;
+ default:
+ sub_name = "unknown text justification";
+ break;
+ }
+ break;
+ case O_ARC:
+ switch (subtype)
+ {
+ case T_3_POINT_ARC:
+ sub_name = "three-point arc";
+ break;
+ default:
+ sub_name = "unknown arc";
+ break;
+ }
+ break;
+ case O_COMPOUND:
+ sub_name = "compound";
+ break;
+ case O_END_COMPOUND:
+ sub_name = "end compound";
+ break;
+ default:
+ sub_name = "unknown";
+ break;
+ }
+ return (sub_name);
+}
+/* subtype_name */
+
+
+static int curchar = FIRST_CHAR; /* assignment here is not important */
+
+Void finit (VOID)
+{
+ curchar = char_code;
+ OUTPUT ("%%\n");
+ OUTPUT ("%% gt fig2mfpic version %s for mfpic %s and graphbase %s\n",
+ VERSION, MFPIC_VERSION, GRAPHBASE_VERSION);
+ OUTPUT ("%% compiled as %s", progname);
+#ifdef __STDC__
+ OUTPUT (" from file %s on %s %s", __FILE__, __DATE__, __TIME__);
+#endif
+ OUTPUT ("\n");
+ OUTPUT ("%% --- Preamble\n");
+ OUTPUT ("%%\n");
+ /* test whether drawing macros (eg, "mfpic.tex") have been input */
+ OUTPUT ("\\ifx\\opengraphsfile\\undefined\n");
+ /* if they have not, assume output is intended as a stand-alone TeX file */
+ OUTPUT (" \\def\\endfigtomfpic{\\par\\vfill\\supereject\\end}");
+ OUTPUT (" %% like bye, but not outer.\n");
+ OUTPUT (" \\message{You didn't input the drawing macros,");
+ OUTPUT (" so, Gw, I will.}\n");
+ OUTPUT (" \\message{NB: I'll exit after closegraphsfile.}\n");
+ OUTPUT ("%%\n");
+ /* input drawing macros now */
+ OUTPUT (" \\input %s\n", draw_macros);
+ OUTPUT ("%%\n");
+ /* of course, the assumption might be wrong */
+ /* but if the drawing macros were previously input */
+ OUTPUT ("\\else\n");
+ /* then this is an "encapsulated TeX" :-) file */
+ OUTPUT (" \\let\\endfigtomfpic=\\relax\n");
+ OUTPUT ("\\fi\n");
+ OUTPUT ("\\def\\polyline{\\polycurve}\n");
+ OUTPUT ("%%\n");
+ OUTPUT ("\\opengraphsfile{%s}\n", mf_ofile);
+ define_polydash();
+}
+/* finit */
+
+/* Augment the TeX and MF drawing macros with a dash polyline */
+Void define_polydash (VOID)
+{
+#define BAD_KLUGE
+#ifdef BAD_KLUGE
+ /* ! temporary partial attempt */
+ OUTPUT ("\\def\\polydash{\\dottedline}\n");
+#else
+ OUTPUT ("\\def\\polydash{%%\n");
+ OUTPUT (" \\mfcmd{%%\n");
+ /* ! need something substantial here */
+ OUTPUT (" \n");
+ OUTPUT (" }%%\n");
+ OUTPUT ("}%%\n");
+#endif
+}
+/* define_polydash */
+
+/* input picture <-> output character */
+Void cinit (VOID)
+{
+ if (nchar < MAXNCHAR)
+ {
+ bbbegun = 0; /* no bounding box estimate yet, for this picture */
+ /* comment : current input file, and corresponding output character */
+ OUTPUT ("%%\n%% \"%s\" (char %d)\n%%\n", curfigfile, curchar);
+ /* X, Y drawing units (pt), picture bounding box (drawing units) */
+ OUTPUT ("\\mfpic[%.4lf][%.4lf]{%.4lf}{%.4lf}{%.4lf}{%.4lf}\n",
+ xscale / oupi * PT_PER_INCH,
+ yscale / oupi * PT_PER_INCH,
+ xl, xu, yl, yu);
+ }
+}
+/* cinit */
+
+#define DSWAP(x,y) {double temp = x; x = y; y = temp;}
+
+Void cfin (VOID)
+{
+ OUTPUT ("\\endmfpic\n");
+ /* bounding box comment, to replace estimate in cinit() */
+ if (bbbegun)
+ {
+ double pxl, pxu, pyl, pyu;
+ int xsgn = (xscale / oupi * PT_PER_INCH < 0.0 ? -1 : 1);
+ int ysgn = (yscale / oupi * PT_PER_INCH < 0.0 ? -1 : 1);
+
+ pxl = xt(bxl);
+ pxu = xt(bxu);
+ pyl = yt(byl);
+ pyu = yt(byu);
+
+ if (xsgn * pxl > xsgn * pxu)
+ DSWAP (pxl, pxu);
+ if (ysgn * pyl > ysgn * pyu)
+ DSWAP (pyl, pyu);
+
+ OUTPUT ("%% Bounding box is now estimated to be:\n");
+ OUTPUT ("%% \\mfpic[%.4lf][%.4lf]{%.4lf}{%.4lf}{%.4lf}{%.4lf}\n",
+ xscale / oupi * PT_PER_INCH,
+ yscale / oupi * PT_PER_INCH,
+ pxl, pxu, pyl, pyu);
+ }
+ OUTPUT ("%%\n%% end \"%s\" (char %d)\n%%\n", curfigfile, curchar);
+ ++ nchar;
+ ++ curchar;
+}
+/* cfin */
+
+Void ffin (VOID)
+{
+ if (nchar > 0)
+ {
+ OUTPUT ("\\closegraphsfile\n");
+ OUTPUT ("\\endfigtomfpic\n");
+ }
+}
+/* ffin */
+
+int
+get_line
+#ifdef __STDC__
+ (FILE * figfp)
+#else
+ (figfp)
+ FILE * figfp;
+#endif
+{
+ /* Read next line of Fig file figfp, including linefeed, */
+ /* into buffer of at most BUF_SIZE characters. */
+
+ int retval;
+
+ if (fgets (buf, BUF_SIZE, figfp) == NULL)
+ {
+ /* No line */
+ retval = FALSE;
+ }
+ else
+ {
+ /* Count all lines */
+ ++ linenum;
+ if (debug)
+ {
+ display_line();
+ }
+ retval = TRUE;
+ }
+ return retval;
+}
+/* get_line */
+
+int
+next_src_line
+#ifdef __STDC__
+ (FILE * figfp)
+#else
+ (figfp)
+ FILE * figfp;
+#endif
+{
+ /* Read next non-empty, non-comment line of Fig file figfp, if any */
+ int flag = 0;
+ while (!flag)
+ {
+ if (!get_line (figfp))
+ flag = -1; /* No more lines */
+ else if (*buf != '\n' && *buf != '#')
+ flag = 1; /* Good! A non-empty, non-comment line */
+ /* _Skip_ empty and comment lines */
+ }
+ return flag; /* 1 or -1 */
+}
+/* next_src_line */
+
+Void
+display_line (VOID)
+{
+ MsgType LineNum;
+
+ sprintf (LineNum, "Line %d: ", linenum);
+ Lwrite (LineNum);
+ Lwrite (buf);
+ Lflush ();
+}
+/* display_line */
+
+int
+get_int
+#ifdef __STDC__
+ (char ** bufpa, int * ya)
+#else
+ (bufpa, ya)
+ char ** bufpa;
+ int * ya;
+#endif
+/* bufpa = Address of (a buffer pointer : I/O). */
+/* ya = Address of (a int : O). */
+{
+
+ /* Skip leading blanks of *bufpa, then try to read a decimal */
+ /* integer from it into ya, advancing bufpa while successful. */
+ /* Return TRUE if an integer is found, FALSE otherwise. */
+ /*............................................................. */
+ /* It's hard to believe that traditional K&R has no convenient */
+ /* library function for this extremely common task. */
+ /* OR something like fscanf, that uses a data structure to keep */
+ /* track of its current position, and has a variety of formats. */
+ /*............................................................. */
+
+ int found = FALSE;
+ if (bufpa == NULL || *bufpa == NULL || ya == NULL)
+ {
+ put_msg ("About to dereference a NULL pointer");
+ found = FALSE;
+ }
+ else
+ {
+ char * start = *bufpa;
+ *ya = (int) strtol (start, bufpa, 10);
+ if (*bufpa != start)
+ found = TRUE;
+ }
+ return (found);
+}
+/* get_int */
+
+int
+get_double
+#ifdef __STDC__
+ (FILE * figfp, char ** bufpa, double * ya)
+#else
+ (figfp, bufpa, ya)
+ FILE * figfp;
+ char ** bufpa;
+ double * ya;
+#endif
+/* figfp = Address of (a FILE buffer : I/O). */
+/* bufpa = Address of (a buffer pointer : I/O). */
+/* ya = Address of (a double : O). */
+{
+
+ /* Skip leading blanks of *bufpa, then try to read a floating */
+ /* point number from it into ya, advancing bufpa while successful. */
+ /* Return TRUE if a number is found, FALSE otherwise. */
+
+ int found = FALSE;
+ if (bufpa == NULL || *bufpa == NULL || ya == NULL)
+ {
+ put_msg ("About to dereference a NULL pointer");
+ found = FALSE;
+ }
+ else
+ {
+ char * start;
+ while (buffer_empty (*bufpa))
+ {
+ next_src_line (figfp);
+ *bufpa = buf;
+ }
+ start = *bufpa;
+ *ya = strtod (start, bufpa);
+ if (*bufpa != start)
+ found = TRUE;
+ }
+ return (found);
+}
+/* get_double */
+
+/* end of fig2mfpic of Wed 8 Jun 1994 */
diff --git a/graphics/fig2mfpic/graphbase.mf b/graphics/fig2mfpic/graphbase.mf
new file mode 100644
index 0000000000..3fe370a944
--- /dev/null
+++ b/graphics/fig2mfpic/graphbase.mf
@@ -0,0 +1,1228 @@
+%%% Author: Geoffrey Tobin.
+%%% Address: G.Tobin@ee.latrobe.edu.au
+%%%
+%%% File: graphbase.mf
+%%%
+
+mode_setup;
+message "graphbase 0.2 fig 2a - 13:32 GMT +10 Thu 16 June 1994";
+
+% set up local environment
+
+def mfpicenv =
+begingroup
+
+% miscellaneous utilities
+
+% gt - op_pair operates with "op"
+% on both parts of a pair p.
+
+save op_pair;
+
+vardef op_pair (text op) (expr p) =
+ (op (xpart p), op (ypart p))
+enddef;
+
+save floorpair, ceilingpair;
+
+def floorpair = op_pair (floor) enddef;
+def ceilingpair = op_pair (ceiling) enddef;
+
+% gt - Should there be more error-checking,
+% eg of types, in these utility routines?
+% That would slow them down.
+
+% gt - textpairs converts the text t into the
+% array of n pairs, pts, that it contains.
+
+save textpairs;
+
+def textpairs (text t) (suffix pairs_, n_) =
+ n_ := 0;
+ for q=t:
+ pairs_[incr n_] := q;
+ endfor;
+enddef;
+
+% gt - Watch out! Need to ensure that "p_", etc.,
+% don't clash with any name in the passed text "t".
+% That's a nasty error to trace!
+%
+% A name conflict between local variables and variables
+% in a text parameter is especially likely in low-level
+% utility macros, such as minpair, maxpair and corner.
+%
+% Unfortunately, we can't *ensure* it won't happen.
+% So I appended the underscore to reduce the
+% probability of that happening.
+%
+% Evidently that's why Knuth uses "u_" in "max" and
+% "min" in "plain.mf".
+
+% gt - corner may be used for finding
+% a corner of the bounding box of the
+% set of points listed in u and t.
+% Other uses may be imaginable. (?)
+
+save corner;
+
+vardef corner (text xop) (text yop)
+ (expr u)(text t) =
+ save p_;
+ pair p_;
+ p_ := u;
+ for q=t:
+ p_ := (xop (xpart p_, xpart q),
+ yop (ypart p_, ypart q));
+ endfor;
+ p_
+enddef;
+
+% gt - bottom right, bottom right,
+% top left, top right corners.
+
+save blpair, brpair, tlpair, trpair;
+
+def blpair = corner (min) (min) enddef;
+def brpair = corner (max) (min) enddef;
+def tlpair = corner (min) (max) enddef;
+def trpair = corner (max) (max) enddef;
+
+def minpair = blpair enddef;
+def maxpair = trpair enddef;
+
+% setup
+% gt - sets the graphics coordinates.
+
+save bounds,
+ xneg,xpos,yneg,ypos;
+
+def bounds(expr a,b,c,d) =
+ xneg:=a;
+ xpos:=b;
+ yneg:=c;
+ ypos:=d;
+enddef;
+
+% conversion
+
+save xconv;
+
+def xconv(expr xvalue) =
+ ((xvalue-xneg)/(xpos-xneg))*w
+enddef;
+
+save unxconv;
+
+def unxconv(expr pvalue) =
+ ((pvalue/w)*(xpos-xneg)+xneg)
+enddef;
+
+save yconv;
+
+def yconv(expr yvalue) =
+ ((yvalue-yneg)/(ypos-yneg))*h
+enddef;
+
+save ztr;
+
+transform ztr;
+
+save setztr;
+
+def setztr =
+ ztr:=identity
+ shifted -(xneg,yneg)
+ xscaled (w/(xpos-xneg))
+ yscaled (h/(ypos-yneg));
+enddef;
+
+% pen width
+% in pixel coordinates
+
+save penwd;
+newinternal penwd;
+interim penwd := 0.5pt;
+
+% arrowheads
+% in pixel coordinates
+
+% hdwdr = arrowhead's ratio of width to length,
+% hdten = tension used in drawing its barbs.
+
+save hdwdr, hdten;
+newinternal hdwdr, hdten;
+interim hdwdr := 1;
+interim hdten := 1;
+
+% draw an arrowhead.
+
+save head, p,side;
+
+def head(expr front, back, width, t) =
+ pair p[], side;
+ side := (width/2) *
+ ((front-back) rotated 90);
+ p1 := back + side;
+ p2 := back - side;
+ draw front{back-front}..tension t..p1;
+ draw front{back-front}..tension t..p2;
+enddef;
+
+% draw an arrowhead of length hlen
+% for a path f.
+
+save headpath, p;
+
+def headpath(expr f,hlen) =
+ pair p[];
+ p2:=point infinity of f;
+ p1:=direction infinity of f;
+ if p1<>(0,0):
+ head(p2,p2-(hlen*unitvector(p1)),
+ hdwdr,hdten);
+ fi;
+enddef;
+
+% shading and hatching routines
+% in pixel coordinates
+
+% gt - modified onedot based on
+% plain metafont's "drawdot".
+% Used in stipple shading.
+%
+% Note:
+% currentpen_path, def_pen_path_,
+% t_, and penspeck are defined
+% in plain metafont ("plain.mf"
+% or "plain.base").
+
+save onedot;
+
+def onedot(expr p)(suffix v) =
+ if unknown currentpen_path:
+ def_pen_path_
+ fi;
+ addto v
+ contour currentpen_path
+ shifted p.t_
+ withpen penspeck
+enddef;
+
+% gt - draw path f in picture v.
+% ("onepath" is the old "onedot",
+% but f is intended to be a general path.)
+% Used, eg, in hatching and in drawpaths.
+
+save onepath;
+
+def onepath (expr f) (suffix v) =
+ addto v doublepath f
+ withpen currentpen;
+enddef;
+
+% gt - Paths must be continuous - I think
+% - but using suffix, we can pass arrays
+% of paths.
+%
+% My eventual goal is to do as much as
+% feasible, and memory-affordable, in
+% graphics coordinates, so we can rotate
+% and otherwise transform sets of paths
+% before drawing.
+
+% gt - draw the n paths f[] in picture v.
+
+save drawpaths;
+
+def drawpaths (expr n) (suffix f, v) =
+ for i=1 upto n:
+ onepath (f[i], v);
+ endfor;
+enddef;
+
+% clip picture v to interior of path f.
+
+save clip;
+
+vardef clip(expr f)(suffix v) =
+ save vt;
+ picture vt;
+ vt:=v;
+ cull vt keeping (1,infinity);
+ addto vt contour f;
+ cull vt keeping (2,infinity);
+ vt
+enddef;
+
+% gt - find bounding box of path f.
+
+save boundingbox, p;
+
+def boundingbox (expr f) (suffix ll, ur) =
+ ur := ll := point 0 of f;
+ pair p[];
+ for i=0 upto length f:
+ p0 := point i of f;
+ p1 := precontrol i of f;
+ p2 := postcontrol i of f;
+ ll := minpair (ll, p0, p1, p2);
+ ur := maxpair (ur, p0, p1, p2);
+ endfor;
+enddef;
+
+% gt - shading.
+
+% gt - I'm not so happy with dot densities
+% over a uniform range.
+% Here's code to approximate what may
+% be the human eye's light sensitivity.
+%
+% Mind you, this sort of stuff is done much
+% faster in C.
+
+save exp;
+
+vardef exp (expr x) =
+ mexp (256 * x)
+enddef;
+
+% graya scales the spacing sp;
+% grayb scales the graylevel g.
+
+save graya, grayb;
+
+newinternal graya, grayb;
+
+% initial values of gray parameters.
+
+interim graya := 0.5 pt;
+interim grayb := 3/20;
+
+% setgraypars sets gray parameters.
+% experimentation is recommended.
+
+save setgraypars;
+
+def setgraypars (expr a, b) =
+ graya := a;
+ grayb := b;
+enddef;
+
+% gt - grayspace gives the dot spacing
+% for graylevel g.
+%
+% Not sure how this model performs.
+
+save grayspace;
+
+vardef grayspace (expr g) =
+ if g <= 1: % white
+ infinity
+ elseif g >= 21: % black
+ 0
+ else: % gray
+ graya / (1 - exp (-g * grayb))
+ fi
+enddef;
+
+% gt - stipple upright box with lower left
+% at ll, upper right at ur, in picture v;
+% 2sp is dot spacing (rows offset by sp).
+%
+% NB: "stipple" means "shade with dots",
+% if I understand my English dictionary.
+%
+% Thomas Leathrum devised the trick whereby
+% the dots are arranged on a regular grid
+% of mesh size sp by sp with the pixel
+% origin as one crosspoint. This ensures
+% that objects shaded with the same stipple
+% density may be cleanly overlaid.
+
+save shadebox, sll, mn, m, n, twosp, p;
+
+def shadebox (expr sp, ll, ur) (suffix v) =
+ pair sll;
+ sll:=sp*(ceilingpair(ll/sp));
+ pair mn;
+ mn:=floorpair((ur-sll)/sp);
+ m:=xpart mn;
+ n:=ypart mn;
+ twosp:=2sp;
+ v:=nullpicture;
+ pair p[];
+ p2:=sll;
+ for i=0 upto m:
+ p3:=p2 if odd i: +(0,sp) fi;
+ for j=0 upto n:
+ if (not odd (i+j)):
+ onedot (p3, v);
+ p3:=p3+(0,twosp);
+ fi;
+ endfor;
+ p2:=p2+(sp,0);
+ endfor;
+enddef;
+
+% stipple interior of closed path f;
+% if spacing not positive, fill.
+
+save shadepath, ll, ur, v;
+
+def shadepath (expr sp, f) =
+ if not cycle f: ;
+ elseif sp<=0:
+ fill f;
+ elseif sp < infinity:
+ pair ll, ur;
+ boundingbox (f, ll, ur);
+ picture v;
+ shadebox (sp, ll, ur, v);
+ addto currentpicture
+ also clip(f,v);
+ fi;
+enddef;
+
+% gt - hatch an upright box in picture v,
+% with line separation sep x sep.
+%
+% Notice the similarity to shadebox.
+
+save hatchbox, llx, lly, urx, ury, sll,
+ mn, m, n, f;
+
+def hatchbox (expr sep, ll, ur) (suffix v) =
+ llx := xpart ll;
+ lly := ypart ll;
+ urx := xpart ur;
+ ury := ypart ur;
+ pair sll;
+ sll := sep * ceilingpair (ll/sep);
+ pair mn;
+ mn := floorpair ((ur-sll)/sep);
+ m := xpart mn;
+ n := ypart mn;
+ v := nullpicture;
+ path f;
+ f := (xpart sll, lly)--(xpart sll, ury);
+ for i=0 upto m:
+ onepath (f, v);
+ f := f translated (sep, 0);
+ endfor;
+ f := (llx, ypart sll)--(urx, ypart sll);
+ for j=0 upto n:
+ onepath (f, v);
+ f := f translated (0, sep);
+ endfor;
+enddef;
+
+save hatchpath, ll, ur, v;
+
+def hatchpath (expr sep, f) =
+ if not cycle f: ;
+ elseif sep<=0:
+ fill f;
+ elseif sep < infinity:
+ pair ll, ur;
+ boundingbox (f, ll, ur);
+ picture v;
+ hatchbox (sep, ll, ur, v);
+ addto currentpicture
+ also clip (f, v);
+ fi;
+enddef;
+
+% gt - shading & hatching macros
+% with a syntax like draw, fill,
+% unfill and erase.
+% sp, sep are in pixel coords,
+% f in graphics coordinates;
+% f is transformed transparently.
+
+save shade;
+
+def shade (expr sp) expr f =
+ shadepath (sp, f transformed ztr);
+enddef;
+
+save hatch;
+
+def hatch (expr sep) expr f =
+ hatchpath (sep, f transformed ztr);
+enddef;
+
+% gt - common combinations.
+
+save drawshade;
+
+def drawshade (expr sp) expr f =
+ draw f transformed ztr;
+ shade (sp) f;
+enddef;
+
+save drawhatch;
+
+def drawhatch (expr sep) expr f =
+ draw f transformed ztr;
+ hatch (sep) f;
+enddef;
+
+% * rest of macros start in graphing
+% coordinates but convert to pixel
+% to draw
+% * variables ending in "_px"
+% converted to pixel
+% * exceptions are the TeX dimensions
+% here called:
+% ptwd, hlen, dlen, slen, len, sp, sep
+% all of which are in pixel coordinates
+% * macros beginning with "mk" operate
+% entirely in graphing coordinates
+
+% general path construction
+
+save mkpath;
+
+vardef mkpath(expr smooth, cyclic, n)
+ (suffix pts) =
+ if smooth:
+ if cyclic:
+ pts[1]{pts[2]-pts[n]}
+ else:
+ pts[1]
+ fi
+ for i=2 upto n-1:
+ ..pts[i]{pts[i+1]-pts[i-1]}
+ endfor
+ if cyclic:
+ ..pts[n]{pts[1]-pts[n-1]}..cycle
+ else:
+ ..pts[n]
+ fi
+ else:
+ for i=1 upto n-1:
+ pts[i] --
+ endfor
+ pts[n]
+ if cyclic:
+ -- cycle
+ fi
+ fi
+enddef;
+
+% points, lines, and arrows
+
+save pointd, p;
+
+def pointd(expr a,ptwd) =
+ pair p_px;
+ p_px:=a transformed ztr;
+ fill fullcircle scaled ptwd shifted p_px;
+enddef;
+
+save line;
+
+def line(expr a,b) =
+ draw (a..b) transformed ztr;
+enddef;
+
+% gt - arrowpath draws path f
+% with an arrowhead;
+% hlen is in pixel coordinates;
+% f is in graphics coords;
+% f is transformed transparently.
+% Compare shade, hatch, etc.,
+% and contrast shadepath.
+
+save arrowpath, f_px;
+
+def arrowpath (expr hlen) expr f =
+ path f_px;
+ f_px := f transformed ztr;
+ draw f_px;
+ headpath (f_px, hlen);
+enddef;
+
+% gt - arrow now uses arrowpath.
+
+save arrow;
+
+def arrow(expr tl,hd,hlen) =
+ arrowpath (hlen) tl..hd ;
+enddef;
+
+% gt - "px" was too frequent
+% in dottedline, and made the code
+% hard to read, so I've deleted it.
+% Only a and b are in graphics coords.
+
+save dottedline,
+ p, v, l, delta, n;
+
+def dottedline (expr a, b, dlen, slen) =
+ pair p[];
+ p1 := a transformed ztr;
+ p3 := b transformed ztr;
+ l := length (p3-p1);
+ if (l > 2dlen) and
+ (dlen >= 0) and (slen >= 0):
+ else:
+ pair v;
+ v := unitvector (p3-p1);
+ n := floor ((l+slen-dlen) / (dlen+slen));
+ delta := (l-dlen) / n - (dlen+slen);
+ for i=1 upto n:
+ p2 := p1 + dlen * v;
+ draw p1..p2;
+ p1 := p2 + (slen+delta) * v;
+ endfor;
+ fi;
+ draw p1..p3;
+enddef;
+
+save dottedarrow;
+
+def dottedarrow(expr tl,hd,dlen,
+ slen,hlen) =
+ dottedline(tl,hd,dlen,slen);
+ headpath((tl..hd) transformed ztr,hlen);
+enddef;
+
+% axes and axis marks
+
+save axes;
+
+def axes(expr hlen) =
+ arrow((0,yneg),(0,ypos),hlen);
+ arrow((xneg,0),(xpos,0),hlen);
+enddef;
+
+save xmarks;
+
+def xmarks(expr len)(text t) =
+ for a=t:
+ draw (xconv(a),yconv(0)-(len/2))..
+ (xconv(a),yconv(0)+(len/2));
+ endfor;
+enddef;
+
+save ymarks;
+
+def ymarks(expr len)(text t) =
+ for a=t:
+ draw (xconv(0)-(len/2),yconv(a))..
+ (xconv(0)+(len/2),yconv(a));
+ endfor;
+enddef;
+
+% upright rectangles
+
+save mkrect;
+
+vardef mkrect(expr ll,ur) =
+ ll--(xpart ll,ypart ur)--
+ ur--(xpart ur,ypart ll)--cycle
+enddef;
+
+save rect;
+
+def rect(expr ll,ur) =
+ draw mkrect(ll,ur) transformed ztr;
+enddef;
+
+save dottedrect;
+
+def dottedrect(expr ll,ur,dlen,slen) =
+ dottedline(ll,(xpart ll,ypart ur),
+ dlen,slen);
+ dottedline((xpart ll,ypart ur),ur,
+ dlen,slen);
+ dottedline(ur,(xpart ur,ypart ll),
+ dlen,slen);
+ dottedline((xpart ur,ypart ll),ll,
+ dlen,slen);
+enddef;
+
+save block;
+
+def block(expr ll,ur) =
+ fill mkrect(ll,ur) transformed ztr;
+enddef;
+
+% gt - rectshade now uses shade.
+
+save rectshade;
+
+def rectshade(expr sp,ll,ur) =
+ shade (sp) mkrect (ll, ur);
+enddef;
+
+% circles and ellipses
+
+save mkellipse;
+
+vardef mkellipse(expr center,radx,rady,
+ angle) =
+ save t;
+ transform t;
+ t := identity
+ xscaled (2 * radx)
+ yscaled (2 * rady)
+ rotated angle
+ shifted center;
+ fullcircle transformed t
+enddef;
+
+save ellipse;
+
+def ellipse(expr center,radx,rady,
+ angle) =
+ draw
+ mkellipse(center,radx,rady,angle)
+ transformed ztr;
+enddef;
+
+save circle;
+
+def circle(expr center,rad) =
+ ellipse(center,rad,rad,0);
+enddef;
+
+% gt - ellshade now uses shade.
+
+save ellshade;
+
+def ellshade (expr sp, center,
+ radx, rady, angle) =
+ shade (sp)
+ mkellipse (center, radx, rady, angle);
+enddef;
+
+save circshade;
+
+def circshade(expr sp, center,rad) =
+ ellshade(sp,center,rad,rad,0);
+enddef;
+
+% circular arcs
+
+% gt - mkarc now calculates
+% n using ceiling, not floor;
+% and saves theta, not i.
+
+save mkarc;
+
+vardef mkarc(expr center,from,sweep) =
+ pair p,q;
+ path f;
+ if sweep=0: f:=from
+ else:
+ n:=floor(abs(sweep)/45)+1;
+ if n<3: n:=3; fi;
+ theta:=sweep/(n-1);
+ f:=p:=from;
+ for i:=2 upto n:
+ p:=p rotatedabout (center,theta);
+ q:=p-center; q:=q rotated 90;
+ if theta<0: q:=-q; fi;
+ f:=f..p{unitvector q};
+ endfor;
+ fi;
+ f
+enddef;
+
+
+% gt - note that when sweep is a multiple
+% of 360 degrees, disp is logically
+% infinite, not zero; then the center is
+% at infinity. In practice, arccenter
+% ought not to be called in that case.
+
+save arccenter;
+
+vardef arccenter(expr from,to,sweep)=
+ if from=to:
+ from
+ else:
+ pair midpt;
+ midpt:=(0.5)[from,to];
+ if (sweep mod 360)=0:
+ midpt
+ else:
+ disp:=cosd(sweep/2)/sind(sweep/2);
+ midpt+(disp*((to-from) rotated 90)/2)
+ fi
+ fi
+enddef;
+
+% gt - mkarcto makes an arc given two points
+% on the arc and the sweep angle.
+% If sweep is a multiple of 360 degrees,
+% then the arc is a straight line;
+% if sweep is also nonzero, then that
+% line should be infinite, but I use
+% from--to instead.
+
+save mkarcto;
+
+vardef mkarcto(expr from,to,sweep) =
+ pair center;
+ center:=arccenter(from,to,sweep);
+ (mkarc(center, from, sweep))
+enddef;
+
+% gt - arc now uses mkarcto.
+
+save arc;
+
+def arc(expr from,to,sweep) =
+ draw mkarcto (from, to, sweep)
+ transformed ztr;
+enddef;
+
+% gt - arcarrow now uses mkarcto
+% and arrowpath.
+
+save arcarrow;
+
+def arcarrow(expr hlen,from,to,sweep) =
+ arrowpath (hlen) mkarcto (from, to, sweep);
+enddef;
+
+% gt - mkchordto makes a cyclic path from
+% the arc from "from" to "to" with a sweep
+% angle of "sweep", and its chord from
+% "to" to "from".
+
+save mkchordto;
+
+vardef mkchordto (expr from, to, sweep) =
+ mkarcto (from, to, sweep) -- cycle
+enddef;
+
+% gt - arcshade now uses mkchordto
+% and shade.
+
+save arcshade;
+
+def arcshade(expr sp,from,to,sweep) =
+ shade (sp) mkchordto (from, to, sweep);
+enddef;
+
+% gt - three-point arcs.
+
+save mkarcthree;
+
+vardef mkarcthree (expr first, second, third) =
+ sweep:=2*(angle(third-second)-angle(second-first));
+ sweep:=sweep mod 720;
+ if sweep > 360: sweep:=sweep-720; fi
+ critical:=5;
+ if abs(sweep) <= critical: % center may blow out
+ pair p[]; p1:=first; p2:=second; p3:=third;
+ mkpath(true,false,3,p)
+ else:
+ pair m[], d[], center;
+ m1:=(0.5)[first,second]; d1:=(second-first) rotated 90;
+ m2:=(0.5)[second,third]; d2:=(third-second) rotated 90;
+ center = m1+whatever*d1 = m2+whatever*d2;
+ mkarc(center,first,sweep)
+ fi
+enddef;
+
+save arcthreecenter;
+
+vardef arcthreecenter (expr first, mid, last) =
+ save c, m, d;
+ pair c, m[], d[];
+ d1 := (mid - first) rotated 90;
+ d2 := (last - mid) rotated 90;
+ m1 := 0.5 [first, mid];
+ m2 := 0.5 [mid, last];
+ c = m1 + whatever * d1 = m2 + whatever * d2;
+ c
+enddef;
+
+save arcthree;
+
+def arcthree (expr first, mid, last) =
+ draw mkarcthree (first, mid, last) transformed ztr;
+enddef;
+
+save arcthreearrow;
+
+def arcthreearrow (expr hlen, first, mid, last) =
+ arrowpath (hlen) mkarcthree (first, mid, last);
+enddef;
+
+% modified polar coordinates
+
+% gt - mklinedir makes a path from point "a"
+% to a point displaced "len" in direction "theta"
+% from "a".
+
+save mklinedir;
+
+vardef mklinedir (expr a, theta, len) =
+ a -- (a + len * (dir theta))
+enddef;
+
+% gt - linedir now uses mklinedir.
+
+save linedir;
+
+def linedir(expr a,theta,len) =
+ draw mklinedir (a, theta, len)
+ transformed ztr;
+enddef;
+
+% gt - arrowdir now uses mklinedir
+% and arrowpath.
+
+save arrowdir;
+
+def arrowdir(expr hlen,a,theta,len) =
+ arrowpath (hlen)
+ mklinedir (a, theta, len);
+enddef;
+
+% gt - mkarcth makes an arc path with
+% given center, radius "rad", initial
+% angle "frtheta", and final angle
+% "totheta".
+
+save mkarcth;
+
+vardef mkarcth (expr center,
+ frtheta, totheta, rad) =
+ save from;
+ pair from;
+ from := center + rad * (dir frtheta);
+ mkarc (center, from, totheta-frtheta)
+enddef;
+
+% gt - arcth now uses mkarcth.
+
+save arcth;
+
+def arcth(expr center,
+ frtheta,totheta,rad) =
+ draw mkarcth (center, frtheta,
+ totheta, rad)
+ transformed ztr;
+enddef;
+
+% gt - arcth now uses mkarcth
+% and arrowpath.
+
+save arctharrow;
+
+def arctharrow(expr hlen,center,
+ frtheta,totheta,rad) =
+ arrowpath (hlen)
+ mkarcth (center, frtheta,
+ totheta, rad);
+enddef;
+
+% gt - mkwedge makes a wedge-shaped path
+% with apex at "center", radius "rad",
+% initial angle "frtheta", and final angle
+% "totheta".
+
+save mkwedge;
+
+vardef mkwedge (expr center, frtheta, totheta, rad) =
+ center -- mkarcth (from, frtheta, totheta, rad)
+ -- cycle
+enddef;
+
+% gt - wedge draws a sector of a circle.
+
+save wedge;
+
+def wedge (expr center, frtheta, totheta, rad) =
+ draw mkwedge (center, frtheta, totheta, rad)
+ transformed ztr;
+enddef;
+
+% gt - wedgeshade now uses mkwedge and shade.
+
+save wedgeshade;
+
+def wedgeshade (expr sp, center,
+ frtheta, totheta, rad) =
+ shade (sp) mkwedge (center, frtheta, totheta, rad);
+enddef;
+
+% gt - drawshadewedge draws and shades a wedge.
+
+save drawshadewedge;
+
+def drawshadewedge (expr sp, center,
+ frtheta, totheta, rad) =
+ draw mkwedge (center, frtheta, totheta, rad)
+ transformed ztr;
+ shade (sp) mkwedge (center, frtheta, totheta, rad);
+enddef;
+
+% curves
+
+% gt - watch out for that "text containing a local
+% variable's name" conflict! I dearly wish that
+% weren't a danger.
+% Perhaps it's not so likely at the level of "mkcurve",
+% as the "mk" macros are often fed numeric constants.
+
+save mkcurve;
+
+vardef mkcurve(expr smooth,cyclic)
+ (text t) =
+ save n_, p_;
+ pair p_[];
+ textpairs (t) (p_, n_);
+ mkpath(smooth,cyclic,n_,p_)
+enddef;
+
+save curve;
+
+def curve(expr smooth,cyclic)
+ (text t) =
+ draw mkcurve(smooth,cyclic,t)
+ transformed ztr;
+enddef;
+
+% gt - curvedarrow now uses arrowpath.
+
+save curvedarrow;
+
+def curvedarrow(expr smooth,hlen)
+ (text t) =
+ arrowpath (hlen)
+ mkcurve (smooth, false, t);
+enddef;
+
+% shading of cyclic curves
+
+% gt - cycleshade now uses shade.
+
+save cycleshade;
+
+def cycleshade(expr sp,smooth)(text t) =
+ shade (sp) mkcurve (smooth,true,t);
+enddef;
+
+% gt - interpolated splines with controls.
+
+% gt - mkipath uses the interpolation points,
+% p[], and the left and right control points,
+% l[] and r[].
+% Observe that for cyclic I-splines, l[n] is
+% used, not l1, though they are equal; this
+% simplifies the algorithm.
+
+save mkipath;
+
+vardef mkipath (expr closed, n)
+ (suffix p, l, r) =
+ for i=1 upto n-1:
+ p[i]..controls r[i] and l[i+1]..
+ endfor
+ if closed:
+ cycle
+ else:
+ p[n]
+ fi
+enddef;
+
+% gt - mkisplineA uses the I-spline data,
+% in the order that Fig 2.1 gives them,
+% points line pl and control line cl,
+% stores them in p[], l[] and r[],
+% then calls mkipath.
+%
+% pl should have the form:
+% (x1,y1) ... (xn,yn)
+% and cl the form:
+% (lx1,ly1) (rx1,ry1) ... (lxn,lyn) (rxn,ryn)
+% which reflect how Fig outputs its data.
+%
+% Don't feed it the "9999 9999", please!
+%
+% Perhaps the input should be massaged by a
+% preprocessor program (e.g. in C), to separate
+% the initially interleaved left and right control
+% points, before being given to graphbase?
+% That would simplify mkisplineA, and run faster.
+
+save mkisplineA;
+
+vardef mkisplineA (expr closed)
+ (text pl) (text cl) =
+ save p, l, r, n, i, isleft;
+ pair p[], l[], r[];
+ boolean isleft;
+ textpairs (pl) (p, n);
+ i := 1;
+ isleft := true;
+ for b=cl:
+ if isleft:
+ l[i] := b;
+ isleft := false;
+ else:
+ r[i] := b;
+ i := i+1;
+ isleft := true;
+ fi;
+ endfor;
+ mkipath (closed, n, p, l, r)
+enddef;
+
+% gt - mkisplineB uses the points line,
+% and the separated left and right controls.
+%
+% See how much simpler this is than
+% mkisplineA.
+
+save mkisplineB;
+
+vardef mkisplineB (expr closed)
+ (text pl) (text lc) (text rc) =
+ save p, l, r, n, i;
+ pair p[], l[], r[];
+ textpairs (pl) (p, n);
+ textpairs (lc) (l, i);
+ textpairs (rc) (r, i);
+ mkipath (closed, n, p, l, r)
+enddef;
+
+% gt - the usual variations.
+%
+% These use mkisplineA. I'd prefer
+% mkisplineB.
+
+% draw an interpolated spline,
+% with points line pl and interleaved
+% control line cl.
+
+save ispline;
+
+def ispline (expr closed)
+ (text pl) (text cl) =
+ draw mkisplineA (closed) (pl) (cl)
+ transformed ztr;
+enddef;
+
+save isplinearrow;
+
+def isplinearrow (expr hlen, closed)
+ (text pl) (text cl) =
+ arrowpath (hlen)
+ mkisplineA (closed) (pl) (cl);
+enddef;
+
+% gt - isplineshade assumes that the
+% I-spline is closed.
+
+save isplineshade;
+
+def isplineshade (expr sp)
+ (text pl) (text cl) =
+ shade (sp)
+ mkisplineA (true) (pl) (cl);
+enddef;
+
+% functions
+
+% gt - better be on the safe side with
+% the function text, so use "_" on local
+% variables in "mkfcn".
+
+save mkfcn;
+
+vardef mkfcn(expr smooth,bmin,bmax,bst)
+ (suffix bv)(text fcnpr) =
+ save p_, i_;
+ pair p_[];
+ i_ := 0;
+ for bv=bmin step bst
+ until bmax+(bst/2):
+ p_[incr i_] := fcnpr;
+ endfor;
+ mkpath (smooth, false, i_ , p_)
+enddef;
+
+save function;
+
+def function(expr smooth,xmin,xmax,st)
+ (text fx) =
+ draw mkfcn (smooth, xmin, xmax, st,
+ x, (x,fx))
+ transformed ztr;
+enddef;
+
+save parafcn;
+
+def parafcn(expr smooth,tmin,tmax,st)
+ (text ft) =
+ draw mkfcn (smooth, tmin, tmax, st,
+ t, ft)
+ transformed ztr;
+enddef;
+
+% gt - mksfn constructs a path from
+% two functions and the verticals
+% at either side.
+%
+% mksfn is used by shadefcn.
+
+save mksfn;
+
+vardef mksfn (expr smooth, xmin, xmax, st)
+ (text fcni) (text fcnii) =
+ mkfcn(smooth,xmin,xmax,st,x,(x,fcni))
+ --
+ reverse
+ mkfcn(smooth,xmin,xmax,st,x,(x,fcnii))
+ -- cycle
+enddef;
+
+% gt - description:
+% shadefcn shades between two functions over
+% the range xmin to xmax, stepping by st,
+% with dot spacing sp.
+% it does not draw the functions.
+
+% gt - shadefcn now uses mksfn.
+% I don't see the connection between the dot
+% spacing sp and the function step size st.
+
+save shadefcn, st;
+
+def shadefcn(expr sp, xmin, xmax)
+ (text fcni)(text fcnii) =
+ st := unxconv (sp);
+ shade (sp)
+ mksfn (false, xmin, xmax, st) (fcni) (fcnii);
+enddef;
+
+% gt - drawshadefcn draws both functions fcni
+% and fcnii, and shades between them.
+
+save drawshadefcn;
+
+def drawshadefcn (expr sp, smooth, xmin, xmax, st)
+ (text fcni) (text fcnii) =
+ function (smooth, xmin, xmax, st) (fcni);
+ function (smooth, xmin, xmax, st) (fcnii);
+ shadefcn (sp, xmin, xmax) (fcni) (fcnii);
+enddef;
+
+enddef; % mfpicenv
+
+def endmfpicenv =
+ endgroup;
+enddef;
+
+
+% end graphbase.mf
diff --git a/graphics/fig2mfpic/mfpic.tex b/graphics/fig2mfpic/mfpic.tex
new file mode 100644
index 0000000000..2c41e258a3
--- /dev/null
+++ b/graphics/fig2mfpic/mfpic.tex
@@ -0,0 +1,422 @@
+%%%
+%%% File: mfpic.tex
+%%% Version: 0.25
+%%%
+%%% Principal Author: Thomas Leathrum
+%%% Assistants: Bryan Green, Geoffrey Tobin
+%%%
+
+% preliminary version of macros
+% save catcode, as Michael Downes of AMS recommends.
+\chardef\oldatcatcode=\catcode`@
+\catcode`@=11 % letter
+\def\@wout{\immediate\write16\relax}
+\@wout {}
+\@wout
+ {mfpic version 0.25 - 19:20 GMT +10:00 Wed 13 Oct 93}
+\@wout
+ {fixes for TFM, LaTeX (picture), fractions, catcode, sharp.}
+\@wout
+ {tests for bad label options, mf char codes out of range (0 - 255).}
+\@wout
+ {localised short-range declarations.}
+\@wout {}
+% test whether mfpic is used in LaTeX.
+\newif\if@inlatex
+% idea from _The TeXbook_ (1986), p. 384:
+% \@mfundefined must remain undefined.
+\ifx\picture\@mfundefined
+ \@inlatexfalse
+ \@wout {MFPIC: not in latex}
+\else
+ \@inlatextrue
+ \@wout {MFPIC: in latex}
+\fi
+\@wout {}
+% local declarations
+\wlog {MFPIC: local declarations}
+\newwrite\@outx
+\newbox\@labeledgraph
+\newdimen\@graphwd
+\newcount\@code
+% dimension parameters
+\wlog {}
+\wlog {MFPIC: dimension parameters}
+\newdimen\mfpicunit
+\newdimen\pointsize
+\newdimen\shadespace
+\newdimen\headlen
+\newdimen\axisheadlen
+\newdimen\hashlen
+\newdimen\dashlen
+\newdimen\dashspace
+% default dimension settings
+\mfpicunit=1pt
+\pointsize=2pt
+\shadespace=1pt
+\headlen=3pt
+\axisheadlen=5pt
+\hashlen=4pt
+\dashlen=4pt
+\dashspace=4pt
+% standard setting macros
+\def\darkershade{%
+ \multiply\shadespace by 5
+ \divide\shadespace by 6}
+\def\lightershade{%
+ \multiply\shadespace by 6
+ \divide\shadespace by 5}
+\def\dashlineset{%
+ \dashlen=4pt
+ \dashspace=4pt}
+\def\dotlineset{%
+ \dashlen=1pt
+ \dashspace=2pt}
+% direct output to Metafont file
+% only valid b/w \open- and \close- graphsfile.
+\def\mfcmd#1{%
+ \immediate\write\@outx{#1}}
+% pen size setting
+\def\@pickup{%
+ \mfcmd{pickup pencircle scaled penwd;}}
+\def\pen#1{%
+ \mfcmd{interim penwd:=#1;}
+ \@pickup}
+% arrowhead shape setting
+\def\headshape#1#2{%
+ \mfcmd{interim hdwdr:=#1;
+ interim hdten:=#2;}}
+% open and close file
+\def\opengraphsfile#1%
+{%
+ \@code33 % first graphic is `!'
+ \immediate\openout\@outx=#1.mf
+ \batchmode
+ \font\@graph=#1
+ \errorstopmode
+ \immediate\write16 {}
+ \ifx\@graph\nullfont
+ \font\@graph=dummy
+ \immediate\write16
+ {MFPIC: ** Graphic's TFM file #1.tfm not found. **}
+ \immediate\write16
+ {MFPIC: ** Process #1.mf! Then reprocess this file. **}
+ \immediate\write16
+ {MFPIC: `Missing character' messages will log the graphic characters.}
+ \else
+ \immediate\write16
+ {MFPIC: Graphic's TFM file found.}
+ \immediate\write16
+ {MFPIC: Nevertheless, if PK font's changed, reprocess #1.mf.}
+ \immediate\write16
+ {MFPIC: If TFM's changed, reprocess #1.mf, and then this TeX file.}
+ \fi
+ \immediate\write16 {}
+ \mfcmd{mag:=\number\mag/1000;}
+ \mfcmd{input graphbase.mf;}
+ % set global defaults
+ \mfcmd{mfpicenv;}
+ \headshape{1}{1}
+ \pen{0.5 pt}%
+}% -- end \opengraphsfile
+\def\closegraphsfile
+{%
+ \mfcmd{}
+ \mfcmd{endmfpicenv;}
+ \mfcmd{end.}
+ \immediate\closeout\@outx
+}% -- end \closegraphsfile
+% a useful macro not in plain TeX.
+\def\mf@gobble#1{}
+% for output of # (c/o Donald Arseneau).
+\def\mf@s{\expandafter\mf@gobble\string\#}
+% beginning mfpicture environment
+\def\@mfpicture#1#2#3#4#5#6{%
+ % dimension conversion: ##1 is a dimen.
+ \def\@xconv##1{%
+ \global\advance ##1 by -#3 \mfpicunit
+ \global ##1 = #1 ##1}
+ \def\@yconv##1{%
+ \global\advance ##1 by -#5 \mfpicunit
+ \global ##1 = -#2 ##1}
+ % set up TeX
+ \global\font\@tcurr=\fontname\font
+ \relax
+ \bgroup
+ \nullfont
+ \global\@graphwd = #4 \mfpicunit
+ \@xconv\@graphwd
+ \global\setbox\@labeledgraph=\vtop
+ {\hbox{\@graph\char\@code}}
+ % set up Metafont file
+ \mfcmd{}
+ \mfcmd{unitlen:=\the\mfpicunit\mf@s;}
+ \mfcmd{xscale:=#1*unitlen; yscale:=#2*unitlen;
+ xneg:=#3; xpos:=#4;
+ yneg:=#5; ypos:=#6;}
+ \mfcmd{beginchar (\the\@code,
+ (xpos-xneg)*xscale,
+ (ypos-yneg)*yscale,
+ 0);}
+ \mfcmd{setztr;}
+ \@pickup
+ % metafont drawing macros
+ % points, lines, and arrows
+ \def\point##1{%
+ \mfcmd{pointd(##1, \the\pointsize);}}
+ \def\line##1{%
+ \mfcmd{line(##1);}}
+ \def\arrow##1{%
+ \mfcmd{arrow(##1, \the\headlen);}}
+ \def\dottedline##1{%
+ \mfcmd{dottedline(##1, \the\dashlen,
+ \the\dashspace);}}
+ \def\dottedarrow##1{%
+ \mfcmd{dottedarrow(##1, \the\dashlen,
+ \the\dashspace, \the\headlen);}}
+ % axes and axis marks
+ \def\axes
+ {\mfcmd{axes(\the\axisheadlen);}}
+ \def\xmarks##1{%
+ \mfcmd{xmarks(\the\hashlen, ##1);}}
+ \def\ymarks##1{%
+ \mfcmd{ymarks(\the\hashlen, ##1);}}
+ % polygons
+ \def\rect##1{%
+ \mfcmd{rect(##1);}}
+ \def\dottedrect##1{%
+ \mfcmd{dottedrect(##1,
+ \the\dashlen, \the\dashspace);}}
+ \def\block##1{%
+ \mfcmd{block(##1);}}
+ \def\rectshade##1{%
+ \mfcmd{rectshade(\the\shadespace, ##1);}}
+ \def\polygon##1{%
+ \mfcmd{curve(false, true, ##1);}}
+ \def\polyshade##1{%
+ \mfcmd{cycleshade(\the\shadespace,
+ false, ##1);}}
+ \def\polyfill##1{%
+ \mfcmd{cycleshade(0, false, ##1);}}
+ % circles and ellipses
+ \def\circle##1{%
+ \mfcmd{circle(##1);}}
+ \def\ellipse##1{%
+ \mfcmd{ellipse(##1, 0);}}
+ \def\rotatedellipse##1{%
+ \mfcmd{ellipse(##1);}}
+ \def\circshade##1{%
+ \mfcmd{circshade(\the\shadespace, ##1);}}
+ \def\ellshade##1{%
+ \mfcmd{ellshade(\the\shadespace, ##1, 0);}}
+ \def\rotatedellshade##1{%
+ \mfcmd{ellshade(\the\shadespace, ##1);}}
+ \def\cdisk##1{%
+ \mfcmd{circshade(0, ##1);}}
+ \def\edisk##1{%
+ \mfcmd{ellshade(0, ##1, 0);}}
+ \def\rotatededisk##1{%
+ \mfcmd{ellshade(0, ##1);}}
+ % circular arcs
+ \def\arc##1{%
+ \mfcmd{arc(##1);}}
+ \def\arcarrow##1{%
+ \mfcmd{arcarrow(\the\headlen, ##1);}}
+ \def\arcshade##1{%
+ \mfcmd{arcshade(\the\shadespace, ##1);}}
+ \def\arcfill##1{%
+ \mfcmd{arcshade(0, ##1);}}
+ % polar coordinates
+ \def\linedir##1{%
+ \mfcmd{linedir(##1);}}
+ \def\arrowdir##1{%
+ \mfcmd{arrowdir(\the\headlen, ##1);}}
+ \def\arcth##1{%
+ \mfcmd{arcth(##1);}}
+ \def\arctharrow##1{%
+ \mfcmd{arctharrow(\the\headlen, ##1);}}
+ \def\wedgeshade##1{%
+ \mfcmd{wedgeshade(\the\shadespace, ##1);}}
+ \def\wedgefill##1{%
+ \mfcmd{wedgeshade(0, ##1);}}
+ % curves
+ \def\curve##1{%
+ \mfcmd{curve(true, false, ##1);}}
+ \def\polyline##1{%
+ \mfcmd{curve(false, false, ##1);}}
+ \let\polycurve=\polyline
+ \def\curvedarrow##1{%
+ \mfcmd{curvedarrow(true,
+ \the\headlen, ##1);}}
+ \def\polyarrow##1{%
+ \mfcmd{curvedarrow(false,
+ \the\headlen, ##1);}}
+ % cyclic curves
+ \def\cyclic##1{%
+ \mfcmd{curve(true, true, ##1);}}
+ \def\cycleshade##1{%
+ \mfcmd{cycleshade(\the\shadespace,
+ true, ##1);}}
+ \def\cyclefill##1{%
+ \mfcmd{cycleshade(0, true, ##1);}}
+ % functions
+ \def\function##1{%
+ \mfcmd{function(true, ##1);}}
+ \def\polyfunction##1{%
+ \mfcmd{function(false, ##1);}}
+ \def\parafcn##1{%
+ \mfcmd{parafcn(true, ##1);}}
+ \def\polyparafcn##1{%
+ \mfcmd{parafcn(false, ##1);}}
+ \def\shadefcn##1##2##3{%
+ \mfcmd{shadefcn(\the\shadespace, ##1)
+ (##2) (##3);}}
+ % labels
+ \def\@mflabel[##1##2]##3##4##5{%
+ % compute width of graph with label
+ % and reset size if necessary
+ {% local env. for \@btemp.
+ \chardef\@btemp=255\relax
+ \setbox\@btemp=\hbox{\@tcurr##5}
+ {% local env. for \@xtemp.
+ \dimendef\@xtemp=0\relax
+ \@xtemp = ##3 \mfpicunit
+ \@xconv\@xtemp
+ \advance\@xtemp by\wd\@btemp
+ \ifdim\@xtemp>\@graphwd
+ \global\@graphwd=\@xtemp\fi
+ }% end local env.
+ % set label onto picture
+ \global\setbox\@labeledgraph=
+ \vtop{\unvbox\@labeledgraph
+ \vbox to 0 pt{%
+ \if##1t\relax\else
+ \if##1c\kern-0.5\ht\@btemp\else
+ \if##1b\kern-\ht\@btemp\else
+ \immediate\write16 {}
+ \immediate\write16
+ {MFPIC: label: vertical option `##1' unknown, will treat as `b'}
+ \immediate\write16 {}
+ \kern-\ht\@btemp
+ \fi\fi\fi
+ {% local env. for \@ytemp.
+ \dimendef\@ytemp=0\relax
+ \@ytemp = ##4 \mfpicunit
+ \@yconv\@ytemp
+ \kern\@ytemp
+ }% end local env.
+ \hbox{%
+ \if##2l\relax\else
+ \if##2c\kern-0.5\wd\@btemp\else
+ \if##2r\kern-\wd\@btemp\else
+ \immediate\write16 {}
+ \immediate\write16
+ {MFPIC: label: horizontal option `##2' unknown, will treat as `l'}
+ \immediate\write16 {}
+ \fi\fi\fi
+ {% local env. for \@xtemp.
+ \dimendef\@xtemp=0\relax
+ \@xtemp = ##3 \mfpicunit
+ \@xconv\@xtemp
+ \kern\@xtemp
+ }% end local env.
+ \box\@btemp}% -- end \hbox
+ \vss}% -- end \vbox
+ \nointerlineskip}% -- end \vtop
+ }% end local env.
+ }% -- end \@mflabel
+ \def\@labeldefault{\@mflabel[bl]}
+ \def\@dolabel{%
+ \if[\@nchr\expandafter\@mflabel
+ \else\expandafter\@labeldefault\fi}
+ \def\mflabel{\futurelet\@nchr\@dolabel}
+ % captions
+ % \@docaption is called by \endmfpicture
+ \def\@docaption{}
+ \def\mfcaption##1{%
+ % redefine to set caption
+ \def\@docaption{%
+ % allow forced line breaks
+ \def\\{%
+ \global\font\@curr=\fontname\font
+ \relax\egroup \hbox\bgroup\@curr}
+ % compute adjustments to center
+ \chardef\@btemp=255\relax
+ \setbox\@btemp=\vbox
+ {\hbox{\@tcurr##1}}
+ \ifdim\wd\@btemp>\@graphwd
+ \global\@graphwd=\wd\@btemp\fi
+ % set caption onto picture
+ \global\setbox\@labeledgraph=\vbox
+ {\unvbox\@labeledgraph
+ \medskip\hbox
+ {\noindent
+ \dimendef\@centerskip=0\relax
+ \@centerskip=\@graphwd
+ \advance\@centerskip -\wd\@btemp
+ \divide\@centerskip by 2\relax
+ \kern\@centerskip
+ \box\@btemp
+ }% -- end \hbox
+ \vss
+ }% -- end \vbox
+ }% -- end \@docaption
+ }% -- end \mfcaption
+ % backward compatibility:
+ \let\label=\mflabel
+ \let\caption=\mfcaption
+ % end of object macros
+}% -- end \@mfpicture
+% setting up optional arguments
+\def\@piciii#1#2#3#4{%
+ \@mfpicture{\@param}{\@param}%
+ {#1}{#2}{#3}{#4}}
+\def\@picii[#1]#2#3#4#5{%
+ \@mfpicture{\@param}{#1}%
+ {#2}{#3}{#4}{#5}}
+\def\@pici{%
+ \if[\@nchr\expandafter\@picii
+ \else\expandafter\@piciii\fi}
+\def\mfpicture [#1]{%
+ {% local env. for \@outrange.
+ \def\@outrange {%
+ \immediate\write16 {}
+ \immediate\write16
+ {MFPIC: ** Sorry, mfpic makes characters between 0 and 255, inclusive;}
+ \immediate\write16
+ {MFPIC: ** if you want more, then I suggest you start another graphics font;}
+ \immediate\write16
+ {MFPIC: * in the meantime mfpic will use the dummy font for new graphics.}
+ \immediate\write16 {}
+ \font\@graph=dummy\relax
+ }% -- end \@outrange
+ \ifx \@code < 0 \@outrange \else
+ \ifx \@code > 255 \@outrange \fi\fi
+ }% end local env.
+ \def\@param{#1}%
+ \futurelet\@nchr\@pici
+}% -- end \mfpicture
+% ending mfpicture environment:
+\def\endmfpicture{%
+ \mfcmd{endchar;}
+ \@docaption\egroup
+ \hbox to\@graphwd{%
+ \box\@labeledgraph\hss}
+ \global\advance\@code1
+}% -- end \endmfpicture
+%
+% Abbreviations:
+\let\mfpic=\mfpicture
+\let\endmfpic=\endmfpicture
+%
+\if@inlatex
+ \relax
+\else % NOT in LaTeX.
+ % backward compatibility:
+ \let\picture=\mfpicture
+ \let\endpicture=\endmfpicture
+\fi
+% restore catcode.
+\catcode`@=\oldatcatcode
+%
+% end mfpic.tex
diff --git a/graphics/fig2mfpic/tidied.fig b/graphics/fig2mfpic/tidied.fig
new file mode 100644
index 0000000000..ec311b0f5c
--- /dev/null
+++ b/graphics/fig2mfpic/tidied.fig
@@ -0,0 +1,31 @@
+#FIG 2.1
+80 2
+5 1 0 1 -1 0 0 0 0.000 0 0 0 119.658 197.289 114 164 149 214 99 224
+1 3 0 1 -1 0 0 0 0.000 1 0.000 159 74 27 27 159 74 186 101
+1 4 0 1 -1 0 0 0 0.000 1 0.000 354 74 30 30 324 74 384 74
+1 1 0 1 -1 0 0 0 0.000 1 0.000 224 64 61 21 224 64 284 44
+1 2 0 1 -1 0 0 0 0.000 1 0.000 234 126 30 12 204 114 264 139
+2 3 0 1 -1 0 0 0 0.000 -1 0 0
+ 404 114 404 164 474 169 439 124 529 129 529 94 449 94 439 94 429 109 399 119 404 114 9999 9999
+2 2 0 1 -1 0 0 0 0.000 0 0 0
+ 124 94 124 49 29 49 29 94 124 94 9999 9999
+2 4 0 1 -1 0 0 0 0.000 7 0 0
+ 99 159 99 109 29 109 29 159 99 159 9999 9999
+2 3 0 1 -1 0 0 0 0.000 0 0 0
+ 59 189 59 160 34 145 9 159 9 188 34 203 59 189 9999 9999
+2 5 0 1 -1 0 0 0 0.000 0 0 0
+ 0 <empty>
+ 199 169 244 169 244 204 199 204 199 169 9999 9999
+2 1 0 1 -1 0 0 0 0.000 -1 0 0
+ 644 69 599 109 664 124 619 139 614 139 614 144 669 159 669 159 579 164 569 164 574 179 614 204 609 199 9999 9999
+3 1 0 1 -1 0 0 0 0.000 0 0
+ 154 114 109 144 184 154 174 134 114 119 124 114 154 114 9999 9999
+3 3 0 1 -1 0 0 0 0.000 0 0
+ 449 39 414 54 434 89 479 94 469 64 419 64 394 59 404 29 434 49 454 64 454 49 449 39 9999 9999
+ 452.965 40.452 435.497 34.054 418.429 40.783 409.311 67.992 424.311 82.636 444.883 96.148 470.562 104.437 484.893 86.710 477.507 70.132 455.549 54.305 430.468 65.136 413.152 63.421 398.658 67.026 388.223 49.045 394.014 32.426 415.386 25.093 427.288 44.252 438.654 52.292 448.500 66.750 457.300 62.350 454.836 52.541 453.377 46.361 452.965 40.452 435.497 34.054
+3 2 0 1 -1 0 0 0 0.000 0 0
+ 524 34 509 59 524 64 574 69 549 99 514 89 509 74 539 69 549 69 599 54 539 49 524 49 479 44 474 44 479 39 9999 9999
+ 0.000 0.000 510.139 45.692 506.389 51.942 510.888 64.103 520.425 63.235 535.361 66.430 569.096 57.009 577.811 78.319 560.827 95.356 537.976 102.397 521.660 96.334 510.673 85.814 506.086 78.840 514.605 64.690 532.038 69.576 541.289 68.811 546.688 69.339 561.067 67.229 599.556 59.317 598.359 47.867 552.733 49.571 535.579 48.858 527.424 49.190 513.663 48.427 489.337 44.573 477.858 43.937 474.403 44.972 473.573 42.969 474.823 41.719 0.000 0.000
+3 0 0 1 -1 0 0 0 0.000 0 0
+ 359 119 294 119 334 149 369 169 304 169 294 149 9999 9999
+4 0 0 12 0 -1 0 0.000 4 11 71 289 209 $Hello there!$
diff --git a/graphics/fig2mfpic/various.fig b/graphics/fig2mfpic/various.fig
new file mode 100644
index 0000000000..99e043a11a
--- /dev/null
+++ b/graphics/fig2mfpic/various.fig
@@ -0,0 +1,40 @@
+#FIG 2.1
+80 2
+5 1 0 1 -1 0 0 0 0.000 0 0 0 119.658 197.289 114 164 149 214 99 224
+1 3 0 1 -1 0 0 0 0.000 1 0.000 159 74 27 27 159 74 186 101
+1 4 0 1 -1 0 0 0 0.000 1 0.000 354 74 30 30 324 74 384 74
+1 1 0 1 -1 0 0 0 0.000 1 0.000 224 64 61 21 224 64 284 44
+1 2 0 1 -1 0 0 0 0.000 1 0.000 234 126 30 12 204 114 264 139
+7 1 0 0 0 0 1 -1 0 0.000 0.000 0 0 389 194 30 8 1
+7 2 0 0 0 0 1 -1 0 0.000 0.000 0 0 399 209 15 14 1
+7 3 0 0 0 0 1 -1 0 0.000 0.000 0 0 444 194 15 30 1
+7 7 1 0 0 0 1 -1 0 0.000 0.000 0 0 494 189 15 30 1
+7 4 0 0 0 0 1 -1 0 0.000 0.000 0 0 544 189 25 18 1
+7 9 0 0 0 0 1 -1 0 0.000 0.000 0 0 479 219 50 25 1
+7 8 0 0 0 0 1 -1 0 0.000 0.000 0 0 549 219 5 5 1
+7 5 0 0 0 0 1 -1 0 0.000 0.000 0 0 574 219 12 14 1
+7 6 1 1 2 0 1 -1 0 0.000 0.000 0 0 644 219 50 30 1
+2 3 0 1 -1 0 0 0 0.000 -1 0 0
+ 404 114 404 164 474 169 439 124 529 129 529 94 449 94 439 94 429 109 399 119 404 114 9999 9999
+2 2 0 1 -1 0 0 0 0.000 0 0 0
+ 124 94 124 49 29 49 29 94 124 94 9999 9999
+2 4 0 1 -1 0 0 0 0.000 7 0 0
+ 99 159 99 109 29 109 29 159 99 159 9999 9999
+2 3 0 1 -1 0 0 0 0.000 0 0 0
+ 59 189 59 160 34 145 9 159 9 188 34 203 59 189 9999 9999
+2 5 0 1 -1 0 0 0 0.000 0 0 0
+ 0 <empty>
+ 199 169 244 169 244 204 199 204 199 169 9999 9999
+2 1 0 1 -1 0 0 0 0.000 -1 0 0
+ 644 69 599 109 664 124 619 139 614 139 614 144 669 159 669 159 579 164 569 164 574 179 614 204 609 199 9999 9999
+3 1 0 1 -1 0 0 0 0.000 0 0
+ 154 114 109 144 184 154 174 134 114 119 124 114 154 114 9999 9999
+3 3 0 1 -1 0 0 0 0.000 0 0
+ 449 39 414 54 434 89 479 94 469 64 419 64 394 59 404 29 434 49 454 64 454 49 449 39 9999 9999
+ 452.965 40.452 435.497 34.054 418.429 40.783 409.311 67.992 424.311 82.636 444.883 96.148 470.562 104.437 484.893 86.710 477.507 70.132 455.549 54.305 430.468 65.136 413.152 63.421 398.658 67.026 388.223 49.045 394.014 32.426 415.386 25.093 427.288 44.252 438.654 52.292 448.500 66.750 457.300 62.350 454.836 52.541 453.377 46.361 452.965 40.452 435.497 34.054
+3 2 0 1 -1 0 0 0 0.000 0 0
+ 524 34 509 59 524 64 574 69 549 99 514 89 509 74 539 69 549 69 599 54 539 49 524 49 479 44 474 44 479 39 9999 9999
+ 0.000 0.000 510.139 45.692 506.389 51.942 510.888 64.103 520.425 63.235 535.361 66.430 569.096 57.009 577.811 78.319 560.827 95.356 537.976 102.397 521.660 96.334 510.673 85.814 506.086 78.840 514.605 64.690 532.038 69.576 541.289 68.811 546.688 69.339 561.067 67.229 599.556 59.317 598.359 47.867 552.733 49.571 535.579 48.858 527.424 49.190 513.663 48.427 489.337 44.573 477.858 43.937 474.403 44.972 473.573 42.969 474.823 41.719 0.000 0.000
+3 0 0 1 -1 0 0 0 0.000 0 0
+ 359 119 294 119 334 149 369 169 304 169 294 149 9999 9999
+4 0 0 12 0 -1 0 0.000 4 11 71 289 209 $Hello there!$