[net.sources] plot

david@utzoo.UUCP (David Trueman) (10/26/84)

Following is a shell archive of the source for a V7 plot(3) library for
Hewlett-Packard plotters which speak HPGL (HP Graphics Language).  We have
now had fairly extensive experience using this software with our HP7470
2-pen plotter.

We have had enough requests for this software that we felt it was worth
posting to the net.  The package was written jointly by myself and
Henry Spencer.  While the package has been fairly well-exercised, should
any bugs show up, please let us know.

# This is a shell archive.  Remove anything before this line, then
# unpack it by saving it in a file and typing "sh file".  (Files
# unpacked will be owned by you and have default permissions.)
#
# This archive contains:
# Makefile arc.c box.c circle.c close.c cont.c dot.c erase.c hpglchord.c label.c line.c linmod.c move.c onoff.c open.c point.c space.c

echo x - Makefile
cat > "Makefile" << '//E*O*F Makefile//'
# Define CIRELBUG if the plotter has the firmware bug that puts it into
# relative-coordinate mode after a circle or an arc.
CFLAGS=-O -DCIRELBUG

all:	libhpgl.a

libhpgl.a:	 arc.o box.o circle.o close.o cont.o dot.o erase.o label.o line.o \
	linmod.o move.o open.o point.o space.o onoff.o hpglchord.o
	ar rc libhpgl.a *.o

clean:
	rm -f *.o libhpgl.a

mv:	all
	mv libhpgl.a ..
//E*O*F Makefile//

echo x - arc.c
cat > "arc.c" << '//E*O*F arc.c//'
/* @(#)arc.c	1.5 of 4 Aug 84 */

#include <math.h>
#define	sq(x)	((double)(x) * (double)(x))

extern int hpglchord();

arc(xc, yc, xs, ys, xe, ye)
int xc, yc;	/* center of arc */
int xs, ys;	/* starting point */
int xe, ye;	/* end point */
{
	double as, ae;
	double angle;
	double rs;
	double pi = 3.14159265358979323846;

	as = atan2((double)(ys - yc), (double)(xs - xc)) * (180/pi);
	ae = atan2((double)(ye - yc), (double)(xe - xc)) * (180/pi);
	angle = ae - as;
	if (angle < 0)
		angle += 360;

	rs = sqrt(sq(xs - xc) + sq(ys - yc));

	move(xs, ys);
	on();
	printf("PD;");
	printf("AA %d,%d,%.2f,%d;", xc, yc, angle, hpglchord((int)rs));
#ifdef CIRELBUG
	printf("PA;");		/* back into absolute mode -- firmware bug */
#endif
	off();
}
//E*O*F arc.c//

echo x - box.c
cat > "box.c" << '//E*O*F box.c//'
box(x0, y0, x1, y1)
int x0, y0;	/* one corner */
int x1, y1;	/* other corner */
{
	move(x0, y0);
	cont(x0, y1);
	cont(x1, y1);
	cont(x1, y0);
	cont(x0, y0);
	move(x1, y1);
}
//E*O*F box.c//

echo x - circle.c
cat > "circle.c" << '//E*O*F circle.c//'
/* @(#)circle.c	1.4 of 31 July 84 */
extern int hpglchord();

circle(x, y, r)
int x, y;	/* center */
int r;	/* radius */
{
	move(x, y);
	on();
	printf("CI %d,%d;", r, hpglchord(r));
#ifdef CIRELBUG
	printf("PA;");		/* back into absolute mode -- firmware bug */
#endif
	off();
}
//E*O*F circle.c//

echo x - close.c
cat > "close.c" << '//E*O*F close.c//'
/* @(#)close.c	1.2 of 26 July 84 */
#include <stdio.h>

closepl()
{
	on();
	printf("PU;");		/* pen up */
	printf("SP;");		/* put pen away */
	off();
	fflush(stdout);
}
//E*O*F close.c//

echo x - cont.c
cat > "cont.c" << '//E*O*F cont.c//'
cont(x, y)
int x, y; 	/* point to move to */
{
	on();
	printf("PD %d,%d;", x, y);
	off();
}
//E*O*F cont.c//

echo x - dot.c
cat > "dot.c" << '//E*O*F dot.c//'
dot()
{
	on();
	off();
}
//E*O*F dot.c//

echo x - erase.c
cat > "erase.c" << '//E*O*F erase.c//'
erase()
{
	on();
	off();
}
//E*O*F erase.c//

echo x - hpglchord.c
cat > "hpglchord.c" << '//E*O*F hpglchord.c//'
/* @(#)hpglchord.c	1.2 of 2 Oct 84 */

extern int hpglsize;		/* Size of coordinate space. */

#define	MINCHA	5		/* Minimum chord angle. */

/*
 * hpglchord - compute a suitable chord angle for circle/arc
 */
int
hpglchord(r)
int r;		/* radius */
{
	int changle;

	/*
	 * The following calculation is essentially just chord/radius,
	 * where chord is the desired chord size (10 machine units).
	 * This yields an (approximate) result in radians, which is then
	 * multiplied by (360/2pi), about 57, to yield degrees.  The
	 * messy part is that the desired chord needs to be expressed in
	 * user units, and care is needed to avoid overflow and underflow
	 * in integer arithmetic.  A 10-unit chord is 1/720 of the machine
	 * coordinate space, so hpglsize/720 would be the chord.  Shuffling,
	 * we have (57/720)*(hpglsize/r).  (1/13) is close to (57/720)
	 * and involves much less chance of over/underflow problems.
	 *
	 * Actually, the machine coordinate space isn't always (in fact,
	 * ever!) 7200x7200 any more, but the numbers still come out close
	 * enough that it's not worth worrying about.
	 *
	 * After all that, we enforce a minimum chord for speed.  This
	 * pretty much eliminates residual underflow worries.
	 */
	changle = (hpglsize/r)/13;
	if (changle < MINCHA)
		changle = MINCHA;

	return(changle);
}
//E*O*F hpglchord.c//

echo x - label.c
cat > "label.c" << '//E*O*F label.c//'
/* @(#)label.c	1.3 of 26 July 84 */
label(s)
char *s;
{
	on();
	printf("CP -0.3333,-0.25;");	/* offset to center first char */
	printf("LB%s%c", s, 03);
	off();
}
//E*O*F label.c//

echo x - line.c
cat > "line.c" << '//E*O*F line.c//'
line(x0,y0,x1,y1)
int x0, y0;	/* starting point */
int x1, y1;	/* end point */
{
	move(x0,y0);
	cont(x1,y1);
}
//E*O*F line.c//

echo x - linmod.c
cat > "linmod.c" << '//E*O*F linmod.c//'
/* @(#)linmod.c	1.2 of 9 Aug 84 */

#define	STREQ(x, y)	(strcmp((x), (y)) == 0)

linemod(s)
char *s;
{
	char *pattern;

	if (STREQ(s, "dotted"))
		pattern = "1,1";
	else if (STREQ(s, "solid"))
		pattern = "";
	else if (STREQ(s, "longdashed"))
		pattern = "3,1";
	else if (STREQ(s, "shortdashed"))
		pattern = "2,1";
	else if (STREQ(s, "dotdashed"))
		pattern = "4,2";
	on();
	printf("LT %s;", pattern);
	off();
}
//E*O*F linmod.c//

echo x - move.c
cat > "move.c" << '//E*O*F move.c//'
move(x,y)
int x, y; 	/* point to move to */
{
	on();
	printf("PU %d,%d;", x, y);
	off();
}
//E*O*F move.c//

echo x - onoff.c
cat > "onoff.c" << '//E*O*F onoff.c//'
on()
{
	printf("\033.Y");		/* wakeup plotter */
}

off()
{
	printf("\033.Z");		/* turn plotter off again */
}
//E*O*F onoff.c//

echo x - open.c
cat > "open.c" << '//E*O*F open.c//'
/* @(#)open.c	1.5 of 2 Oct 84 */
openpl()
{
	on();
	printf("\033.I81;;17:");	/* set threshold for sending XOFF to 81
					 * and set XON character to DC1
					 */
	printf("\033.N;19:");		/* set XOFF character to DC3 */
	printf("IN;");			/* initialize everything */
	printf("SP 1;");		/* select left pen */
	printf("VS 20;");		/* reduce pen velocity */
	printf("SI 0.1368,0.27;");	/* char size absolute, shrunk a bit */
	off();
}
//E*O*F open.c//

echo x - point.c
cat > "point.c" << '//E*O*F point.c//'
point(xi,yi){
	move(xi,yi);
	cont(xi,yi);
}
//E*O*F point.c//

echo x - space.c
cat > "space.c" << '//E*O*F space.c//'
/* @(#)space.c	1.3 of 2 Oct 84 */

#define	PLOTX	10300	/* How wide is plotter in physical units. */
#define	PLOTY	7650	/* How high is plotter in physical units. */

int hpglsize = 7200;	/* Size of coordinate space, for chord calculations. */

space(x0,y0,x1,y1)
int x0, y0;	/* lower left corner */
int x1, y1;	/* upper right corner */
{
	int absy;
	long aspect;		/* In thousandths. */
	int llx, lly, urx, ury;

	/*
	 * compute physical plot area:  use as much of the paper as
	 * possible while preserving the aspect ratio of the user space.
	 */
	aspect = (1000L * abs(x1 - x0)) / abs(y1 - y0);
	if (aspect > (1000L * PLOTX) / PLOTY) {		/* Wide and squat. */
		llx = 0;
		urx = PLOTX;
		lly = (PLOTY - (int)((1000L * PLOTX) / aspect)) / 2;
		ury = lly + (int)((1000L * PLOTX) / aspect);
	} else {		/* Limited by height, not width. */
		lly = 0;
		ury = PLOTY;
		llx = (PLOTX - (int)((PLOTY * aspect)/1000)) / 2;
		urx = llx + (int)((PLOTY * aspect)/1000);
	}

	on();
	printf("IP %d,%d,%d,%d;", llx, lly, urx, ury);	/* set plot area */
	printf("SC %d,%d,%d,%d;", x0, x1, y0, y1);	/* set scaling */
	off();

	hpglsize = abs(x1 - x0);
	absy = abs(y1 - y0);
	if (absy > hpglsize)
		hpglsize = absy;
}
//E*O*F space.c//

exit 0
-- 
				David Trueman @ U of Toronto Zoology
				{allegra,ihnp4,linus,decvax}!utzoo!david

henry@utzoo.UUCP (Henry Spencer) (10/26/84)

One minor annoyance of this library that perhaps should have been
mentioned in the posting:  the arc() routine needs both floating-point
and the -lm math library.  It's hard to fix this, since plot(3) and
HPGL have different ideas of how to specify arcs, and the transformation
requires non-trivial trigonometry.  If any masochist out there feels
like figuring out how to do all that without floating-point, I'd be
interested in seeing the result.
-- 
				Henry Spencer @ U of Toronto Zoology
				{allegra,ihnp4,linus,decvax}!utzoo!henry