| #include <u.h> |
| #include <libc.h> |
| #include <bio.h> |
| #include <draw.h> |
| #include <event.h> |
| #include <ctype.h> |
| #include "map.h" |
| #undef RAD |
| #undef TWOPI |
| #include "sky.h" |
| |
| /* convert to milliarcsec */ |
| static int32 c = MILLIARCSEC; /* 1 degree */ |
| static int32 m5 = 1250*60*60; /* 5 minutes of ra */ |
| |
| DAngle ramin; |
| DAngle ramax; |
| DAngle decmin; |
| DAngle decmax; |
| int folded; |
| |
| Image *grey; |
| Image *alphagrey; |
| Image *green; |
| Image *lightblue; |
| Image *lightgrey; |
| Image *ocstipple; |
| Image *suncolor; |
| Image *mooncolor; |
| Image *shadowcolor; |
| Image *mercurycolor; |
| Image *venuscolor; |
| Image *marscolor; |
| Image *jupitercolor; |
| Image *saturncolor; |
| Image *uranuscolor; |
| Image *neptunecolor; |
| Image *plutocolor; |
| Image *cometcolor; |
| |
| Planetrec *planet; |
| |
| int32 mapx0, mapy0; |
| int32 mapra, mapdec; |
| double mylat, mylon, mysid; |
| double mapscale; |
| double maps; |
| int (*projection)(struct place*, double*, double*); |
| |
| char *fontname = "/lib/font/bit/luc/unicode.6.font"; |
| |
| /* types Coord and Loc correspond to types in map(3) thus: |
| Coord == struct coord; |
| Loc == struct place, except longitudes are measured |
| positive east for Loc and west for struct place |
| */ |
| |
| typedef struct Xyz Xyz; |
| typedef struct coord Coord; |
| typedef struct Loc Loc; |
| |
| struct Xyz{ |
| double x,y,z; |
| }; |
| |
| struct Loc{ |
| Coord nlat, elon; |
| }; |
| |
| Xyz north = { 0, 0, 1 }; |
| |
| int |
| plotopen(void) |
| { |
| if(display != nil) |
| return 1; |
| if(initdraw(drawerror, nil, nil) < 0){ |
| fprint(2, "initdisplay failed: %r\n"); |
| return -1; |
| } |
| grey = allocimage(display, Rect(0, 0, 1, 1), CMAP8, 1, 0x777777FF); |
| lightgrey = allocimage(display, Rect(0, 0, 1, 1), CMAP8, 1, 0xAAAAAAFF); |
| alphagrey = allocimage(display, Rect(0, 0, 2, 2), RGBA32, 1, 0x77777777); |
| green = allocimage(display, Rect(0, 0, 1, 1), CMAP8, 1, 0x00AA00FF); |
| lightblue = allocimage(display, Rect(0, 0, 1, 1), CMAP8, 1, 0x009EEEFF); |
| ocstipple = allocimage(display, Rect(0, 0, 2, 2), CMAP8, 1, 0xAAAAAAFF); |
| draw(ocstipple, Rect(0, 0, 1, 1), display->black, nil, ZP); |
| draw(ocstipple, Rect(1, 1, 2, 2), display->black, nil, ZP); |
| |
| suncolor = allocimage(display, Rect(0, 0, 1, 1), RGBA32, 1, 0xFFFF77FF); |
| mooncolor = allocimage(display, Rect(0, 0, 1, 1), RGBA32, 1, 0xAAAAAAFF); |
| shadowcolor = allocimage(display, Rect(0, 0, 1, 1), RGBA32, 1, 0x00000055); |
| mercurycolor = allocimage(display, Rect(0, 0, 1, 1), RGBA32, 1, 0xFFAAAAFF); |
| venuscolor = allocimage(display, Rect(0, 0, 1, 1), RGBA32, 1, 0xAAAAFFFF); |
| marscolor = allocimage(display, Rect(0, 0, 1, 1), RGBA32, 1, 0xFF5555FF); |
| jupitercolor = allocimage(display, Rect(0, 0, 1, 1), RGBA32, 1, 0xFFFFAAFF); |
| saturncolor = allocimage(display, Rect(0, 0, 1, 1), RGBA32, 1, 0xAAFFAAFF); |
| uranuscolor = allocimage(display, Rect(0, 0, 1, 1), RGBA32, 1, 0x77DDDDFF); |
| neptunecolor = allocimage(display, Rect(0, 0, 1, 1), RGBA32, 1, 0x77FF77FF); |
| plutocolor = allocimage(display, Rect(0, 0, 1, 1), RGBA32, 1, 0x7777FFFF); |
| cometcolor = allocimage(display, Rect(0, 0, 1, 1), RGBA32, 1, 0xAAAAFFFF); |
| font = openfont(display, fontname); |
| if(font == nil) |
| fprint(2, "warning: no font %s: %r\n", fontname); |
| return 1; |
| } |
| |
| /* |
| * Function heavens() for setting up observer-eye-view |
| * sky charts, plus subsidiary functions. |
| * Written by Doug McIlroy. |
| */ |
| |
| /* heavens(nlato, wlono, nlatc, wlonc) sets up a map(3)-style |
| coordinate change (by calling orient()) and returns a |
| projection function heavens for calculating a star map |
| centered on nlatc,wlonc and rotated so it will appear |
| upright as seen by a ground observer at nlato,wlono. |
| all coordinates (north latitude and west longitude) |
| are in degrees. |
| */ |
| |
| Coord |
| mkcoord(double degrees) |
| { |
| Coord c; |
| |
| c.l = degrees*PI/180; |
| c.s = sin(c.l); |
| c.c = cos(c.l); |
| return c; |
| } |
| |
| Xyz |
| ptov(struct place p) |
| { |
| Xyz v; |
| |
| v.z = p.nlat.s; |
| v.x = p.nlat.c * p.wlon.c; |
| v.y = -p.nlat.c * p.wlon.s; |
| return v; |
| } |
| |
| double |
| dot(Xyz a, Xyz b) |
| { |
| return a.x*b.x + a.y*b.y + a.z*b.z; |
| } |
| |
| Xyz |
| cross(Xyz a, Xyz b) |
| { |
| Xyz v; |
| |
| v.x = a.y*b.z - a.z*b.y; |
| v.y = a.z*b.x - a.x*b.z; |
| v.z = a.x*b.y - a.y*b.x; |
| return v; |
| } |
| |
| double |
| len(Xyz a) |
| { |
| return sqrt(dot(a, a)); |
| } |
| |
| /* An azimuth vector from a to b is a tangent to |
| the sphere at a pointing along the (shorter) |
| great-circle direction to b. It lies in the |
| plane of the vectors a and b, is perpendicular |
| to a, and has a positive compoent along b, |
| provided a and b span a 2-space. Otherwise |
| it is null. (aXb)Xa, where X denotes cross |
| product, is such a vector. */ |
| |
| Xyz |
| azvec(Xyz a, Xyz b) |
| { |
| return cross(cross(a,b), a); |
| } |
| |
| /* Find the azimuth of point b as seen |
| from point a, given that a is distinct |
| from either pole and from b */ |
| |
| double |
| azimuth(Xyz a, Xyz b) |
| { |
| Xyz aton = azvec(a,north); |
| Xyz atob = azvec(a,b); |
| double lenaton = len(aton); |
| double lenatob = len(atob); |
| double az = acos(dot(aton,atob)/(lenaton*lenatob)); |
| |
| if(dot(b,cross(north,a)) < 0) |
| az = -az; |
| return az; |
| } |
| |
| /* Find the rotation (3rd argument of orient() in the |
| map projection package) for the map described |
| below. The return is radians; it must be converted |
| to degrees for orient(). |
| */ |
| |
| double |
| rot(struct place center, struct place zenith) |
| { |
| Xyz cen = ptov(center); |
| Xyz zen = ptov(zenith); |
| |
| if(cen.z > 1-FUZZ) /* center at N pole */ |
| return PI + zenith.wlon.l; |
| if(cen.z < FUZZ-1) /* at S pole */ |
| return -zenith.wlon.l; |
| if(fabs(dot(cen,zen)) > 1-FUZZ) /* at zenith */ |
| return 0; |
| return azimuth(cen, zen); |
| } |
| |
| int (* |
| heavens(double zlatdeg, double zlondeg, double clatdeg, double clondeg))(struct place*, double*, double*) |
| { |
| struct place center; |
| struct place zenith; |
| |
| center.nlat = mkcoord(clatdeg); |
| center.wlon = mkcoord(clondeg); |
| zenith.nlat = mkcoord(zlatdeg); |
| zenith.wlon = mkcoord(zlondeg); |
| projection = stereographic(); |
| orient(clatdeg, clondeg, rot(center, zenith)*180/PI); |
| return projection; |
| } |
| |
| int |
| maptoxy(int32 ra, int32 dec, double *x, double *y) |
| { |
| double lat, lon; |
| struct place pl; |
| |
| lat = angle(dec); |
| lon = angle(ra); |
| pl.nlat.l = lat; |
| pl.nlat.s = sin(lat); |
| pl.nlat.c = cos(lat); |
| pl.wlon.l = lon; |
| pl.wlon.s = sin(lon); |
| pl.wlon.c = cos(lon); |
| normalize(&pl); |
| return projection(&pl, x, y); |
| } |
| |
| /* end of 'heavens' section */ |
| |
| int |
| setmap(int32 ramin, int32 ramax, int32 decmin, int32 decmax, Rectangle r, int zenithup) |
| { |
| int c; |
| double minx, maxx, miny, maxy; |
| |
| c = 1000*60*60; |
| mapra = ramax/2+ramin/2; |
| mapdec = decmax/2+decmin/2; |
| |
| if(zenithup) |
| projection = heavens(mylat, mysid, (double)mapdec/c, (double)mapra/c); |
| else{ |
| orient((double)mapdec/c, (double)mapra/c, 0.); |
| projection = stereographic(); |
| } |
| mapx0 = (r.max.x+r.min.x)/2; |
| mapy0 = (r.max.y+r.min.y)/2; |
| maps = ((double)Dy(r))/(double)(decmax-decmin); |
| if(maptoxy(ramin, decmin, &minx, &miny) < 0) |
| return -1; |
| if(maptoxy(ramax, decmax, &maxx, &maxy) < 0) |
| return -1; |
| /* |
| * It's tricky to get the scale right. This noble attempt scales |
| * to fit the lengths of the sides of the rectangle. |
| */ |
| mapscale = Dx(r)/(minx-maxx); |
| if(mapscale > Dy(r)/(maxy-miny)) |
| mapscale = Dy(r)/(maxy-miny); |
| /* |
| * near the pole It's not a rectangle, though, so this scales |
| * to fit the corners of the trapezoid (a triangle at the pole). |
| */ |
| mapscale *= (cos(angle(mapdec))+1.)/2; |
| if(maxy < miny){ |
| /* upside down, between zenith and pole */ |
| fprint(2, "reverse plot\n"); |
| mapscale = -mapscale; |
| } |
| return 1; |
| } |
| |
| Point |
| map(int32 ra, int32 dec) |
| { |
| double x, y; |
| Point p; |
| |
| if(maptoxy(ra, dec, &x, &y) > 0){ |
| p.x = mapscale*x + mapx0; |
| p.y = mapscale*-y + mapy0; |
| }else{ |
| p.x = -100; |
| p.y = -100; |
| } |
| return p; |
| } |
| |
| int |
| dsize(int mag) /* mag is 10*magnitude; return disc size */ |
| { |
| double d; |
| |
| mag += 25; /* make mags all positive; sirius is -1.6m */ |
| d = (130-mag)/10; |
| /* if plate scale is huge, adjust */ |
| if(maps < 100.0/MILLIARCSEC) |
| d *= .71; |
| if(maps < 50.0/MILLIARCSEC) |
| d *= .71; |
| return d; |
| } |
| |
| void |
| drawname(Image *scr, Image *col, char *s, int ra, int dec) |
| { |
| Point p; |
| |
| if(font == nil) |
| return; |
| p = addpt(map(ra, dec), Pt(4, -1)); /* font has huge ascent */ |
| string(scr, p, col, ZP, font, s); |
| } |
| |
| int |
| npixels(DAngle diam) |
| { |
| Point p0, p1; |
| |
| diam = DEG(angle(diam)*MILLIARCSEC); /* diam in milliarcsec */ |
| diam /= 2; /* radius */ |
| /* convert to plate scale */ |
| /* BUG: need +100 because we sometimes crash in library if we plot the exact center */ |
| p0 = map(mapra+100, mapdec); |
| p1 = map(mapra+100+diam, mapdec); |
| return hypot(p0.x-p1.x, p0.y-p1.y); |
| } |
| |
| void |
| drawdisc(Image *scr, DAngle semidiam, int ring, Image *color, Point pt, char *s) |
| { |
| int d; |
| |
| d = npixels(semidiam*2); |
| if(d < 5) |
| d = 5; |
| fillellipse(scr, pt, d, d, color, ZP); |
| if(ring == 1) |
| ellipse(scr, pt, 5*d/2, d/2, 0, color, ZP); |
| if(ring == 2) |
| ellipse(scr, pt, d, d, 0, grey, ZP); |
| if(s){ |
| d = stringwidth(font, s); |
| pt.x -= d/2; |
| pt.y -= font->height/2 + 1; |
| string(scr, pt, display->black, ZP, font, s); |
| } |
| } |
| |
| void |
| drawplanet(Image *scr, Planetrec *p, Point pt) |
| { |
| if(strcmp(p->name, "sun") == 0){ |
| drawdisc(scr, p->semidiam, 0, suncolor, pt, nil); |
| return; |
| } |
| if(strcmp(p->name, "moon") == 0){ |
| drawdisc(scr, p->semidiam, 0, mooncolor, pt, nil); |
| return; |
| } |
| if(strcmp(p->name, "shadow") == 0){ |
| drawdisc(scr, p->semidiam, 2, shadowcolor, pt, nil); |
| return; |
| } |
| if(strcmp(p->name, "mercury") == 0){ |
| drawdisc(scr, p->semidiam, 0, mercurycolor, pt, "m"); |
| return; |
| } |
| if(strcmp(p->name, "venus") == 0){ |
| drawdisc(scr, p->semidiam, 0, venuscolor, pt, "v"); |
| return; |
| } |
| if(strcmp(p->name, "mars") == 0){ |
| drawdisc(scr, p->semidiam, 0, marscolor, pt, "M"); |
| return; |
| } |
| if(strcmp(p->name, "jupiter") == 0){ |
| drawdisc(scr, p->semidiam, 0, jupitercolor, pt, "J"); |
| return; |
| } |
| if(strcmp(p->name, "saturn") == 0){ |
| drawdisc(scr, p->semidiam, 1, saturncolor, pt, "S"); |
| |
| return; |
| } |
| if(strcmp(p->name, "uranus") == 0){ |
| drawdisc(scr, p->semidiam, 0, uranuscolor, pt, "U"); |
| |
| return; |
| } |
| if(strcmp(p->name, "neptune") == 0){ |
| drawdisc(scr, p->semidiam, 0, neptunecolor, pt, "N"); |
| |
| return; |
| } |
| if(strcmp(p->name, "pluto") == 0){ |
| drawdisc(scr, p->semidiam, 0, plutocolor, pt, "P"); |
| |
| return; |
| } |
| if(strcmp(p->name, "comet") == 0){ |
| drawdisc(scr, p->semidiam, 0, cometcolor, pt, "C"); |
| return; |
| } |
| |
| pt.x -= stringwidth(font, p->name)/2; |
| pt.y -= font->height/2; |
| string(scr, pt, grey, ZP, font, p->name); |
| } |
| |
| void |
| tolast(char *name) |
| { |
| int i, nlast; |
| Record *r, rr; |
| |
| /* stop early to simplify inner loop adjustment */ |
| nlast = 0; |
| for(i=0,r=rec; i<nrec-nlast; i++,r++) |
| if(r->type == Planet) |
| if(name==nil || strcmp(r->u.planet.name, name)==0){ |
| rr = *r; |
| memmove(rec+i, rec+i+1, (nrec-i-1)*sizeof(Record)); |
| rec[nrec-1] = rr; |
| --i; |
| --r; |
| nlast++; |
| } |
| } |
| |
| int |
| bbox(int32 extrara, int32 extradec, int quantize) |
| { |
| int i; |
| Record *r; |
| int ra, dec; |
| int rah, ram, d1, d2; |
| double r0; |
| |
| ramin = 0x7FFFFFFF; |
| ramax = -0x7FFFFFFF; |
| decmin = 0x7FFFFFFF; |
| decmax = -0x7FFFFFFF; |
| |
| for(i=0,r=rec; i<nrec; i++,r++){ |
| if(r->type == Patch){ |
| radec(r->index, &rah, &ram, &dec); |
| ra = 15*rah+ram/4; |
| r0 = c/cos(dec*PI/180); |
| ra *= c; |
| dec *= c; |
| if(dec == 0) |
| d1 = c, d2 = c; |
| else if(dec < 0) |
| d1 = c, d2 = 0; |
| else |
| d1 = 0, d2 = c; |
| }else if(r->type==SAO || r->type==NGC || r->type==Planet || r->type==Abell){ |
| ra = r->u.ngc.ra; |
| dec = r->u.ngc.dec; |
| d1 = 0, d2 = 0, r0 = 0; |
| }else |
| continue; |
| if(dec+d2+extradec > decmax) |
| decmax = dec+d2+extradec; |
| if(dec-d1-extradec < decmin) |
| decmin = dec-d1-extradec; |
| if(folded){ |
| ra -= 180*c; |
| if(ra < 0) |
| ra += 360*c; |
| } |
| if(ra+r0+extrara > ramax) |
| ramax = ra+r0+extrara; |
| if(ra-extrara < ramin) |
| ramin = ra-extrara; |
| } |
| |
| if(decmax > 90*c) |
| decmax = 90*c; |
| if(decmin < -90*c) |
| decmin = -90*c; |
| if(ramin < 0) |
| ramin += 360*c; |
| if(ramax >= 360*c) |
| ramax -= 360*c; |
| |
| if(quantize){ |
| /* quantize to degree boundaries */ |
| ramin -= ramin%m5; |
| if(ramax%m5 != 0) |
| ramax += m5-(ramax%m5); |
| if(decmin > 0) |
| decmin -= decmin%c; |
| else |
| decmin -= c - (-decmin)%c; |
| if(decmax > 0){ |
| if(decmax%c != 0) |
| decmax += c-(decmax%c); |
| }else if(decmax < 0){ |
| if(decmax%c != 0) |
| decmax += ((-decmax)%c); |
| } |
| } |
| |
| if(folded){ |
| if(ramax-ramin > 270*c){ |
| fprint(2, "ra range too wide %ld°\n", (ramax-ramin)/c); |
| return -1; |
| } |
| }else if(ramax-ramin > 270*c){ |
| folded = 1; |
| return bbox(0, 0, quantize); |
| } |
| |
| return 1; |
| } |
| |
| int |
| inbbox(DAngle ra, DAngle dec) |
| { |
| int min; |
| |
| if(dec < decmin) |
| return 0; |
| if(dec > decmax) |
| return 0; |
| min = ramin; |
| if(ramin > ramax){ /* straddling 0h0m */ |
| min -= 360*c; |
| if(ra > 180*c) |
| ra -= 360*c; |
| } |
| if(ra < min) |
| return 0; |
| if(ra > ramax) |
| return 0; |
| return 1; |
| } |
| |
| int |
| gridra(int32 mapdec) |
| { |
| mapdec = abs(mapdec)+c/2; |
| mapdec /= c; |
| if(mapdec < 60) |
| return m5; |
| if(mapdec < 80) |
| return 2*m5; |
| if(mapdec < 85) |
| return 4*m5; |
| return 8*m5; |
| } |
| |
| #define GREY (nogrey? display->white : grey) |
| |
| void |
| plot(char *flags) |
| { |
| int i, j, k; |
| char *t; |
| int32 x, y; |
| int ra, dec; |
| int m; |
| Point p, pts[10]; |
| Record *r; |
| Rectangle rect, r1; |
| int dx, dy, nogrid, textlevel, nogrey, zenithup; |
| Image *scr; |
| char *name, buf[32]; |
| double v; |
| |
| if(plotopen() < 0) |
| return; |
| nogrid = 0; |
| nogrey = 0; |
| textlevel = 1; |
| dx = 512; |
| dy = 512; |
| zenithup = 0; |
| for(;;){ |
| if(t = alpha(flags, "nogrid")){ |
| nogrid = 1; |
| flags = t; |
| continue; |
| } |
| if((t = alpha(flags, "zenith")) || (t = alpha(flags, "zenithup")) ){ |
| zenithup = 1; |
| flags = t; |
| continue; |
| } |
| if((t = alpha(flags, "notext")) || (t = alpha(flags, "nolabel")) ){ |
| textlevel = 0; |
| flags = t; |
| continue; |
| } |
| if((t = alpha(flags, "alltext")) || (t = alpha(flags, "alllabel")) ){ |
| textlevel = 2; |
| flags = t; |
| continue; |
| } |
| if(t = alpha(flags, "dx")){ |
| dx = strtol(t, &t, 0); |
| if(dx < 100){ |
| fprint(2, "dx %d too small (min 100) in plot\n", dx); |
| return; |
| } |
| flags = skipbl(t); |
| continue; |
| } |
| if(t = alpha(flags, "dy")){ |
| dy = strtol(t, &t, 0); |
| if(dy < 100){ |
| fprint(2, "dy %d too small (min 100) in plot\n", dy); |
| return; |
| } |
| flags = skipbl(t); |
| continue; |
| } |
| if((t = alpha(flags, "nogrey")) || (t = alpha(flags, "nogray"))){ |
| nogrey = 1; |
| flags = skipbl(t); |
| continue; |
| } |
| if(*flags){ |
| fprint(2, "syntax error in plot\n"); |
| return; |
| } |
| break; |
| } |
| flatten(); |
| folded = 0; |
| |
| if(bbox(0, 0, 1) < 0) |
| return; |
| if(ramax-ramin<100 || decmax-decmin<100){ |
| fprint(2, "plot too small\n"); |
| return; |
| } |
| |
| scr = allocimage(display, Rect(0, 0, dx, dy), RGB24, 0, DBlack); |
| if(scr == nil){ |
| fprint(2, "can't allocate image: %r\n"); |
| return; |
| } |
| rect = scr->r; |
| rect.min.x += 16; |
| rect = insetrect(rect, 40); |
| if(setmap(ramin, ramax, decmin, decmax, rect, zenithup) < 0){ |
| fprint(2, "can't set up map coordinates\n"); |
| return; |
| } |
| if(!nogrid){ |
| for(x=ramin; ; ){ |
| for(j=0; j<nelem(pts); j++){ |
| /* use double to avoid overflow */ |
| v = (double)j / (double)(nelem(pts)-1); |
| v = decmin + v*(decmax-decmin); |
| pts[j] = map(x, v); |
| } |
| bezspline(scr, pts, nelem(pts), Endsquare, Endsquare, 0, GREY, ZP); |
| ra = x; |
| if(folded){ |
| ra -= 180*c; |
| if(ra < 0) |
| ra += 360*c; |
| } |
| p = pts[0]; |
| p.x -= stringwidth(font, hm5(angle(ra)))/2; |
| string(scr, p, GREY, ZP, font, hm5(angle(ra))); |
| p = pts[nelem(pts)-1]; |
| p.x -= stringwidth(font, hm5(angle(ra)))/2; |
| p.y -= font->height; |
| string(scr, p, GREY, ZP, font, hm5(angle(ra))); |
| if(x == ramax) |
| break; |
| x += gridra(mapdec); |
| if(x > ramax) |
| x = ramax; |
| } |
| for(y=decmin; y<=decmax; y+=c){ |
| for(j=0; j<nelem(pts); j++){ |
| /* use double to avoid overflow */ |
| v = (double)j / (double)(nelem(pts)-1); |
| v = ramin + v*(ramax-ramin); |
| pts[j] = map(v, y); |
| } |
| bezspline(scr, pts, nelem(pts), Endsquare, Endsquare, 0, GREY, ZP); |
| p = pts[0]; |
| p.x += 3; |
| p.y -= font->height/2; |
| string(scr, p, GREY, ZP, font, deg(angle(y))); |
| p = pts[nelem(pts)-1]; |
| p.x -= 3+stringwidth(font, deg(angle(y))); |
| p.y -= font->height/2; |
| string(scr, p, GREY, ZP, font, deg(angle(y))); |
| } |
| } |
| /* reorder to get planets in front of stars */ |
| tolast(nil); |
| tolast("moon"); /* moon is in front of everything... */ |
| tolast("shadow"); /* ... except the shadow */ |
| |
| for(i=0,r=rec; i<nrec; i++,r++){ |
| dec = r->u.ngc.dec; |
| ra = r->u.ngc.ra; |
| if(folded){ |
| ra -= 180*c; |
| if(ra < 0) |
| ra += 360*c; |
| } |
| if(textlevel){ |
| name = nameof(r); |
| if(name==nil && textlevel>1 && r->type==SAO){ |
| snprint(buf, sizeof buf, "SAO%ld", r->index); |
| name = buf; |
| } |
| if(name) |
| drawname(scr, nogrey? display->white : alphagrey, name, ra, dec); |
| } |
| if(r->type == Planet){ |
| drawplanet(scr, &r->u.planet, map(ra, dec)); |
| continue; |
| } |
| if(r->type == SAO){ |
| m = r->u.sao.mag; |
| if(m == UNKNOWNMAG) |
| m = r->u.sao.mpg; |
| if(m == UNKNOWNMAG) |
| continue; |
| m = dsize(m); |
| if(m < 3) |
| fillellipse(scr, map(ra, dec), m, m, nogrey? display->white : lightgrey, ZP); |
| else{ |
| ellipse(scr, map(ra, dec), m+1, m+1, 0, display->black, ZP); |
| fillellipse(scr, map(ra, dec), m, m, display->white, ZP); |
| } |
| continue; |
| } |
| if(r->type == Abell){ |
| ellipse(scr, addpt(map(ra, dec), Pt(-3, 2)), 2, 1, 0, lightblue, ZP); |
| ellipse(scr, addpt(map(ra, dec), Pt(3, 2)), 2, 1, 0, lightblue, ZP); |
| ellipse(scr, addpt(map(ra, dec), Pt(0, -2)), 1, 2, 0, lightblue, ZP); |
| continue; |
| } |
| switch(r->u.ngc.type){ |
| case Galaxy: |
| j = npixels(r->u.ngc.diam); |
| if(j < 4) |
| j = 4; |
| if(j > 10) |
| k = j/3; |
| else |
| k = j/2; |
| ellipse(scr, map(ra, dec), j, k, 0, lightblue, ZP); |
| break; |
| |
| case PlanetaryN: |
| p = map(ra, dec); |
| j = npixels(r->u.ngc.diam); |
| if(j < 3) |
| j = 3; |
| ellipse(scr, p, j, j, 0, green, ZP); |
| line(scr, Pt(p.x, p.y+j+1), Pt(p.x, p.y+j+4), |
| Endsquare, Endsquare, 0, green, ZP); |
| line(scr, Pt(p.x, p.y-(j+1)), Pt(p.x, p.y-(j+4)), |
| Endsquare, Endsquare, 0, green, ZP); |
| line(scr, Pt(p.x+j+1, p.y), Pt(p.x+j+4, p.y), |
| Endsquare, Endsquare, 0, green, ZP); |
| line(scr, Pt(p.x-(j+1), p.y), Pt(p.x-(j+4), p.y), |
| Endsquare, Endsquare, 0, green, ZP); |
| break; |
| |
| case DiffuseN: |
| case NebularCl: |
| p = map(ra, dec); |
| j = npixels(r->u.ngc.diam); |
| if(j < 4) |
| j = 4; |
| r1.min = Pt(p.x-j, p.y-j); |
| r1.max = Pt(p.x+j, p.y+j); |
| if(r->u.ngc.type != DiffuseN) |
| draw(scr, r1, ocstipple, ocstipple, ZP); |
| line(scr, Pt(p.x-j, p.y-j), Pt(p.x+j, p.y-j), |
| Endsquare, Endsquare, 0, green, ZP); |
| line(scr, Pt(p.x-j, p.y+j), Pt(p.x+j, p.y+j), |
| Endsquare, Endsquare, 0, green, ZP); |
| line(scr, Pt(p.x-j, p.y-j), Pt(p.x-j, p.y+j), |
| Endsquare, Endsquare, 0, green, ZP); |
| line(scr, Pt(p.x+j, p.y-j), Pt(p.x+j, p.y+j), |
| Endsquare, Endsquare, 0, green, ZP); |
| break; |
| |
| case OpenCl: |
| p = map(ra, dec); |
| j = npixels(r->u.ngc.diam); |
| if(j < 4) |
| j = 4; |
| fillellipse(scr, p, j, j, ocstipple, ZP); |
| break; |
| |
| case GlobularCl: |
| j = npixels(r->u.ngc.diam); |
| if(j < 4) |
| j = 4; |
| p = map(ra, dec); |
| ellipse(scr, p, j, j, 0, lightgrey, ZP); |
| line(scr, Pt(p.x-(j-1), p.y), Pt(p.x+j, p.y), |
| Endsquare, Endsquare, 0, lightgrey, ZP); |
| line(scr, Pt(p.x, p.y-(j-1)), Pt(p.x, p.y+j), |
| Endsquare, Endsquare, 0, lightgrey, ZP); |
| break; |
| |
| } |
| } |
| flushimage(display, 1); |
| displayimage(scr); |
| } |
| |
| int |
| runcommand(char *command, int p[2]) |
| { |
| switch(rfork(RFPROC|RFFDG|RFNOWAIT)){ |
| case -1: |
| return -1; |
| default: |
| break; |
| case 0: |
| dup(p[1], 1); |
| close(p[0]); |
| close(p[1]); |
| execlp("rc", "rc", "-c", command, nil); |
| fprint(2, "can't exec %s: %r", command); |
| exits(nil); |
| } |
| return 1; |
| } |
| |
| void |
| parseplanet(char *line, Planetrec *p) |
| { |
| char *fld[6]; |
| int i, nfld; |
| char *s; |
| |
| if(line[0] == '\0') |
| return; |
| line[10] = '\0'; /* terminate name */ |
| s = strrchr(line, ' '); |
| if(s == nil) |
| s = line; |
| else |
| s++; |
| strcpy(p->name, s); |
| for(i=0; s[i]!='\0'; i++) |
| p->name[i] = tolower(s[i]); |
| p->name[i] = '\0'; |
| nfld = getfields(line+11, fld, nelem(fld), 1, " "); |
| p->ra = dangle(getra(fld[0])); |
| p->dec = dangle(getra(fld[1])); |
| p->az = atof(fld[2])*MILLIARCSEC; |
| p->alt = atof(fld[3])*MILLIARCSEC; |
| p->semidiam = atof(fld[4])*1000; |
| if(nfld > 5) |
| p->phase = atof(fld[5]); |
| else |
| p->phase = 0; |
| } |
| |
| void |
| astro(char *flags, int initial) |
| { |
| int p[2]; |
| int i, n, np; |
| char cmd[256], buf[4096], *lines[20], *fld[10]; |
| |
| snprint(cmd, sizeof cmd, "astro -p %s", flags); |
| if(pipe(p) < 0){ |
| fprint(2, "can't pipe: %r\n"); |
| return; |
| } |
| if(runcommand(cmd, p) < 0){ |
| close(p[0]); |
| close(p[1]); |
| fprint(2, "can't run astro: %r"); |
| return; |
| } |
| close(p[1]); |
| n = readn(p[0], buf, sizeof buf-1); |
| if(n <= 0){ |
| fprint(2, "no data from astro\n"); |
| return; |
| } |
| if(!initial) |
| Bwrite(&bout, buf, n); |
| buf[n] = '\0'; |
| np = getfields(buf, lines, nelem(lines), 0, "\n"); |
| if(np <= 1){ |
| fprint(2, "astro: not enough output\n"); |
| return; |
| } |
| Bprint(&bout, "%s\n", lines[0]); |
| Bflush(&bout); |
| /* get latitude and longitude */ |
| if(getfields(lines[0], fld, nelem(fld), 1, " ") < 8) |
| fprint(2, "astro: can't read longitude: too few fields\n"); |
| else{ |
| mysid = getra(fld[5])*180./PI; |
| mylat = getra(fld[6])*180./PI; |
| mylon = getra(fld[7])*180./PI; |
| } |
| /* |
| * Each time we run astro, we generate a new planet list |
| * so multiple appearances of a planet may exist as we plot |
| * its motion over time. |
| */ |
| planet = malloc(NPlanet*sizeof planet[0]); |
| if(planet == nil){ |
| fprint(2, "astro: malloc failed: %r\n"); |
| exits("malloc"); |
| } |
| memset(planet, 0, NPlanet*sizeof planet[0]); |
| for(i=1; i<np; i++) |
| parseplanet(lines[i], &planet[i-1]); |
| } |