ngspice/xgraph/tgif.c

331 lines
8.1 KiB
C
Raw Permalink Normal View History

2004-01-25 10:00:31 +01:00
/*
* Tgif Output
*
* Christos Zoulas
*/
#include <stdio.h>
#include <string.h> /* for strlen() */
2004-01-25 10:00:31 +01:00
#include <X11/Xlib.h>
#include "hard_devices.h"
#include "xgout.h"
#define COLOR "DarkSlateGray"
typedef struct {
char *title_font;
char *axis_font;
int title_size;
int axis_size;
FILE *strm;
} Info;
char *tgif_prologue[] =
{
"state(0,13,0,0,0,16,1,5,1,1,0,0,1,0,1,0,1,0,4,0,0,0,10,0).\n",
"%\n",
"% Tgif xgraph output.\n",
"%\n",
0
};
/*
* Hardcopy Interface for Xgraph
*
* Major differences from first version:
* Four new parameters are passed to the device initialization routine:
* title_family, title_size, axis_family, and axis_size. See the
* description of xg_init() for details.
*
* Clipping is done automatically by xgraph. The xg_clip() routine
* is obsolete.
*
* The xg_line() routine has become the xg_seg() routine. It now
* draws segments rather than a series of lines.
*
* A new field (max_segs) in the device structure now specifies
* the maximum number of segments the device can handle in a group.
*/
void tgifText();
void tgifDot();
void tgifSeg();
void tgifEnd();
int
tgifInit(strm, width, height, title_family, title_size,
axis_family, axis_size, flags, out_info, errmsg)
FILE *strm; /* Output stream */
int width,
height; /* Size of space (microns) */
char *title_family; /* Name of title font family */
double title_size; /* Title font height (points) */
char *axis_family; /* Name of axis font family */
double axis_size; /* Axis font height (points) */
int flags; /* Flags */
xgOut *out_info; /* Device info (RETURN) */
char errmsg[ERRBUFSIZE]; /* Error message area */
{
Info *tgif_info;
char **l;
double scx,
scy;
tgif_info = (Info *) Malloc(sizeof(*tgif_info));
for (l = tgif_prologue; *l; l++)
fprintf(strm, "%s\n", *l);
out_info->dev_flags = 0;
scx = width / 512.0;
scy = height / 512.0;
if (scx > scy) {
scy /= scx;
scx = 1;
}
else {
scx /= scy;
scy = 1;
}
out_info->bdr_pad = title_size / 4;
out_info->axis_pad = 2.0 * axis_size;
out_info->legend_pad = 0;
out_info->area_w = width * 0.00283 * scx; /* pts per micron */
out_info->area_h = height * 0.00283 * scy;
out_info->tick_len = axis_size;
out_info->axis_height = axis_size;
out_info->title_height = title_size;
out_info->axis_width = (axis_size * 5.0) / 12.0;
out_info->title_width = (title_size * 5.0) / 12.0;
out_info->max_segs = 100;
out_info->xg_text = tgifText;
out_info->xg_seg = tgifSeg;
out_info->xg_dot = tgifDot;
out_info->xg_end = tgifEnd;
out_info->user_state = (char *) tgif_info;
tgif_info->title_font = title_family;
tgif_info->axis_font = axis_family;
tgif_info->title_size = title_size;
tgif_info->axis_size = axis_size;
tgif_info->strm = strm;
return 1;
}
/* Text justifications */
#define T_CENTER 0
#define T_LEFT 1
#define T_UPPERLEFT 2
#define T_TOP 3
#define T_UPPERRIGHT 4
#define T_RIGHT 5
#define T_LOWERRIGHT 6
#define T_BOTTOM 7
#define T_LOWERLEFT 8
/* Text styles */
#define T_AXIS 0
#define T_TITLE 1
static void
tgif_just(x, y, just, size, len)
int *x,
*y; /* Given location (lower left) */
int just; /* Justification */
int size; /* Size in points */
int len; /* Number of chars */
/*
* Unfortunately, tgif really can't display text with a justification.
* This is a horrible hack to try to get around the problem. It tries
* to compute a rough bounding box for the text based on the text height
* and the string length and offset `x,y' appropriately for the justification.
* This is only a hack...
*/
{
int t_width,
t_height;
t_height = size;
t_width = (size * len * 5) / 12; /* Horrible estimate */
switch (just) {
case T_CENTER:
*x -= t_width / 2;
*y -= t_height / 2;
break;
case T_LEFT:
*y -= t_height / 2;
break;
case T_UPPERLEFT:
/* nothing */
break;
case T_TOP:
*x -= t_width / 2;
break;
case T_UPPERRIGHT:
*x -= t_width;
break;
case T_RIGHT:
*x -= t_width;
*y -= t_height / 2;
break;
case T_LOWERRIGHT:
*x -= t_width;
*y -= t_height;
break;
case T_BOTTOM:
*x -= t_width / 2;
*y -= t_height;
break;
case T_LOWERLEFT:
*y -= t_height;
break;
}
/*
* Also, tgif seems to put a space above all text it draws. The
* computation below compensates for this.
*/
*y += (size / 3);
}
void
tgifText(user_state, x, y, text, just, style)
char *user_state; /* Value set in xg_init */
int x,
y; /* Text position (pixels) */
char *text; /* Null terminated text */
int just; /* Justification (above) */
int style; /* Text style (above) */
/*
* This routine should draw text at the indicated position using
* the indicated justification and style. The justification refers
* to the location of the point in reference to the text. For example,
* if just is T_LOWERLEFT, (x,y) should be located at the lower left
* edge of the text string.
*/
{
char *font;
int size;
Info *tgif = (Info *) user_state;
/*
* Obj = text(_Color,_X,_Y,_Font,_TextStyle,_TextSize,_NumLines,_TextJust,
* _TextRotate,_PenPat,_BBoxW,_BBoxH,_Id,_TextDPI,_Asc,_Des,
* _ObjFill,_Vspace,StrList),
*/
/* font ok too */
style == T_AXIS ? tgif->axis_font :
tgif->title_font;
/* ok 0, 1 as in tgif */
size = style == T_AXIS ? tgif->axis_size :
tgif->title_size;
tgif_just(&x, &y, just, size, strlen(text));
if (size <= 8)
size = 0;
else if (size <= 10)
size = 1;
else if (size <= 12)
size = 2;
else if (size <= 14)
size = 3;
else if (size <= 18)
size = 4;
else
size = 5;
fprintf(tgif->strm,
"text('%s',%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,[\n\t",
COLOR, x, y, 0, style, size, 1, 0, 0, 1, 0, 0, 0, 0, 18, 4, 0, 0);
fprintf(tgif->strm,
"\"%s\"]).\n", text);
}
/* Line Styles */
#define L_AXIS 0
#define L_ZERO 1
#define L_VAR 2
void
tgifSeg(user_state, ns, seglist, width, style, lappr, color)
char *user_state; /* Value set in xg_init */
int ns; /* Number of segments */
XSegment *seglist; /* X array of segments */
int width; /* Width of lines */
int style; /* See above */
int lappr; /* Line appearence */
int color; /* Line color (if any) */
{
Info *tgif = (Info *) user_state;
int i,
j,
k;
/*
* poly(_Color,_NumVs,_Vs,_LineStyle,_LineWidth,_PenPat,_Id,_Spline,
* _ObjFill,_Dash,AttrList),
*/
static int style_list[] =
{
1, 10, 7, 6, 5, 4, 3, 2
};
for (i = 0; i < ns; i++) {
fprintf(tgif->strm, "poly('%s',2,[%d,%d,%d,%d],", COLOR,
seglist[i].x1, seglist[i].y1,
seglist[i].x2, seglist[i].y2);
fprintf(tgif->strm, "%d,%d,%d,%d,%d,%d,%d,[\n]).\n", 0, width,
style_list[lappr], 0, 0, style_list[lappr], 0);
}
}
/* Marker styles */
#define P_PIXEL 0
#define P_DOT 1
#define P_MARK 2
void
tgifDot(user_state, x, y, style, type, color)
char *user_state; /* Value set in xg_init */
int x,
y; /* Location in pixel units */
int style; /* Dot style */
int type; /* Type of marker */
int color; /* Marker color (if any) */
/*
* This routine should draw a marker at location `x,y'. If the
* style is P_PIXEL, the dot should be a single pixel. If
* the style is P_DOT, the dot should be a reasonably large
* dot. If the style is P_MARK, it should be a distinguished
* mark which is specified by `type' (0-7). If the output
* device is capable of color, the marker should be drawn in
* `color' (0-7) which corresponds with the color for xg_line.
*/
{
}
void
tgifEnd(user_state)
char *user_state;
/*
* This routine is called after a drawing sequence is complete.
* It can be used to clean up the user state and set the device
* state appropriately. This routine is optional in the structure.
*/
{
Info *tgif = (Info *) user_state;
fclose(tgif->strm);
}