338 lines
9.7 KiB
C
338 lines
9.7 KiB
C
/*
|
|
* HPGL Output
|
|
*
|
|
* Tom Quarles
|
|
*/
|
|
|
|
#define MAPX(state,x) ( (x) + P1X + state->clipminX )
|
|
#define MAPY(state,y) ( MAXY - (y) + P1Y - state->clipminY)
|
|
|
|
#include "copyright.h"
|
|
#include "xgraph.h"
|
|
#include "plotter.h"
|
|
#include <stdio.h>
|
|
#include <math.h>
|
|
|
|
static void hpglText();
|
|
static void hpglSeg();
|
|
static void hpglDot();
|
|
static void hpglEnd();
|
|
|
|
static xgOut hpglInfo =
|
|
{
|
|
D_COLOR, /* device characteristics */
|
|
MAXX, /* width */
|
|
MAXY, /* height */
|
|
200, /* border padding */
|
|
0, /* extra space around axis labels */
|
|
250, /* tick length - approx 1/4 inch */
|
|
50, /* spacing above legend lables */
|
|
0, /* axis font width */
|
|
0, /* axis font height */
|
|
0, /* title font width */
|
|
0, /* title font height */
|
|
1000000, /* maximum number of segments */
|
|
|
|
hpglText, /* text output function */
|
|
hpglSeg, /* segment drawing function */
|
|
hpglDot, /* dot/marker drawing function */
|
|
hpglEnd, /* end of plot function */
|
|
|
|
NULL, /* userInfo */
|
|
};
|
|
|
|
typedef struct {
|
|
double axis_w;
|
|
double axis_h;
|
|
double title_w;
|
|
double title_h;
|
|
FILE *plotterFile;
|
|
int clipminX;
|
|
int clipminY;
|
|
int clipmaxX;
|
|
int clipmaxY;
|
|
} mydata;
|
|
|
|
/*ARGSUSED*/
|
|
int
|
|
hpglInit(stream, width, height, title_family, title_size,
|
|
axis_family, axis_size, flags, outInfo, errmsg)
|
|
FILE *stream; /* output stream */
|
|
int width; /* desired width of space in microns */
|
|
int height; /* desired height in microns */
|
|
char *title_family; /* name of font for titles */
|
|
double title_size; /* size of font for titles */
|
|
char *axis_family; /* name of font for axes */
|
|
double axis_size; /* size of font for axes */
|
|
int flags; /* predicate values (ignored) */
|
|
xgOut *outInfo; /* my structure */
|
|
char errmsg[ERRBUFSIZE]; /* a place to complain to */
|
|
{
|
|
mydata *myInfo;
|
|
|
|
myInfo = (mydata *) Malloc(sizeof(mydata));
|
|
if (myInfo == NULL)
|
|
return 0;
|
|
*outInfo = hpglInfo;
|
|
outInfo->area_w = MIN(MAXX, width / 25);
|
|
outInfo->area_h = MIN(MAXY, height / 25);
|
|
/* magic formulas: input sizes are in points = 1/72 inch */
|
|
/* my sizes are in cm */
|
|
/* plotter units are in units of .025mm ~= 1/1016 inch */
|
|
/*
|
|
* have to warn of height 1.5 times larger or get bitten by plotter's
|
|
* internal padding
|
|
*/
|
|
/* widths are (arbitrarily) selected to be 2/3 of the height */
|
|
/* (cancels with width factor) */
|
|
myInfo->axis_w = axis_size * .666 * 2.54 / 72.;
|
|
myInfo->axis_h = axis_size * 2.54 / 72.;
|
|
myInfo->title_w = title_size * .666 * 2.54 / 72.;
|
|
myInfo->title_h = title_size * 2.54 / 72.;
|
|
|
|
outInfo->axis_pad = axis_size * 1016. * 1.5 / 72.;
|
|
outInfo->axis_width = axis_size * 1016. * 1.5 / 72.;
|
|
outInfo->axis_height = axis_size * 1016. * .666 / 72.;
|
|
outInfo->title_width = title_size * 1016. * 1.5 / 72.;
|
|
outInfo->title_height = title_size * 1016. * .666 / 72.;
|
|
outInfo->user_state = (char *) myInfo;
|
|
myInfo->plotterFile = stream;
|
|
myInfo->clipminX = 0;
|
|
myInfo->clipminY = 0;
|
|
myInfo->clipmaxX = MAXX;
|
|
myInfo->clipmaxY = MAXY;
|
|
fprintf(myInfo->plotterFile, "PG;IN;\n");
|
|
fprintf(myInfo->plotterFile, "DI1,0;\n");
|
|
fprintf(myInfo->plotterFile, "IW%d,%d,%d,%d;\n", MAPX(myInfo, 0),
|
|
MAPY(myInfo, myInfo->clipmaxY - myInfo->clipminY),
|
|
MAPX(myInfo, myInfo->clipmaxX - myInfo->clipminX),
|
|
MAPY(myInfo, 0));
|
|
return (1);
|
|
}
|
|
|
|
static void
|
|
hpglText(userState, x, y, text, just, style)
|
|
mydata *userState; /* my state information */
|
|
int x,
|
|
y; /* coords of text origin */
|
|
char *text; /* what to put there */
|
|
int just; /* how to justify */
|
|
|
|
/*
|
|
* where the origin is relative to where the text should go as a function of
|
|
* the various values of just
|
|
*
|
|
* T_UPPERLEFT T_TOP T_UPPERRIGHT T_LEFT T_CENTER T_RIGHT
|
|
* T_LOWERLEFT T_BOTTOM T_LOWERRIGHT
|
|
*
|
|
*/
|
|
int style; /* T_AXIS = axis font, T_TITLE = title font */
|
|
|
|
{
|
|
fprintf(userState->plotterFile, "PU;SP%d;", TEXTCOLOR);
|
|
fprintf(userState->plotterFile, "PA%d,%d;", MAPX(userState, x), MAPY(userState, y));
|
|
switch (style) {
|
|
case T_AXIS:
|
|
fprintf(userState->plotterFile, "SI%f,%f;", userState->axis_w, userState->axis_h);
|
|
break;
|
|
case T_TITLE:
|
|
fprintf(userState->plotterFile, "SI%f,%f;", userState->title_w, userState->title_h);
|
|
break;
|
|
default:
|
|
printf("bad text style %d in hpglText\n", style);
|
|
exit(1);
|
|
break;
|
|
}
|
|
switch (just) {
|
|
case T_UPPERLEFT:
|
|
fprintf(userState->plotterFile, "LO3;\n");
|
|
break;
|
|
case T_TOP:
|
|
fprintf(userState->plotterFile, "LO6;\n");
|
|
break;
|
|
case T_UPPERRIGHT:
|
|
fprintf(userState->plotterFile, "LO9;\n");
|
|
break;
|
|
case T_LEFT:
|
|
fprintf(userState->plotterFile, "LO2;\n");
|
|
break;
|
|
case T_CENTER:
|
|
fprintf(userState->plotterFile, "LO5;\n");
|
|
break;
|
|
case T_RIGHT:
|
|
fprintf(userState->plotterFile, "LO8;\n");
|
|
break;
|
|
case T_LOWERLEFT:
|
|
fprintf(userState->plotterFile, "LO1;\n");
|
|
break;
|
|
case T_BOTTOM:
|
|
fprintf(userState->plotterFile, "LO4;\n");
|
|
break;
|
|
case T_LOWERRIGHT:
|
|
fprintf(userState->plotterFile, "LO7;\n");
|
|
break;
|
|
default:
|
|
printf("bad justification type %d in hpglText\n", just);
|
|
exit(1);
|
|
break;
|
|
}
|
|
fprintf(userState->plotterFile, "LB%s\03;", text);
|
|
}
|
|
|
|
|
|
|
|
static int penselect[8] =
|
|
{PEN1, PEN2, PEN3, PEN4, PEN5, PEN6, PEN7, PEN8};
|
|
static int lineselect[8] =
|
|
{LINE1, LINE2, LINE3, LINE4, LINE5, LINE6,
|
|
LINE7, LINE8};
|
|
|
|
|
|
|
|
static void
|
|
hpglSeg(userState, ns, segs, width, style, lappr, color)
|
|
mydata *userState; /* my state information (not used) */
|
|
int ns; /* number of segments */
|
|
XSegment *segs; /* X array of segments */
|
|
int width; /* width of lines in pixels */
|
|
int style; /* L_VAR = dotted, L_AXIS = grid, L_ZERO = axis */
|
|
int lappr; /* line style */
|
|
int color; /* line color */
|
|
{
|
|
int i;
|
|
|
|
if (style == L_ZERO) {
|
|
fprintf(userState->plotterFile, "SP%d;", PENAXIS); /* select correct pen */
|
|
fprintf(userState->plotterFile, "LT;"); /* solid line style */
|
|
}
|
|
else if (style == L_AXIS) {
|
|
fprintf(userState->plotterFile, "SP%d;", PENGRID); /* select correct pen */
|
|
fprintf(userState->plotterFile, "LT;"); /* solid line style */
|
|
}
|
|
else if (style == L_VAR) {
|
|
if ((color < 0) || (color > 7)) {
|
|
printf("out of range line color %d in hpglLine\n", color);
|
|
exit(1);
|
|
}
|
|
fprintf(userState->plotterFile, "SP%d;", penselect[color]); /* select correct pen */
|
|
if ((lappr < 0) || (lappr > 7)) {
|
|
printf("out of range line style %d in hpglLine\n", lappr);
|
|
exit(1);
|
|
}
|
|
if (lappr == 0) {
|
|
fprintf(userState->plotterFile, "LT;"); /* select solid line
|
|
* type */
|
|
}
|
|
else {
|
|
fprintf(userState->plotterFile, "LT%d;", lineselect[lappr]); /* select line type */
|
|
}
|
|
}
|
|
else {
|
|
printf("unknown style %d in hpglLine\n", style);
|
|
exit(1);
|
|
}
|
|
for (i = 0; i < ns; i++) {
|
|
if (!i || ((segs[i].x1 != segs[i - 1].x2) || (segs[i].y1 != segs[i - 1].y2))) {
|
|
/* MOVE */
|
|
fprintf(userState->plotterFile, "PU;PA%d,%d;\n", MAPX(userState, segs[i].x1),
|
|
MAPY(userState, segs[i].y1));
|
|
}
|
|
/* DRAW */
|
|
if (width <= 1) {
|
|
fprintf(userState->plotterFile, "PD;PA%d,%d;\n", MAPX(userState, segs[i].x2),
|
|
MAPY(userState, segs[i].y2));
|
|
}
|
|
else { /* ugly - wide lines -> rectangles */
|
|
double frac;
|
|
int lx,
|
|
ly;
|
|
int urx,
|
|
ury,
|
|
ulx,
|
|
uly,
|
|
llx,
|
|
lly,
|
|
lrx,
|
|
lry;
|
|
|
|
frac = (width / 2) / sqrt((double)
|
|
((segs[i].x1 - segs[i].x2) *
|
|
(segs[i].x1 - segs[i].x2)) +
|
|
((segs[i].y1 - segs[i].y2) *
|
|
(segs[i].y1 - segs[i].y2)));
|
|
lx = frac * (segs[i].y2 - segs[i].y1);
|
|
ly = -frac * (segs[i].x2 - segs[i].x1);
|
|
urx = segs[i].x2 + lx;
|
|
ury = segs[i].y2 + ly;
|
|
ulx = segs[i].x2 - lx;
|
|
uly = segs[i].y2 - ly;
|
|
llx = segs[i].x1 - lx;
|
|
lly = segs[i].y1 - ly;
|
|
lrx = segs[i].x1 + lx;
|
|
lry = segs[i].y1 + ly;
|
|
fprintf(userState->plotterFile, "PU;PA%d,%d;", MAPX(userState, llx),
|
|
MAPY(userState, lly));
|
|
fprintf(userState->plotterFile, "PM0;");
|
|
fprintf(userState->plotterFile, "PD,PA%d,%D;PA%d,%D;PA%d,%d;\n",
|
|
MAPX(userState, lrx), MAPY(userState, lry),
|
|
MAPX(userState, urx), MAPY(userState, ury),
|
|
MAPX(userState, ulx), MAPY(userState, uly));
|
|
fprintf(userState->plotterFile, "PM2;FP;EP;");
|
|
}
|
|
}
|
|
fprintf(userState->plotterFile, "PU;");
|
|
}
|
|
|
|
static char *markselect[8] =
|
|
{MARK1, MARK2, MARK3, MARK4, MARK5, MARK6,
|
|
MARK7, MARK8};
|
|
|
|
static void
|
|
hpglDot(userState, x, y, style, type, color)
|
|
mydata *userState; /* my state information (not used) */
|
|
int x,
|
|
y; /* coord of dot */
|
|
int style; /* type of dot */
|
|
int type; /* dot style variation */
|
|
int color; /* color of dot */
|
|
{
|
|
/* move to given coord */
|
|
fprintf(userState->plotterFile, "PU;PA%d,%d;\n", MAPX(userState, x), MAPY(userState, y));
|
|
if ((color < 0) || (color > 7)) {
|
|
printf("unknown color %d in hpglDot\n", color);
|
|
exit(1);
|
|
}
|
|
fprintf(userState->plotterFile, "SP%d;", penselect[color]);
|
|
if (style == P_PIXEL) {
|
|
fprintf(userState->plotterFile, "PD;PU;\n");
|
|
}
|
|
else if (style == P_DOT) {
|
|
fprintf(userState->plotterFile, "LT;PM0;CI40;PM2;FT;EP;\n");
|
|
}
|
|
else if (style == P_MARK) {
|
|
if ((type < 0) || (type > 7)) {
|
|
printf("unknown marker type %d in hpglDot\n", type);
|
|
exit(1);
|
|
}
|
|
/*
|
|
* fprintf(userState->plotterFile,"LT;CA5;LO4;SI0.1;LB%s\03;\n",marksele
|
|
* ct[type]);
|
|
*/
|
|
fprintf(userState->plotterFile, "LT;CS5;LO4;SI0.15;SM%s;PR0,0;SM;CS;\n", markselect[type]);
|
|
}
|
|
else {
|
|
printf("unknown marker style %d in hpglDot\n", style);
|
|
exit(1);
|
|
}
|
|
}
|
|
|
|
static void
|
|
hpglEnd(userState)
|
|
mydata *userState; /* my state information (not used) */
|
|
|
|
{
|
|
fprintf(userState->plotterFile, "SP;PG;IN;\n");
|
|
fflush(userState->plotterFile);
|
|
return;
|
|
}
|