xref: /plan9/sys/src/cmd/scat/plot.c (revision 9a747e4fd48b9f4522c70c07e8f882a15030f964)
159cc4ca5SDavid du Colombier #include <u.h>
259cc4ca5SDavid du Colombier #include <libc.h>
359cc4ca5SDavid du Colombier #include <bio.h>
459cc4ca5SDavid du Colombier #include <draw.h>
559cc4ca5SDavid du Colombier #include <event.h>
659cc4ca5SDavid du Colombier #include <ctype.h>
759cc4ca5SDavid du Colombier #include "map.h"
859cc4ca5SDavid du Colombier #undef	RAD
959cc4ca5SDavid du Colombier #undef	TWOPI
1059cc4ca5SDavid du Colombier #include "sky.h"
1159cc4ca5SDavid du Colombier 
1259cc4ca5SDavid du Colombier 	/* convert to milliarcsec */
1359cc4ca5SDavid du Colombier static long	c = MILLIARCSEC;	/* 1 degree */
1459cc4ca5SDavid du Colombier static long	m5 = 1250*60*60;	/* 5 minutes of ra */
1559cc4ca5SDavid du Colombier 
1659cc4ca5SDavid du Colombier DAngle	ramin;
1759cc4ca5SDavid du Colombier DAngle	ramax;
1859cc4ca5SDavid du Colombier DAngle	decmin;
1959cc4ca5SDavid du Colombier DAngle	decmax;
2059cc4ca5SDavid du Colombier int		folded;
2159cc4ca5SDavid du Colombier 
2259cc4ca5SDavid du Colombier Image	*grey;
2359cc4ca5SDavid du Colombier Image	*alphagrey;
2459cc4ca5SDavid du Colombier Image	*green;
2559cc4ca5SDavid du Colombier Image	*lightblue;
2659cc4ca5SDavid du Colombier Image	*lightgrey;
2759cc4ca5SDavid du Colombier Image	*ocstipple;
2859cc4ca5SDavid du Colombier Image	*suncolor;
2959cc4ca5SDavid du Colombier Image	*mooncolor;
3059cc4ca5SDavid du Colombier Image	*shadowcolor;
3159cc4ca5SDavid du Colombier Image	*mercurycolor;
3259cc4ca5SDavid du Colombier Image	*venuscolor;
3359cc4ca5SDavid du Colombier Image	*marscolor;
3459cc4ca5SDavid du Colombier Image	*jupitercolor;
3559cc4ca5SDavid du Colombier Image	*saturncolor;
3659cc4ca5SDavid du Colombier Image	*uranuscolor;
3759cc4ca5SDavid du Colombier Image	*neptunecolor;
3859cc4ca5SDavid du Colombier Image	*plutocolor;
3959cc4ca5SDavid du Colombier Image	*cometcolor;
4059cc4ca5SDavid du Colombier 
4159cc4ca5SDavid du Colombier Planetrec	*planet;
4259cc4ca5SDavid du Colombier 
4359cc4ca5SDavid du Colombier long	mapx0, mapy0;
4459cc4ca5SDavid du Colombier long	mapra, mapdec;
4559cc4ca5SDavid du Colombier double	mylat, mylon, mysid;
4659cc4ca5SDavid du Colombier double	mapscale;
4759cc4ca5SDavid du Colombier double	maps;
4859cc4ca5SDavid du Colombier int (*projection)(struct place*, double*, double*);
4959cc4ca5SDavid du Colombier 
5059cc4ca5SDavid du Colombier char *fontname = "/lib/font/bit/lucida/unicode.6.font";
5159cc4ca5SDavid du Colombier 
5259cc4ca5SDavid du Colombier /* types Coord and Loc correspond to types in map(3) thus:
5359cc4ca5SDavid du Colombier    Coord == struct coord;
5459cc4ca5SDavid du Colombier    Loc == struct place, except longitudes are measured
5559cc4ca5SDavid du Colombier      positive east for Loc and west for struct place
5659cc4ca5SDavid du Colombier */
5759cc4ca5SDavid du Colombier 
5859cc4ca5SDavid du Colombier typedef struct Xyz Xyz;
5959cc4ca5SDavid du Colombier typedef struct coord Coord;
6059cc4ca5SDavid du Colombier typedef struct Loc Loc;
6159cc4ca5SDavid du Colombier 
6259cc4ca5SDavid du Colombier struct Xyz{
6359cc4ca5SDavid du Colombier 	double x,y,z;
6459cc4ca5SDavid du Colombier };
6559cc4ca5SDavid du Colombier 
6659cc4ca5SDavid du Colombier struct Loc{
6759cc4ca5SDavid du Colombier 	Coord nlat, elon;
6859cc4ca5SDavid du Colombier };
6959cc4ca5SDavid du Colombier 
7059cc4ca5SDavid du Colombier Xyz north = { 0, 0, 1 };
7159cc4ca5SDavid du Colombier 
7259cc4ca5SDavid du Colombier int
plotopen(void)7359cc4ca5SDavid du Colombier plotopen(void)
7459cc4ca5SDavid du Colombier {
7559cc4ca5SDavid du Colombier 	if(display != nil)
7659cc4ca5SDavid du Colombier 		return 1;
7759cc4ca5SDavid du Colombier 	display = initdisplay(nil, nil, drawerror);
7859cc4ca5SDavid du Colombier 	if(display == nil){
7959cc4ca5SDavid du Colombier 		fprint(2, "initdisplay failed: %r\n");
8059cc4ca5SDavid du Colombier 		return -1;
8159cc4ca5SDavid du Colombier 	}
8259cc4ca5SDavid du Colombier 	grey = allocimage(display, Rect(0, 0, 1, 1), CMAP8, 1, 0x777777FF);
8359cc4ca5SDavid du Colombier 	lightgrey = allocimage(display, Rect(0, 0, 1, 1), CMAP8, 1, 0xAAAAAAFF);
8459cc4ca5SDavid du Colombier 	alphagrey = allocimage(display, Rect(0, 0, 2, 2), RGBA32, 1, 0x77777777);
8559cc4ca5SDavid du Colombier 	green = allocimage(display, Rect(0, 0, 1, 1), CMAP8, 1, 0x00AA00FF);
8659cc4ca5SDavid du Colombier 	lightblue = allocimage(display, Rect(0, 0, 1, 1), CMAP8, 1, 0x009EEEFF);
8759cc4ca5SDavid du Colombier 	ocstipple = allocimage(display, Rect(0, 0, 2, 2), CMAP8, 1, 0xAAAAAAFF);
8859cc4ca5SDavid du Colombier 	draw(ocstipple, Rect(0, 0, 1, 1), display->black, nil, ZP);
8959cc4ca5SDavid du Colombier 	draw(ocstipple, Rect(1, 1, 2, 2), display->black, nil, ZP);
9059cc4ca5SDavid du Colombier 
9159cc4ca5SDavid du Colombier 	suncolor = allocimage(display, Rect(0, 0, 1, 1), RGBA32, 1, 0xFFFF77FF);
9259cc4ca5SDavid du Colombier 	mooncolor = allocimage(display, Rect(0, 0, 1, 1), RGBA32, 1, 0xAAAAAAFF);
9359cc4ca5SDavid du Colombier 	shadowcolor = allocimage(display, Rect(0, 0, 1, 1), RGBA32, 1, 0x00000055);
9459cc4ca5SDavid du Colombier 	mercurycolor = allocimage(display, Rect(0, 0, 1, 1), RGBA32, 1, 0xFFAAAAFF);
9559cc4ca5SDavid du Colombier 	venuscolor = allocimage(display, Rect(0, 0, 1, 1), RGBA32, 1, 0xAAAAFFFF);
9659cc4ca5SDavid du Colombier 	marscolor = allocimage(display, Rect(0, 0, 1, 1), RGBA32, 1, 0xFF5555FF);
9759cc4ca5SDavid du Colombier 	jupitercolor = allocimage(display, Rect(0, 0, 1, 1), RGBA32, 1, 0xFFFFAAFF);
9859cc4ca5SDavid du Colombier 	saturncolor = allocimage(display, Rect(0, 0, 1, 1), RGBA32, 1, 0xAAFFAAFF);
9959cc4ca5SDavid du Colombier 	uranuscolor = allocimage(display, Rect(0, 0, 1, 1), RGBA32, 1, 0x77DDDDFF);
10059cc4ca5SDavid du Colombier 	neptunecolor = allocimage(display, Rect(0, 0, 1, 1), RGBA32, 1, 0x77FF77FF);
10159cc4ca5SDavid du Colombier 	plutocolor = allocimage(display, Rect(0, 0, 1, 1), RGBA32, 1, 0x7777FFFF);
10259cc4ca5SDavid du Colombier 	cometcolor = allocimage(display, Rect(0, 0, 1, 1), RGBA32, 1, 0xAAAAFFFF);
10359cc4ca5SDavid du Colombier 	font = openfont(display, fontname);
10459cc4ca5SDavid du Colombier 	if(font == nil)
10559cc4ca5SDavid du Colombier 		fprint(2, "warning: no font %s: %r\n", fontname);
10659cc4ca5SDavid du Colombier 	return 1;
10759cc4ca5SDavid du Colombier }
10859cc4ca5SDavid du Colombier 
10959cc4ca5SDavid du Colombier /*
11059cc4ca5SDavid du Colombier  * Function heavens() for setting up observer-eye-view
11159cc4ca5SDavid du Colombier  * sky charts, plus subsidiary functions.
11259cc4ca5SDavid du Colombier  * Written by Doug McIlroy.
11359cc4ca5SDavid du Colombier  */
11459cc4ca5SDavid du Colombier 
11559cc4ca5SDavid du Colombier /* heavens(nlato, wlono, nlatc, wlonc) sets up a map(3)-style
11659cc4ca5SDavid du Colombier    coordinate change (by calling orient()) and returns a
11759cc4ca5SDavid du Colombier    projection function heavens for calculating a star map
11859cc4ca5SDavid du Colombier    centered on nlatc,wlonc and rotated so it will appear
11959cc4ca5SDavid du Colombier    upright as seen by a ground observer at nlato,wlono.
12059cc4ca5SDavid du Colombier    all coordinates (north latitude and west longitude)
12159cc4ca5SDavid du Colombier    are in degrees.
12259cc4ca5SDavid du Colombier */
12359cc4ca5SDavid du Colombier 
12459cc4ca5SDavid du Colombier Coord
mkcoord(double degrees)12559cc4ca5SDavid du Colombier mkcoord(double degrees)
12659cc4ca5SDavid du Colombier {
12759cc4ca5SDavid du Colombier 	Coord c;
12859cc4ca5SDavid du Colombier 
12959cc4ca5SDavid du Colombier 	c.l = degrees*PI/180;
13059cc4ca5SDavid du Colombier 	c.s = sin(c.l);
13159cc4ca5SDavid du Colombier 	c.c = cos(c.l);
13259cc4ca5SDavid du Colombier 	return c;
13359cc4ca5SDavid du Colombier }
13459cc4ca5SDavid du Colombier 
13559cc4ca5SDavid du Colombier Xyz
ptov(struct place p)13659cc4ca5SDavid du Colombier ptov(struct place p)
13759cc4ca5SDavid du Colombier {
13859cc4ca5SDavid du Colombier 	Xyz v;
13959cc4ca5SDavid du Colombier 
14059cc4ca5SDavid du Colombier 	v.z = p.nlat.s;
14159cc4ca5SDavid du Colombier 	v.x = p.nlat.c * p.wlon.c;
14259cc4ca5SDavid du Colombier 	v.y = -p.nlat.c * p.wlon.s;
14359cc4ca5SDavid du Colombier 	return v;
14459cc4ca5SDavid du Colombier }
14559cc4ca5SDavid du Colombier 
14659cc4ca5SDavid du Colombier double
dot(Xyz a,Xyz b)14759cc4ca5SDavid du Colombier dot(Xyz a, Xyz b)
14859cc4ca5SDavid du Colombier {
14959cc4ca5SDavid du Colombier 	return a.x*b.x + a.y*b.y + a.z*b.z;
15059cc4ca5SDavid du Colombier }
15159cc4ca5SDavid du Colombier 
15259cc4ca5SDavid du Colombier Xyz
cross(Xyz a,Xyz b)15359cc4ca5SDavid du Colombier cross(Xyz a, Xyz b)
15459cc4ca5SDavid du Colombier {
15559cc4ca5SDavid du Colombier 	Xyz v;
15659cc4ca5SDavid du Colombier 
15759cc4ca5SDavid du Colombier 	v.x = a.y*b.z - a.z*b.y;
15859cc4ca5SDavid du Colombier 	v.y = a.z*b.x - a.x*b.z;
15959cc4ca5SDavid du Colombier 	v.z = a.x*b.y - a.y*b.x;
16059cc4ca5SDavid du Colombier 	return v;
16159cc4ca5SDavid du Colombier }
16259cc4ca5SDavid du Colombier 
16359cc4ca5SDavid du Colombier double
len(Xyz a)16459cc4ca5SDavid du Colombier len(Xyz a)
16559cc4ca5SDavid du Colombier {
16659cc4ca5SDavid du Colombier 	return sqrt(dot(a, a));
16759cc4ca5SDavid du Colombier }
16859cc4ca5SDavid du Colombier 
16959cc4ca5SDavid du Colombier /* An azimuth vector from a to b is a tangent to
17059cc4ca5SDavid du Colombier    the sphere at a pointing along the (shorter)
17159cc4ca5SDavid du Colombier    great-circle direction to b.  It lies in the
17259cc4ca5SDavid du Colombier    plane of the vectors a and b, is perpendicular
17359cc4ca5SDavid du Colombier    to a, and has a positive compoent along b,
17459cc4ca5SDavid du Colombier    provided a and b span a 2-space.  Otherwise
17559cc4ca5SDavid du Colombier    it is null.  (aXb)Xa, where X denotes cross
17659cc4ca5SDavid du Colombier    product, is such a vector. */
17759cc4ca5SDavid du Colombier 
17859cc4ca5SDavid du Colombier Xyz
azvec(Xyz a,Xyz b)17959cc4ca5SDavid du Colombier azvec(Xyz a, Xyz b)
18059cc4ca5SDavid du Colombier {
18159cc4ca5SDavid du Colombier 	return cross(cross(a,b), a);
18259cc4ca5SDavid du Colombier }
18359cc4ca5SDavid du Colombier 
18459cc4ca5SDavid du Colombier /* Find the azimuth of point b as seen
18559cc4ca5SDavid du Colombier    from point a, given that a is distinct
18659cc4ca5SDavid du Colombier    from either pole and from b */
18759cc4ca5SDavid du Colombier 
18859cc4ca5SDavid du Colombier double
azimuth(Xyz a,Xyz b)18959cc4ca5SDavid du Colombier azimuth(Xyz a, Xyz b)
19059cc4ca5SDavid du Colombier {
19159cc4ca5SDavid du Colombier 	Xyz aton = azvec(a,north);
19259cc4ca5SDavid du Colombier 	Xyz atob = azvec(a,b);
19359cc4ca5SDavid du Colombier 	double lenaton = len(aton);
19459cc4ca5SDavid du Colombier 	double lenatob = len(atob);
19559cc4ca5SDavid du Colombier 	double az = acos(dot(aton,atob)/(lenaton*lenatob));
19659cc4ca5SDavid du Colombier 
19759cc4ca5SDavid du Colombier 	if(dot(b,cross(north,a)) < 0)
19859cc4ca5SDavid du Colombier 		az = -az;
19959cc4ca5SDavid du Colombier 	return az;
20059cc4ca5SDavid du Colombier }
20159cc4ca5SDavid du Colombier 
20259cc4ca5SDavid du Colombier /* Find the rotation (3rd argument of orient() in the
20359cc4ca5SDavid du Colombier    map projection package) for the map described
20459cc4ca5SDavid du Colombier    below.  The return is radians; it must be converted
20559cc4ca5SDavid du Colombier    to degrees for orient().
20659cc4ca5SDavid du Colombier */
20759cc4ca5SDavid du Colombier 
20859cc4ca5SDavid du Colombier double
rot(struct place center,struct place zenith)20959cc4ca5SDavid du Colombier rot(struct place center, struct place zenith)
21059cc4ca5SDavid du Colombier {
21159cc4ca5SDavid du Colombier 	Xyz cen = ptov(center);
21259cc4ca5SDavid du Colombier 	Xyz zen = ptov(zenith);
21359cc4ca5SDavid du Colombier 
21459cc4ca5SDavid du Colombier 	if(cen.z > 1-FUZZ) 	/* center at N pole */
21559cc4ca5SDavid du Colombier 		return PI + zenith.wlon.l;
21659cc4ca5SDavid du Colombier 	if(cen.z < FUZZ-1)		/* at S pole */
21759cc4ca5SDavid du Colombier 		return -zenith.wlon.l;
21859cc4ca5SDavid du Colombier 	if(fabs(dot(cen,zen)) > 1-FUZZ)	/* at zenith */
21959cc4ca5SDavid du Colombier 		return 0;
22059cc4ca5SDavid du Colombier 	return azimuth(cen, zen);
22159cc4ca5SDavid du Colombier }
22259cc4ca5SDavid du Colombier 
22359cc4ca5SDavid du Colombier int (*
heavens(double zlatdeg,double zlondeg,double clatdeg,double clondeg)22459cc4ca5SDavid du Colombier heavens(double zlatdeg, double zlondeg, double clatdeg, double clondeg))(Loc*, double*, double*)
22559cc4ca5SDavid du Colombier {
22659cc4ca5SDavid du Colombier 	struct place center;
22759cc4ca5SDavid du Colombier 	struct place zenith;
22859cc4ca5SDavid du Colombier 
22959cc4ca5SDavid du Colombier 	center.nlat = mkcoord(clatdeg);
23059cc4ca5SDavid du Colombier 	center.wlon = mkcoord(clondeg);
23159cc4ca5SDavid du Colombier 	zenith.nlat = mkcoord(zlatdeg);
23259cc4ca5SDavid du Colombier 	zenith.wlon = mkcoord(zlondeg);
23359cc4ca5SDavid du Colombier 	projection = stereographic();
23459cc4ca5SDavid du Colombier 	orient(clatdeg, clondeg, rot(center, zenith)*180/PI);
23559cc4ca5SDavid du Colombier 	return projection;
23659cc4ca5SDavid du Colombier }
23759cc4ca5SDavid du Colombier 
23859cc4ca5SDavid du Colombier int
maptoxy(long ra,long dec,double * x,double * y)23959cc4ca5SDavid du Colombier maptoxy(long ra, long dec, double *x, double *y)
24059cc4ca5SDavid du Colombier {
24159cc4ca5SDavid du Colombier 	double lat, lon;
24259cc4ca5SDavid du Colombier 	struct place pl;
24359cc4ca5SDavid du Colombier 
24459cc4ca5SDavid du Colombier 	lat = angle(dec);
24559cc4ca5SDavid du Colombier 	lon = angle(ra);
24659cc4ca5SDavid du Colombier 	pl.nlat.l = lat;
24759cc4ca5SDavid du Colombier 	pl.nlat.s = sin(lat);
24859cc4ca5SDavid du Colombier 	pl.nlat.c = cos(lat);
24959cc4ca5SDavid du Colombier 	pl.wlon.l = lon;
25059cc4ca5SDavid du Colombier 	pl.wlon.s = sin(lon);
25159cc4ca5SDavid du Colombier 	pl.wlon.c = cos(lon);
25259cc4ca5SDavid du Colombier 	normalize(&pl);
25359cc4ca5SDavid du Colombier 	return projection(&pl, x, y);
25459cc4ca5SDavid du Colombier }
25559cc4ca5SDavid du Colombier 
25659cc4ca5SDavid du Colombier /* end of 'heavens' section */
25759cc4ca5SDavid du Colombier 
25859cc4ca5SDavid du Colombier int
setmap(long ramin,long ramax,long decmin,long decmax,Rectangle r,int zenithup)25959cc4ca5SDavid du Colombier setmap(long ramin, long ramax, long decmin, long decmax, Rectangle r, int zenithup)
26059cc4ca5SDavid du Colombier {
26159cc4ca5SDavid du Colombier 	int c;
26259cc4ca5SDavid du Colombier 	double minx, maxx, miny, maxy;
26359cc4ca5SDavid du Colombier 
26459cc4ca5SDavid du Colombier 	c = 1000*60*60;
26559cc4ca5SDavid du Colombier 	mapra = ramax/2+ramin/2;
26659cc4ca5SDavid du Colombier 	mapdec = decmax/2+decmin/2;
26759cc4ca5SDavid du Colombier 
26859cc4ca5SDavid du Colombier 	if(zenithup)
26959cc4ca5SDavid du Colombier 		projection = heavens(mylat, mysid, (double)mapdec/c, (double)mapra/c);
27059cc4ca5SDavid du Colombier 	else{
27159cc4ca5SDavid du Colombier 		orient((double)mapdec/c, (double)mapra/c, 0.);
27259cc4ca5SDavid du Colombier 		projection = stereographic();
27359cc4ca5SDavid du Colombier 	}
27459cc4ca5SDavid du Colombier 	mapx0 = (r.max.x+r.min.x)/2;
27559cc4ca5SDavid du Colombier 	mapy0 = (r.max.y+r.min.y)/2;
27659cc4ca5SDavid du Colombier 	maps = ((double)Dy(r))/(double)(decmax-decmin);
27759cc4ca5SDavid du Colombier 	if(maptoxy(ramin, decmin, &minx, &miny) < 0)
27859cc4ca5SDavid du Colombier 		return -1;
27959cc4ca5SDavid du Colombier 	if(maptoxy(ramax, decmax, &maxx, &maxy) < 0)
28059cc4ca5SDavid du Colombier 		return -1;
28159cc4ca5SDavid du Colombier 	/*
28259cc4ca5SDavid du Colombier 	 * It's tricky to get the scale right.  This noble attempt scales
28359cc4ca5SDavid du Colombier 	 * to fit the lengths of the sides of the rectangle.
28459cc4ca5SDavid du Colombier 	 */
28559cc4ca5SDavid du Colombier 	mapscale = Dx(r)/(minx-maxx);
28659cc4ca5SDavid du Colombier 	if(mapscale > Dy(r)/(maxy-miny))
28759cc4ca5SDavid du Colombier 		mapscale = Dy(r)/(maxy-miny);
28859cc4ca5SDavid du Colombier 	/*
28959cc4ca5SDavid du Colombier 	 * near the pole It's not a rectangle, though, so this scales
29059cc4ca5SDavid du Colombier 	 * to fit the corners of the trapezoid (a triangle at the pole).
29159cc4ca5SDavid du Colombier 	 */
29259cc4ca5SDavid du Colombier 	mapscale *= (cos(angle(mapdec))+1.)/2;
29359cc4ca5SDavid du Colombier 	if(maxy  < miny){
29459cc4ca5SDavid du Colombier 		/* upside down, between zenith and pole */
29559cc4ca5SDavid du Colombier 		fprint(2, "reverse plot\n");
29659cc4ca5SDavid du Colombier 		mapscale = -mapscale;
29759cc4ca5SDavid du Colombier 	}
29859cc4ca5SDavid du Colombier 	return 1;
29959cc4ca5SDavid du Colombier }
30059cc4ca5SDavid du Colombier 
30159cc4ca5SDavid du Colombier Point
map(long ra,long dec)30259cc4ca5SDavid du Colombier map(long ra, long dec)
30359cc4ca5SDavid du Colombier {
30459cc4ca5SDavid du Colombier 	double x, y;
30559cc4ca5SDavid du Colombier 	Point p;
30659cc4ca5SDavid du Colombier 
30759cc4ca5SDavid du Colombier 	if(maptoxy(ra, dec, &x, &y) > 0){
30859cc4ca5SDavid du Colombier 		p.x = mapscale*x + mapx0;
30959cc4ca5SDavid du Colombier 		p.y = mapscale*-y + mapy0;
31059cc4ca5SDavid du Colombier 	}else{
31159cc4ca5SDavid du Colombier 		p.x = -100;
31259cc4ca5SDavid du Colombier 		p.y = -100;
31359cc4ca5SDavid du Colombier 	}
31459cc4ca5SDavid du Colombier 	return p;
31559cc4ca5SDavid du Colombier }
31659cc4ca5SDavid du Colombier 
31759cc4ca5SDavid du Colombier int
dsize(int mag)31859cc4ca5SDavid du Colombier dsize(int mag)	/* mag is 10*magnitude; return disc size */
31959cc4ca5SDavid du Colombier {
32059cc4ca5SDavid du Colombier 	double d;
32159cc4ca5SDavid du Colombier 
32259cc4ca5SDavid du Colombier 	mag += 25;	/* make mags all positive; sirius is -1.6m */
32359cc4ca5SDavid du Colombier 	d = (130-mag)/10;
32459cc4ca5SDavid du Colombier 	/* if plate scale is huge, adjust */
32559cc4ca5SDavid du Colombier 	if(maps < 100.0/MILLIARCSEC)
32659cc4ca5SDavid du Colombier 		d *= .71;
32759cc4ca5SDavid du Colombier 	if(maps < 50.0/MILLIARCSEC)
32859cc4ca5SDavid du Colombier 		d *= .71;
32959cc4ca5SDavid du Colombier 	return d;
33059cc4ca5SDavid du Colombier }
33159cc4ca5SDavid du Colombier 
33259cc4ca5SDavid du Colombier void
drawname(Image * scr,Image * col,char * s,int ra,int dec)33359cc4ca5SDavid du Colombier drawname(Image *scr, Image *col, char *s, int ra, int dec)
33459cc4ca5SDavid du Colombier {
33559cc4ca5SDavid du Colombier 	Point p;
33659cc4ca5SDavid du Colombier 
33759cc4ca5SDavid du Colombier 	if(font == nil)
33859cc4ca5SDavid du Colombier 		return;
33959cc4ca5SDavid du Colombier 	p = addpt(map(ra, dec), Pt(4, -1));	/* font has huge ascent */
34059cc4ca5SDavid du Colombier 	string(scr, p, col, ZP, font, s);
34159cc4ca5SDavid du Colombier }
34259cc4ca5SDavid du Colombier 
34359cc4ca5SDavid du Colombier int
npixels(DAngle diam)34459cc4ca5SDavid du Colombier npixels(DAngle diam)
34559cc4ca5SDavid du Colombier {
34659cc4ca5SDavid du Colombier 	Point p0, p1;
34759cc4ca5SDavid du Colombier 
34859cc4ca5SDavid du Colombier 	diam = DEG(angle(diam)*MILLIARCSEC);	/* diam in milliarcsec */
34959cc4ca5SDavid du Colombier 	diam /= 2;	/* radius */
35059cc4ca5SDavid du Colombier 	/* convert to plate scale */
35159cc4ca5SDavid du Colombier 	/* BUG: need +100 because we sometimes crash in library if we plot the exact center */
35259cc4ca5SDavid du Colombier 	p0 = map(mapra+100, mapdec);
35359cc4ca5SDavid du Colombier 	p1 = map(mapra+100+diam, mapdec);
35459cc4ca5SDavid du Colombier 	return hypot(p0.x-p1.x, p0.y-p1.y);
35559cc4ca5SDavid du Colombier }
35659cc4ca5SDavid du Colombier 
35759cc4ca5SDavid du Colombier void
drawdisc(Image * scr,DAngle semidiam,int ring,Image * color,Point pt,char * s)35859cc4ca5SDavid du Colombier drawdisc(Image *scr, DAngle semidiam, int ring, Image *color, Point pt, char *s)
35959cc4ca5SDavid du Colombier {
36059cc4ca5SDavid du Colombier 	int d;
36159cc4ca5SDavid du Colombier 
36259cc4ca5SDavid du Colombier 	d = npixels(semidiam*2);
36359cc4ca5SDavid du Colombier 	if(d < 5)
36459cc4ca5SDavid du Colombier 		d = 5;
36559cc4ca5SDavid du Colombier 	fillellipse(scr, pt, d, d, color, ZP);
36659cc4ca5SDavid du Colombier 	if(ring == 1)
36759cc4ca5SDavid du Colombier 		ellipse(scr, pt, 5*d/2, d/2, 0, color, ZP);
36859cc4ca5SDavid du Colombier 	if(ring == 2)
36959cc4ca5SDavid du Colombier 		ellipse(scr, pt, d, d, 0, grey, ZP);
37059cc4ca5SDavid du Colombier 	if(s){
37159cc4ca5SDavid du Colombier 		d = stringwidth(font, s);
37259cc4ca5SDavid du Colombier 		pt.x -= d/2;
37359cc4ca5SDavid du Colombier 		pt.y -= font->height/2 + 1;
37459cc4ca5SDavid du Colombier 		string(scr, pt, display->black, ZP, font, s);
37559cc4ca5SDavid du Colombier 	}
37659cc4ca5SDavid du Colombier }
37759cc4ca5SDavid du Colombier 
37859cc4ca5SDavid du Colombier void
drawplanet(Image * scr,Planetrec * p,Point pt)37959cc4ca5SDavid du Colombier drawplanet(Image *scr, Planetrec *p, Point pt)
38059cc4ca5SDavid du Colombier {
38159cc4ca5SDavid du Colombier 	if(strcmp(p->name, "sun") == 0){
38259cc4ca5SDavid du Colombier 		drawdisc(scr, p->semidiam, 0, suncolor, pt, nil);
38359cc4ca5SDavid du Colombier 		return;
38459cc4ca5SDavid du Colombier 	}
38559cc4ca5SDavid du Colombier 	if(strcmp(p->name, "moon") == 0){
38659cc4ca5SDavid du Colombier 		drawdisc(scr, p->semidiam, 0, mooncolor, pt, nil);
38759cc4ca5SDavid du Colombier 		return;
38859cc4ca5SDavid du Colombier 	}
38959cc4ca5SDavid du Colombier 	if(strcmp(p->name, "shadow") == 0){
39059cc4ca5SDavid du Colombier 		drawdisc(scr, p->semidiam, 2, shadowcolor, pt, nil);
39159cc4ca5SDavid du Colombier 		return;
39259cc4ca5SDavid du Colombier 	}
39359cc4ca5SDavid du Colombier 	if(strcmp(p->name, "mercury") == 0){
39459cc4ca5SDavid du Colombier 		drawdisc(scr, p->semidiam, 0, mercurycolor, pt, "m");
39559cc4ca5SDavid du Colombier 		return;
39659cc4ca5SDavid du Colombier 	}
39759cc4ca5SDavid du Colombier 	if(strcmp(p->name, "venus") == 0){
39859cc4ca5SDavid du Colombier 		drawdisc(scr, p->semidiam, 0, venuscolor, pt, "v");
39959cc4ca5SDavid du Colombier 		return;
40059cc4ca5SDavid du Colombier 	}
40159cc4ca5SDavid du Colombier 	if(strcmp(p->name, "mars") == 0){
40259cc4ca5SDavid du Colombier 		drawdisc(scr, p->semidiam, 0, marscolor, pt, "M");
40359cc4ca5SDavid du Colombier 		return;
40459cc4ca5SDavid du Colombier 	}
40559cc4ca5SDavid du Colombier 	if(strcmp(p->name, "jupiter") == 0){
40659cc4ca5SDavid du Colombier 		drawdisc(scr, p->semidiam, 0, jupitercolor, pt, "J");
40759cc4ca5SDavid du Colombier 		return;
40859cc4ca5SDavid du Colombier 	}
40959cc4ca5SDavid du Colombier 	if(strcmp(p->name, "saturn") == 0){
41059cc4ca5SDavid du Colombier 		drawdisc(scr, p->semidiam, 1, saturncolor, pt, "S");
41159cc4ca5SDavid du Colombier 
41259cc4ca5SDavid du Colombier 		return;
41359cc4ca5SDavid du Colombier 	}
41459cc4ca5SDavid du Colombier 	if(strcmp(p->name, "uranus") == 0){
41559cc4ca5SDavid du Colombier 		drawdisc(scr, p->semidiam, 0, uranuscolor, pt, "U");
41659cc4ca5SDavid du Colombier 
41759cc4ca5SDavid du Colombier 		return;
41859cc4ca5SDavid du Colombier 	}
41959cc4ca5SDavid du Colombier 	if(strcmp(p->name, "neptune") == 0){
42059cc4ca5SDavid du Colombier 		drawdisc(scr, p->semidiam, 0, neptunecolor, pt, "N");
42159cc4ca5SDavid du Colombier 
42259cc4ca5SDavid du Colombier 		return;
42359cc4ca5SDavid du Colombier 	}
42459cc4ca5SDavid du Colombier 	if(strcmp(p->name, "pluto") == 0){
42559cc4ca5SDavid du Colombier 		drawdisc(scr, p->semidiam, 0, plutocolor, pt, "P");
42659cc4ca5SDavid du Colombier 
42759cc4ca5SDavid du Colombier 		return;
42859cc4ca5SDavid du Colombier 	}
42959cc4ca5SDavid du Colombier 	if(strcmp(p->name, "comet") == 0){
43059cc4ca5SDavid du Colombier 		drawdisc(scr, p->semidiam, 0, cometcolor, pt, "C");
43159cc4ca5SDavid du Colombier 		return;
43259cc4ca5SDavid du Colombier 	}
43359cc4ca5SDavid du Colombier 
43459cc4ca5SDavid du Colombier 	pt.x -= stringwidth(font, p->name)/2;
43559cc4ca5SDavid du Colombier 	pt.y -= font->height/2;
43659cc4ca5SDavid du Colombier 	string(scr, pt, grey, ZP, font, p->name);
43759cc4ca5SDavid du Colombier }
43859cc4ca5SDavid du Colombier 
43959cc4ca5SDavid du Colombier void
tolast(char * name)44059cc4ca5SDavid du Colombier tolast(char *name)
44159cc4ca5SDavid du Colombier {
44259cc4ca5SDavid du Colombier 	int i, nlast;
44359cc4ca5SDavid du Colombier 	Record *r, rr;
44459cc4ca5SDavid du Colombier 
44559cc4ca5SDavid du Colombier 	/* stop early to simplify inner loop adjustment */
44659cc4ca5SDavid du Colombier 	nlast = 0;
44759cc4ca5SDavid du Colombier 	for(i=0,r=rec; i<nrec-nlast; i++,r++)
44859cc4ca5SDavid du Colombier 		if(r->type == Planet)
44959cc4ca5SDavid du Colombier 			if(name==nil || strcmp(r->planet.name, name)==0){
45059cc4ca5SDavid du Colombier 				rr = *r;
45159cc4ca5SDavid du Colombier 				memmove(rec+i, rec+i+1, (nrec-i-1)*sizeof(Record));
45259cc4ca5SDavid du Colombier 				rec[nrec-1] = rr;
45359cc4ca5SDavid du Colombier 				--i;
45459cc4ca5SDavid du Colombier 				--r;
45559cc4ca5SDavid du Colombier 				nlast++;
45659cc4ca5SDavid du Colombier 			}
45759cc4ca5SDavid du Colombier }
45859cc4ca5SDavid du Colombier 
45959cc4ca5SDavid du Colombier int
bbox(long extrara,long extradec,int quantize)46059cc4ca5SDavid du Colombier bbox(long extrara, long extradec, int quantize)
46159cc4ca5SDavid du Colombier {
46259cc4ca5SDavid du Colombier 	int i;
46359cc4ca5SDavid du Colombier 	Record *r;
46459cc4ca5SDavid du Colombier 	int ra, dec;
46559cc4ca5SDavid du Colombier 	int rah, ram, d1, d2;
46659cc4ca5SDavid du Colombier 	double r0;
46759cc4ca5SDavid du Colombier 
46859cc4ca5SDavid du Colombier 	ramin = 0x7FFFFFFF;
46959cc4ca5SDavid du Colombier 	ramax = -0x7FFFFFFF;
47059cc4ca5SDavid du Colombier 	decmin = 0x7FFFFFFF;
47159cc4ca5SDavid du Colombier 	decmax = -0x7FFFFFFF;
47259cc4ca5SDavid du Colombier 
47359cc4ca5SDavid du Colombier 	for(i=0,r=rec; i<nrec; i++,r++){
47459cc4ca5SDavid du Colombier 		if(r->type == Patch){
47559cc4ca5SDavid du Colombier 			radec(r->index, &rah, &ram, &dec);
47659cc4ca5SDavid du Colombier 			ra = 15*rah+ram/4;
47759cc4ca5SDavid du Colombier 			r0 = c/cos(dec*PI/180);
47859cc4ca5SDavid du Colombier 			ra *= c;
47959cc4ca5SDavid du Colombier 			dec *= c;
48059cc4ca5SDavid du Colombier 			if(dec == 0)
48159cc4ca5SDavid du Colombier 				d1 = c, d2 = c;
48259cc4ca5SDavid du Colombier 			else if(dec < 0)
48359cc4ca5SDavid du Colombier 				d1 = c, d2 = 0;
48459cc4ca5SDavid du Colombier 			else
48559cc4ca5SDavid du Colombier 				d1 = 0, d2 = c;
48659cc4ca5SDavid du Colombier 		}else if(r->type==SAO || r->type==NGC || r->type==Planet || r->type==Abell){
48759cc4ca5SDavid du Colombier 			ra = r->ngc.ra;
48859cc4ca5SDavid du Colombier 			dec = r->ngc.dec;
48959cc4ca5SDavid du Colombier 			d1 = 0, d2 = 0, r0 = 0;
49059cc4ca5SDavid du Colombier 		}else
49159cc4ca5SDavid du Colombier 			continue;
49259cc4ca5SDavid du Colombier 		if(dec+d2+extradec > decmax)
49359cc4ca5SDavid du Colombier 			decmax = dec+d2+extradec;
49459cc4ca5SDavid du Colombier 		if(dec-d1-extradec < decmin)
49559cc4ca5SDavid du Colombier 			decmin = dec-d1-extradec;
49659cc4ca5SDavid du Colombier 		if(folded){
49759cc4ca5SDavid du Colombier 			ra -= 180*c;
49859cc4ca5SDavid du Colombier 			if(ra < 0)
49959cc4ca5SDavid du Colombier 				ra += 360*c;
50059cc4ca5SDavid du Colombier 		}
50159cc4ca5SDavid du Colombier 		if(ra+r0+extrara > ramax)
50259cc4ca5SDavid du Colombier 			ramax = ra+r0+extrara;
50359cc4ca5SDavid du Colombier 		if(ra-extrara < ramin)
50459cc4ca5SDavid du Colombier 			ramin = ra-extrara;
50559cc4ca5SDavid du Colombier 	}
50659cc4ca5SDavid du Colombier 
50759cc4ca5SDavid du Colombier 	if(decmax > 90*c)
50859cc4ca5SDavid du Colombier 		decmax = 90*c;
50959cc4ca5SDavid du Colombier 	if(decmin < -90*c)
51059cc4ca5SDavid du Colombier 		decmin = -90*c;
51159cc4ca5SDavid du Colombier 	if(ramin < 0)
51259cc4ca5SDavid du Colombier 		ramin += 360*c;
51359cc4ca5SDavid du Colombier 	if(ramax >= 360*c)
51459cc4ca5SDavid du Colombier 		ramax -= 360*c;
51559cc4ca5SDavid du Colombier 
51659cc4ca5SDavid du Colombier 	if(quantize){
51759cc4ca5SDavid du Colombier 		/* quantize to degree boundaries */
51859cc4ca5SDavid du Colombier 		ramin -= ramin%m5;
51959cc4ca5SDavid du Colombier 		if(ramax%m5 != 0)
52059cc4ca5SDavid du Colombier 			ramax += m5-(ramax%m5);
52159cc4ca5SDavid du Colombier 		if(decmin > 0)
52259cc4ca5SDavid du Colombier 			decmin -= decmin%c;
52359cc4ca5SDavid du Colombier 		else
52459cc4ca5SDavid du Colombier 			decmin -= c - (-decmin)%c;
52559cc4ca5SDavid du Colombier 		if(decmax > 0){
52659cc4ca5SDavid du Colombier 			if(decmax%c != 0)
52759cc4ca5SDavid du Colombier 				decmax += c-(decmax%c);
52859cc4ca5SDavid du Colombier 		}else if(decmax < 0){
52959cc4ca5SDavid du Colombier 			if(decmax%c != 0)
53059cc4ca5SDavid du Colombier 				decmax += ((-decmax)%c);
53159cc4ca5SDavid du Colombier 		}
53259cc4ca5SDavid du Colombier 	}
53359cc4ca5SDavid du Colombier 
53459cc4ca5SDavid du Colombier 	if(folded){
53559cc4ca5SDavid du Colombier 		if(ramax-ramin > 270*c){
53659cc4ca5SDavid du Colombier 			fprint(2, "ra range too wide %ld°\n", (ramax-ramin)/c);
53759cc4ca5SDavid du Colombier 			return -1;
53859cc4ca5SDavid du Colombier 		}
53959cc4ca5SDavid du Colombier 	}else if(ramax-ramin > 270*c){
54059cc4ca5SDavid du Colombier 		folded = 1;
54159cc4ca5SDavid du Colombier 		return bbox(0, 0, quantize);
54259cc4ca5SDavid du Colombier 	}
54359cc4ca5SDavid du Colombier 
54459cc4ca5SDavid du Colombier 	return 1;
54559cc4ca5SDavid du Colombier }
54659cc4ca5SDavid du Colombier 
54759cc4ca5SDavid du Colombier int
inbbox(DAngle ra,DAngle dec)54859cc4ca5SDavid du Colombier inbbox(DAngle ra, DAngle dec)
54959cc4ca5SDavid du Colombier {
55059cc4ca5SDavid du Colombier 	int min;
55159cc4ca5SDavid du Colombier 
55259cc4ca5SDavid du Colombier 	if(dec < decmin)
55359cc4ca5SDavid du Colombier 		return 0;
55459cc4ca5SDavid du Colombier 	if(dec > decmax)
55559cc4ca5SDavid du Colombier 		return 0;
55659cc4ca5SDavid du Colombier 	min = ramin;
55759cc4ca5SDavid du Colombier 	if(ramin > ramax){	/* straddling 0h0m */
55859cc4ca5SDavid du Colombier 		min -= 360*c;
55959cc4ca5SDavid du Colombier 		if(ra > 180*c)
56059cc4ca5SDavid du Colombier 			ra -= 360*c;
56159cc4ca5SDavid du Colombier 	}
56259cc4ca5SDavid du Colombier 	if(ra < min)
56359cc4ca5SDavid du Colombier 		return 0;
56459cc4ca5SDavid du Colombier 	if(ra > ramax)
56559cc4ca5SDavid du Colombier 		return 0;
56659cc4ca5SDavid du Colombier 	return 1;
56759cc4ca5SDavid du Colombier }
56859cc4ca5SDavid du Colombier 
56959cc4ca5SDavid du Colombier int
gridra(long mapdec)57059cc4ca5SDavid du Colombier gridra(long mapdec)
57159cc4ca5SDavid du Colombier {
57259cc4ca5SDavid du Colombier 	mapdec = abs(mapdec)+c/2;
57359cc4ca5SDavid du Colombier 	mapdec /= c;
57459cc4ca5SDavid du Colombier 	if(mapdec < 60)
57559cc4ca5SDavid du Colombier 		return m5;
57659cc4ca5SDavid du Colombier 	if(mapdec < 80)
57759cc4ca5SDavid du Colombier 		return 2*m5;
57859cc4ca5SDavid du Colombier 	if(mapdec < 85)
57959cc4ca5SDavid du Colombier 		return 4*m5;
58059cc4ca5SDavid du Colombier 	return 8*m5;
58159cc4ca5SDavid du Colombier }
58259cc4ca5SDavid du Colombier 
58359cc4ca5SDavid du Colombier #define	GREY	(nogrey? display->white : grey)
58459cc4ca5SDavid du Colombier 
58559cc4ca5SDavid du Colombier void
plot(char * flags)58659cc4ca5SDavid du Colombier plot(char *flags)
58759cc4ca5SDavid du Colombier {
58859cc4ca5SDavid du Colombier 	int i, j, k;
58959cc4ca5SDavid du Colombier 	char *t;
59059cc4ca5SDavid du Colombier 	long x, y;
59159cc4ca5SDavid du Colombier 	int ra, dec;
59259cc4ca5SDavid du Colombier 	int m;
59359cc4ca5SDavid du Colombier 	Point p, pts[10];
59459cc4ca5SDavid du Colombier 	Record *r;
59559cc4ca5SDavid du Colombier 	Rectangle rect, r1;
59659cc4ca5SDavid du Colombier 	int dx, dy, nogrid, textlevel, nogrey, zenithup;
59759cc4ca5SDavid du Colombier 	Image *scr;
59859cc4ca5SDavid du Colombier 	char *name, buf[32];
59959cc4ca5SDavid du Colombier 	double v;
60059cc4ca5SDavid du Colombier 
60159cc4ca5SDavid du Colombier 	if(plotopen() < 0)
60259cc4ca5SDavid du Colombier 		return;
60359cc4ca5SDavid du Colombier 	nogrid = 0;
60459cc4ca5SDavid du Colombier 	nogrey = 0;
60559cc4ca5SDavid du Colombier 	textlevel = 1;
60659cc4ca5SDavid du Colombier 	dx = 512;
60759cc4ca5SDavid du Colombier 	dy = 512;
60859cc4ca5SDavid du Colombier 	zenithup = 0;
60959cc4ca5SDavid du Colombier 	for(;;){
61059cc4ca5SDavid du Colombier 		if(t = alpha(flags, "nogrid")){
61159cc4ca5SDavid du Colombier 			nogrid = 1;
61259cc4ca5SDavid du Colombier 			flags = t;
61359cc4ca5SDavid du Colombier 			continue;
61459cc4ca5SDavid du Colombier 		}
61559cc4ca5SDavid du Colombier 		if((t = alpha(flags, "zenith")) || (t = alpha(flags, "zenithup")) ){
61659cc4ca5SDavid du Colombier 			zenithup = 1;
61759cc4ca5SDavid du Colombier 			flags = t;
61859cc4ca5SDavid du Colombier 			continue;
61959cc4ca5SDavid du Colombier 		}
62059cc4ca5SDavid du Colombier 		if((t = alpha(flags, "notext")) || (t = alpha(flags, "nolabel")) ){
62159cc4ca5SDavid du Colombier 			textlevel = 0;
62259cc4ca5SDavid du Colombier 			flags = t;
62359cc4ca5SDavid du Colombier 			continue;
62459cc4ca5SDavid du Colombier 		}
62559cc4ca5SDavid du Colombier 		if((t = alpha(flags, "alltext")) || (t = alpha(flags, "alllabel")) ){
62659cc4ca5SDavid du Colombier 			textlevel = 2;
62759cc4ca5SDavid du Colombier 			flags = t;
62859cc4ca5SDavid du Colombier 			continue;
62959cc4ca5SDavid du Colombier 		}
63059cc4ca5SDavid du Colombier 		if(t = alpha(flags, "dx")){
63159cc4ca5SDavid du Colombier 			dx = strtol(t, &t, 0);
63259cc4ca5SDavid du Colombier 			if(dx < 100){
63359cc4ca5SDavid du Colombier 				fprint(2, "dx %d too small (min 100) in plot\n", dx);
63459cc4ca5SDavid du Colombier 				return;
63559cc4ca5SDavid du Colombier 			}
63659cc4ca5SDavid du Colombier 			flags = skipbl(t);
63759cc4ca5SDavid du Colombier 			continue;
63859cc4ca5SDavid du Colombier 		}
63959cc4ca5SDavid du Colombier 		if(t = alpha(flags, "dy")){
64059cc4ca5SDavid du Colombier 			dy = strtol(t, &t, 0);
64159cc4ca5SDavid du Colombier 			if(dy < 100){
64259cc4ca5SDavid du Colombier 				fprint(2, "dy %d too small (min 100) in plot\n", dy);
64359cc4ca5SDavid du Colombier 				return;
64459cc4ca5SDavid du Colombier 			}
64559cc4ca5SDavid du Colombier 			flags = skipbl(t);
64659cc4ca5SDavid du Colombier 			continue;
64759cc4ca5SDavid du Colombier 		}
64859cc4ca5SDavid du Colombier 		if((t = alpha(flags, "nogrey")) || (t = alpha(flags, "nogray"))){
64959cc4ca5SDavid du Colombier 			nogrey = 1;
65059cc4ca5SDavid du Colombier 			flags = skipbl(t);
65159cc4ca5SDavid du Colombier 			continue;
65259cc4ca5SDavid du Colombier 		}
65359cc4ca5SDavid du Colombier 		if(*flags){
65459cc4ca5SDavid du Colombier 			fprint(2, "syntax error in plot\n");
65559cc4ca5SDavid du Colombier 			return;
65659cc4ca5SDavid du Colombier 		}
65759cc4ca5SDavid du Colombier 		break;
65859cc4ca5SDavid du Colombier 	}
65959cc4ca5SDavid du Colombier 	flatten();
66059cc4ca5SDavid du Colombier 	folded = 0;
66159cc4ca5SDavid du Colombier 
66259cc4ca5SDavid du Colombier 	if(bbox(0, 0, 1) < 0)
66359cc4ca5SDavid du Colombier 		return;
66459cc4ca5SDavid du Colombier 	if(ramax-ramin<100 || decmax-decmin<100){
66559cc4ca5SDavid du Colombier 		fprint(2, "plot too small\n");
66659cc4ca5SDavid du Colombier 		return;
66759cc4ca5SDavid du Colombier 	}
66859cc4ca5SDavid du Colombier 
669*9a747e4fSDavid du Colombier 	scr = allocimage(display, Rect(0, 0, dx, dy), RGB24, 0, DBlack);
67059cc4ca5SDavid du Colombier 	if(scr == nil){
67159cc4ca5SDavid du Colombier 		fprint(2, "can't allocate image: %r\n");
67259cc4ca5SDavid du Colombier 		return;
67359cc4ca5SDavid du Colombier 	}
67459cc4ca5SDavid du Colombier 	rect = scr->r;
67559cc4ca5SDavid du Colombier 	rect.min.x += 16;
67659cc4ca5SDavid du Colombier 	rect = insetrect(rect, 40);
67759cc4ca5SDavid du Colombier 	if(setmap(ramin, ramax, decmin, decmax, rect, zenithup) < 0){
67859cc4ca5SDavid du Colombier 		fprint(2, "can't set up map coordinates\n");
67959cc4ca5SDavid du Colombier 		return;
68059cc4ca5SDavid du Colombier 	}
68159cc4ca5SDavid du Colombier 	if(!nogrid){
68259cc4ca5SDavid du Colombier 		for(x=ramin; ; ){
68359cc4ca5SDavid du Colombier 			for(j=0; j<nelem(pts); j++){
68459cc4ca5SDavid du Colombier 				/* use double to avoid overflow */
68559cc4ca5SDavid du Colombier 				v = (double)j / (double)(nelem(pts)-1);
68659cc4ca5SDavid du Colombier 				v = decmin + v*(decmax-decmin);
68759cc4ca5SDavid du Colombier 				pts[j] = map(x, v);
68859cc4ca5SDavid du Colombier 			}
68959cc4ca5SDavid du Colombier 			bezspline(scr, pts, nelem(pts), Endsquare, Endsquare, 0, GREY, ZP);
69059cc4ca5SDavid du Colombier 			ra = x;
69159cc4ca5SDavid du Colombier 			if(folded){
69259cc4ca5SDavid du Colombier 				ra -= 180*c;
69359cc4ca5SDavid du Colombier 				if(ra < 0)
69459cc4ca5SDavid du Colombier 					ra += 360*c;
69559cc4ca5SDavid du Colombier 			}
69659cc4ca5SDavid du Colombier 			p = pts[0];
69759cc4ca5SDavid du Colombier 			p.x -= stringwidth(font, hm5(angle(ra)))/2;
69859cc4ca5SDavid du Colombier 			string(scr, p, GREY, ZP, font, hm5(angle(ra)));
69959cc4ca5SDavid du Colombier 			p = pts[nelem(pts)-1];
70059cc4ca5SDavid du Colombier 			p.x -= stringwidth(font, hm5(angle(ra)))/2;
70159cc4ca5SDavid du Colombier 			p.y -= font->height;
70259cc4ca5SDavid du Colombier 			string(scr, p, GREY, ZP, font, hm5(angle(ra)));
70359cc4ca5SDavid du Colombier 			if(x == ramax)
70459cc4ca5SDavid du Colombier 				break;
70559cc4ca5SDavid du Colombier 			x += gridra(mapdec);
70659cc4ca5SDavid du Colombier 			if(x > ramax)
70759cc4ca5SDavid du Colombier 				x = ramax;
70859cc4ca5SDavid du Colombier 		}
70959cc4ca5SDavid du Colombier 		for(y=decmin; y<=decmax; y+=c){
71059cc4ca5SDavid du Colombier 			for(j=0; j<nelem(pts); j++){
71159cc4ca5SDavid du Colombier 				/* use double to avoid overflow */
71259cc4ca5SDavid du Colombier 				v = (double)j / (double)(nelem(pts)-1);
71359cc4ca5SDavid du Colombier 				v = ramin + v*(ramax-ramin);
71459cc4ca5SDavid du Colombier 				pts[j] = map(v, y);
71559cc4ca5SDavid du Colombier 			}
71659cc4ca5SDavid du Colombier 			bezspline(scr, pts, nelem(pts), Endsquare, Endsquare, 0, GREY, ZP);
71759cc4ca5SDavid du Colombier 			p = pts[0];
71859cc4ca5SDavid du Colombier 			p.x += 3;
71959cc4ca5SDavid du Colombier 			p.y -= font->height/2;
72059cc4ca5SDavid du Colombier 			string(scr, p, GREY, ZP, font, deg(angle(y)));
72159cc4ca5SDavid du Colombier 			p = pts[nelem(pts)-1];
72259cc4ca5SDavid du Colombier 			p.x -= 3+stringwidth(font, deg(angle(y)));
72359cc4ca5SDavid du Colombier 			p.y -= font->height/2;
72459cc4ca5SDavid du Colombier 			string(scr, p, GREY, ZP, font, deg(angle(y)));
72559cc4ca5SDavid du Colombier 		}
72659cc4ca5SDavid du Colombier 	}
72759cc4ca5SDavid du Colombier 	/* reorder to get planets in front of stars */
72859cc4ca5SDavid du Colombier 	tolast(nil);
72959cc4ca5SDavid du Colombier 	tolast("moon");		/* moon is in front of everything... */
73059cc4ca5SDavid du Colombier 	tolast("shadow");	/* ... except the shadow */
73159cc4ca5SDavid du Colombier 
73259cc4ca5SDavid du Colombier 	for(i=0,r=rec; i<nrec; i++,r++){
73359cc4ca5SDavid du Colombier 		dec = r->ngc.dec;
73459cc4ca5SDavid du Colombier 		ra = r->ngc.ra;
73559cc4ca5SDavid du Colombier 		if(folded){
73659cc4ca5SDavid du Colombier 			ra -= 180*c;
73759cc4ca5SDavid du Colombier 			if(ra < 0)
73859cc4ca5SDavid du Colombier 				ra += 360*c;
73959cc4ca5SDavid du Colombier 		}
74059cc4ca5SDavid du Colombier 		if(textlevel){
74159cc4ca5SDavid du Colombier 			name = nameof(r);
74259cc4ca5SDavid du Colombier 			if(name==nil && textlevel>1 && r->type==SAO){
74359cc4ca5SDavid du Colombier 				snprint(buf, sizeof buf, "SAO%ld", r->index);
74459cc4ca5SDavid du Colombier 				name = buf;
74559cc4ca5SDavid du Colombier 			}
74659cc4ca5SDavid du Colombier 			if(name)
74759cc4ca5SDavid du Colombier 				drawname(scr, nogrey? display->white : alphagrey, name, ra, dec);
74859cc4ca5SDavid du Colombier 		}
74959cc4ca5SDavid du Colombier 		if(r->type == Planet){
75059cc4ca5SDavid du Colombier 			drawplanet(scr, &r->planet, map(ra, dec));
75159cc4ca5SDavid du Colombier 			continue;
75259cc4ca5SDavid du Colombier 		}
75359cc4ca5SDavid du Colombier 		if(r->type == SAO){
75459cc4ca5SDavid du Colombier 			m = r->sao.mag;
75559cc4ca5SDavid du Colombier 			if(m == UNKNOWNMAG)
75659cc4ca5SDavid du Colombier 				m = r->sao.mpg;
75759cc4ca5SDavid du Colombier 			if(m == UNKNOWNMAG)
75859cc4ca5SDavid du Colombier 				continue;
75959cc4ca5SDavid du Colombier 			m = dsize(m);
76059cc4ca5SDavid du Colombier 			if(m < 3)
76159cc4ca5SDavid du Colombier 				fillellipse(scr, map(ra, dec), m, m, nogrey? display->white : lightgrey, ZP);
76259cc4ca5SDavid du Colombier 			else{
76359cc4ca5SDavid du Colombier 				ellipse(scr, map(ra, dec), m+1, m+1, 0, display->black, ZP);
76459cc4ca5SDavid du Colombier 				fillellipse(scr, map(ra, dec), m, m, display->white, ZP);
76559cc4ca5SDavid du Colombier 			}
76659cc4ca5SDavid du Colombier 			continue;
76759cc4ca5SDavid du Colombier 		}
76859cc4ca5SDavid du Colombier 		if(r->type == Abell){
76959cc4ca5SDavid du Colombier 			ellipse(scr, addpt(map(ra, dec), Pt(-3, 2)), 2, 1, 0, lightblue, ZP);
77059cc4ca5SDavid du Colombier 			ellipse(scr, addpt(map(ra, dec), Pt(3, 2)), 2, 1, 0, lightblue, ZP);
77159cc4ca5SDavid du Colombier 			ellipse(scr, addpt(map(ra, dec), Pt(0, -2)), 1, 2, 0, lightblue, ZP);
77259cc4ca5SDavid du Colombier 			continue;
77359cc4ca5SDavid du Colombier 		}
77459cc4ca5SDavid du Colombier 		switch(r->ngc.type){
77559cc4ca5SDavid du Colombier 		case Galaxy:
77659cc4ca5SDavid du Colombier 			j = npixels(r->ngc.diam);
77759cc4ca5SDavid du Colombier 			if(j < 4)
77859cc4ca5SDavid du Colombier 				j = 4;
77959cc4ca5SDavid du Colombier 			if(j > 10)
78059cc4ca5SDavid du Colombier 				k = j/3;
78159cc4ca5SDavid du Colombier 			else
78259cc4ca5SDavid du Colombier 				k = j/2;
78359cc4ca5SDavid du Colombier 			ellipse(scr, map(ra, dec), j, k, 0, lightblue, ZP);
78459cc4ca5SDavid du Colombier 			break;
78559cc4ca5SDavid du Colombier 
78659cc4ca5SDavid du Colombier 		case PlanetaryN:
78759cc4ca5SDavid du Colombier 			p = map(ra, dec);
78859cc4ca5SDavid du Colombier 			j = npixels(r->ngc.diam);
78959cc4ca5SDavid du Colombier 			if(j < 3)
79059cc4ca5SDavid du Colombier 				j = 3;
79159cc4ca5SDavid du Colombier 			ellipse(scr, p, j, j, 0, green, ZP);
79259cc4ca5SDavid du Colombier 			line(scr, Pt(p.x, p.y+j+1), Pt(p.x, p.y+j+4),
79359cc4ca5SDavid du Colombier 				Endsquare, Endsquare, 0, green, ZP);
79459cc4ca5SDavid du Colombier 			line(scr, Pt(p.x, p.y-(j+1)), Pt(p.x, p.y-(j+4)),
79559cc4ca5SDavid du Colombier 				Endsquare, Endsquare, 0, green, ZP);
79659cc4ca5SDavid du Colombier 			line(scr, Pt(p.x+j+1, p.y), Pt(p.x+j+4, p.y),
79759cc4ca5SDavid du Colombier 				Endsquare, Endsquare, 0, green, ZP);
79859cc4ca5SDavid du Colombier 			line(scr, Pt(p.x-(j+1), p.y), Pt(p.x-(j+4), p.y),
79959cc4ca5SDavid du Colombier 				Endsquare, Endsquare, 0, green, ZP);
80059cc4ca5SDavid du Colombier 			break;
80159cc4ca5SDavid du Colombier 
80259cc4ca5SDavid du Colombier 		case DiffuseN:
80359cc4ca5SDavid du Colombier 		case NebularCl:
80459cc4ca5SDavid du Colombier 			p = map(ra, dec);
80559cc4ca5SDavid du Colombier 			j = npixels(r->ngc.diam);
80659cc4ca5SDavid du Colombier 			if(j < 4)
80759cc4ca5SDavid du Colombier 				j = 4;
80859cc4ca5SDavid du Colombier 			r1.min = Pt(p.x-j, p.y-j);
80959cc4ca5SDavid du Colombier 			r1.max = Pt(p.x+j, p.y+j);
81059cc4ca5SDavid du Colombier 			if(r->ngc.type != DiffuseN)
81159cc4ca5SDavid du Colombier 				draw(scr, r1, ocstipple, ocstipple, ZP);
81259cc4ca5SDavid du Colombier 			line(scr, Pt(p.x-j, p.y-j), Pt(p.x+j, p.y-j),
81359cc4ca5SDavid du Colombier 				Endsquare, Endsquare, 0, green, ZP);
81459cc4ca5SDavid du Colombier 			line(scr, Pt(p.x-j, p.y+j), Pt(p.x+j, p.y+j),
81559cc4ca5SDavid du Colombier 				Endsquare, Endsquare, 0, green, ZP);
81659cc4ca5SDavid du Colombier 			line(scr, Pt(p.x-j, p.y-j), Pt(p.x-j, p.y+j),
81759cc4ca5SDavid du Colombier 				Endsquare, Endsquare, 0, green, ZP);
81859cc4ca5SDavid du Colombier 			line(scr, Pt(p.x+j, p.y-j), Pt(p.x+j, p.y+j),
81959cc4ca5SDavid du Colombier 				Endsquare, Endsquare, 0, green, ZP);
82059cc4ca5SDavid du Colombier 			break;
82159cc4ca5SDavid du Colombier 
82259cc4ca5SDavid du Colombier 		case OpenCl:
82359cc4ca5SDavid du Colombier 			p = map(ra, dec);
82459cc4ca5SDavid du Colombier 			j = npixels(r->ngc.diam);
82559cc4ca5SDavid du Colombier 			if(j < 4)
82659cc4ca5SDavid du Colombier 				j = 4;
82759cc4ca5SDavid du Colombier 			fillellipse(scr, p, j, j, ocstipple, ZP);
82859cc4ca5SDavid du Colombier 			break;
82959cc4ca5SDavid du Colombier 
83059cc4ca5SDavid du Colombier 		case GlobularCl:
83159cc4ca5SDavid du Colombier 			j = npixels(r->ngc.diam);
83259cc4ca5SDavid du Colombier 			if(j < 4)
83359cc4ca5SDavid du Colombier 				j = 4;
83459cc4ca5SDavid du Colombier 			p = map(ra, dec);
83559cc4ca5SDavid du Colombier 			ellipse(scr, p, j, j, 0, lightgrey, ZP);
83659cc4ca5SDavid du Colombier 			line(scr, Pt(p.x-(j-1), p.y), Pt(p.x+j, p.y),
83759cc4ca5SDavid du Colombier 				Endsquare, Endsquare, 0, lightgrey, ZP);
83859cc4ca5SDavid du Colombier 			line(scr, Pt(p.x, p.y-(j-1)), Pt(p.x, p.y+j),
83959cc4ca5SDavid du Colombier 				Endsquare, Endsquare, 0, lightgrey, ZP);
84059cc4ca5SDavid du Colombier 			break;
84159cc4ca5SDavid du Colombier 
84259cc4ca5SDavid du Colombier 		}
84359cc4ca5SDavid du Colombier 	}
84459cc4ca5SDavid du Colombier 	flushimage(display, 1);
84559cc4ca5SDavid du Colombier 	displayimage(scr);
84659cc4ca5SDavid du Colombier }
84759cc4ca5SDavid du Colombier 
84859cc4ca5SDavid du Colombier int
runcommand(char * command,int p[2])84959cc4ca5SDavid du Colombier runcommand(char *command, int p[2])
85059cc4ca5SDavid du Colombier {
85159cc4ca5SDavid du Colombier 	switch(rfork(RFPROC|RFFDG|RFNOWAIT)){
85259cc4ca5SDavid du Colombier 	case -1:
85359cc4ca5SDavid du Colombier 		return -1;
85459cc4ca5SDavid du Colombier 	default:
85559cc4ca5SDavid du Colombier 		break;
85659cc4ca5SDavid du Colombier 	case 0:
85759cc4ca5SDavid du Colombier 		dup(p[1], 1);
85859cc4ca5SDavid du Colombier 		close(p[0]);
85959cc4ca5SDavid du Colombier 		close(p[1]);
86059cc4ca5SDavid du Colombier 		execl("/bin/rc", "rc", "-c", command, nil);
86159cc4ca5SDavid du Colombier 		fprint(2, "can't exec %s: %r", command);
86259cc4ca5SDavid du Colombier 		exits(nil);
86359cc4ca5SDavid du Colombier 	}
86459cc4ca5SDavid du Colombier 	return 1;
86559cc4ca5SDavid du Colombier }
86659cc4ca5SDavid du Colombier 
86759cc4ca5SDavid du Colombier void
parseplanet(char * line,Planetrec * p)86859cc4ca5SDavid du Colombier parseplanet(char *line, Planetrec *p)
86959cc4ca5SDavid du Colombier {
87059cc4ca5SDavid du Colombier 	char *fld[6];
87159cc4ca5SDavid du Colombier 	int i, nfld;
87259cc4ca5SDavid du Colombier 	char *s;
87359cc4ca5SDavid du Colombier 
87459cc4ca5SDavid du Colombier 	if(line[0] == '\0')
87559cc4ca5SDavid du Colombier 		return;
87659cc4ca5SDavid du Colombier 	line[10] = '\0';	/* terminate name */
87759cc4ca5SDavid du Colombier 	s = strrchr(line, ' ');
87859cc4ca5SDavid du Colombier 	if(s == nil)
87959cc4ca5SDavid du Colombier 		s = line;
88059cc4ca5SDavid du Colombier 	else
88159cc4ca5SDavid du Colombier 		s++;
88259cc4ca5SDavid du Colombier 	strcpy(p->name, s);
88359cc4ca5SDavid du Colombier 	for(i=0; s[i]!='\0'; i++)
88459cc4ca5SDavid du Colombier 		p->name[i] = tolower(s[i]);
88559cc4ca5SDavid du Colombier 	p->name[i] = '\0';
88659cc4ca5SDavid du Colombier 	nfld = getfields(line+11, fld, nelem(fld), 1, " ");
88759cc4ca5SDavid du Colombier 	p->ra = dangle(getra(fld[0]));
88859cc4ca5SDavid du Colombier 	p->dec = dangle(getra(fld[1]));
88959cc4ca5SDavid du Colombier 	p->az = atof(fld[2])*MILLIARCSEC;
89059cc4ca5SDavid du Colombier 	p->alt = atof(fld[3])*MILLIARCSEC;
89159cc4ca5SDavid du Colombier 	p->semidiam = atof(fld[4])*1000;
89259cc4ca5SDavid du Colombier 	if(nfld > 5)
89359cc4ca5SDavid du Colombier 		p->phase = atof(fld[5]);
89459cc4ca5SDavid du Colombier 	else
89559cc4ca5SDavid du Colombier 		p->phase = 0;
89659cc4ca5SDavid du Colombier }
89759cc4ca5SDavid du Colombier 
89859cc4ca5SDavid du Colombier void
astro(char * flags,int initial)89959cc4ca5SDavid du Colombier astro(char *flags, int initial)
90059cc4ca5SDavid du Colombier {
90159cc4ca5SDavid du Colombier 	int p[2];
90259cc4ca5SDavid du Colombier 	int i, n, np;
90359cc4ca5SDavid du Colombier 	char cmd[256], buf[4096], *lines[20], *fld[10];
90459cc4ca5SDavid du Colombier 
90559cc4ca5SDavid du Colombier 	snprint(cmd, sizeof cmd, "/bin/astro -p %s", flags);
90659cc4ca5SDavid du Colombier 	if(pipe(p) < 0){
90759cc4ca5SDavid du Colombier 		fprint(2, "can't pipe: %r\n");
90859cc4ca5SDavid du Colombier 		return;
90959cc4ca5SDavid du Colombier 	}
91059cc4ca5SDavid du Colombier 	if(runcommand(cmd, p) < 0){
91159cc4ca5SDavid du Colombier 		close(p[0]);
91259cc4ca5SDavid du Colombier 		close(p[1]);
91359cc4ca5SDavid du Colombier 		fprint(2, "can't run astro: %r");
91459cc4ca5SDavid du Colombier 		return;
91559cc4ca5SDavid du Colombier 	}
91659cc4ca5SDavid du Colombier 	close(p[1]);
91759cc4ca5SDavid du Colombier 	n = readn(p[0], buf, sizeof buf-1);
91859cc4ca5SDavid du Colombier 	if(n <= 0){
91959cc4ca5SDavid du Colombier 		fprint(2, "no data from astro\n");
92059cc4ca5SDavid du Colombier 		return;
92159cc4ca5SDavid du Colombier 	}
92259cc4ca5SDavid du Colombier 	if(!initial)
92359cc4ca5SDavid du Colombier 		Bwrite(&bout, buf, n);
92459cc4ca5SDavid du Colombier 	buf[n] = '\0';
92559cc4ca5SDavid du Colombier 	np = getfields(buf, lines, nelem(lines), 0, "\n");
92659cc4ca5SDavid du Colombier 	if(np <= 1){
92759cc4ca5SDavid du Colombier 		fprint(2, "astro: not enough output\n");
92859cc4ca5SDavid du Colombier 		return;
92959cc4ca5SDavid du Colombier 	}
93059cc4ca5SDavid du Colombier 	Bprint(&bout, "%s\n", lines[0]);
93159cc4ca5SDavid du Colombier 	Bflush(&bout);
93259cc4ca5SDavid du Colombier 	/* get latitude and longitude */
93359cc4ca5SDavid du Colombier 	if(getfields(lines[0], fld, nelem(fld), 1, " ") < 8)
93459cc4ca5SDavid du Colombier 		fprint(2, "astro: can't read longitude: too few fields\n");
93559cc4ca5SDavid du Colombier 	else{
93659cc4ca5SDavid du Colombier 		mysid = getra(fld[5])*180./PI;
93759cc4ca5SDavid du Colombier 		mylat = getra(fld[6])*180./PI;
93859cc4ca5SDavid du Colombier 		mylon = getra(fld[7])*180./PI;
93959cc4ca5SDavid du Colombier 	}
94059cc4ca5SDavid du Colombier 	/*
94159cc4ca5SDavid du Colombier 	 * Each time we run astro, we generate a new planet list
94259cc4ca5SDavid du Colombier 	 * so multiple appearances of a planet may exist as we plot
94359cc4ca5SDavid du Colombier 	 * its motion over time.
94459cc4ca5SDavid du Colombier 	 */
94559cc4ca5SDavid du Colombier 	planet = malloc(NPlanet*sizeof planet[0]);
94659cc4ca5SDavid du Colombier 	if(planet == nil){
94759cc4ca5SDavid du Colombier 		fprint(2, "astro: malloc failed: %r\n");
94859cc4ca5SDavid du Colombier 		exits("malloc");
94959cc4ca5SDavid du Colombier 	}
95059cc4ca5SDavid du Colombier 	memset(planet, 0, NPlanet*sizeof planet[0]);
95159cc4ca5SDavid du Colombier 	for(i=1; i<np; i++)
95259cc4ca5SDavid du Colombier 		parseplanet(lines[i], &planet[i-1]);
95359cc4ca5SDavid du Colombier }
954