1/* Hello, Emacs, this is -*-C-*- */
2
3/* GNUPLOT -- mif.trm */
4
5/*[
6 * Copyright 1992, 1993, 1998, 2004
7 *
8 * Permission to use, copy, and distribute this software and its
9 * documentation for any purpose with or without fee is hereby granted,
10 * provided that the above copyright notice appear in all copies and
11 * that both that copyright notice and this permission notice appear
12 * in supporting documentation.
13 *
14 * Permission to modify the software is granted, but not the right to
15 * distribute the complete modified source code.  Modifications are to
16 * be distributed as patches to the released version.  Permission to
17 * distribute binaries produced by compiling modified sources is granted,
18 * provided you
19 *   1. distribute the corresponding source modifications from the
20 *    released version in the form of a patch file along with the binaries,
21 *   2. add special version identification to distinguish your version
22 *    in addition to the base release version number,
23 *   3. provide your name and address as the primary contact for the
24 *    support of your modified version, and
25 *   4. retain our contact information in regard to use of the base
26 *    software.
27 * Permission to distribute the released version of the source code along
28 * with corresponding source modifications in the form of a patch file is
29 * granted with same provisions 2 through 4 for binary distributions.
30 *
31 * This software is provided "as is" without express or implied warranty
32 * to the extent permitted by applicable law.
33]*/
34
35/*
36 * This file is included by ../term.c.
37 *
38 * This terminal driver was developed for
39 *      gnuplot for unix version 3.0 (patchlevel 1)
40 *      gnuplot for unix version 3.2 (patchlevel 2)
41 *
42 * This terminal driver supports:
43 *      Frame Maker MIF format version 3.00
44 *
45 * Options for this terminal driver (set terminal mif [options]):
46 *      colour /        Draw primitives with line types >= 0 in colour (sep. 2-7)
47 *      monochrome      Draw primitives in black (sep. 0)
48 *
49 *      polyline /      Draw lines as continuous curves
50 *      vectors         Draw lines as collections of vectors
51 *
52 *      help / ?        Print short usage description on stderr
53 *
54 * Properties for this terminal driver:
55 *     -Gnuplot size of worksheet:              MIF_XMAX * MIF_YMAX
56 *     -Unit in MIF output:                     cm
57 *     -Plot primitives with the same pen will
58 *      be grouped in the same MIF group.
59 *     -Plot primitives with line types >= 0
60 *      will as default be drawn in colour.
61 *     -Lines are plotted as collections of
62 *      vectors, or as continuous lines (default)
63 *     -Plot primitives in a plot will be in a
64 *      Frame in MIF. Several plot Frames will
65 *      be collected in one large Frame.
66 *     -Point size of MIF output characters:    MIF_PSIZE
67 *     -Used font for MIF output characters:    Times
68 *     -Supports vertical text
69 *     -points and dots as characters
70 *     -character formats for TextLines
71 *
72 * AUTHORS:
73 *      Olof Franksson, Physics IV, KTH, S-100 44 Stockholm, Sweden
74 *
75 * NEW TERMINAL FORMAT:  David C. Schooley
76
77 * COMMENTS:
78 *      Send comments and/or suggestions to olof@fysik4.kth.se
79 *
80 * CHANGES:
81 *	Changed to new terminal format 9/29/95		schooley@ee.gatech.edu
82 *      Changed order of routine declarations.          olof@fysik4.kth.se
83 *      Changed mechanism for pen pattern selection.    kssingvo@immd4.informatik.uni-erlangen.de
84 *      Support for vertical text.                      kssingvo@immd4.informatik.uni-erlangen.de
85 *      Fixed plot bug for "set size XS,YS", XS/YS > 1. olof@fysik4.kth.se
86 *	Support colored text				merritt@u.washington.edu
87 *	Support box fill and pattern fill		merritt@u.washington.edu
88 *
89 */
90
91#include "driver.h"
92
93#ifdef TERM_REGISTER
94register_term(mif)
95#endif
96
97
98
99#ifdef TERM_PROTO
100TERM_PUBLIC void MIF_init(void);
101TERM_PUBLIC void MIF_graphics(void);
102TERM_PUBLIC void MIF_text(void);
103TERM_PUBLIC void MIF_linetype(int linetype);
104TERM_PUBLIC void MIF_move(unsigned int x, unsigned int y);
105TERM_PUBLIC void MIF_vector(unsigned int x, unsigned int y);
106TERM_PUBLIC void MIF_put_text(unsigned int x, unsigned int y, const char *str);
107TERM_PUBLIC int MIF_text_angle(int ang);
108TERM_PUBLIC void MIF_reset(void);
109TERM_PUBLIC void MIF_options(void);
110TERM_PUBLIC int MIF_justify_text(enum JUSTIFY mode);
111TERM_PUBLIC void MIF_point(unsigned int x, unsigned int y, int number);
112TERM_PUBLIC void MIF_boxfill(int style, unsigned int x1, unsigned int y1,
113	    unsigned int width, unsigned int height);
114TERM_PUBLIC void MIF_filled_polygon(int points, gpiPoint* corners);
115
116/** Coordinates **/
117/* The cast to float is not necessary because we are dividing by a float */
118/* On OSK the cast to a float is not allowed in a constant expression which */
119/* is used by the declaration and initialization of mif_line */
120/* Converts gnuplot units to MIF units */
121#define GNP_TO_MIF(P)   ((P) / 1000.0)
122/* Basic unit: 0.01 mm (15cm -> 15*10*100=15000) */
123#define MIF_XMAX 15000
124/* Basic unit: 0.01 mm (10cm -> 10*10*100=10000) */
125#define MIF_YMAX 10000
126
127#define MIF_XLAST (MIF_XMAX - 1)
128#define MIF_YLAST (MIF_YMAX - 1)
129
130static int insert_mif_line(double fx, double fy);
131static int proc_group_id(int group_id);
132static void free_mif_line(void);
133static void put_mif_line(void);
134static void MIF_set_font(const char *);
135static void mif_put_point(unsigned int x, unsigned int y, int np);
136
137#endif
138
139#ifndef TERM_PROTO_ONLY
140#ifdef TERM_BODY
141
142#ifndef cfree
143# define cfree free
144#endif
145
146static struct mif_line {	/* Line point structure specification */
147    float fpos_x;		/* Line point X coordinate */
148    float fpos_y;		/*            Y coordinate */
149    struct mif_line *next;	/* Pointer to next line point */
150    struct mif_line *prev;	/* Pointer to previous line point */
151} mif_line =
152{				/* Current position structure. Adjust for origin. Local for this file. */
153    GNP_TO_MIF(0),
154	GNP_TO_MIF(MIF_YLAST),
155	&mif_line,
156	&mif_line
157};
158
159/** Characters **/
160#define MIF_PSIZE 9		/* Point size of used characters */
161
162#define MIF_VCHAR (MIF_YMAX/31)	/* Distance between rows (a guess) */
163#define MIF_HCHAR (MIF_XMAX/95)	/* Distance between characters (a guess) */
164
165/** Scale marks **/
166#define MIF_VTIC  (MIF_YMAX/150)	/* Size of scale mark (vert) */
167#define MIF_HTIC  (MIF_XMAX/225)	/* Size of scale mark (hor) */
168
169/** Drawing properties **/
170static char mif_justify[64];	/* How to justify the used text */
171static char mif_pen[64], mif_pen_width[64], mif_separation[64];		/* How to plot */
172static char mif_textcolor[64];	/* EAM parallels separation */
173
174static int mif_text_ang = 0;		/* Rotation angle of text */
175
176static int mif_fill_patterns[] = {7,12,3,0,9,8,14,13};
177#define MIF_FILL_SOLID  0
178#define MIF_FILL_NONE  15
179
180#define MIF_NPENS 16		/* Number of MIF pen types */
181static int mif_pentype = 0;	/* Pen type to use. Also used to create groups for graphics */
182#define MIF_PEN_TO_GROUP(P)     ( 1 + (P) )	/* Map pen type to group number. Must be >= 1 */
183
184static int mif_pattern_table[MIF_NPENS] =
185{ /* Table, which pattern should be used for drawing */
186    0,				/* border  */
187    1,				/* not used */
188    2, 3, 4, 8, 12, 13,		/* other lines: functions, data, ... (5 is used for grid; 6,7 is (nearly) invisible) */
189    5,				/* grid */
190    9, 10, 11, 12, 13, 14, 15	/* not used */
191};
192
193/** MIF groups administration **/
194#define MIF_NGROUP_ID           20
195static struct mif_group_id {
196    int group_existence;
197/* This group id should generate a MIF group */
198#define MIF_GROUP_EXISTS        1
199/* This group id should not generate a MIF group */
200#define MIF_GROUP_NOT_EXISTS    0
201
202    int group_id;
203#define MIF_INVALID_GROUP_ID    0	/* An invalid MIF group ID */
204
205} mif_group_id[MIF_NGROUP_ID];	/* List of used group ID:s and corresponding MIF groups existence */
206
207/** Semaphores **/
208static int mif_initialized = 0;	/* != 0 when output is active */
209static int mif_in_frame = 0;	/* != 0 when inside a plot frame */
210static int mif_frameno = -1;	/* Current frame number */
211static int mif_colour = TRUE;	/* == TRUE when colour should be used */
212static int mif_polyline = TRUE;	/* == TRUE when lines are drawn as continuous curves */
213
214struct mpt {			/* point definition structure */
215    int chr;			/* character for point */
216    float x_offset, y_offset;	/* offset for vertical positioning */
217    char *font;			/* font */
218};
219
220static char zgnuplot[] = "ZGnuplot"; /* character formats */
221static char zgnuplotp[] = "ZGnuplotP";
222static char zgnuplotd[] = "ZGnuplotD";
223static const char *mif_font = NULL; /* actual character format */
224
225static struct mpt mpt[POINT_TYPES + 1] =
226{				/* point definition data */
227    {'.', 0.000, 0.005, zgnuplotd, /* dot */ },
228
229    {'G', 0.002, 0.084, zgnuplotp, /* diamond */ },
230    {';', 0.002, 0.084, zgnuplotp, /* plus */ },
231    {'n', 0.002, 0.084, zgnuplotp, /* box */ },
232    {'5', 0.002, 0.084, zgnuplotp, /* X */ },
233    {'s', 0.002, 0.062, zgnuplotp, /* triangle */ },
234    {'K', 0.005, 0.075, zgnuplotp, /* star */ },
235};
236
237/* diamond is offset 0, dot is offset -1 */
238static struct mpt *mif_point = &(mpt[1]);
239
240
241/** Declaration of routine/s for internal use **/
242static int insert_mif_line(double fx, double fy);
243static int proc_group_id(int group_id);
244
245enum MIF_id {
246    MIF_MONOCHROME, MIF_COLOR, MIF_VECTORS, MIF_POLYLINE, MIF_HELP,
247    MIF_OTHER
248};
249
250static struct gen_table MIF_opts[] =
251{
252    { "m$onochrome", MIF_MONOCHROME },
253    { "c$olor", MIF_COLOR },
254    { "c$olour", MIF_COLOR },
255    { "v$ectors", MIF_VECTORS },
256    { "p$olyline", MIF_POLYLINE },
257    { "h$elp", MIF_HELP },
258    { "?$", MIF_HELP },
259    { NULL, MIF_OTHER }
260};
261
262/** Routine/s **/
263
264/* Called when this terminal type is set in order to parse options */
265TERM_PUBLIC void
266MIF_options()
267{
268    while (!END_OF_COMMAND) {
269	switch(lookup_table(&MIF_opts[0],c_token)) {
270	/* Colour options */
271	case MIF_MONOCHROME:
272	    mif_colour = FALSE;
273	    c_token++;
274	    break;
275	case MIF_COLOR:
276	    mif_colour = TRUE;
277	    c_token++;
278	    break;
279	/* Curve options */
280	case MIF_VECTORS:
281	    mif_polyline = FALSE;
282	    c_token++;
283	    break;
284	case MIF_POLYLINE:
285	    mif_polyline = TRUE;
286	    c_token++;
287	    break;
288	/* Short help */
289	case MIF_HELP:
290	case MIF_OTHER:
291	default:
292	    fprintf(stderr, "\
293Usage: set terminal mif [options]\n\
294\toptions:\n\
295\t\tcolour /        Draw primitives with line types >= 0 in colour (sep. 2-7)\n\
296\t\tmonochrome      Draw primitives in black (sep. 0)\n\n\
297\t\tpolyline /      Draw lines as continuous curves\n\
298\t\tvectors         Draw lines as collections of vectors\n\n\
299\t\thelp / ?        Print short usage description on stderr\n");
300	    c_token++;
301	    break;
302	}
303    }
304    sprintf(term_options, "%s %s",
305	    (mif_colour == TRUE) ? "colour" : "monochrome",
306	    (mif_polyline == TRUE) ? "polyline" : "vectors");
307}
308
309/* Deallocate the used line structure elements */
310static void
311free_mif_line()
312{
313    struct mif_line *tline;
314
315    while (mif_line.prev != &mif_line) {
316	/* Unlink */
317	tline = mif_line.prev;
318	mif_line.prev = mif_line.prev->prev;
319	mif_line.prev->next = &mif_line;
320
321	/* Deallocate */
322	free(tline);
323    }
324
325    /* Make sure that the list will be empty */
326    mif_line.prev = &mif_line;
327    mif_line.next = &mif_line;
328}
329
330/* Draw the pending line. Change current position. */
331static void
332put_mif_line()
333{
334    int np, i;
335    struct mif_line *tline;
336
337    /* Process if inside a Frame */
338    if (mif_initialized != 0 && mif_in_frame != 0) {
339
340	/* Count the number of available points */
341	for (tline = mif_line.next, np = 1; tline != &mif_line; tline = tline->next, np++);
342
343	/* Draw line (at least two points) */
344	if (np >= 2) {
345
346	    /* Line preamble */
347	    fprintf(gpoutfile, "\t<PolyLine <GroupID %d> %s %s %s <Fill 15>\n",
348		    MIF_PEN_TO_GROUP(mif_pentype), mif_pen, mif_pen_width, mif_separation);
349
350	    /* Draw the line elements */
351	    fprintf(gpoutfile, "\t\t<NumPoints %d> ", np);
352	    for (i = 0, tline = &mif_line; i < np; i++, tline = tline->next) {
353		if (i % 4 == 0)
354		    fputs("\n\t\t", gpoutfile);
355		fprintf(gpoutfile, "<Point  %.3f %.3f> ",
356			tline->fpos_x, tline->fpos_y);
357	    }
358
359	    /* Line post amble */
360	    fputs("\n\t>\n", gpoutfile);
361
362	    /* Register the used group ID */
363	    proc_group_id(MIF_PEN_TO_GROUP(mif_pentype));
364
365	    /* Avoid to redraw this. The MIF system should remember it. */
366	    mif_pen[0] = '\0';
367	    mif_pen_width[0] = '\0';
368	    mif_separation[0] = '\0';
369
370	    /* Move current position to end of line */
371	    mif_line.fpos_x = mif_line.prev->fpos_x;
372	    mif_line.fpos_y = mif_line.prev->fpos_y;
373
374	    /* Restore the line */
375	    free_mif_line();
376	}
377    }				/* Line processed */
378}
379
380/* Filled box support - Ethan Merritt <merritt@u.washington.edu> */
381TERM_PUBLIC void
382MIF_boxfill(int style, unsigned int x1, unsigned int y1,
383	    unsigned int width, unsigned int height)
384{
385    int fill_pattern;
386
387    int fillpar = style >> 4;
388    style &= 0xf;
389    switch (style) {
390	default:
391	case FS_EMPTY:	fill_pattern = 7;
392			break;
393	case FS_SOLID:	fill_pattern = MIF_FILL_SOLID;
394			break;
395	case FS_PATTERN:fill_pattern = mif_fill_patterns[fillpar % 8];
396			break;
397    }
398
399    /* Object preamble */
400    fprintf(gpoutfile, "\t<Rectangle <GroupID %d> %s\n",
401	    MIF_PEN_TO_GROUP(mif_pentype), mif_separation);
402
403    /* Set fill type */
404    fprintf(gpoutfile, "\t\t<Fill %d>\n", fill_pattern);
405
406    /* Draw the box */
407    fprintf(gpoutfile, "\t\t<ShapeRect %.3f %.3f %.3f %.3f>\n",
408	GNP_TO_MIF(x1), GNP_TO_MIF(MIF_YLAST - (y1+height)),
409	GNP_TO_MIF(width), GNP_TO_MIF(height));
410
411    /* End of object */
412    fputs("\n\t>\n", gpoutfile);
413
414    /* Register the used group ID */
415    proc_group_id(MIF_PEN_TO_GROUP(mif_pentype));
416
417}
418
419/* Filled polygon. Ethan Merritt <merritt@u.washington.edu> */
420TERM_PUBLIC void
421MIF_filled_polygon(int points, gpiPoint* corners)
422{
423    int i;
424
425    /* Object preamble */
426    fprintf(gpoutfile, "\t<Polygon <GroupID %d>\n",
427	    MIF_PEN_TO_GROUP(mif_pentype));
428
429    /* Set fill type */
430    fprintf(gpoutfile, "\t\t<Fill %d>\n", MIF_FILL_SOLID);
431
432    /* Draw the line elements */
433    fprintf(gpoutfile, "\t\t<NumPoints %d> ", points);
434    for (i=0; i<points; i++) {
435	fprintf(gpoutfile, "<Point  %.3f %.3f> ",
436		GNP_TO_MIF(corners[i].x),
437		GNP_TO_MIF(MIF_YLAST - corners[i].y));
438    }
439
440    /* End of object */
441    fputs("\n\t>\n", gpoutfile);
442
443    /* Register the used group ID */
444    proc_group_id(MIF_PEN_TO_GROUP(mif_pentype));
445
446}
447
448/* Draw a point */
449static void
450mif_put_point(unsigned int x, unsigned int y, int np)
451{
452    /* Process if inside a Frame */
453    if (mif_initialized != 0 && mif_in_frame != 0) {
454
455	/* Draw pending line */
456	if (mif_polyline == TRUE)
457	    put_mif_line();
458
459	/* Adjust current position for text-graphics alignment */
460	MIF_move(x, y);
461
462	/* center text */
463	MIF_justify_text(CENTRE);
464
465	/* Draw the point */
466	fprintf(gpoutfile, "\t<TextLine <GroupID %d> %s\n",
467		MIF_PEN_TO_GROUP(mif_pentype),
468		mif_textcolor);
469
470	MIF_set_font(mif_point[np].font);
471
472	fprintf(gpoutfile, "\t\t<TLOrigin  %.3f %.3f> %s <String `%c'>\n",
473		mif_line.fpos_x + mif_point[np].x_offset,
474		mif_line.fpos_y + mif_point[np].y_offset,
475		mif_justify,
476		mif_point[np].chr);
477	fputs("\t>\n", gpoutfile);
478
479	/* Register the used group ID */
480	proc_group_id(MIF_PEN_TO_GROUP(mif_pentype));
481
482	/* Avoid to redraw this. The MIF system should remember it. */
483	mif_justify[0] = '\0';
484
485    }				/* Point processed */
486}
487
488
489/*
490 *  draw points
491 */
492TERM_PUBLIC void
493MIF_point(unsigned int x, unsigned int y, int number)
494{
495    if (number < 0) {		/* dot */
496	number = -1;
497    } else {			/* point */
498	number %= POINT_TYPES;
499    }
500    mif_put_point(x, y, number);
501}
502
503
504/* Set up a MIF output file */
505TERM_PUBLIC void
506MIF_init()
507{
508    int i;
509
510    /* Process if not inside a MIF file and Frame */
511    if (mif_initialized == 0 && mif_in_frame == 0) {
512	/* Tell this terminal driver that the output is initialized and
513	 * no current frames are processed */
514	mif_initialized = 1;
515	mif_in_frame = 0;
516
517	/* Reset internal position */
518	free_mif_line();
519	mif_line.fpos_x = GNP_TO_MIF(0);
520	mif_line.fpos_y = GNP_TO_MIF(MIF_YLAST);
521
522	/* Reset drawing properties strings */
523	mif_pen[0] = '\0';
524	mif_pen_width[0] = '\0';
525	mif_separation[0] = '\0';
526
527	MIF_justify_text(LEFT);
528
529	/* Reset group ID generator */
530	for (i = 0; i < MIF_NGROUP_ID; i++) {
531	    mif_group_id[i].group_id = MIF_INVALID_GROUP_ID;
532	    mif_group_id[i].group_existence = MIF_GROUP_NOT_EXISTS;
533	}
534
535	/* Identify ourselves */
536	/*bs show borders */
537	/* Setup a default environment to use */
538	fprintf(gpoutfile, "\
539<MIFFile 3.00> # Generated by gnuplot version %s patchlevel %s; identifies this as a MIF file\n\
540#\n\
541# show borders\n\
542<Document\n<DBordersOn Yes>\n>\n\
543# Set a default pen pattern, pen width, unit and font for subsequent objects\n\
544<Pen 0>\n\
545<Fill 15>\n\
546<PenWidth 0.5 pt>\n\
547<Separation 0>\n\
548<Units Ucm>\n\
549<FontCatalog\n\
550\t<Font <FTag `%s'><FFamily `Times'><FSize %d><FPlain Yes>>\n\
551\t<Font <FTag `%s'><FFamily `ZapfDingbats'><FSize 7.0 pt><FPlain Yes>>\n\
552\t<Font <FTag `%s'><FFamily `Symbol'><FSize 5.0 pt><FPlain Yes>>\n\
553>\n\
554#\n",
555		gnuplot_version, gnuplot_patchlevel,
556		zgnuplot, MIF_PSIZE,
557		zgnuplotp,
558		zgnuplotd);
559    }				/* MIF file created */
560}
561
562/* Finish of a MIF output file */
563TERM_PUBLIC void
564MIF_reset()
565{
566    /* Process if inside a MIF file and not inside a Frame */
567    if (mif_initialized != 0 && mif_in_frame == 0) {
568	/* Finish off the MIF file */
569	fputs("\
570#\n\
571# End of MIFFile\n", gpoutfile);
572
573	/* Tell this terminal driver that the output is finished */
574	mif_initialized = 0;
575
576	/* bs: reset frame number */
577	mif_frameno = -1;
578
579    }				/* MIF file finished */
580}
581
582/* Start plotting a Frame (-> graphics mode) */
583TERM_PUBLIC void
584MIF_graphics()
585{
586    int i;
587
588    /* Process if not inside a Frame */
589    if (mif_initialized != 0 && mif_in_frame == 0) {
590	/* Tell that this terminal driver is working with a plot frame */
591	mif_in_frame = 1;
592
593	/* Update frame number */
594	mif_frameno++;
595
596	/* Set current position */
597	free_mif_line();
598	mif_line.fpos_x = GNP_TO_MIF(0);
599	mif_line.fpos_y = GNP_TO_MIF(MIF_YLAST);
600
601	/* Set drawing properties */
602	mif_pen[0] = '\0';
603	mif_pen_width[0] = '\0';
604	mif_separation[0] = '\0';
605
606	MIF_justify_text(LEFT);
607
608	/* Reset group ID generator */
609	for (i = 0; i < MIF_NGROUP_ID; i++) {
610	    mif_group_id[i].group_id = MIF_INVALID_GROUP_ID;
611	    mif_group_id[i].group_existence = MIF_GROUP_NOT_EXISTS;
612	}
613
614	/* Frame preamble */
615	fprintf(gpoutfile, "\
616#\n\
617# Frame number %d with plot of graphics\n\
618<Frame\n\
619\t<Pen 15>\n\
620\t<Fill 15>\n\
621\t<PenWidth  0.5 pt>\n\
622\t<Separation 0>\n\
623\t<BRect 2.000 %.3f %.3f %.3f>\n\
624\t<NSOffset  0.000>\n\
625\t<BLOffset  0.000>\n",
626	    mif_frameno,
627	    ((float) mif_frameno) * GNP_TO_MIF(MIF_YMAX + 100),
628	    GNP_TO_MIF(MIF_XMAX), GNP_TO_MIF(MIF_YMAX));
629    }				/* Frame created */
630}
631
632/* Stop plotting a Frame (-> text mode) */
633TERM_PUBLIC void
634MIF_text()
635{
636    int i;
637
638    /* Process if inside a Frame */
639    if (mif_initialized != 0 && mif_in_frame != 0) {
640
641	/* Draw pending line */
642	if (mif_polyline == TRUE)
643	    put_mif_line();
644
645	/* Group the used plot primitives */
646	fputs("\
647\t#\n\
648\t# Group the the objects in groups to make the chart easier to manipulate\n\
649\t# after it's imported into FrameMaker.\n", gpoutfile);
650
651	for (i = 0; i < MIF_NGROUP_ID; i++) {
652	    if (mif_group_id[i].group_id != MIF_INVALID_GROUP_ID &&
653		mif_group_id[i].group_existence == MIF_GROUP_EXISTS) {
654		fprintf(gpoutfile, "\
655\t<Group\n\
656\t\t<ID %d>\n\
657\t>\n", mif_group_id[i].group_id);
658	    }
659	}
660
661	/* Frame post amble */
662	fprintf(gpoutfile, "\
663>\n\
664# End of Frame number %d\n\
665#\n",
666		mif_frameno);
667
668	/* Tell that this terminal driver is not working with a plot frame */
669	mif_in_frame = 0;
670    }				/* Frame finished */
671}
672
673/* Select type of line in graphics */
674/* NOTE: actually written to output the first time a primitive
675 * is drawn AFTER this call */
676/* -2=border, -1=X/Y-axis, 0-13=lines, and 14-=mapped back */
677TERM_PUBLIC void
678MIF_linetype(int linetype)
679{
680    /* Process if inside a Frame */
681    if (mif_initialized != 0 && mif_in_frame != 0) {
682
683	/* Draw pending line */
684	if (mif_polyline == TRUE)
685	    put_mif_line();
686
687	/* Translate gnuplot pen types to MIF pen types */
688	if (linetype < 0) {	/* Special lines */
689	    if (linetype == LT_AXIS) {
690		mif_pentype = 8 + MIF_NPENS;	/* -1 */
691		if (mif_colour == TRUE)
692		    sprintf(mif_separation, " <Separation 0> ");
693	    } else {
694		mif_pentype = 0 + MIF_NPENS;	/* -2 or less */
695		if (mif_colour == TRUE)
696		    sprintf(mif_separation, " <Separation 0> ");
697	    }
698	    sprintf(mif_pen_width, " <PenWidth 1.0 pt> ");
699	    /* EAM - set text color to black */
700	    sprintf(mif_textcolor, " <Font <FSeparation 0>> ");
701	} else {		/* Normal lines */
702	    mif_pentype = (linetype) % MIF_NPENS;	/* 0-(MIF_NPENS-1) */
703	    sprintf(mif_pen_width, " <PenWidth 0.1 pt> ");
704	    if (mif_colour == TRUE)
705		sprintf(mif_separation, " <Separation %d> ",
706			2 + (mif_pentype % 6));	/* 2-7 */
707	    /* EAM - set text color also */
708	    if (mif_colour == TRUE)
709		sprintf(mif_textcolor, " <Font <FSeparation %d>> ",
710			2 + (mif_pentype % 6));	/* 2-7 */
711	}
712
713	/* Set pen type */
714	sprintf(mif_pen, " <Pen %d> ",
715		mif_pattern_table[mif_pentype % MIF_NPENS]);
716
717    }				/* Primitive processed */
718}
719
720/* Allow arbitrary text rotation */
721TERM_PUBLIC int
722MIF_text_angle(int ang)
723{
724    mif_text_ang = ang;
725    return (TRUE);
726}
727
728/* Justify following text lines (MIF_put_text()) relative to the
729 * insertion point
730 * NOTE: actually written to output in text primitives which are
731 * drawn AFTER this call */
732TERM_PUBLIC int
733MIF_justify_text(enum JUSTIFY mode)
734{
735    int rval = TRUE;
736
737    /* Process if inside a Frame */
738    if (mif_initialized != 0 && mif_in_frame != 0) {
739	switch (mode) {
740	case LEFT:
741	    sprintf(mif_justify, " <TLAlignment Left> ");
742	    break;
743	case CENTRE:
744	    sprintf(mif_justify, " <TLAlignment Center> ");
745	    break;
746	case RIGHT:
747	    sprintf(mif_justify, " <TLAlignment Right> ");
748	    break;
749	default:
750	    rval = FALSE;
751	    break;
752	}
753
754    }
755    /* Primitive processed */
756    else {
757	rval = FALSE;
758    }
759
760    return (rval);
761}
762
763/* Draw a vector from current position to (x, y) and change current position.
764 * NOTE: actually written to output the first time another primitive
765 * is called AFTER this call */
766TERM_PUBLIC void
767MIF_vector(unsigned int x, unsigned int y)
768{
769    /* Process if inside a Frame */
770    if (mif_initialized != 0 && mif_in_frame != 0) {
771
772	/* Setup the vector as a part of the line */
773	insert_mif_line(GNP_TO_MIF(x), GNP_TO_MIF(MIF_YLAST - (int) y));
774
775	/* Draw pending line -> vector */
776	if (mif_polyline == FALSE)
777	    put_mif_line();
778
779    }				/* Vector processed */
780}
781
782/* Move current position */
783TERM_PUBLIC void
784MIF_move(unsigned int x, unsigned int y)
785{
786    /* Process if inside a Frame */
787    if (mif_initialized != 0 && mif_in_frame != 0) {
788
789	/* Draw pending line */
790	if (mif_polyline == TRUE)
791	    put_mif_line();
792
793	mif_line.fpos_x = GNP_TO_MIF(x);
794	mif_line.fpos_y = GNP_TO_MIF(MIF_YLAST - (int) y);
795    }
796}
797
798
799/* set font */
800static void
801MIF_set_font(const char *font)
802{
803    if (font != mif_font) {
804	fprintf(gpoutfile, "\t\t<Font\n\t\t\t<FTag `%s'>\n\t\t>\n", font);
805	mif_font = font;
806    }
807}
808
809
810/* Draw the text string str at (x, y). Adjust according to MIF_justify_text().
811 * Change current position. */
812TERM_PUBLIC void
813MIF_put_text(unsigned int x, unsigned int y, const char str[])
814{
815    /* Process if inside a Frame */
816    if (mif_initialized != 0 && mif_in_frame != 0) {
817
818	/* Draw pending line */
819	if (mif_polyline == TRUE)
820	    put_mif_line();
821
822	/* Adjust current position for text-graphics alignment */
823	MIF_move(x, y - MIF_VCHAR / 5);
824
825	if (strlen(str) > 0) {
826
827	    /* Draw the text */
828	    fprintf(gpoutfile, "\t<TextLine <GroupID %d> %s %s %s %s\n",
829		    MIF_PEN_TO_GROUP(mif_pentype), mif_pen,
830		    mif_pen_width, mif_separation, mif_textcolor);
831
832	    MIF_set_font(zgnuplot);
833
834	    fprintf(gpoutfile, "\
835\t\t<TLOrigin  %.3f %.3f> %s <Angle %d> <String `%s'>\n\
836\t>\n",
837		    mif_line.fpos_x, mif_line.fpos_y, mif_justify,
838		    mif_text_ang, str);
839
840	    /* Register the used group ID */
841	    proc_group_id(MIF_PEN_TO_GROUP(mif_pentype));
842
843	    /* Avoid to redraw this. The MIF system should remember it. */
844	    mif_pen[0] = '\0';
845	    mif_pen_width[0] = '\0';
846	    mif_separation[0] = '\0';
847
848	    mif_justify[0] = '\0';	/* Independent of linetype */
849	}
850    }				/* Text processed */
851}
852
853
854/* Insert one point in the line */
855static int
856insert_mif_line(double fx, double fy)
857{
858    int rval = TRUE;
859
860    if ((mif_line.prev->next = (struct mif_line *) gp_alloc(sizeof(struct mif_line),
861	"MIF driver")) != (struct mif_line *) NULL) {
862	/* Link */
863	mif_line.prev->next->next = &mif_line;
864	mif_line.prev->next->prev = mif_line.prev;
865	mif_line.prev = mif_line.prev->next;
866
867	/* Fill */
868	mif_line.prev->fpos_x = fx;
869	mif_line.prev->fpos_y = fy;
870
871	rval = TRUE;
872    } else {			/* Failed to allocate */
873	/* Relink */
874	mif_line.prev->next = &mif_line;
875
876	rval = FALSE;
877    }
878
879    return (rval);
880}
881
882/* Register group ID. Update group ID existence. */
883/* Returns:     1       group_id belongs to a MIF group
884		0       group_id does not belong to a MIF group
885	       -1       not inside a Frame
886	       -2       group ID list is full
887 */
888static int
889proc_group_id(int group_id)
890{
891    int i, rval = 0;
892
893    /* Process if inside a Frame */
894    if (mif_initialized != 0 && mif_in_frame != 0) {
895
896	/* Find out the group ID, or a free group ID slot index. */
897	for (i = 0; i < MIF_NGROUP_ID &&
898	     mif_group_id[i].group_id != MIF_INVALID_GROUP_ID &&
899	     mif_group_id[i].group_id != group_id;
900	     i++) {
901	    /* Don't check the group_existence variable */
902	}
903
904	if (i < MIF_NGROUP_ID) {
905	    if (mif_group_id[i].group_id == MIF_INVALID_GROUP_ID) {
906		/* Register as new group ID for eventual use as MIF group */
907		mif_group_id[i].group_id = group_id;
908		mif_group_id[i].group_existence = MIF_GROUP_NOT_EXISTS;
909	    } else {
910		/* If second use of this group ID -> create a new MIF group */
911		if (mif_group_id[i].group_id == group_id) {
912		    mif_group_id[i].group_existence = MIF_GROUP_EXISTS;
913		    /* NOTE: a group MUST have at least two members. */
914		    rval = 1;
915		}
916	    }
917	} else {
918	    rval = -2;		/* No place for this group ID in the list */
919	}
920
921    }
922    /* Group ID processed */
923    else {
924	rval = -1;		/* Not inside a Frame */
925    }
926
927    /* Return MIF group status */
928    return (rval);
929}
930
931
932#endif
933
934
935#ifdef TERM_TABLE
936
937TERM_TABLE_START(mif_driver)
938    "mif", "Frame maker MIF 3.00 format",
939    MIF_XMAX, MIF_YMAX, MIF_VCHAR, MIF_HCHAR,
940    MIF_VTIC, MIF_HTIC, MIF_options, MIF_init, MIF_reset,
941    MIF_text, null_scale, MIF_graphics, MIF_move, MIF_vector,
942    MIF_linetype, MIF_put_text, MIF_text_angle,
943    MIF_justify_text, MIF_point, do_arrow, set_font_null,
944    0, /* pointsize */
945    0, /* flags */
946    0, 0, /* suspend, resume */
947    MIF_boxfill,
948    0  /* linewidth */
949#ifdef USE_MOUSE
950    , 0, 0, 0, 0, 0
951#endif
952    ,0 /* make_palette */
953    ,0 /* previous_palette */
954    ,0 /* set_color */
955    ,MIF_filled_polygon /* filled_polygon */
956TERM_TABLE_END(mif_driver)
957
958#undef LAST_TERM
959#define LAST_TERM mif_driver
960
961#endif
962#endif /* TERM_PROTO_ONLY */
963
964#ifdef TERM_HELP
965START_HELP(mif)
966"1 mif",
967"?commands set terminal mif",
968"?set terminal mif",
969"?set term mif",
970"?terminal mif",
971"?term mif",
972"?mif",
973" Note: Legacy terminal.",
974" The `mif` terminal driver produces Frame Maker MIF format version 3.00.  It",
975" plots in MIF Frames with the size 15*10 cm, and plot primitives with the same",
976" pen will be grouped in the same MIF group.  Plot primitives in a `gnuplot`",
977" page will be plotted in a MIF Frame, and several MIF Frames are collected in",
978" one large MIF Frame.  The MIF font used for text is \"Times\".",
979"",
980" Several options may be set in the MIF 3.00 driver.",
981"",
982" Syntax:",
983"       set terminal mif {color | colour | monochrome} {polyline | vectors}",
984"                        {help | ?}",
985"",
986" `colour` plots lines with line types >= 0 in colour (MIF sep. 2--7) and",
987" `monochrome` plots all line types in black (MIF sep. 0).",
988" `polyline` plots curves as continuous curves and `vectors` plots curves as",
989" collections of vectors.",
990" `help` and `?` print online help on standard error output---both print a",
991" short description of the usage; `help` also lists the options.",
992"",
993" Examples:",
994"       set term mif colour polylines    # defaults",
995"       set term mif                     # defaults",
996"       set term mif vectors",
997"       set term mif help"
998END_HELP(mif)
999#endif /* TERM_HELP */
1000