[unix-pc.sources] A Yale starchart driver for the UNIX-PC

rck@ihuxv.ATT.COM (R. C. Kukuk) (12/12/87)

The subject line says it all; the README says a little more.

#!/bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #!/bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create the files:
#	Makefile
#	README
#	allcons
#	starchart.1
#	starchart.c
#	starchart.h
#	starvdi.c
#	tonet
# This archive created: Fri Dec 11 15:52:40 1987
export PATH; PATH=/bin:$PATH
if test -f 'Makefile'
then
	echo shar: over-writing existing file "'Makefile'"
fi
cat << \SHAR_EOF > 'Makefile'
#
# Author: Petri Launiainen, Intrinsic Oy, Tampere, FINLAND (pl@intrin.FI)
#
# Based on the work of Alan W. Paeth
#

SHELL = /bin/sh

#
# put the Yale Star Catalog file path here: because the yale.star is
# static (stars don't change so often :->), consider using some static
# library path here - relative one is used for quick testing

#STAR = "/usr/lib/starchart/yale.star"
STAR = "/u/rck/Filecabinet/src/yale/yale.star"

# similarly assign the Messier file path:

#MESS = "/usr/lib/starchart/messier.star"
MESS = "/u/rck/Filecabinet/src/yale/messier.star"

CONST = "/u/rck/Filecabinet/src/yale/con.locs"

# put the planet position file path here: it should be preferably
# relative, thus allowing everyone to change planet positions according
# to their interests.  This file changes when the 'planet' program is
# executed

PLANET = "/u/rck/Filecabinet/src/yale/planet.star"

# notice that starchart.o and planet are made dependent on Makefile, due
# to the STAR, MESS, CONST and PLANET definitions here

# put the installation directory here

BINDIR = /usr/lbin

CFLAGS = -O -DSTARFILE='$(STAR)' -DPLANETFILE='$(PLANET)' \
	-DMESSFILE='$(MESS)' -DCONSTFILE='$(CONST)'
LFLAGS =

# star chart calculation routine file

COBJ = starchart.o

# default binary names: if you change these, change also the corresponding
# make tags

BINS = epoch moonphase planet startek stardsp starpic starhp \
	starlaser starpost starvdi

all:	\
	planet\
	starhp\
	stardsp\
	starvdi\
	startek\
	starpic\
	starpost\
	starlaser\
	epoch\
	moonphase

test:
	stardsp -c ori

install: all
	strip $(BINS)
	mv $(BINS) $(BINDIR)

starchart.o: starchart.c starchart.h Makefile

moonphase: moonphase.o
	cc $(LFLAGS) moonphase.o -lm -o $@

epoch: epoch.o
	cc $(LFLAGS) epoch.o -lm -o $@

planet:	planet.o Makefile
	cc $(LFLAGS) $(DEFINES) planet.o -lm -o $@

stardsp: $(COBJ) stardsp.o
	cc $(LFLAGS) $(COBJ) stardsp.o -lm -o $@

starvdi: $(COBJ) starvdi.o
	cc -G $(LFLAGS) starvdi.o $(COBJ) -lm -lcvdi -o $@

starpic: $(COBJ) starpic.o
	cc $(LFLAGS) $(COBJ) starpic.o -lm -o $@

startek: $(COBJ) startek.o starimages.o
	cc $(LFLAGS) $(COBJ) startek.o starimages.o -lm -o $@

starhp: $(COBJ) starhp.o starimages.o
	cc $(LFLAGS) $(COBJ) starhp.o starimages.o -lm -o $@

starlaser: $(COBJ) starlaser.o starimages.o
	cc $(LFLAGS) $(COBJ) starlaser.o starimages.o -lm -o $@

starpost: $(COBJ) starpost.o
	cc $(LFLAGS) $(COBJ) starpost.o -lm -o $@

make clean:
	rm -f *.o mlog core
SHAR_EOF
if test -f 'README'
then
	echo shar: over-writing existing file "'README'"
fi
cat << \SHAR_EOF > 'README'
This archive contains a starchart driver for the GSS-VDI implementation
on the UNIX-PC.  A modified starchart.c, starchart.h and Makefile are
included.  allcons is just a thrown in freebie, try it, you may like it!

Starchart.c was also modified to print out all defined constellation
tags, so a modified starchart.1 is also included.

The star database is not included; I'm assuming you've already snarfed
it off the network.

BTW:  If anyone knows how to get rid of that wasteful, thick border
surrounding the VDI window, please let me know.  That display area needs
every pixel it can get.

Ron Kukuk
AT&T Bell Labs
SHAR_EOF
if test -f 'allcons'
then
	echo shar: over-writing existing file "'allcons'"
fi
cat << \SHAR_EOF > 'allcons'
NAPTIME=120
while read cons rest 
do
	case "$cons" in
		/*)
		continue
		;;

		*)
		starvdi -c $cons &
		PID=$!
		sleep $NAPTIME
		kill $PID
		;;
	esac
done < con.locs
SHAR_EOF
if test -f 'starchart.1'
then
	echo shar: over-writing existing file "'starchart.1'"
fi
cat << \SHAR_EOF > 'starchart.1'
.TH starchart LOCAL 9/22/87
.ad b
.SH NAME
stardsp, starpic, startek, starpost, starhp, starlaser
.br
\- print astronomical star charts using Yale database.
.SH SYNOPSIS
\fBstar* RA DE [ scale title maglim lbllim ]\fR
.br
or
.br
\fB-r Ra -d Dl -s scale -t title -m maglim -l lbllim -f x.star\fR
.br
or
.br
\fB-c [ constellation | ? ] ...
.SH DESCRIPTION
These programs generate star charts based on data extracted from the Yale
public domain star catalog.
Output is to the terminal 
.RB (stardsp),
Unix PIC file format
.RB (starpic),
Tektronix
vector format
.RB (startek),
PostScript format
.RB (starpost),
Hewlett-Packard terminal vector format
.RB (starhp)
or in Hewlett-Packard Laserjet printer format
.RB (starlaser).
.PP
Star data is optionally overlayed with other cosmic objects, such as planets.
If limiting magnitudes are properly set and the Messier database is available,
Messier objects and some NGC objects are also printed.
.PP
The starchart center is specified by two parameters: Right
Ascension [0.00 to 24.00 hours] and Declination [-90.00 to +90.00 degrees].
An optional third parameter defines the N/S range of the output window, in
degrees of declination.  Digits after decimal point are taken as minutes:
object positions can therefore be taken directly from a star catalog.
.PP
An optional fourth parameter gives a title.  This conforms to the 'old'
Yale star chart format.  Two new parameters can be added after title,
defining the magnitude limit and label printing magnitude limit.  These
are discussed below.  All parameters can be given by using options,
which offers more flexibility. Parameters are:
.TP
.B \-r
Right ascension.
.TP
.B \-d
Declination.
.TP
.B \-s
Scale.
.TP
.B \-t
Title.  All these work as described above.  New options are:
.TP
.B \-m
Star limiting magnitude. This sets limits on the faintest stars displayed
on the "master" view. Default limits are device driver dependent (more below).
The "thumbnail" finder view is set to a related limit.
.TP
.B \-l
Label limiting magnitude. The new Yale database contains both a small set of
familiar names (for stars and special objects), plus an extensive list of
labels (Greek Bayer letter or Flamsteed numbers). Star names (including planet
names) always print for this small set. To avoid clutter, the labels may be
omitted below a cut-off magnitude by specifying this value.
.TP
.B \-c
A three or four character mnemonic follows, which is a search string for a
matching line-item entry in the file \fBcon.locs\fP. If found, then the
initial values for Ra, Decl, Scale and Title are taken from that file.
An option of '?' prints the current set of constellation mnemonics.
Because the command line is parsed from left to right, subsequent switches
might change the scale, title, or otherwise fine-tune the new defaults.
.TP
.B \-f
A file may be given containing ephemerides in the .star format, which will
overlay the output. This is also useful for generating constellation
boundaries, Milky Way isophots, and planet or satellite tracks. (The .star
format additionally includes records for vector and text annotation).
.PP
The present implementations draw two viewports: a ``master'' chart plus a
``thumbnail'' overview with low limiting magnitude.
Their location and the limiting magnitude is specified by records in
the device driver, allowing the chart layout be tuned on a per-device basis.
The output is annotated with viewport boundaries, a legend and axis labels.
.PP
Sanson's sinusoidal projection is used to map coordinates.
This projection preserves both area and linearity in Declination (y axis).
It gives good conformality (angle correctness) near the equator, so it is
useful along the Ecliptic.
Lines of RA converge at the poles (unlike cylindrical projections),
though Cassiopeia and the Dipper reproduce well.
.SH EXAMPLES 
.nf
# Sagittarius: a nice bunch of Messier objects.
starpost -c sgr -t "(Sagittarius 31 Oct 87)" >sag.ps
.sp
# Orion: the belt lies near 5h40m in RA, just below the CE.
stardsp 5.32 -5 12 "Trapezium (Orion)" 8 5 | more
.fi
.SH FILES
.nf
.ta 2.6i
\fByale.star\fP	stellar information (mandatory)
\fBmessier.star\fP	Messier objects (optional)
\fBplanet.star\fP	Planets (optional)
\fBcon.locs\fP	default mnemonic locations
.fi
.br
.sp
These default paths can be easily changed in the Makefile.
.SH BUGS
No testing for bogus ranges and scales which may wrap the poles.
The present implementation expects
.B yale.star
sorted by decreasing magnitude so that output is sequential, and then cuts off
below a limiting magnitude.
For more detailed charts spatial sorting is more appropriate.
.PP
If <minutes> part of the parameters is greater than 59 it is silently
truncated to 59.
.PP
All .star file coordinates are for epoch E2000.0. The Messier objects
in \fBmessier.star\fP were taken from precessed E1975.0 data. The additional
NGC objects were taken from data in the star atlas by \fINorton\fP and
precessed from E1950.0. Rough guesses on visual magnitude were made.
.SH AUTHOR/EDITOR
Alan Paeth, University of Waterloo (AWPaeth@watCGL)
.SH CONTRIBUTORS
Petri Launiainen (pl@intrin.FI)
.br
Jyrki Yli-Nokari (jty@intrin.FI)
.br
Robert Tidd (inp@VIOLET.BERKELEY.EDU)
SHAR_EOF
if test -f 'starchart.c'
then
	echo shar: over-writing existing file "'starchart.c'"
fi
cat << \SHAR_EOF > 'starchart.c'
/*
 * starchart.c -- version 2, September 1987
 *
 * (c) copyright 1987 by Alan Paeth (awpaeth@watcgl)
 */

/*
 ! Version 2 modification authors:
 !
 !   [a] Petri Launiainen, pl@intrin.FI (with Jyrki Yli-Nokari, jty@intrin.FI)
 !   [b] Bob Tidd, inp@VIOLET.BERKELEY.EDU
 !   [c] Alan Paeth, awpaeth@watcgl
 !   [d] R. C. Kukuk
 !
 ! Changes and Additions:
 !
 !a   [1] STARFILE, PLANETFILE, etc. path designations are now in the Makefile
 !ac  [2] Fractional Ra and Decl values are now hh.mm and mm.ss (base 60)
 !a   [3] Command syntax now allows flags as well as old style (arg placement)
 !ab  [4] Extended Yale database (courtesy B. Tidd) also supported on input
 !bc  [5] Greek+Flamsteed numbers now appear as a hardcopy annotation
 !bc  [6] Constellation file finds ra,dl,scale from command line pattern
 !c   [7] New symbols for Nebulae, Galaxies and Clusters added (based on [4])
 !c   [8] Double star indications added (provisions for variable stars) ([4])
 !a   [9] Limiting magnitude flags for stars and labels allowed
 !c  [10] Legend column reformatted to contain additional symbols [4]
 !a  [11] Internal symbol compiler created for raster glyph creation
 !c  [12] add Yale records for "moveto"/"drawto" and text annotations
 !c  [13] added -f file.star to add ephemeride data
 !d  [14] Wrote driver for UNIX-PC version of GSS VDI.
 !d  [15] Added -c ? to print set of constellation tags.
 !
 ! Bug Fixes:
 !
 !a   [1] no more core dumps (on SysV) when given bad command line parameters
 !c   [2] Negative RA indications now "wrap" to 24hrs, etc.
 !bc  [3] Mag values *rounded* to nearest unit value (common Atlas convention)
 !c   [4] Removed any device dependent subroutines (eg. getopt).
 !d   [5] #Ifdef'ed sscanf() format in constellation read.
 !d   [6] Renamed function "xform" to fix a VDI library symbol clash.
 !
 ! Final integration by the original author [c].
 ! Questions, suggestions, and fixes should be e-mailed to him.
 */

#include <stdio.h>
#include <math.h>

#ifdef	BERZERK
#include <strings.h>
#endif

#include <ctype.h>
#include "starchart.h"

/*
 * datasets are local, unless defined in Makefile
 */

#ifndef STARFILE
#define STARFILE	"./yale.star"
#endif

#ifndef PLANETFILE
#define PLANETFILE	"./planet.star"
#endif

#ifndef MESSFILE
#define MESSFILE	"./messier.star"
#endif

#ifndef CONSTFILE
#define CONSTFILE	"./con.locs"
#endif

#define DCOS(x) (cos((x)*3.14159265354/180.0))
#define MAX(a,b) ((a)>(b)?(a):(b))
#define MIN(a,b) ((a)<(b)?(a):(b))

#define THUMBDIFF 2.5	/* thumbnail mag lim is brighter */
#define THUMBMAX 5.0	/* but no lower than this value */
#define THUMBRATIO 1.2	/* and scaled by this size (yet is already wider) */
#define THUMBDEG 10.0	/* but this is the floor on finder scale */
#define FSIZESML 8	/* point size for star designation */
#define FSIZELRG 10	/* point size for other object annotations */

double	max(), modup(), moddown();
double	ftod(), htod(), atof();

/* globals */

char	*progname;		/* program name for errors */
double	ra, de, sc;		/* global chart attributes */
char	*title;
char	*userfile;		/* potential .star file of user ephemerides */

/* the code */

main(argc, argv)
int	argc;
char	*argv[];
	{
	double	thumbscale;

	commandline(argc, argv);

	vecopen();

	chartparms(&master, ra, de, sc);

	thumbscale = MAX(sc * THUMBRATIO, THUMBDEG);
	chartparms(&thumbnail, ra, de, thumbscale);

	thumbnail.maglim = MIN(THUMBMAX, master.maglim - THUMBDIFF);
	chartall(&master);

	chartall(&thumbnail);

	chartlegend(&master);

	vecclose();

	exit(0);
}


commandline(argc, argv)
char	**argv;
	{
	int	j;
	static char	*usage = 
	"\nusage:\tstar* [ Ra Dcl Scale Title Maglim Labellim ]\nor\tstar* [ -r Ra -d Dcl -s Scale -t Title -m Maglim -l Labellim -f x.star ]\nor\tstar*  [ -c con (3 or 4 letters chosen from con.locs) -l ... ]";

	progname = argv[0];
	title = NULL;
	ra = 0.0;
	de = 0.0;
	sc = 0.0;
	/*
	 * check command line style
	 */
	if (argc == 1) 
		die("No arguments - %s", usage);

	if ((argv[1][0] == '-') && isalpha(argv[1][1])) {
		/*
		 * new style command line (using flags)
		 */
		for (j = 1; j < argc; j++) {
			if (argv[j][0] != '-') 
				die("unknown argument - %s", argv[j]);

			switch (argv[j][1]) {
			case 'c': 
				findconst(argv[++j]); 
				break;

			case 'r': 
				ra = htod(argv[++j]); 
				break;

			case 'd': 
				de = htod(argv[++j]); 
				break;

			case 's': 
				sc = atof(argv[++j]); 
				break;

			case 'l': 
				master.lbllim = (float)(atof(argv[++j])); 
				break;

			case 'm': 
				master.maglim = (float)(atof(argv[++j])); 
				break;

			case 't': 
				title = argv[++j]; 
				break;

			case 'f': 
				userfile = argv[++j]; 
				break;

			case 'u': 
				die("%s", usage);
			default:  
				die("unknown switch - %s", argv[j]);
			}
			if (j == argc) 
				die("trailing command line flag - %s",
				    argv[j-1]);
		}
	} else {
		/*
		 * old style command line (position dependent)
		 */
		switch (argc) {
		case 7: 
			master.maglim = (float)(atof(argv[6]));
		case 6: 
			master.lbllim = (float)(atof(argv[5]));
		case 5: 
			title = argv[4];
		case 4: 
			sc = atof(argv[3]);
		case 3: 
			de = htod(argv[2]);
		case 2: 
			ra = htod(argv[1]); 
			break;
		default: 
			die("too many arguments - %s", usage);
		}
	}
}


double	ftod(x)
double	x;
	{
	int	full;

	full = x;
	return(full + (x - full) * 100.0 / 60.0);
}


double	htod(s)
char	*s;
	{
	/*
	 * htod(str) reads floating point strings of the form {+-}hh.{mm} thus
	 * allowing for fractional values in base 60 (ie, degrees/minutes).
	 */
#ifdef	GOOBER
    double x, sign;
    int full, frac;
    char *t;
    t = s-1;
    while(*++t) {
	if ((*t == ' ') || (*t = '\t') || (*t == '\n')) break;
	if (((*t<'0') || (*t>'9') ) && (*t!='.') && (*t!='+') && (*t!='-'))
	    die("non-digit in dd.mm style numeric argument: %s", s);
	}
    if (s == NULL) return 0.0;
    full = frac = 0;
    sign = 1.0;
    if (*s == '-')
	{
	sign = -1.0;
	s++;
	}
    else if (*s == '+') s++;
    while (*s && *s != '.') full = 10 * full + *s++ - '0';
    if (*s++ == '.')
	{
	if (*s) frac = 10 * (*s++ - '0');
	if (*s) frac += *s++ - '0';
	if (frac > 59) frac = 59;
	}
    x = (double) full + ((double) frac) / 60.0;
    return sign * x;
#endif
	return(ftod(atof(s)));
}


chartparms(chart, ras, decl, scl)
double	ras, decl, scl;
map chart;
	{
	double	adj, xscale;

	chart->racen = ras * 360.0 / 24.0;
	chart->dlcen = decl;
	chart->scale = scl;
	if (chart->scale == 0.0) 
		chart->scale = 15.0;

	chart->north = chart->dlcen + chart->scale / 2.0;
	chart->south = chart->dlcen - chart->scale / 2.0;
	/*
	 * xscale is other than chart->scale in order to widen the
	 * horizontal viewing area, which otherwise shrinks near the
	 * poles under Sanson's projection this happens in polar maps
	 * which do not span the celestial equator
	 */
	adj = 1.0;
	if (chart->north * chart->south > 0.0)
		adj = max(DCOS(chart->north), DCOS(chart->south));
	xscale = chart->scale / adj;

	chart->east  = (chart->racen + xscale * chart->ww / chart->wh / 2.0);
	chart->west  = (chart->racen - xscale * chart->ww / chart->wh / 2.0);
	chart->yscale = chart->wh / chart->scale;
}


chartlegend(chart)
map chart;
	{
	char	ras[2], dls[20], outstr[40];
	if ( ! title) 
		title = "LEGEND";
	rastr(ras, chart->racen);
	declstr(dls, chart->dlcen);
	sprintf(outstr, "(%s,%s lim: %2.1f)", ras, dls, chart->maglim);

	vecsize(16); 
	vecsyms(65, 220, title);
	vecsize(10); 
	vecsyms(65, 185, outstr);

	vecsize(12);
	drawStar(65, 150, 0, 'S', NULL);
	vecsyms(95, 150, "<0.5");
	if (chart->maglim >= 0.5) {
		vecsize(10);
		drawStar(230, 150, 1, 'S', NULL);
		vecsyms(260, 150, "<1.5");
	}
	if (chart->maglim >= 1.5) {
		vecsize(9);
		drawStar(65, 125, 2, 'S', NULL);
		vecsyms(95, 125, "<2.5");
	}
	if (chart->maglim >= 2.5) {
		vecsize(8);
		drawStar(230, 125, 3, 'S', NULL);
		vecsyms(260, 125, "<3.5");
	}
	if (chart->maglim >= 3.5) {
		vecsize(7);
		drawStar(65, 100, 4, 'S', NULL);
		vecsyms(95, 100, "<4.5");
	}
	if (chart->maglim > 4.5) {
		vecsize(6);
		drawStar(230, 100, 5, 'S', NULL);
		vecsyms(260, 100, ">4.5");
	}

	vecsize(10); 
	vecsyms(95,  75, "double");  
	drawStar(65,  75, 2, 'D', NULL);
	vecsize(10); 
	vecsyms(260,  75, "variable");
	drawStar(230,  75, 2, 'V', NULL);

	vecsize(10); 
	vecsyms(95,  50, "planet");  
	drawPlan(65,  50, 1, 'S', NULL);
	vecsize(10); 
	vecsyms(260,  50, "galaxy");  
	drawGalx(230,  50, 1, 'S', NULL);

	vecsize(10); 
	vecsyms(95,  25, "nebula");  
	drawNebu(65,  25, 1, 'S', NULL);
	vecsize(10); 
	vecsyms(260,  25, "cluster"); 
	drawClus(230,  25, 1, 'S', NULL);
}


readstar(file, lat, lon, mag, code, subcode, color, label, name)
FILE *file;
double	*lat, *lon, *mag;
char	*code, *subcode, *color, *label, *name;
	{
#define LINELEN 80
	char	sbuf[LINELEN+1], *ptr;
	double	rah, ram, ras, dld, dlm, dl, inten;
	int	len, i;
	/*
	 * file formats:
	 * new
	 *	064509-1643-99SDA1a CMASirius
	 *	051432-0812015SDB8b ORIRigel
	 * old
	 *	064509-1643-146SSSirius
	 *	051432-08120015SSRigel
	 */
	fgets(sbuf, LINELEN, file);
	if (feof(file)) 
		return(1);
	/*
	 * sscanf of floats is TOOO slow:
	 *     sscanf(sbuf, "%2f%2f%2f%c%2f%2f ... );
	 * use alternate:
	 */
#define F2(i) ((double)((sbuf[i]-'0')*10+sbuf[i+1]-'0'))
#define F3(i) ((double)((sbuf[i]-'0')*100+(sbuf[i+1]-'0')*10+sbuf[i+2]-'0'))
#define F4(i) ((double)((sbuf[i]-'0')*1000+(sbuf[i+1]-'0')*100+(sbuf[i+2])-'0')*10+sbuf[i+3]-'0')
	rah = F2(0);
	ram = F2(2);
	ras = F2(4);
	dld = F2(7);
	dlm = F2(9);
	/*
	 * common code
	 */
#define DLDEGSEC 3600.0
#define DLMINSEC 60.0
#define RAHRSSEC 54000.0
#define RAMINSEC 900.0
#define RASECSEC 15.0

	*lon = (RAHRSSEC * rah + RAMINSEC * ram + RASECSEC * ras) / DLDEGSEC;
	dl = (DLDEGSEC * dld + DLMINSEC * dlm) / DLDEGSEC;
	*lat = (sbuf[6]  == '-') ? -dl : dl;
	if (isdigit(sbuf[14])) {
		/*
		 * old reduced Yale catalog
		 */
		inten = F3(12);
		if (sbuf[11] == '0' || sbuf[11] == '+') 
			*mag = inten / 100.0;
		else if (sbuf[11] == '-') 
			*mag = -inten / 100.0;
		else 
			*mag = F4(11);	/* new feature for stars >= 10.0 mag */
		if (sbuf[11] != 0)
			code[0] = sbuf[15];
		subcode[0] = sbuf[16];
		color[0] = '\0'; 
		strcpy(color, "  "); /* set unknowns to blanks */
		label[0] = '\0';
		name[0] = '\0'; 
		strncat(name, &sbuf[17], strlen(&sbuf[17]) - 1);
	} else {
		/*
		 * new reduced Yale catalog
		 */
		*mag = ((sbuf[11] == '-') ? -F2(12) : F3(11)) / 100.0;
		code[0] = sbuf[14];	/* let's get Sirius */
		subcode[0] = sbuf[15];
		color[0] = '\0';
		label[0] = '\0';
		name[0] = '\0';
		switch (code[0]) {
		case 'C':
		case 'N':
		case 'G':
			/*
			 * name vs label:
			 *
			 * A "name" is a common English term for a star or
			 * cosmic object (eg Polaris, Pleiades). A label is
			 * an official designation for such an object (eg
			 * alpha-Ursa Minor, M45). For stars, labels are
			 * taken from the two column Bayer/Flamsteed field
			 * in the new reduced label format and the proper name
			 * from the "name" field (the label field might also
			 * include the three letter IAU constellation
			 * designation, but at present these are ignored)
			 *
			 * For non-stellar objects, the Bayer and IAU fields
			 * are typically blank (and always ignored), and the
			 * "name" field consists of the designation followed
			 * by an optional proper name, or perhaps just an
			 * annotation, the latter flagged by a leading ","
			 * and ignored by the software. For instance, the
			 * entry "m45 Pleiades" forms a label "m45" and a name
			 * "Pleiades", but the entry "m6  ,butterfly shape"
			 * forms merely the label "m6".
			 *
			 * At the present, the charting software which is
			 * supplied this data on a call to "readstar" will
			 * print names in favor of labels.
			 */
			/*
			 * extract Messier number and name
			 */
			strcpy(color, "  ");
			ptr = &sbuf[23];
			i = 0;
			while (isalnum(*ptr)) 
				label[i++] = *ptr++;

			label[i] = '\0';
			i = 0;
			while (*ptr == ' ') 
				ptr++;
			while (*ptr != ',' && *ptr != '\n' && *ptr)
				name[i++] = *ptr++;
			name[i] = '\0';
			break;

		default:
			/*
			 * extract color, label and name
			 */
			strncat(color, &sbuf[16], 2);
			strncat(label, &sbuf[18], strlen(&sbuf[18]) - 1);
			if ((len = strlen(label)) > 5) {
				strncat(name, &label[5], len - 5);
				label[5] = '\0';
			}
		}
	}
	return(0);
}


transform(chart, lat, lon, xloc, yloc)
map chart;
double	lat, lon;
int	*xloc, *yloc;
	{
	/*
	 * This is Sanson's Sinusoidal projection. Its properties:
	 *   (1) area preserving
	 *   (2) preserves linearity along y axis (declination/azimuth)
	 */
	*xloc = chart->wx + chart->ww / 2
		+ (chart->racen - lon) * chart->yscale * DCOS(lat);
	*yloc = chart->wy + (int)((lat - chart->south) * chart->yscale);
}


chartall(chart)
map	chart;
	{
	/*
	 * we might "die" after drawing the borders, but we want
	 * stars to overlay the border for imaging software which
	 * may handle the bottom-up 2-1/2D order of printing correctly
	 * (eg PostScript).
	 */
	chartoutline(chart);

	chartgrid(chart);

	if (!chartfile(chart, STARFILE)) 
		die("open fail on %s", STARFILE);

	chartfile(chart, PLANETFILE);

	chartfile(chart, MESSFILE);

	if (userfile) {
		if (!chartfile(chart, userfile)) 
			die("open fail on %s", userfile);
	}
}


chartfile(chart, filename)
map chart;
char	*filename;
	{
#define READMODE "r"
#define OPENFAIL 0
	FILE * sfile;
	if ((sfile = fopen(filename, READMODE)) == OPENFAIL) 
		return(0);
	chartobjects(chart, sfile);
	fclose(sfile);
	return(1);
}


chartobjects(chart, file)
map chart;
FILE *file;
	{
	double	lat, lon, mag;
	char	code[1], subcode[1], label[100], name[100], color [3], *ptr;
	int	xloc, yloc, staronly, smallflag, vecmode, gkflag, xcur, ycur;

	for ( ; ; ) {
		if (readstar(file, &lat, &lon, &mag, code, subcode, color,
		    label, name)) 
			break;
		if ((mag > chart->maglim) && (code[0] == 'S')) 
			break;
		if ((chart->west < 0.0) && (lon > 180.0)) 
			lon -= 360.0;
		if ((chart->east > 360.0) && (lon < 180.0)) 
			lon += 360.0;
		if ((lon >= chart->west) && (lon <= chart->east) && 
		    (lat >= chart->south) && (lat <= chart->north) && 
		    (mag <= chart->maglim) ) {
			transform(chart, lat, lon, &xloc, &yloc);
			smallflag = vecmode = staronly = gkflag = 0;
			switch (code[0]) {
			case 'S': 
				drawStar(xloc, yloc, (int)(mag + 0.5), subcode[0], color);
				staronly = 1;
				break;
			case 'P': 
				drawPlan(xloc, yloc); 
				break;
			case 'N': 
				drawNebu(xloc, yloc); 
				break;
			case 'G': 
				drawGalx(xloc, yloc); 
				break;
			case 'C': 
				drawClus(xloc, yloc); 
				break;
			case 'I': /* invisible */
				break;
			case 'V': 
				vecmode = 1;
				/* vector: check subcode */
				switch (subcode[0]) {
				case 'M': 
					vecmove(xloc, yloc); 
					break;
				case 'D': 
					vecdrawdot(xloc, yloc); 
					break;
				case 'H': 
					vecdrawhyph(xloc, yloc); 
					break;
				case 'S':	/* solid */
				default:  
					vecdraw(xloc, yloc); 
					break;
				}
				break;
			}
			if (((mag < chart->lbllim) || ! staronly) && ! vecmode) {
				/*
				 * pick up object name or label if
				 * (star < limit), (nonstar), and (not vector)
				 */
				ptr = NULL;
				if (*name != '\0') {
					ptr = name;	/* name > label */
				} else if (*label != '\0') {
					ptr = label;
					if (staronly) {
						smallflag = 1;
						ptr[2] = '\0';	/* snuff the IAU designation */
						if (islower(ptr[0]) ||
						    ptr[0] == 'E' ||
						    ptr[0] == 'O' || 
						    ptr[0] == '@' ||
						    ptr[0] == '%') {
							/*
							 *Greek Bayer char(s)
							 */
							gkflag = 1;
							if (ptr[1] == ' ') 
								ptr[1] = '\0';
						}
					}
				}
				if (ptr != NULL) {
					vecsize(smallflag ? FSIZESML : FSIZELRG);
					/*
					 * vecsyms* --
					 * some x offset present to avoid
					 * overstriking corresponding object.
					 * Note that some bias is already
					 * precent (obj is center-align,
					 * text is left align)
					 */
					if (gkflag) 
						vecsymsgk(xloc + 10, yloc, ptr);
					else 
						vecsyms(xloc + 10, yloc, ptr);
				}
			}
		}
	}
}


/*
 * Chart Construction
 */
chartgrid(chart)
map chart;
	{
	charthgrid(chart, 15.0, 18);
	charthgrid(chart, 5.0, 12);
	charthgrid(chart, 1.0, 6);
	chartvgrid(chart, 10.0, 18);
	chartvgrid(chart, 5.0 , 12);
	chartvgrid(chart, 1.0, 6);
}


chartoutline(chart)
map	chart;
	{
	double	start, inc;
	int	xloc, xloc2, yloc, yloc2, div, i;

	transform(chart, chart->south, chart->west, &xloc,  &yloc);
	transform(chart, chart->south, chart->east, &xloc2, &yloc2);
	vecmovedraw(xloc, yloc, xloc2, yloc2);
	transform(chart, chart->north, chart->west, &xloc,  &yloc);
	transform(chart, chart->north, chart->east, &xloc2, &yloc2);
	vecmovedraw(xloc, yloc, xloc2, yloc2);

	inc = (chart->north - chart->south);
	div = (int) inc;
	if (div < 1) 
		div = 1;
	inc /= div;
	start = chart->south;
	transform(chart, start, chart->west, &xloc, &yloc);
	vecmove(xloc, yloc);
	for (i = 0; i < div; i++) {
		start += inc;
		transform(chart, start, chart->west, &xloc, &yloc);
		vecdraw(xloc, yloc);
	}
	start = chart->south;
	transform(chart, start, chart->east, &xloc, &yloc);
	vecmove(xloc, yloc);
	for (i = 0; i < div; i++) {
		start += inc;
		transform(chart, start, chart->east, &xloc, &yloc);
		vecdraw(xloc, yloc);
	}
}


rastr(str, ras)
char	*str;
double	ras;
	{
	int	hrs, min;
	if (ras < 0.0) 
		ras += 360.0;
	if (ras > 360.0) 
		ras -= 360.0;
	hrs = (int)(ras / 15.0);
	min = (int)((ras - hrs * 15.0) * 4.0);
	sprintf(str, "%dh", hrs);
	if (min) 
		sprintf(str, "%s%02dm", str, min);
}


declstr(str, dl)
char	*str;
double	dl;
	{
	int	deg, min;
	if (dl == 0.0) 
		sprintf(str, "%s", " ");
	else if (dl > 0.0) 
		sprintf(str, "%s", "+");
	else
	 {
		sprintf(str, "%s", "-");
		dl = -dl;
	}
	/*
	 * Watch out for the "pole wrap" syndrome.
	 */
	if (dl > 90.0)
		dl = 90. - (dl - 90.);

	deg = (int)(dl);
	min = (int)((dl - deg) * 60.0);
	sprintf(str, "%s%02dd", str, deg);
	if (min) 
		sprintf(str, "%s%02dm", str, min);
}


charthgrid(chart, inc, hgt)
map chart;
double	inc;
	{
#define HTICKLIM 2
#define HTEXTLIM 80
	double	start, stop, ras;
	int	xloc, xloc2, yloc, xloc3, yloc3;
	start = modup(chart->west, inc);
	stop = moddown(chart->east, inc);
	transform(chart, chart->south, start, &xloc, &yloc);
	transform(chart, chart->south, start + inc, &xloc2, &yloc);
	if (xloc - xloc2 > HTICKLIM) {
		for (ras = start; ras <= stop; ras += inc) {
			transform(chart, chart->south, ras, &xloc3, &yloc3);
			vecmovedraw(xloc3, yloc3 - hgt, xloc3, yloc3);
			if (xloc - xloc2 > HTEXTLIM) {
				char	tstr[20];
				rastr(tstr, ras);
				vecsize(10);
				vecsyms(xloc3 + 2, yloc - 17, tstr);
			}
		}
	}
}


chartvgrid(chart, inc, wid)
map chart;
double	inc;
	{
#define VTICKLIM 2
#define VTEXTLIM 20
	double	start, stop, dl;
	int	xloc, yloc, yloc2, xloc3, yloc3;
	start = modup(chart->south, inc);
	stop = moddown(chart->north, inc);
	transform(chart, start, chart->west, &xloc, &yloc);
	transform(chart, start + inc, chart->west, &xloc, &yloc2);
	if (yloc2 - yloc > VTICKLIM) {
		for (dl = start; dl <= stop; dl += inc) {
			transform(chart, dl, chart->west, &xloc3, &yloc3);
			vecmovedraw(xloc3, yloc3, xloc3 + wid, yloc3);
			if (yloc2 - yloc > VTEXTLIM) {
				char	tstr[20];
				declstr(tstr, dl);
				vecsize(10);
				vecsyms(xloc3 + 24, yloc3, tstr);
			}
		}
	}
}


/*
 * General Utilities
 */
double	max(a, b)
double	a, b;
	{
	if (a > b) 
		return(a);
	return(b);
}


double	modup(a, b)
double	a, b;
	{
	double	new;
	new = ((double)((int)(a / b)) * b);
	if (new >= a) 
		return(new);
	return(new += b);
}


double	moddown(a, b)
double	a, b;
	{
	double	new;
	new = ((double)((int)(a / b)) * b);
	if (new <= a) 
		return(new);
	return (new -= b);
}


die(a, b)
char	*a, *b;
	{
	fprintf(stderr, "%s: ", progname);
	fprintf(stderr, a, b);
	fprintf(stderr, "\n");
	exit(1);
}


static char	legend[LINELEN];

findconst(tag)
char	*tag;
	{
	/*
	 * lookup "con.locs" for a matching tag, and then substitute
	 * initial values for ra, decl, scale, and label.
	 * File layout follows:
	 *
	 * com  13    25   10   Coma Bereneces
	 * cor  15.45 28   10   Corona Borealis
	 * 0....+....1....+....2....+....3
	 */
	char	*newline;
	FILE	*cfile;
	int	taglen;
	char	cbuf[LINELEN+1];

	if ((cfile = fopen(CONSTFILE, "r")) == NULL)
		die("open fail on %s", CONSTFILE);
	/*
	 * Print current tags if tag is "?".
	 */
	if ( ! strcmp(tag, "?")) {
		prttags(cfile);
		exit(0);
	}
	taglen = strlen(tag);
	if ((taglen < 3) || (taglen > 4))
		die("constellation name must be three or four characters");

	for (; ; ) {
		fgets(cbuf, LINELEN, cfile);
		if (ferror(cfile)) 
			die("read error in %s", CONSTFILE);

		if (feof(cfile)) 
			break;

		if (strncmp(tag, cbuf, taglen) == 0) {
#ifdef	BERZERK
			sscanf(&cbuf[taglen], "%f%f%f %[^\n]", &ra, &de,
			    &sc, legend);
#else
			sscanf(&cbuf[taglen], "%lf%lf%lf %[^\n]", &ra, &de,
			    &sc, legend);
#endif
			ra = ftod(ra);
			de = ftod(de);
			if ((newline = index(legend, '\n')) != 0) 
				*newline = '\0';
			title = legend;
			return;
		}
	}
	die("Constellation '%s' not found", tag);
}

/*
 * Print the constellation tags from con.locs.
 */
prttags(cfp)
FILE	*cfp;
	{
	int	llen, lentmp;
	char	inbuf[LINELEN], *cp1, *cp2;

#define	LINEMAX	(LINELEN - 10)

	fprintf(stdout, "These are the constellation tags:\n   ");
	llen = 3;
	cp1 = inbuf;
	/*
	 * And print the tags.
	 */
	while (fgets(cp1, LINELEN, cfp)) {
		/*
		 * Skip comments
		 */
		if (*cp1 == '/')
			continue;
		/*
		 * Find the end of constellation tag.
		 */
		for (cp2 = cp1; ! isspace(*cp2); cp2++)
			;

		*cp2 = '\0';

		/*
		 *  Check for line overflow.
		 */
		if (llen + (lentmp = strlen(cp1) + 1) > LINEMAX) {
			llen = 3;
			fprintf(stdout, "\n   ");
		}
		llen += lentmp;
		/*
		 *  Print it at last
		 */
		fprintf(stdout, " %s", cp1);
	}
	putchar('\n');
	fclose(cfp);
}

/*
 ! Future Development
 !
 ! Here is my "wish" list of items not added in this version (#2). I have
 ! intentionally included it here with the source code in an attempt to direct
 ! the course of further software development.
 !
 ! It is hoped that this will simplify the task of coordinating the eventual
 ! reintegration of new features created by such a large software community.
 ! Wishes are listed in rough order of simplicity and evolution.
 !
 ! Software:
 !
 ! [0] add glyphs for double stars/variable stars + Greek on bitmap devices.
 ! [1] write better PostScript macros.
 ! [2] integrate a "boundary.star" to draw constellation boundaries.
 ! [3] rewrite "moonphase" to add ra/decl information, merge into "planet.c".
 ! [4] break yale.star into constellation files (and remove "cons" field).
 ! [5] write "orbit.c" for asteroid overlays.
 ! [6] add a polar plot facility (round window?) for high declinations
 ! [7] rework planet.star to give planet tracks for a range of dates.
 !
 ! Database additions:
 !
 ! [1'] convert a larger database (9th-10th mag) into Yale format.
 ! [2'] Milky Way isophots
 ! [3'] Ecliptic track (dotted line vectors)
 ! [4'] IAU Constellation boundaries (see [2])
 !
 ! (comments)
 !
 ! [0] Is best facilitated by revising the image compiler in "starimages.c".
 ! [1] Would allow nice glyphs for non-stellar objects, scaled continuously
 !     to the right size. The code already provides a "halo" feature when
 !     generating stars in bright to dim (large to small) order, following
 !     a common aesthetic convention in many atlases. Variable stars are
 !     given rings, bars pass through double stars, etc., but a more
 !     comprehensive set of glyphs would be nice.
 !
 !     Starchart now allows user specified generation of text and vectors,
 !     which are useful for giving planet tracks across a range of dates, plus
 !     constellation boundaries, and possibly shapes of moon phases ([2], [3]).
 ! [2] I have access to such a database from UC Santa Cruz, and will request
 !     it once proven software is available. It would then be reworked into
 !     the "yale.star" format, using the move/draw commands of.
 ! [3] Burgess' book "Celestial Basic" gives routines for this, but lacks the
 !     precision of the work by Meesus (see planet.man). Done correctly, one
 !     should be able to check for eclipses, transits and occultations (this
 !     will require that "moonphase" know the user's geocentric latitude and
 !     longitude, due to the libration of the moon owing to parallax). This
 !     advanced version would print the profile of the moon's limb, with
 !     terminator. The "basic" version would just give a planet symbol.
 ! [4] Break-down by constellation would be a simple conceptual organization.
 !     It is also helpful to users requiring detailed finder charts of select
 !     regions. At the very least, the thirteen files for ecliptic-based
 !     constellation (~the Zodiac) would be quite helpful. The three character
 !     constellation field in the "label" field of the newer (but still
 !     reduced) version of yale.star would then go.
 ! [5] I have already produced tables of Keplerian elements for asteroids
 !     to the 10th mag. I also have code to read the data and solve for various
 !     related values (e.g. eccentric anomoly from mean anomoly). Left are
 !     the routines to find earth's position, plus the spherical trig needed
 !     to convert this into Ra and Decl. This would best be integrated into
 !     "planet.c", which already does the latter. Interested parties should
 !     e-mail me for the files "orbit.c" and "asteroids.el".
 ! [6] xcen and ycen would be ignored, and scale would give the limit of
 !     declination (90.0-scale). Provisions to choose which pole needed, too.
 !     I believe stereographic projection would be the best, being both
 !     conformal and preserving of circles (as circles of new radii).
 ! [7] A complete rework would probably also place moon and asteroid calcs
 !     here, in addition to generating "track" output records.
 !
 ! [1'] Electronic databases to the 10th mag rumored to exist, containing on
 !	the order of 40000 stars. Don't ask me where to find them.
 ! [2'] No idea where to find
 ! [3'] Should not be too hard
 */
SHAR_EOF
if test -f 'starchart.h'
then
	echo shar: over-writing existing file "'starchart.h'"
fi
cat << \SHAR_EOF > 'starchart.h'
typedef struct  {
	float	racen, dlcen, scale;
	float	north, south, east, west;
	float	maglim, lbllim;
	int	wx, wy, ww, wh;
	float	yscale;
}	mapblock, *map;

extern	mapblock	master, thumbnail;

#ifndef	BERZERK
#define	index	strchr
char	*strchr();
#endif
SHAR_EOF
if test -f 'starvdi.c'
then
	echo shar: over-writing existing file "'starvdi.c'"
fi
cat << \SHAR_EOF > 'starvdi.c'
/*
 * Virtual Device Interface for UNIX-PC.
 */

#include <stdio.h>
#include <ctype.h>

#include "starchart.h"

#define XMAX	32767			/* Max X on UNIX PC */
#define YMAX	17704			/* Max Y on UNIX PC */

#define	SCALE	30

/*
 * Chart parameters (limiting magnitude and window x,y,w,h).
 * Display is assumed to be 554 (y) by 1024 (x) (17704/32767).
 */

mapblock thumbnail = 	{ 
	0.0, 0.0, 0.0,			/* racen, dlcen, scale */
	0.0, 0.0, 0.0, 0.0,		/* north, south, east, west */
	3.0, 1.0,			/* maglim, lbllim */
	20, 554/2,			/* wx, wy origin (ll corner) */
	(3*554)/5, 554/2,		/* ww, wh */
	0.0				/* yscale */
};

mapblock master = 	{ 		/* Ditto */
	0.0, 0.0, 0.0,
	0.0, 0.0, 0.0, 0.0,
	5.9, 4.0,
	440, 48,
	564, 524,
	0.0
};

/*
 * Line types and fill directives.
 */
#define SOLID	1
#define	DASHED	2
#define	DOTTED	3

#define HOLLOW	0
#define HATCH	3
#define BLACK 	0
#define WHITE 	1

#define	STORE	4

static	short	pixop = STORE;
static	short	display;
static	short	printer;
static	short	disp_out[66];
static	short	prtr_out[66];

static	short	disp_in[19] = {
	1,			/* ndc index (equal axis ratios) */
	1,			/* polyline line type */
	WHITE,			/* polyline color index */
	3,			/* polymarker type */
	WHITE,			/* polymarker color index */
	1,			/* graphics text font */
	WHITE,			/* graphics text color index */
	SOLID,			/* fill interior style */
	1,			/* fill style index */
	WHITE,			/* fill color index */
	1,			/* display prompts */
	'D', 'I', 'S', 'P', 'L', 'A', 'Y', ' ',  /* device name */
};

static	short	prtr_in[19] = {
	1,			/* equal axis ratios */
	1,			/* solid line type */
	WHITE,			/* line color index to use - white */
	3,			/* marker type - star */
	WHITE,			/* marker color index - white */
	1,			/* text font to use - normal */
	WHITE,			/* text color - white */
	SOLID,			/* fill interior style - hollow */
	1,			/* fill style index */
	WHITE,			/* fill color index */
	1,			/* send device messages to screen */
	'P', 'R', 'I', 'N', 'T', 'E', 'R', ' '	/* device name */
};

/*
 * initialize 7300 graphics window and VDI
 */
vecopen()
	{
	short	d1, d2;

	/*
	 * initialize VDI
	 */
	if (v_opnwk(disp_in, &display, disp_out) != 0)
		die("%s", "VDI initialization error");

	/*
	 * Set STORE (overwrite) mode for writing operations.
	 */
	if (vswr_mode(display, pixop) < 0)
		die("%s", "Overwrite setup error");

	/*
	 * Set text alignment, left justified, centered vertically.
	 */
	vst_alignment(display, (short) 0, (short) 1, &d1, &d2);
}

static	textsize = 7;

vecsize(points)
int	points;
	{
	textsize = points;
}

static	short	oldx, oldy;
static	short	linetype = SOLID;

vecmove(x, y)
	{
	oldx = x * SCALE;
	oldy = y * SCALE;
}

vecdrawdot(x, y)
	{
	linetype = DOTTED;
	vecdraw(x, y);
	linetype = SOLID;
}

vecdrawhyph(x, y)
	{
	linetype = DASHED;
	vecdraw(x, y);
	linetype = SOLID;
}

vecdraw(x, y)
	{
	short	p1[2], p2[2];

	p1[0] = oldx;
	p1[1] = oldy;
	p2[0] = x * SCALE;
	p2[1] = y * SCALE;
	oldx = x * SCALE;
	oldy = y * SCALE;

	draw_line(p1, p2);
}

vecsyms(x, y, s)
char	*s;
	{
	char	c;

	vecmove(x, y);

	x *= SCALE;
	y *= SCALE;
	draw_text(x, y, s, textsize, 0);
}

vecmovedraw(x1, y1, x2, y2)
	{
	vecmove(x1, y1);
	vecdraw(x2, y2);
}

drawPlan(x, y)
	{
	draw2(x, y, 'P');
}

drawStar(x, y, mag, type, color)
char	type, *color;
	{
	switch (mag) {
	case -1: 
		draw0(x, y, type); 
		break;
	case 0: 
		draw0(x, y, type); 
		break;
	case 1: 
		draw1(x, y, type); 
		break;
	case 2: 
		draw2(x, y, type); 
		break;
	case 3: 
		draw3(x, y, type); 
		break;
	case 4: 
		draw4(x, y, type); 
		break;
	default: 
		draw5(x, y, type); 
		break;
	}
}

#define	STARSIZE	(4*SCALE)

draw0(x, y, type)
	{
	draw_disk(x, y, (8*STARSIZE)/5, type);
}

draw1(x, y, type)
	{
	draw_disk(x, y, (7*STARSIZE)/5, type);
}

draw2(x, y, type)
	{
	draw_disk(x, y, (6*STARSIZE)/5, type);
}

draw3(x, y, type)
	{
	draw_disk(x, y, (5*STARSIZE)/5, type);
}

draw4(x, y, type)
	{
	draw_disk(x, y, (short) 4, type);
}

draw5(x, y, type)
	{
	draw_disk(x, y, (short) 5, type);
}

drawGalx(x, y)
	{
	vecsyms(x, y, "@");
}

drawNebu(x, y)
	{
	vecsyms(x, y, "~");
}

drawClus(x, y)
	{
	vecsyms(x, y, "%");
}

draw_disk(x, y, radius, type)
short	x, y;
short	radius, type;
	{
	short	pp[4];

	x *= SCALE;
	y *= SCALE;

	if (radius == 5) {		/* Actually magnitude */
		/*
		 * Draw one pixel by drawing a very, very short
		 * horizontal line.
		 */
		pp[0] = x;
		pp[1] = y;
		pp[2] = x + SCALE;
		pp[3] = y;
		v_pline(display, 2, pp);
	} else if (radius == 4) {	/* Actually magnitude */
		/*
		 * Draw a three by three pixel box (centered).
		 */
		x -= SCALE;
		y -= SCALE;
		pp[0] = x;
		pp[1] = y;
		pp[2] = x + 3*SCALE;
		pp[3] = y + 3*SCALE;
		vsl_type(display, SOLID);
		vsf_interior(display, SOLID);
		v_bar(display, pp);
	} else {
		switch (type) {
		case 'P':			/* Planet */
			/*
			 * Draw a cross at the location; first the
			 * horizontal, then the vertical line.
			 */
			pp[0] = x - radius;
			pp[2] = x + radius;
			pp[1] = pp[3] = y;
			v_pline(display, 2, pp);
			pp[0] = pp[2] = x;
			pp[1] = y - radius;
			pp[3] = y + radius;
			v_pline(display, 2, pp);
			break;

		case 'D':			/* Double */
			/*
			 * Split the disk with a horizontal line.
			 */
			pp[0] = x - 2*radius;
			pp[2] = x + 2*radius;
			pp[1] = pp[3] = y;
			v_pline(display, 2, pp);
			goto disk;

		case 'V':			/* Variable */
			/*
			 * Draw a circle around the disk.
			 */
			vsl_type(display, SOLID);
			vsf_interior(display, HOLLOW);
			v_circle(display, x, y, 2*radius);
			/* Fall through */

		default:
		disk:				/* Basic star shape */
			vsl_type(display, SOLID);
			vsf_interior(display, SOLID);
			v_circle(display, x, y, radius);
			break;
		}
	}
}

vecsymsgk(x, y, str)
char	*str;
	{
	vecsyms(x, y, str);
}

draw_text(x, y, str, size, rot)
short	x, y;
char	*str;
short	size;
short	rot;
	{
	short	d1, d2, d3;

	vst_rotation(display, rot*10);
	vst_height(display, size, &d1, &d2, &d3);
	v_gtext(display, x, y, str);
}

#include <signal.h>

onward(sig)
	{
	signal(sig, onward);
}

vecclose()
	{
	signal(SIGINT, onward);		/* Set up for the kill */
	signal(SIGTERM, onward);
	pause();			/* Wait for it */
	v_clrwk(display);
	v_clswk(display);
}

draw_line(xy_a, xy_b)
short	xy_a[2], xy_b[2];
	{
	short	xy[4];

	xy[0] = xy_a[0];
	xy[1] = xy_a[1];
	xy[2] = xy_b[0];
	xy[3] = xy_b[1];

	vsl_type(display, linetype);
	v_pline(display, 2, xy);
}

prtr_open()
	{
	if (v_opnwk(prtr_in, &printer, prtr_out) != 0)
		return(0);
	else
		return(1);
}

prtr_close()
	{
	v_clswk(printer);
}
SHAR_EOF
#	End of shell archive
exit 0