diff options
Diffstat (limited to 'src/cmd/scat/scat.c')
-rw-r--r-- | src/cmd/scat/scat.c | 1671 |
1 files changed, 1671 insertions, 0 deletions
diff --git a/src/cmd/scat/scat.c b/src/cmd/scat/scat.c new file mode 100644 index 00000000..9579706a --- /dev/null +++ b/src/cmd/scat/scat.c @@ -0,0 +1,1671 @@ +#include <u.h> +#include <libc.h> +#include <bio.h> +#include <draw.h> +#include <event.h> +#include "sky.h" +#include "strings.c" + +enum +{ + NNGC=7840, /* number of NGC numbers [1..NNGC] */ + NIC = 5386, /* number of IC numbers */ + NNGCrec=NNGC+NIC, /* number of records in the NGC catalog (including IC's, starting at NNGC */ + NMrec=122, /* number of M records */ + NM=110, /* number of M numbers */ + NAbell=2712, /* number of records in the Abell catalog */ + NName=1000, /* number of prose names; estimated maximum (read from editable text file) */ + NBayer=1517, /* number of bayer entries */ + NSAO=258998, /* number of SAO stars */ + MAXcon=1932, /* maximum number of patches in a constellation */ + Ncon=88, /* number of constellations */ + Npatch=92053, /* highest patch number */ +}; + +char ngctype[NNGCrec]; +Mindexrec mindex[NMrec]; +Namerec name[NName]; +Bayerec bayer[NBayer]; +long con[MAXcon]; +ushort conindex[Ncon+1]; +long patchaddr[Npatch+1]; + +Record *rec; +Record *orec; +Record *cur; + +char *dir; +int saodb; +int ngcdb; +int abelldb; +int ngctypedb; +int mindexdb; +int namedb; +int bayerdb; +int condb; +int conindexdb; +int patchdb; +char parsed[3]; +long nrec; +long nreca; +long norec; +long noreca; + +Biobuf bin; +Biobuf bout; + +void +main(int argc, char *argv[]) +{ + char *line; + + dir = unsharp(DIR); + Binit(&bin, 0, OREAD); + Binit(&bout, 1, OWRITE); + if(argc != 1) + dir = argv[1]; + astro("", 1); + while(line = Brdline(&bin, '\n')){ + line[Blinelen(&bin)-1] = 0; + lookup(line, 1); + Bflush(&bout); + } + if(display != nil){ + closedisplay(display); + /* automatic refresh of rio window is triggered by mouse */ + // close(open("/dev/mouse", OREAD)); + } + return; +} + +void +reset(void) +{ + nrec = 0; + cur = rec; +} + +void +grow(void) +{ + nrec++; + if(nreca < nrec){ + nreca = nrec+50; + rec = realloc(rec, nreca*sizeof(Record)); + if(rec == 0){ + fprint(2, "scat: realloc fails\n"); + exits("realloc"); + } + } + cur = rec+nrec-1; +} + +void +copy(void) +{ + if(noreca < nreca){ + noreca = nreca; + orec = realloc(orec, nreca*sizeof(Record)); + if(orec == 0){ + fprint(2, "scat: realloc fails\n"); + exits("realloc"); + } + } + memmove(orec, rec, nrec*sizeof(Record)); + norec = nrec; +} + +int +eopen(char *s) +{ + char buf[128]; + int f; + + sprint(buf, "%s/%s.scat", dir, s); + f = open(buf, 0); + if(f<0){ + fprint(2, "scat: can't open %s\n", buf); + exits("open"); + } + return f; +} + + +void +Eread(int f, char *name, void *addr, long n) +{ + if(read(f, addr, n) != n){ /* BUG! */ + fprint(2, "scat: read error on %s\n", name); + exits("read"); + } +} + +char* +skipbl(char *s) +{ + while(*s!=0 && (*s==' ' || *s=='\t')) + s++; + return s; +} + +char* +skipstr(char *s, char *t) +{ + while(*s && *s==*t) + s++, t++; + return skipbl(s); +} + +/* produce little-endian long at address l */ +long +Long(long *l) +{ + uchar *p; + + p = (uchar*)l; + return (long)p[0]|((long)p[1]<<8)|((long)p[2]<<16)|((long)p[3]<<24); +} + +/* produce little-endian long at address l */ +int +Short(short *s) +{ + uchar *p; + + p = (uchar*)s; + return p[0]|(p[1]<<8); +} + +void +nameopen(void) +{ + Biobuf b; + int i; + char *l, *p; + + if(namedb == 0){ + namedb = eopen("name"); + Binit(&b, namedb, OREAD); + for(i=0; i<NName; i++){ + l = Brdline(&b, '\n'); + if(l == 0) + break; + p = strchr(l, '\t'); + if(p == 0){ + Badformat: + Bprint(&bout, "warning: name.scat bad format; line %d\n", i+1); + break; + } + *p++ = 0; + strcpy(name[i].name, l); + if(strncmp(p, "ngc", 3) == 0) + name[i].ngc = atoi(p+3); + else if(strncmp(p, "ic", 2) == 0) + name[i].ngc = atoi(p+2)+NNGC; + else if(strncmp(p, "sao", 3) == 0) + name[i].sao = atoi(p+3); + else if(strncmp(p, "abell", 5) == 0) + name[i].abell = atoi(p+5); + else + goto Badformat; + } + if(i == NName) + Bprint(&bout, "warning: too many names in name.scat (max %d); extra ignored\n", NName); + close(namedb); + + bayerdb = eopen("bayer"); + Eread(bayerdb, "bayer", bayer, sizeof bayer); + close(bayerdb); + for(i=0; i<NBayer; i++) + bayer[i].sao = Long(&bayer[i].sao); + } +} + +void +saoopen(void) +{ + if(saodb == 0){ + nameopen(); + saodb = eopen("sao"); + } +} + +void +ngcopen(void) +{ + if(ngcdb == 0){ + nameopen(); + ngcdb = eopen("ngc2000"); + ngctypedb = eopen("ngc2000type"); + Eread(ngctypedb, "ngctype", ngctype, sizeof ngctype); + close(ngctypedb); + } +} + +void +abellopen(void) +{ + /* nothing extra to do with abell: it's directly indexed by number */ + if(abelldb == 0) + abelldb = eopen("abell"); +} + +void +patchopen(void) +{ + Biobuf *b; + long l, m; + char buf[100]; + + if(patchdb == 0){ + patchdb = eopen("patch"); + sprint(buf, "%s/patchindex.scat", dir); + b = Bopen(buf, OREAD); + if(b == 0){ + fprint(2, "can't open %s\n", buf); + exits("open"); + } + for(m=0,l=0; l<=Npatch; l++) + patchaddr[l] = m += Bgetc(b)*4; + Bterm(b); + } +} + +void +mopen(void) +{ + int i; + + if(mindexdb == 0){ + mindexdb = eopen("mindex"); + Eread(mindexdb, "mindex", mindex, sizeof mindex); + close(mindexdb); + for(i=0; i<NMrec; i++) + mindex[i].ngc = Short(&mindex[i].ngc); + } +} + +void +constelopen(void) +{ + int i; + + if(condb == 0){ + condb = eopen("con"); + conindexdb = eopen("conindex"); + Eread(conindexdb, "conindex", conindex, sizeof conindex); + close(conindexdb); + for(i=0; i<Ncon+1; i++) + conindex[i] = Short((short*)&conindex[i]); + } +} + +void +lowercase(char *s) +{ + for(; *s; s++) + if('A'<=*s && *s<='Z') + *s += 'a'-'A'; +} + +int +loadngc(long index) +{ + static int failed; + long j; + + ngcopen(); + j = (index-1)*sizeof(NGCrec); + grow(); + cur->type = NGC; + cur->index = index; + seek(ngcdb, j, 0); + /* special case: NGC data may not be available */ + if(read(ngcdb, &cur->ngc, sizeof(NGCrec)) != sizeof(NGCrec)){ + if(!failed){ + fprint(2, "scat: NGC database not available\n"); + failed++; + } + cur->type = NONGC; + cur->ngc.ngc = 0; + cur->ngc.ra = 0; + cur->ngc.dec = 0; + cur->ngc.diam = 0; + cur->ngc.mag = 0; + return 0; + } + cur->ngc.ngc = Short(&cur->ngc.ngc); + cur->ngc.ra = Long(&cur->ngc.ra); + cur->ngc.dec = Long(&cur->ngc.dec); + cur->ngc.diam = Long(&cur->ngc.diam); + cur->ngc.mag = Short(&cur->ngc.mag); + return 1; +} + +int +loadabell(long index) +{ + long j; + + abellopen(); + j = index-1; + grow(); + cur->type = Abell; + cur->index = index; + seek(abelldb, j*sizeof(Abellrec), 0); + Eread(abelldb, "abell", &cur->abell, sizeof(Abellrec)); + cur->abell.abell = Short(&cur->abell.abell); + if(cur->abell.abell != index){ + fprint(2, "bad format in abell catalog\n"); + exits("abell"); + } + cur->abell.ra = Long(&cur->abell.ra); + cur->abell.dec = Long(&cur->abell.dec); + cur->abell.glat = Long(&cur->abell.glat); + cur->abell.glong = Long(&cur->abell.glong); + cur->abell.rad = Long(&cur->abell.rad); + cur->abell.mag10 = Short(&cur->abell.mag10); + cur->abell.pop = Short(&cur->abell.pop); + cur->abell.dist = Short(&cur->abell.dist); + return 1; +} + +int +loadsao(int index) +{ + if(index<=0 || index>NSAO) + return 0; + saoopen(); + grow(); + cur->type = SAO; + cur->index = index; + seek(saodb, (index-1)*sizeof(SAOrec), 0); + Eread(saodb, "sao", &cur->sao, sizeof(SAOrec)); + cur->sao.ra = Long(&cur->sao.ra); + cur->sao.dec = Long(&cur->sao.dec); + cur->sao.dra = Long(&cur->sao.dra); + cur->sao.ddec = Long(&cur->sao.ddec); + cur->sao.mag = Short(&cur->sao.mag); + cur->sao.mpg = Short(&cur->sao.mpg); + cur->sao.hd = Long(&cur->sao.hd); + return 1; +} + +int +loadplanet(int index, Record *r) +{ + if(index<0 || index>NPlanet || planet[index].name[0]=='\0') + return 0; + grow(); + cur->type = Planet; + cur->index = index; + /* check whether to take new or existing record */ + if(r == nil) + memmove(&cur->planet, &planet[index], sizeof(Planetrec)); + else + memmove(&cur->planet, &r->planet, sizeof(Planetrec)); + return 1; +} + +int +loadpatch(long index) +{ + int i; + + patchopen(); + if(index<=0 || index>Npatch) + return 0; + grow(); + cur->type = Patch; + cur->index = index; + seek(patchdb, patchaddr[index-1], 0); + cur->patch.nkey = (patchaddr[index]-patchaddr[index-1])/4; + Eread(patchdb, "patch", cur->patch.key, cur->patch.nkey*4); + for(i=0; i<cur->patch.nkey; i++) + cur->patch.key[i] = Long(&cur->patch.key[i]); + return 1; +} + +int +loadtype(int t) +{ + int i; + + ngcopen(); + for(i=0; i<NNGCrec; i++) + if(t == (ngctype[i])){ + grow(); + cur->type = NGCN; + cur->index = i+1; + } + return 1; +} + +void +flatten(void) +{ + int i, j, notflat; + Record *or; + long key; + + loop: + copy(); + reset(); + notflat = 0; + for(i=0,or=orec; i<norec; i++,or++){ + switch(or->type){ + default: + fprint(2, "bad type %d in flatten\n", or->type); + break; + + case NONGC: + break; + + case Planet: + case Abell: + case NGC: + case SAO: + grow(); + memmove(cur, or, sizeof(Record)); + break; + + case NGCN: + if(loadngc(or->index)) + notflat = 1; + break; + + case NamedSAO: + loadsao(or->index); + notflat = 1; + break; + + case NamedNGC: + if(loadngc(or->index)) + notflat = 1; + break; + + case NamedAbell: + loadabell(or->index); + notflat = 1; + break; + + case PatchC: + loadpatch(or->index); + notflat = 1; + break; + + case Patch: + for(j=1; j<or->patch.nkey; j++){ + key = or->patch.key[j]; + if((key&0x3F) == SAO) + loadsao((key>>8)&0xFFFFFF); + else if((key&0x3F) == Abell) + loadabell((key>>8)&0xFFFFFF); + else + loadngc((key>>16)&0xFFFF); + } + break; + } + } + if(notflat) + goto loop; +} + +int +ism(int index) +{ + int i; + + for(i=0; i<NMrec; i++) + if(mindex[i].ngc == index) + return 1; + return 0; +} + +char* +alpha(char *s, char *t) +{ + int n; + + n = strlen(t); + if(strncmp(s, t, n)==0 && (s[n]<'a' || 'z'<s[n])) + return skipbl(s+n); + return 0; + +} + +char* +text(char *s, char *t) +{ + int n; + + n = strlen(t); + if(strncmp(s, t, n)==0 && (s[n]==0 || s[n]==' ' || s[n]=='\t')) + return skipbl(s+n); + return 0; + +} + +int +cull(char *s, int keep, int dobbox) +{ + int i, j, nobj, keepthis; + Record *or; + char *t; + int dogrtr, doless, dom, dosao, dongc, doabell; + int mgrtr, mless; + char obj[100]; + + memset(obj, 0, sizeof(obj)); + nobj = 0; + dogrtr = 0; + doless = 0; + dom = 0; + dongc = 0; + dosao = 0; + doabell = 0; + mgrtr = mless= 0; + if(dobbox) + goto Cull; + for(;;){ + if(s[0] == '>'){ + dogrtr = 1; + mgrtr = 10 * strtod(s+1, &t); + if(mgrtr==0 && t==s+1){ + fprint(2, "bad magnitude\n"); + return 0; + } + s = skipbl(t); + continue; + } + if(s[0] == '<'){ + doless = 1; + mless = 10 * strtod(s+1, &t); + if(mless==0 && t==s+1){ + fprint(2, "bad magnitude\n"); + return 0; + } + s = skipbl(t); + continue; + } + if(t = text(s, "m")){ + dom = 1; + s = t; + continue; + } + if(t = text(s, "sao")){ + dosao = 1; + s = t; + continue; + } + if(t = text(s, "ngc")){ + dongc = 1; + s = t; + continue; + } + if(t = text(s, "abell")){ + doabell = 1; + s = t; + continue; + } + for(i=0; names[i].name; i++) + if(t = alpha(s, names[i].name)){ + if(nobj > 100){ + fprint(2, "too many object types\n"); + return 0; + } + obj[nobj++] = names[i].type; + s = t; + goto Continue; + } + break; + Continue:; + } + if(*s){ + fprint(2, "syntax error in object list\n"); + return 0; + } + + Cull: + flatten(); + copy(); + reset(); + if(dom) + mopen(); + if(dosao) + saoopen(); + if(dongc || nobj) + ngcopen(); + if(doabell) + abellopen(); + for(i=0,or=orec; i<norec; i++,or++){ + keepthis = !keep; + if(dobbox && inbbox(or->ngc.ra, or->ngc.dec)) + keepthis = keep; + if(doless && or->ngc.mag <= mless) + keepthis = keep; + if(dogrtr && or->ngc.mag >= mgrtr) + keepthis = keep; + if(dom && (or->type==NGC && ism(or->ngc.ngc))) + keepthis = keep; + if(dongc && or->type==NGC) + keepthis = keep; + if(doabell && or->type==Abell) + keepthis = keep; + if(dosao && or->type==SAO) + keepthis = keep; + for(j=0; j<nobj; j++) + if(or->type==NGC && or->ngc.type==obj[j]) + keepthis = keep; + if(keepthis){ + grow(); + memmove(cur, or, sizeof(Record)); + } + } + return 1; +} + +int +compar(const void *va, const void *vb) +{ + Record *a=(Record*)va, *b=(Record*)vb; + + if(a->type == b->type) + return a->index - b->index; + return a->type - b->type; +} + +void +sort(void) +{ + int i; + Record *r, *s; + + if(nrec == 0) + return; + qsort(rec, nrec, sizeof(Record), compar); + r = rec+1; + s = rec; + for(i=1; i<nrec; i++,r++){ + /* may have multiple instances of a planet in the scene */ + if(r->type==s->type && r->index==s->index && r->type!=Planet) + continue; + memmove(++s, r, sizeof(Record)); + } + nrec = (s+1)-rec; +} + +char greekbuf[128]; + +char* +togreek(char *s) +{ + char *t; + int i, n; + Rune r; + + t = greekbuf; + while(*s){ + for(i=1; i<=24; i++){ + n = strlen(greek[i]); + if(strncmp(s, greek[i], n)==0 && (s[n]==' ' || s[n]=='\t')){ + s += n; + t += runetochar(t, &greeklet[i]); + goto Cont; + } + } + n = chartorune(&r, s); + for(i=0; i<n; i++) + *t++ = *s++; + Cont:; + } + *t = 0; + return greekbuf; +} + +char* +fromgreek(char *s) +{ + char *t; + int i, n; + Rune r; + + t = greekbuf; + while(*s){ + n = chartorune(&r, s); + for(i=1; i<=24; i++){ + if(r == greeklet[i]){ + strcpy(t, greek[i]); + t += strlen(greek[i]); + s += n; + goto Cont; + } + } + for(i=0; i<n; i++) + *t++ = *s++; + Cont:; + } + *t = 0; + return greekbuf; +} + +#ifdef OLD +/* + * Old version + */ +int +coords(int deg) +{ + int i; + int x, y; + Record *or; + long dec, ra, ndec, nra; + int rdeg; + + flatten(); + copy(); + reset(); + deg *= 2; + for(i=0,or=orec; i<norec; i++,or++){ + if(or->type == Planet) /* must keep it here */ + loadplanet(or->index, or); + dec = or->ngc.dec/MILLIARCSEC; + ra = or->ngc.ra/MILLIARCSEC; + rdeg = deg/cos((dec*PI)/180); + for(y=-deg; y<=+deg; y++){ + ndec = dec*2+y; + if(ndec/2>=90 || ndec/2<=-90) + continue; + /* fp errors hurt here, so we round 1' to the pole */ + if(ndec >= 0) + ndec = ndec*500*60*60 + 60000; + else + ndec = ndec*500*60*60 - 60000; + for(x=-rdeg; x<=+rdeg; x++){ + nra = ra*2+x; + if(nra/2 < 0) + nra += 360*2; + if(nra/2 >= 360) + nra -= 360*2; + /* fp errors hurt here, so we round up 1' */ + nra = nra/2*MILLIARCSEC + 60000; + loadpatch(patcha(angle(nra), angle(ndec))); + } + } + } + sort(); + return 1; +} +#endif + +/* + * New version attempts to match the boundaries of the plot better. + */ +int +coords(int deg) +{ + int i; + int x, y, xx; + Record *or; + long min, circle; + double factor; + + flatten(); + circle = 360*MILLIARCSEC; + deg *= MILLIARCSEC; + + /* find center */ + folded = 0; + bbox(0, 0, 0); + /* now expand */ + factor = cos(angle((decmax+decmin)/2)); + if(factor < .2) + factor = .2; + factor = floor(1/factor); + folded = 0; + bbox(factor*deg, deg, 1); + Bprint(&bout, "%s to ", hms(angle(ramin))); + Bprint(&bout, "%s\n", hms(angle(ramax))); + Bprint(&bout, "%s to ", dms(angle(decmin))); + Bprint(&bout, "%s\n", dms(angle(decmax))); + copy(); + reset(); + for(i=0,or=orec; i<norec; i++,or++) + if(or->type == Planet) /* must keep it here */ + loadplanet(or->index, or); + min = ramin; + if(ramin > ramax) + min -= circle; + for(x=min; x<=ramax; x+=250*60*60){ + xx = x; + if(xx < 0) + xx += circle; + for(y=decmin; y<=decmax; y+=250*60*60) + if(-circle/4 < y && y < circle/4) + loadpatch(patcha(angle(xx), angle(y))); + } + sort(); + cull(nil, 1, 1); + return 1; +} + +void +pplate(char *flags) +{ + int i; + long c; + int na, rah, ram, d1, d2; + double r0; + int ra, dec; + long ramin, ramax, decmin, decmax; /* all in degrees */ + Record *r; + int folded; + Angle racenter, deccenter, rasize, decsize, a[4]; + Picture *pic; + + rasize = -1.0; + decsize = -1.0; + na = 0; + for(;;){ + while(*flags==' ') + flags++; + if(('0'<=*flags && *flags<='9') || *flags=='+' || *flags=='-'){ + if(na >= 3) + goto err; + a[na++] = getra(flags); + while(*flags && *flags!=' ') + flags++; + continue; + } + if(*flags){ + err: + Bprint(&bout, "syntax error in plate\n"); + return; + } + break; + } + switch(na){ + case 0: + break; + case 1: + rasize = a[0]; + decsize = rasize; + break; + case 2: + rasize = a[0]; + decsize = a[1]; + break; + case 3: + case 4: + racenter = a[0]; + deccenter = a[1]; + rasize = a[2]; + if(na == 4) + decsize = a[3]; + else + decsize = rasize; + if(rasize<0.0 || decsize<0.0){ + Bprint(&bout, "negative sizes\n"); + return; + } + goto done; + } + folded = 0; + /* convert to milliarcsec */ + c = 1000*60*60; + Again: + if(nrec == 0){ + Bprint(&bout, "empty\n"); + return; + } + ramin = 0x7FFFFFFF; + ramax = -0x7FFFFFFF; + decmin = 0x7FFFFFFF; + decmax = -0x7FFFFFFF; + for(r=rec,i=0; i<nrec; i++,r++){ + if(r->type == Patch){ + radec(r->index, &rah, &ram, &dec); + ra = 15*rah+ram/4; + r0 = c/cos(RAD(dec)); + 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==Abell){ + ra = r->ngc.ra; + dec = r->ngc.dec; + d1 = 0, d2 = 0, r0 = 0; + }else if(r->type==NGCN){ + loadngc(r->index); + continue; + }else if(r->type==NamedSAO){ + loadsao(r->index); + continue; + }else if(r->type==NamedNGC){ + loadngc(r->index); + continue; + }else if(r->type==NamedAbell){ + loadabell(r->index); + continue; + }else + continue; + if(dec+d2 > decmax) + decmax = dec+d2; + if(dec-d1 < decmin) + decmin = dec-d1; + if(folded){ + ra -= 180*c; + if(ra < 0) + ra += 360*c; + } + if(ra+r0 > ramax) + ramax = ra+r0; + if(ra < ramin) + ramin = ra; + } + if(!folded && ramax-ramin>270*c){ + folded = 1; + goto Again; + } + racenter = angle(ramin+(ramax-ramin)/2); + deccenter = angle(decmin+(decmax-decmin)/2); + if(rasize<0 || decsize<0){ + rasize = angle(ramax-ramin)*cos(deccenter); + decsize = angle(decmax-decmin); + } + done: + if(DEG(rasize)>1.1 || DEG(decsize)>1.1){ + Bprint(&bout, "plate too big: %s", ms(rasize)); + Bprint(&bout, " x %s\n", ms(decsize)); + Bprint(&bout, "trimming to 30'x30'\n"); + rasize = RAD(0.5); + decsize = RAD(0.5); + } + Bprint(&bout, "%s %s ", hms(racenter), dms(deccenter)); + Bprint(&bout, "%s", ms(rasize)); + Bprint(&bout, " x %s\n", ms(decsize)); + Bflush(&bout); + flatten(); + pic = image(racenter, deccenter, rasize, decsize); + if(pic == 0) + return; + Bprint(&bout, "plate %s locn %d %d %d %d\n", pic->name, pic->minx, pic->miny, pic->maxx, pic->maxy); + Bflush(&bout); + displaypic(pic); +} + +void +lookup(char *s, int doreset) +{ + int i, j, k; + int rah, ram, deg; + char *starts, *inputline=s, *t, *u; + Record *r; + Rune c; + long n; + double x; + Angle ra; + + lowercase(s); + s = skipbl(s); + + if(*s == 0) + goto Print; + + if(t = alpha(s, "flat")){ + if(*t){ + fprint(2, "flat takes no arguments\n"); + return; + } + if(nrec == 0){ + fprint(2, "no records\n"); + return; + } + flatten(); + goto Print; + } + + if(t = alpha(s, "print")){ + if(*t){ + fprint(2, "print takes no arguments\n"); + return; + } + for(i=0,r=rec; i<nrec; i++,r++) + prrec(r); + return; + } + + if(t = alpha(s, "add")){ + lookup(t, 0); + return; + } + + if(t = alpha(s, "sao")){ + n = strtoul(t, &u, 10); + if(n<=0 || n>NSAO) + goto NotFound; + t = skipbl(u); + if(*t){ + fprint(2, "syntax error in sao\n"); + return; + } + if(doreset) + reset(); + if(!loadsao(n)) + goto NotFound; + goto Print; + } + + if(t = alpha(s, "ngc")){ + n = strtoul(t, &u, 10); + if(n<=0 || n>NNGC) + goto NotFound; + t = skipbl(u); + if(*t){ + fprint(2, "syntax error in ngc\n"); + return; + } + if(doreset) + reset(); + if(!loadngc(n)) + goto NotFound; + goto Print; + } + + if(t = alpha(s, "ic")){ + n = strtoul(t, &u, 10); + if(n<=0 || n>NIC) + goto NotFound; + t = skipbl(u); + if(*t){ + fprint(2, "syntax error in ic\n"); + return; + } + if(doreset) + reset(); + if(!loadngc(n+NNGC)) + goto NotFound; + goto Print; + } + + if(t = alpha(s, "abell")){ + n = strtoul(t, &u, 10); + if(n<=0 || n>NAbell) + goto NotFound; + if(doreset) + reset(); + if(!loadabell(n)) + goto NotFound; + goto Print; + } + + if(t = alpha(s, "m")){ + n = strtoul(t, &u, 10); + if(n<=0 || n>NM) + goto NotFound; + mopen(); + for(j=n-1; mindex[j].m<n; j++) + ; + if(doreset) + reset(); + while(mindex[j].m == n){ + if(mindex[j].ngc){ + grow(); + cur->type = NGCN; + cur->index = mindex[j].ngc; + } + j++; + } + goto Print; + } + + for(i=1; i<=Ncon; i++) + if(t = alpha(s, constel[i])){ + if(*t){ + fprint(2, "syntax error in constellation\n"); + return; + } + constelopen(); + seek(condb, 4L*conindex[i-1], 0); + j = conindex[i]-conindex[i-1]; + Eread(condb, "con", con, 4*j); + if(doreset) + reset(); + for(k=0; k<j; k++){ + grow(); + cur->type = PatchC; + cur->index = Long(&con[k]); + } + goto Print; + } + + if(t = alpha(s, "expand")){ + n = 0; + if(*t){ + if(*t<'0' && '9'<*t){ + Expanderr: + fprint(2, "syntax error in expand\n"); + return; + } + n = strtoul(t, &u, 10); + t = skipbl(u); + if(*t) + goto Expanderr; + } + coords(n); + goto Print; + } + + if(t = alpha(s, "plot")){ + if(nrec == 0){ + Bprint(&bout, "empty\n"); + return; + } + plot(t); + return; + } + + if(t = alpha(s, "astro")){ + astro(t, 0); + return; + } + + if(t = alpha(s, "plate")){ + pplate(t); + return; + } + + if(t = alpha(s, "gamma")){ + while(*t==' ') + t++; + u = t; + x = strtod(t, &u); + if(u > t) + gam.gamma = x; + Bprint(&bout, "%.2f\n", gam.gamma); + return; + } + + if(t = alpha(s, "keep")){ + if(!cull(t, 1, 0)) + return; + goto Print; + } + + if(t = alpha(s, "drop")){ + if(!cull(t, 0, 0)) + return; + goto Print; + } + + for(i=0; planet[i].name[0]; i++){ + if(t = alpha(s, planet[i].name)){ + if(doreset) + reset(); + loadplanet(i, nil); + goto Print; + } + } + + for(i=0; names[i].name; i++){ + if(t = alpha(s, names[i].name)){ + if(*t){ + fprint(2, "syntax error in type\n"); + return; + } + if(doreset) + reset(); + loadtype(names[i].type); + goto Print; + } + } + + switch(s[0]){ + case '"': + starts = ++s; + while(*s != '"') + if(*s++ == 0){ + fprint(2, "bad star name\n"); + return; + } + *s = 0; + if(doreset) + reset(); + j = nrec; + saoopen(); + starts = fromgreek(starts); + for(i=0; i<NName; i++) + if(equal(starts, name[i].name)){ + grow(); + if(name[i].sao){ + rec[j].type = NamedSAO; + rec[j].index = name[i].sao; + } + if(name[i].ngc){ + rec[j].type = NamedNGC; + rec[j].index = name[i].ngc; + } + if(name[i].abell){ + rec[j].type = NamedAbell; + rec[j].index = name[i].abell; + } + strcpy(rec[j].named.name, name[i].name); + j++; + } + if(parsename(starts)) + for(i=0; i<NBayer; i++) + if(bayer[i].name[0]==parsed[0] && + (bayer[i].name[1]==parsed[1] || parsed[1]==0) && + bayer[i].name[2]==parsed[2]){ + grow(); + rec[j].type = NamedSAO; + rec[j].index = bayer[i].sao; + strncpy(rec[j].named.name, starts, sizeof(rec[j].named.name)); + j++; + } + if(j == 0){ + *s = '"'; + goto NotFound; + } + break; + + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + strtoul(s, &t, 10); + if(*t != 'h'){ + BadCoords: + fprint(2, "bad coordinates %s\n", inputline); + break; + } + ra = DEG(getra(s)); + while(*s && *s!=' ' && *s!='\t') + s++; + rah = ra/15; + ra = ra-rah*15; + ram = ra*4; + deg = strtol(s, &t, 10); + if(t == s) + goto BadCoords; + /* degree sign etc. is optional */ + chartorune(&c, t); + if(c == 0xb0) + deg = DEG(getra(s)); + if(doreset) + reset(); + if(abs(deg)>=90 || rah>=24) + goto BadCoords; + if(!loadpatch(patch(rah, ram, deg))) + goto NotFound; + break; + + default: + fprint(2, "unknown command %s\n", inputline); + return; + } + + Print: + if(nrec == 0) + Bprint(&bout, "empty\n"); + else if(nrec <= 2) + for(i=0; i<nrec; i++) + prrec(rec+i); + else + Bprint(&bout, "%ld items\n", nrec); + return; + + NotFound: + fprint(2, "%s not found\n", inputline); + return; +} + +char *ngctypes[] = +{ +[Galaxy] "Gx", +[PlanetaryN] "Pl", +[OpenCl] "OC", +[GlobularCl] "Gb", +[DiffuseN] "Nb", +[NebularCl] "C+N", +[Asterism] "Ast", +[Knot] "Kt", +[Triple] "***", +[Double] "D*", +[Single] "*", +[Uncertain] "?", +[Nonexistent] "-", +[Unknown] " ", +[PlateDefect] "PD", +}; + +char* +ngcstring(int d) +{ + if(d<Galaxy || d>PlateDefect) + return "can't happen"; + return ngctypes[d]; +} + +short descindex[NINDEX]; + +void +printnames(Record *r) +{ + int i, ok, done; + + done = 0; + for(i=0; i<NName; i++){ /* stupid linear search! */ + ok = 0; + if(r->type==SAO && r->index==name[i].sao) + ok = 1; + if(r->type==NGC && r->ngc.ngc==name[i].ngc) + ok = 1; + if(r->type==Abell && r->abell.abell==name[i].abell) + ok = 1; + if(ok){ + if(done++ == 0) + Bprint(&bout, "\t"); + Bprint(&bout, " \"%s\"", togreek(name[i].name)); + } + } + if(done) + Bprint(&bout, "\n"); +} + +int +equal(char *s1, char *s2) +{ + int c; + + while(*s1){ + if(*s1==' '){ + while(*s1==' ') + s1++; + continue; + } + while(*s2==' ') + s2++; + c=*s2; + if('A'<=*s2 && *s2<='Z') + c^=' '; + if(*s1!=c) + return 0; + s1++, s2++; + } + return 1; +} + +int +parsename(char *s) +{ + char *blank; + int i; + + blank = strchr(s, ' '); + if(blank==0 || strchr(blank+1, ' ') || strlen(blank+1)!=3) + return 0; + blank++; + parsed[0] = parsed[1] = parsed[2] = 0; + if('0'<=s[0] && s[0]<='9'){ + i = atoi(s); + parsed[0] = i; + if(i > 100) + return 0; + }else{ + for(i=1; i<=24; i++) + if(strncmp(greek[i], s, strlen(greek[i]))==0){ + parsed[0]=100+i; + goto out; + } + return 0; + out: + if('0'<=s[strlen(greek[i])] && s[strlen(greek[i])]<='9') + parsed[1]=s[strlen(greek[i])]-'0'; + } + for(i=1; i<=88; i++) + if(strcmp(constel[i], blank)==0){ + parsed[2] = i; + return 1; + } + return 0; +} + +char* +dist_grp(int dg) +{ + switch(dg){ + default: + return "unknown"; + case 1: + return "13.3-14.0"; + case 2: + return "14.1-14.8"; + case 3: + return "14.9-15.6"; + case 4: + return "15.7-16.4"; + case 5: + return "16.5-17.2"; + case 6: + return "17.3-18.0"; + case 7: + return ">18.0"; + } +} + +char* +rich_grp(int dg) +{ + switch(dg){ + default: + return "unknown"; + case 0: + return "30-40"; + case 1: + return "50-79"; + case 2: + return "80-129"; + case 3: + return "130-199"; + case 4: + return "200-299"; + case 5: + return ">=300"; + } +} + +char* +nameof(Record *r) +{ + NGCrec *n; + SAOrec *s; + Abellrec *a; + static char buf[128]; + int i; + + switch(r->type){ + default: + return nil; + case SAO: + s = &r->sao; + if(s->name[0] == 0) + return nil; + if(s->name[0] >= 100){ + i = snprint(buf, sizeof buf, "%C", greeklet[s->name[0]-100]); + if(s->name[1]) + i += snprint(buf+i, sizeof buf-i, "%d", s->name[1]); + }else + i = snprint(buf, sizeof buf, " %d", s->name[0]); + snprint(buf+i, sizeof buf-i, " %s", constel[(uchar)s->name[2]]); + break; + case NGC: + n = &r->ngc; + if(n->type >= Uncertain) + return nil; + if(n->ngc <= NNGC) + snprint(buf, sizeof buf, "NGC%4d ", n->ngc); + else + snprint(buf, sizeof buf, "IC%4d ", n->ngc-NNGC); + break; + case Abell: + a = &r->abell; + snprint(buf, sizeof buf, "Abell%4d", a->abell); + break; + } + return buf; +} + +void +prrec(Record *r) +{ + NGCrec *n; + SAOrec *s; + Abellrec *a; + Planetrec *p; + int i, rah, ram, dec, nn; + long key; + + if(r) switch(r->type){ + default: + fprint(2, "can't prrec type %d\n", r->type); + exits("type"); + + case Planet: + p = &r->planet; + Bprint(&bout, "%s", p->name); + Bprint(&bout, "\t%s %s", + hms(angle(p->ra)), + dms(angle(p->dec))); + Bprint(&bout, " %3.2f° %3.2f°", + p->az/(double)MILLIARCSEC, p->alt/(double)MILLIARCSEC); + Bprint(&bout, " %s", + ms(angle(p->semidiam))); + if(r->index <= 1) + Bprint(&bout, " %g", p->phase); + Bprint(&bout, "\n"); + break; + + case NGC: + n = &r->ngc; + if(n->ngc <= NNGC) + Bprint(&bout, "NGC%4d ", n->ngc); + else + Bprint(&bout, "IC%4d ", n->ngc-NNGC); + Bprint(&bout, "%s ", ngcstring(n->type)); + if(n->mag == UNKNOWNMAG) + Bprint(&bout, "----"); + else + Bprint(&bout, "%.1f%c", n->mag/10.0, n->magtype); + Bprint(&bout, "\t%s %s\t%c%.1f'\n", + hm(angle(n->ra)), + dm(angle(n->dec)), + n->diamlim, + DEG(angle(n->diam))*60.); + prdesc(n->desc, desctab, descindex); + printnames(r); + break; + + case Abell: + a = &r->abell; + Bprint(&bout, "Abell%4d %.1f %.2f° %dMpc", a->abell, a->mag10/10.0, + DEG(angle(a->rad)), a->dist); + Bprint(&bout, "\t%s %s\t%.2f %.2f\n", + hm(angle(a->ra)), + dm(angle(a->dec)), + DEG(angle(a->glat)), + DEG(angle(a->glong))); + Bprint(&bout, "\tdist grp: %s rich grp: %s %d galaxies/°²\n", + dist_grp(a->distgrp), + rich_grp(a->richgrp), + a->pop); + printnames(r); + break; + + case SAO: + s = &r->sao; + Bprint(&bout, "SAO%6ld ", r->index); + if(s->mag==UNKNOWNMAG) + Bprint(&bout, "---"); + else + Bprint(&bout, "%.1f", s->mag/10.0); + if(s->mpg==UNKNOWNMAG) + Bprint(&bout, ",---"); + else + Bprint(&bout, ",%.1f", s->mpg/10.0); + Bprint(&bout, " %s %s %.4fs %.3f\"", + hms(angle(s->ra)), + dms(angle(s->dec)), + DEG(angle(s->dra))*(4*60), + DEG(angle(s->ddec))*(60*60)); + Bprint(&bout, " %.3s %c %.2s %ld %d", + s->spec, s->code, s->compid, s->hd, s->hdcode); + if(s->name[0]) + Bprint(&bout, " \"%s\"", nameof(r)); + Bprint(&bout, "\n"); + printnames(r); + break; + + case Patch: + radec(r->index, &rah, &ram, &dec); + Bprint(&bout, "%dh%dm %d°", rah, ram, dec); + key = r->patch.key[0]; + Bprint(&bout, " %s", constel[key&0xFF]); + if((key>>=8) & 0xFF) + Bprint(&bout, " %s", constel[key&0xFF]); + if((key>>=8) & 0xFF) + Bprint(&bout, " %s", constel[key&0xFF]); + if((key>>=8) & 0xFF) + Bprint(&bout, " %s", constel[key&0xFF]); + for(i=1; i<r->patch.nkey; i++){ + key = r->patch.key[i]; + switch(key&0x3F){ + case SAO: + Bprint(&bout, " SAO%ld", (key>>8)&0xFFFFFF); + break; + case Abell: + Bprint(&bout, " Abell%ld", (key>>8)&0xFFFFFF); + break; + default: /* NGC */ + nn = (key>>16)&0xFFFF; + if(nn > NNGC) + Bprint(&bout, " IC%d", nn-NNGC); + else + Bprint(&bout, " NGC%d", nn); + Bprint(&bout, "(%s)", ngcstring(key&0x3F)); + break; + } + } + Bprint(&bout, "\n"); + break; + + case NGCN: + if(r->index <= NNGC) + Bprint(&bout, "NGC%ld\n", r->index); + else + Bprint(&bout, "IC%ld\n", r->index-NNGC); + break; + + case NamedSAO: + Bprint(&bout, "SAO%ld \"%s\"\n", r->index, togreek(r->named.name)); + break; + + case NamedNGC: + if(r->index <= NNGC) + Bprint(&bout, "NGC%ld \"%s\"\n", r->index, togreek(r->named.name)); + else + Bprint(&bout, "IC%ld \"%s\"\n", r->index-NNGC, togreek(r->named.name)); + break; + + case NamedAbell: + Bprint(&bout, "Abell%ld \"%s\"\n", r->index, togreek(r->named.name)); + break; + + case PatchC: + radec(r->index, &rah, &ram, &dec); + Bprint(&bout, "%dh%dm %d\n", rah, ram, dec); + break; + } +} |