/*
 * $Id: fig.trm,v 1.39 1995/12/20 21:47:48 drd Exp $
 */

/* GNUPLOT - fig.trm */
/*
 * Copyright (C) 1990, 1991, 1992
 *
 * Permission to use, copy, and distribute this software and its
 * documentation for any purpose with or without fee is hereby granted,
 * provided that the above copyright notice appear in all copies and
 * that both that copyright notice and this permission notice appear
 * in supporting documentation.
 *
 * Permission to modify the software is granted, but not the right to
 * distribute the modified code.  Modifications are to be distributed
 * as patches to released version.
 *
 * This software  is provided "as is" without express or implied warranty.
 *
 * This file is included by ../term.c.
 *
 * This terminal driver supports:
 *  Fig graphics language
 *
 * AUTHORS
 *  Micah Beck, David Kotz
 *
 * send your comments or suggestions to (info-gnuplot@dartmouth.edu).
 *
 */

/*
 * Original for Fig code output by Micah Beck, 1989
 * Department of Computer Science, Cornell University
 * Updated by David Kotz for gnuplot 2.0
 * More efficient output by Ian Dall
 * Updated to FIG 2.1 (with color) format by Vivek Khera
 * Updated to FIG 3.1 (higher resolution) format by Ian MacPhedran, Jan 1995
 * Updated to conform to newterm format Ian MacPhedran, Apr 1995
 */

#ifndef GOT_DRIVER_H
#include "driver.h"
#endif /* GOT_DRIVER_H */

#ifdef TERM_REGISTER
register_term(fig)
#endif /* TERM_REGISTER */

#ifdef TERM_PROTO
TERM_PUBLIC void FIG_options __P((void));
TERM_PUBLIC void FIG_init __P((void));
TERM_PUBLIC void FIG_graphics __P((void));
TERM_PUBLIC void FIG_text __P((void));
TERM_PUBLIC void FIG_linetype __P((int linetype));
TERM_PUBLIC void FIG_move __P((unsigned int x, unsigned int y));
TERM_PUBLIC void FIG_vector __P((unsigned int ux, unsigned int uy));
TERM_PUBLIC void FIG_arrow __P((unsigned int sx, unsigned int sy, unsigned int ex, unsigned int ey, TBOOLEAN head));
TERM_PUBLIC void FIG_put_text __P((unsigned int x, unsigned int y, char *str));
TERM_PUBLIC int FIG_justify_text __P((enum JUSTIFY mode));
TERM_PUBLIC int FIG_text_angle __P((int angle));
TERM_PUBLIC void FIG_reset __P((void));
TERM_PUBLIC void FIG_lpoint __P((unsigned int x, unsigned int y, int number));

#define GOT_FIG_PROTO
#endif /* TERM_PROTO */

#ifndef TERM_PROTO_ONLY
#ifdef TERM_BODY

#include "object.h"             /* modified from the XFig distribution */
#define FIG_DEFAULT DEFAULT
#define FIG_ROMAN_FONT (0)	/* actually, the default font */
 
#ifndef FIG_RES
/* This is now 1200 per inch */
#define FIG_RES         (1200)
#endif
 
#define FIG_COORD_SYS   2
#define FIG_ORIENT "Portrait"
/* Could be "Landscape" */
#define FIG_JUST "Center"
/* Could be "Flush Left" */
#define FIG_UNIT "Inches"
/* Could be "Metric" */
 
#define FIG_MAGIC       "#FIG 3.1"
#define FIG_HTIC        (5*FIG_RES/80)
#define FIG_VTIC        (5*FIG_RES/80)
#define FIG_FONT_S      (10)	/* size in points */

#define FIG_to_pixel_v(s) ((s)*FIG_RES/72*3/4) /* height of font in pixels */
/* This is fudged to enlarge the drawing area, but gives fairly good results */
#define FIG_to_pixel_h(s) (FIG_to_pixel_v(s)*6/10) /* this is a guess at the width */

#define FIG_VCHAR       FIG_to_pixel_v(FIG_FONT_S) /* just for default, */
#define FIG_HCHAR       FIG_to_pixel_h(FIG_FONT_S) /* not really used   */

enum FIG_poly_stat {FIG_poly_new, FIG_poly_part};
 
static int FIG_posx;
static int FIG_posy;
static int FIG_poly_vec_cnt;
static enum FIG_poly_stat FIG_polyvec_stat;
/* 5 inches wide by 3 inches high */
#define FIG_XMAX (5 * FIG_RES)
#define FIG_YMAX (3 * FIG_RES)
 
#define FIG_XOFF (FIG_RES/4)
#define FIG_YOFF (FIG_RES/4)


#define BFIG_HTIC       (7*FIG_RES/80)
#define BFIG_VTIC       (7*FIG_RES/80)
#define BFIG_FONT_S     (16)	/* size in points */
#define BFIG_VCHAR      FIG_to_pixel_v(BFIG_FONT_S) /* height in pixels of font */
#define BFIG_HCHAR      FIG_to_pixel_h(BFIG_FONT_S) /* this is a guess at the width */
 
static  F_point FIG_points[100];
static	F_line	FIG_line;
 
/* 8 inches wide by 5 inches high */
#define BFIG_XMAX (8 * FIG_RES)
#define BFIG_YMAX (5 * FIG_RES)
 
#define BFIG_XOFF (FIG_RES/2)
#define BFIG_YOFF (FIG_RES/2)
 

static int FIG_type;            /* negative types use real lines */
static float FIG_spacing;       /* length of dash or dot spacing */
static int FIG_justify;         /* Fig justification T_*_JUSTIFIED */
static float FIG_angle;         /* Fig text angle 0=horiz, Pi/2=vert */
static int FIG_use_color = FALSE;	/* do we use color or not? */
static int FIG_is_big = FALSE;	/* big plot ? */
static int FIG_color = DEFAULT;	/* which color to use */
static int FIG_xoff = FIG_XOFF;
static int FIG_yoff = FIG_YOFF;
static int FIG_font_s = FIG_FONT_S;

static void FIG_poly_clean __P((enum FIG_poly_stat stat));


#define FIG_POINT_TYPES POINT_TYPES /* we use the same points */

 
static void
  FIG_poly_clean(stat)
enum FIG_poly_stat stat;
{
  int i,j;
  if(stat == FIG_poly_part) {
	fprintf(outfile, "%d %d %d %d %d %d %d %d %d %9.3f %d %d %d %d %d %d\n",
	 O_POLYLINE, FIG_line.type, FIG_line.style, FIG_line.thickness,
	 FIG_line.pen_color, FIG_line.fill_color, FIG_line.depth,
	 FIG_line.pen_style, FIG_line.fill_style, FIG_line.style_val,
	 FIG_line.join_style, FIG_line.cap_style, FIG_line.radius,
	 0, 0, FIG_poly_vec_cnt);

	j = 0;
	for(i=0;i<FIG_poly_vec_cnt;i++)
	{
	  fprintf(outfile," %d %d",FIG_points[i].x,FIG_points[i].y);
	  if (j++ > 10) { fprintf(outfile,"\n"); j = 0;}
	}
	if (j != 0) {fprintf(outfile,"\n");}
  }
  FIG_polyvec_stat = FIG_poly_new;
}
 
TERM_PUBLIC void FIG_options()
{
	int parse_error=FALSE;

	FIG_use_color = FALSE;	/* default */
	FIG_is_big = FALSE;	/* default */

	while (!END_OF_COMMAND) {
		if (almost_equals(c_token,"m$onochrome")) {
			FIG_use_color=FALSE;
			c_token++;
		}
		else if (almost_equals(c_token,"c$olor")) {
			FIG_use_color=TRUE;
			c_token++;
		}
		else if (almost_equals(c_token,"s$mall")) {
			FIG_is_big=FALSE;
			c_token++;
		}
		else if (almost_equals(c_token,"b$ig")) {
			FIG_is_big=TRUE;
			c_token++;
		}
		else {
			parse_error=TRUE;
			int_error("expecting monochrome, color, small or big",
				  c_token);
		}
	}

	sprintf(term_options,"%s %s", FIG_use_color ? "color" : "monochrome",
				      FIG_is_big ? "big" : "small");

	if(!FIG_is_big) {
		FIG_font_s=FIG_FONT_S;
		term->xmax=FIG_XMAX;
		term->ymax=FIG_YMAX;
		term->v_char=FIG_to_pixel_v(FIG_font_s);
		term->h_char=FIG_to_pixel_h(FIG_font_s);
		term->v_tic=FIG_VTIC;
		term->h_tic=FIG_HTIC;
		FIG_xoff=FIG_XOFF;
		FIG_yoff=FIG_YOFF;
	} else {
		FIG_font_s=BFIG_FONT_S;
		term->xmax=BFIG_XMAX;
		term->ymax=BFIG_YMAX;
		term->v_char=FIG_to_pixel_v(FIG_font_s);
		term->h_char=FIG_to_pixel_h(FIG_font_s);
		term->v_tic=BFIG_VTIC;
		term->h_tic=BFIG_HTIC;
		FIG_xoff=BFIG_XOFF;
		FIG_yoff=BFIG_YOFF;
	}

	if(parse_error) {
		int_error("expecting monochrome, color, small or big",
			  c_token);
	}
}

TERM_PUBLIC void FIG_init()
{
    FIG_posx = FIG_posy = 0;
    FIG_polyvec_stat = FIG_poly_new;
    FIG_linetype(-1);
    FIG_justify_text(LEFT);
    FIG_text_angle(0);

    FIG_line.tagged = FIG_DEFAULT;
    FIG_line.distrib = FIG_DEFAULT;
    FIG_line.type = T_POLYLINE;
    FIG_line.style = 0;
    FIG_line.thickness = 1;
    FIG_line.fill_style = -1;
    FIG_line.depth = 0;
    FIG_line.pen_style =  0;
    FIG_line.for_arrow = NULL;
    FIG_line.back_arrow = NULL;
    FIG_line.cap_style = 0;
    FIG_line.join_style = 0;
    FIG_line.style_val = 0.0;
    FIG_line.radius = 0;
    FIG_line.pic = NULL;
    FIG_line.next = NULL;

    fprintf(outfile, "%s\n", FIG_MAGIC);
    fprintf(outfile, "%s\n%s\n%s\n%d %d\n", FIG_ORIENT, FIG_JUST,
	FIG_UNIT, FIG_RES, FIG_COORD_SYS);
}
 
 
TERM_PUBLIC void FIG_graphics()
{
    FIG_posx = FIG_posy = 0;
    FIG_polyvec_stat = FIG_poly_new;
    /* there is no way to have separate pictures in a FIG file */
}
 
 
TERM_PUBLIC void FIG_text()
{
    /* there is no way to have separate pictures in a FIG file */
    FIG_poly_clean(FIG_polyvec_stat);
    FIG_posx = FIG_posy = 0;
    fflush(outfile);
}
 
 
/* Line types for FIG work like this:
 *  for monochrome:
 *  -2 : solid (border)
 *  -1 : dotted 4 (axes)
 *   0 : solid (first curve)
 *   1 : dotted 3
 *   2 : dashed 3
 *   3 : dotted 6
 *   4 : dashed 6
 *   ... ...
 *  for color, cycle through colors. once colors are used up, repeat colors
 *   but start using dashed lines of different dash length. don't use white
 *   as a color.
 */
 
TERM_PUBLIC void FIG_linetype(linetype)
        int linetype;                   /* expect linetype >= -2 */
{
    int last_FIG_type = FIG_type;
    int last_FIG_spacing = FIG_spacing;
    switch (linetype) {
           case 0:
           case -2: {
                  FIG_type = SOLID_LINE;
                  FIG_spacing = 0.0;
		  if (FIG_use_color) FIG_color = BLACK;
                  break;
           }
           case -1: {
                  FIG_type = DOTTED_LINE;
                  FIG_spacing = 4.0; /* gap */
		  if (FIG_use_color) FIG_color = BLACK;
                  break;
           }
           default: {
                linetype = abs(linetype); /* shouldn't be negative anyway */
                /* now linetype >= 1 */
		if (FIG_use_color) {
		  FIG_type = (linetype >= WHITE);	/* dashed line */
		  FIG_color = linetype % WHITE;
		  FIG_spacing = (linetype / WHITE) * 3;
		} else { /* monochrome */
                  FIG_type = linetype % 2 + 1; /* dotted, dashed, ... */
                  FIG_spacing = (linetype+1) / 2 * 3;
		}
                  break;
           }
    }
    if (FIG_type != last_FIG_type || FIG_spacing != last_FIG_spacing)
      FIG_poly_clean(FIG_polyvec_stat);
}
 
TERM_PUBLIC void FIG_move(x,y)
        unsigned int x,y;
{
    int last_FIG_posx = FIG_posx;
    int last_FIG_posy = FIG_posy;
    FIG_posx = x;
    FIG_posy = y;
    if (FIG_posx != last_FIG_posx || FIG_posy != last_FIG_posy)
          FIG_poly_clean(FIG_polyvec_stat);
}
 
 
TERM_PUBLIC void FIG_vector(ux,uy)
     unsigned int ux,uy;
{
  int x=ux, y=uy;
 
  if (FIG_polyvec_stat != FIG_poly_part)
    {

	FIG_line.pen_color = FIG_color;
	FIG_line.fill_color = FIG_color;
	FIG_line.style = FIG_type;
	FIG_line.style_val = FIG_spacing;
	FIG_poly_vec_cnt = 0;
	FIG_points[FIG_poly_vec_cnt].x=FIG_xoff + FIG_posx;
	FIG_points[FIG_poly_vec_cnt].y=term->ymax
	 + FIG_yoff - FIG_posy;

        FIG_poly_vec_cnt = 1;
        FIG_polyvec_stat = FIG_poly_part;
    }
  FIG_points[FIG_poly_vec_cnt].x = FIG_xoff +  x;
  FIG_points[FIG_poly_vec_cnt].y = term->ymax + FIG_yoff - y;

  FIG_poly_vec_cnt++;
  if (FIG_poly_vec_cnt > 99)
    FIG_poly_clean(FIG_polyvec_stat);
 
  FIG_posx = x;
  FIG_posy = y;
}
 
 
TERM_PUBLIC void FIG_arrow(sx, sy, ex, ey, head)
        unsigned int sx, sy;     /* start coord */
        unsigned int ex, ey;     /* end coord */
	TBOOLEAN head;
{
	FIG_poly_clean(FIG_polyvec_stat);
        fprintf(outfile, "%d %d %d %d %d %d %d %d %d %9.3f %d %d %d %d %d %d\n",
         O_POLYLINE, FIG_line.type, FIG_line.style, FIG_line.thickness,
         FIG_line.pen_color, FIG_line.fill_color, FIG_line.depth,
         FIG_line.pen_style, FIG_line.fill_style, FIG_line.style_val,
         FIG_line.join_style, FIG_line.cap_style, FIG_line.radius,
         head ? 1 : 0, 0, 2);

        /* arrow line */
	if ( head )
	        fprintf(outfile, "%d %d %.3f %.3f %.3f\n",
        	        0, 0, 1.0,
			(double)(term->h_tic/2 + 1),
			(double)term->h_tic        );
        fprintf(outfile, "%d %d %d %d\n",
                FIG_xoff + sx, FIG_yoff + term->ymax - sy,
		FIG_yoff + ex, FIG_yoff + term->ymax - ey);
 
        FIG_posx = ex;
        FIG_posy = ey;
}
 
 
TERM_PUBLIC void FIG_put_text(x, y, str)
        unsigned int x, y;
        char *str;
{
  if (strlen(str) == 0) return;
  FIG_poly_clean(FIG_polyvec_stat);
  y -= term->v_char/2;	/* assuming vertical center justified */
 
    fprintf(outfile, "%d %d %d %d %d %d %6.3f %6.3f %d %6.3f %6.3f %d %d %s\\001\n",
                  O_TEXT, FIG_justify, FIG_color, 0, FIG_DEFAULT,
                  FIG_ROMAN_FONT, (float)FIG_font_s,
		  FIG_angle, SPECIAL_TEXT, (float)term->v_char,
		  (float)term->h_char*strlen(str),
		  FIG_xoff + x, term->ymax + FIG_yoff-y, str);
}
 
TERM_PUBLIC int FIG_justify_text(mode)
        enum JUSTIFY mode;
{
    switch(mode) {
           case LEFT: FIG_justify = T_LEFT_JUSTIFIED; break;
           case CENTRE: FIG_justify = T_CENTER_JUSTIFIED; break;
           case RIGHT: FIG_justify = T_RIGHT_JUSTIFIED; break;
           /* shouldn't happen */
           default: FIG_justify = T_LEFT_JUSTIFIED; return (FALSE); break;
    }
    return (TRUE);
}
 
TERM_PUBLIC int FIG_text_angle(angle)
        int angle;
{
    if (angle)
         FIG_angle = Pi / 2.0;  /* vertical is pi/2 radians */
    else
         FIG_angle = 0.0;               /* horizontal */
    return (TRUE);
}

TERM_PUBLIC void FIG_lpoint(x,y,number)
unsigned int x,y;
int number;
{
    FIG_type = 0; /* Solid lines for marker outline */
    do_point(x,y,number);
}
 
TERM_PUBLIC void FIG_reset()
{
    FIG_poly_clean(FIG_polyvec_stat);
    FIG_posx = FIG_posy = 0;
    fflush(outfile);
}
#endif /* TERM_BODY */

#ifdef TERM_TABLE

TERM_TABLE_START(fig_driver)
   "fig", "FIG 3.1 graphics language: X graphics editor",
  	   FIG_XMAX, FIG_YMAX, FIG_VCHAR, FIG_HCHAR, 
  	   FIG_VTIC, FIG_HTIC, FIG_options, FIG_init, FIG_reset, 
  	   FIG_text, null_scale, FIG_graphics, FIG_move, FIG_vector,
  	   FIG_linetype, FIG_put_text, FIG_text_angle, FIG_justify_text,
  	   FIG_lpoint, FIG_arrow, set_font_null
TERM_TABLE_END(fig_driver)

#undef LAST_TERM
#define LAST_TERM fig_driver
#endif /* TERM_TABLE */
#endif /* TERM_PROTO_ONLY */


#ifdef TERM_HELP
START_HELP(fig)
"1 fig",
"?set terminal fig",
"?fig",
" The `fig` terminal device has the options of either color or  monochrome",
" and small or large image.  The default is monochrome and small.",
"",
" To select color, use:",
"        set terminal fig color",
"",
" To select large, use:",
"        set terminal fig large",
"",
" The large option is a substitute for the `bfig` terminal in earlier version,",
" which is no longer supported."
END_HELP(fig)
#endif
