scat.c 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677
  1. /*
  2. * This file is part of the UCB release of Plan 9. It is subject to the license
  3. * terms in the LICENSE file found in the top-level directory of this
  4. * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
  5. * part of the UCB release of Plan 9, including this file, may be copied,
  6. * modified, propagated, or distributed except according to the terms contained
  7. * in the LICENSE file.
  8. */
  9. #include <u.h>
  10. #include <libc.h>
  11. #include <bio.h>
  12. #include <draw.h>
  13. #include <event.h>
  14. #include "sky.h"
  15. #include "strings.C"
  16. enum
  17. {
  18. NNGC=7840, /* number of NGC numbers [1..NNGC] */
  19. NIC = 5386, /* number of IC numbers */
  20. NNGCrec=NNGC+NIC, /* number of records in the NGC catalog (including IC's, starting at NNGC */
  21. NMrec=122, /* number of M records */
  22. NM=110, /* number of M numbers */
  23. NAbell=2712, /* number of records in the Abell catalog */
  24. NName=1000, /* number of prose names; estimated maximum (read from editable text file) */
  25. NBayer=1517, /* number of bayer entries */
  26. NSAO=258998, /* number of SAO stars */
  27. MAXcon=1932, /* maximum number of patches in a constellation */
  28. Ncon=88, /* number of constellations */
  29. Npatch=92053, /* highest patch number */
  30. };
  31. char ngctype[NNGCrec];
  32. Mindexrec mindex[NMrec];
  33. Namerec name[NName];
  34. Bayerec bayer[NBayer];
  35. int32_t con[MAXcon];
  36. uint16_t conindex[Ncon+1];
  37. int32_t patchaddr[Npatch+1];
  38. Record *rec;
  39. Record *orec;
  40. Record *cur;
  41. char *dir=DIR;
  42. int saodb;
  43. int ngcdb;
  44. int abelldb;
  45. int ngctypedb;
  46. int mindexdb;
  47. int namedb;
  48. int bayerdb;
  49. int condb;
  50. int conindexdb;
  51. int patchdb;
  52. char parsed[3];
  53. int32_t nrec;
  54. int32_t nreca;
  55. int32_t norec;
  56. int32_t noreca;
  57. Biobuf bin;
  58. Biobuf bout;
  59. int
  60. main(int argc, char *argv[])
  61. {
  62. char *line;
  63. Binit(&bin, 0, OREAD);
  64. Binit(&bout, 1, OWRITE);
  65. if(argc != 1)
  66. dir = argv[1];
  67. astro("", 1);
  68. while((line = Brdline(&bin, '\n'))){
  69. line[Blinelen(&bin)-1] = 0;
  70. lookup(line, 1);
  71. Bflush(&bout);
  72. }
  73. if(display != nil){
  74. closedisplay(display);
  75. /* automatic refresh of rio window is triggered by mouse */
  76. close(open("/dev/mouse", OREAD));
  77. }
  78. return 0;
  79. }
  80. void
  81. reset(void)
  82. {
  83. nrec = 0;
  84. cur = rec;
  85. }
  86. void
  87. grow(void)
  88. {
  89. nrec++;
  90. if(nreca < nrec){
  91. nreca = nrec+50;
  92. rec = realloc(rec, nreca*sizeof(Record));
  93. if(rec == 0){
  94. fprint(2, "scat: realloc fails\n");
  95. exits("realloc");
  96. }
  97. }
  98. cur = rec+nrec-1;
  99. }
  100. void
  101. copy(void)
  102. {
  103. if(noreca < nreca){
  104. noreca = nreca;
  105. orec = realloc(orec, nreca*sizeof(Record));
  106. if(orec == 0){
  107. fprint(2, "scat: realloc fails\n");
  108. exits("realloc");
  109. }
  110. }
  111. memmove(orec, rec, nrec*sizeof(Record));
  112. norec = nrec;
  113. }
  114. int
  115. eopen(char *s)
  116. {
  117. char buf[128];
  118. int f;
  119. sprint(buf, "%s/%s.scat", dir, s);
  120. f = open(buf, 0);
  121. if(f<0){
  122. fprint(2, "scat: can't open %s\n", buf);
  123. exits("open");
  124. }
  125. return f;
  126. }
  127. void
  128. Eread(int f, char *name, void *addr, int32_t n)
  129. {
  130. if(read(f, addr, n) != n){ /* BUG! */
  131. fprint(2, "scat: read error on %s\n", name);
  132. exits("read");
  133. }
  134. }
  135. char*
  136. skipbl(char *s)
  137. {
  138. while(*s!=0 && (*s==' ' || *s=='\t'))
  139. s++;
  140. return s;
  141. }
  142. char*
  143. skipstr(char *s, char *t)
  144. {
  145. while(*s && *s==*t)
  146. s++, t++;
  147. return skipbl(s);
  148. }
  149. /* produce little-endian long at address l */
  150. int32_t
  151. Long(int32_t *l)
  152. {
  153. uint8_t *p;
  154. p = (uint8_t*)l;
  155. return (int32_t)p[0]|((int32_t)p[1]<<8)|((int32_t)p[2]<<16)|((int32_t)p[3]<<24);
  156. }
  157. /* produce little-endian long at address l */
  158. int
  159. Short(int16_t *s)
  160. {
  161. uint8_t *p;
  162. p = (uint8_t*)s;
  163. return p[0]|(p[1]<<8);
  164. }
  165. void
  166. nameopen(void)
  167. {
  168. Biobuf b;
  169. int i;
  170. char *l, *p;
  171. if(namedb == 0){
  172. namedb = eopen("name");
  173. Binit(&b, namedb, OREAD);
  174. for(i=0; i<NName; i++){
  175. l = Brdline(&b, '\n');
  176. if(l == 0)
  177. break;
  178. p = strchr(l, '\t');
  179. if(p == 0){
  180. Badformat:
  181. Bprint(&bout, "warning: name.scat bad format; line %d\n", i+1);
  182. break;
  183. }
  184. *p++ = 0;
  185. strcpy(name[i].name, l);
  186. if(strncmp(p, "ngc", 3) == 0)
  187. name[i].ngc = atoi(p+3);
  188. else if(strncmp(p, "ic", 2) == 0)
  189. name[i].ngc = atoi(p+2)+NNGC;
  190. else if(strncmp(p, "sao", 3) == 0)
  191. name[i].sao = atoi(p+3);
  192. else if(strncmp(p, "abell", 5) == 0)
  193. name[i].abell = atoi(p+5);
  194. else
  195. goto Badformat;
  196. }
  197. if(i == NName)
  198. Bprint(&bout, "warning: too many names in name.scat (max %d); extra ignored\n", NName);
  199. close(namedb);
  200. bayerdb = eopen("bayer");
  201. Eread(bayerdb, "bayer", bayer, sizeof bayer);
  202. close(bayerdb);
  203. for(i=0; i<NBayer; i++)
  204. bayer[i].sao = Long(&bayer[i].sao);
  205. }
  206. }
  207. void
  208. saoopen(void)
  209. {
  210. if(saodb == 0){
  211. nameopen();
  212. saodb = eopen("sao");
  213. }
  214. }
  215. void
  216. ngcopen(void)
  217. {
  218. if(ngcdb == 0){
  219. nameopen();
  220. ngcdb = eopen("ngc2000");
  221. ngctypedb = eopen("ngc2000type");
  222. Eread(ngctypedb, "ngctype", ngctype, sizeof ngctype);
  223. close(ngctypedb);
  224. }
  225. }
  226. void
  227. abellopen(void)
  228. {
  229. /* nothing extra to do with abell: it's directly indexed by number */
  230. if(abelldb == 0)
  231. abelldb = eopen("abell");
  232. }
  233. void
  234. patchopen(void)
  235. {
  236. Biobuf *b;
  237. int32_t l, m;
  238. char buf[100];
  239. if(patchdb == 0){
  240. patchdb = eopen("patch");
  241. sprint(buf, "%s/patchindex.scat", dir);
  242. b = Bopen(buf, OREAD);
  243. if(b == 0){
  244. fprint(2, "can't open %s\n", buf);
  245. exits("open");
  246. }
  247. for(m=0,l=0; l<=Npatch; l++)
  248. patchaddr[l] = m += Bgetc(b)*4;
  249. Bterm(b);
  250. }
  251. }
  252. void
  253. mopen(void)
  254. {
  255. int i;
  256. if(mindexdb == 0){
  257. mindexdb = eopen("mindex");
  258. Eread(mindexdb, "mindex", mindex, sizeof mindex);
  259. close(mindexdb);
  260. for(i=0; i<NMrec; i++)
  261. mindex[i].ngc = Short(&mindex[i].ngc);
  262. }
  263. }
  264. void
  265. constelopen(void)
  266. {
  267. int i;
  268. if(condb == 0){
  269. condb = eopen("con");
  270. conindexdb = eopen("conindex");
  271. Eread(conindexdb, "conindex", conindex, sizeof conindex);
  272. close(conindexdb);
  273. for(i=0; i<Ncon+1; i++)
  274. conindex[i] = Short((int16_t*)&conindex[i]);
  275. }
  276. }
  277. void
  278. lowercase(char *s)
  279. {
  280. for(; *s; s++)
  281. if('A'<=*s && *s<='Z')
  282. *s += 'a'-'A';
  283. }
  284. int
  285. loadngc(int32_t index)
  286. {
  287. static int failed;
  288. int32_t j;
  289. ngcopen();
  290. j = (index-1)*sizeof(NGCrec);
  291. grow();
  292. cur->type = NGC;
  293. cur->index = index;
  294. seek(ngcdb, j, 0);
  295. /* special case: NGC data may not be available */
  296. if(read(ngcdb, &cur->ngc, sizeof(NGCrec)) != sizeof(NGCrec)){
  297. if(!failed){
  298. fprint(2, "scat: NGC database not available\n");
  299. failed++;
  300. }
  301. cur->type = NONGC;
  302. cur->ngc.ngc = 0;
  303. cur->ngc.ra = 0;
  304. cur->ngc.dec = 0;
  305. cur->ngc.diam = 0;
  306. cur->ngc.mag = 0;
  307. return 0;
  308. }
  309. cur->ngc.ngc = Short(&cur->ngc.ngc);
  310. cur->ngc.ra = Long(&cur->ngc.ra);
  311. cur->ngc.dec = Long(&cur->ngc.dec);
  312. cur->ngc.diam = Long(&cur->ngc.diam);
  313. cur->ngc.mag = Short(&cur->ngc.mag);
  314. return 1;
  315. }
  316. int
  317. loadabell(int32_t index)
  318. {
  319. int32_t j;
  320. abellopen();
  321. j = index-1;
  322. grow();
  323. cur->type = Abell;
  324. cur->index = index;
  325. seek(abelldb, j*sizeof(Abellrec), 0);
  326. Eread(abelldb, "abell", &cur->abell, sizeof(Abellrec));
  327. cur->abell.abell = Short(&cur->abell.abell);
  328. if(cur->abell.abell != index){
  329. fprint(2, "bad format in abell catalog\n");
  330. exits("abell");
  331. }
  332. cur->abell.ra = Long(&cur->abell.ra);
  333. cur->abell.dec = Long(&cur->abell.dec);
  334. cur->abell.glat = Long(&cur->abell.glat);
  335. cur->abell.glong = Long(&cur->abell.glong);
  336. cur->abell.rad = Long(&cur->abell.rad);
  337. cur->abell.mag10 = Short(&cur->abell.mag10);
  338. cur->abell.pop = Short(&cur->abell.pop);
  339. cur->abell.dist = Short(&cur->abell.dist);
  340. return 1;
  341. }
  342. int
  343. loadsao(int index)
  344. {
  345. if(index<=0 || index>NSAO)
  346. return 0;
  347. saoopen();
  348. grow();
  349. cur->type = SAO;
  350. cur->index = index;
  351. seek(saodb, (index-1)*sizeof(SAOrec), 0);
  352. Eread(saodb, "sao", &cur->sao, sizeof(SAOrec));
  353. cur->sao.ra = Long(&cur->sao.ra);
  354. cur->sao.dec = Long(&cur->sao.dec);
  355. cur->sao.dra = Long(&cur->sao.dra);
  356. cur->sao.ddec = Long(&cur->sao.ddec);
  357. cur->sao.mag = Short(&cur->sao.mag);
  358. cur->sao.mpg = Short(&cur->sao.mpg);
  359. cur->sao.hd = Long(&cur->sao.hd);
  360. return 1;
  361. }
  362. int
  363. loadplanet(int index, Record *r)
  364. {
  365. if(index<0 || index>NPlanet || planet[index].name[0]=='\0')
  366. return 0;
  367. grow();
  368. cur->type = Planet;
  369. cur->index = index;
  370. /* check whether to take new or existing record */
  371. if(r == nil)
  372. memmove(&cur->planet, &planet[index], sizeof(Planetrec));
  373. else
  374. memmove(&cur->planet, &r->planet, sizeof(Planetrec));
  375. return 1;
  376. }
  377. int
  378. loadpatch(int32_t index)
  379. {
  380. int i;
  381. patchopen();
  382. if(index<=0 || index>Npatch)
  383. return 0;
  384. grow();
  385. cur->type = Patch;
  386. cur->index = index;
  387. seek(patchdb, patchaddr[index-1], 0);
  388. cur->patch.nkey = (patchaddr[index]-patchaddr[index-1])/4;
  389. Eread(patchdb, "patch", cur->patch.key, cur->patch.nkey*4);
  390. for(i=0; i<cur->patch.nkey; i++)
  391. cur->patch.key[i] = Long(&cur->patch.key[i]);
  392. return 1;
  393. }
  394. int
  395. loadtype(int t)
  396. {
  397. int i;
  398. ngcopen();
  399. for(i=0; i<NNGCrec; i++)
  400. if(t == (ngctype[i])){
  401. grow();
  402. cur->type = NGCN;
  403. cur->index = i+1;
  404. }
  405. return 1;
  406. }
  407. void
  408. flatten(void)
  409. {
  410. int i, j, notflat;
  411. Record *or;
  412. int32_t key;
  413. loop:
  414. copy();
  415. reset();
  416. notflat = 0;
  417. for(i=0,or=orec; i<norec; i++,or++){
  418. switch(or->type){
  419. default:
  420. fprint(2, "bad type %d in flatten\n", or->type);
  421. break;
  422. case NONGC:
  423. break;
  424. case Planet:
  425. case Abell:
  426. case NGC:
  427. case SAO:
  428. grow();
  429. memmove(cur, or, sizeof(Record));
  430. break;
  431. case NGCN:
  432. if(loadngc(or->index))
  433. notflat = 1;
  434. break;
  435. case NamedSAO:
  436. loadsao(or->index);
  437. notflat = 1;
  438. break;
  439. case NamedNGC:
  440. if(loadngc(or->index))
  441. notflat = 1;
  442. break;
  443. case NamedAbell:
  444. loadabell(or->index);
  445. notflat = 1;
  446. break;
  447. case PatchC:
  448. loadpatch(or->index);
  449. notflat = 1;
  450. break;
  451. case Patch:
  452. for(j=1; j<or->patch.nkey; j++){
  453. key = or->patch.key[j];
  454. if((key&0x3F) == SAO)
  455. loadsao((key>>8)&0xFFFFFF);
  456. else if((key&0x3F) == Abell)
  457. loadabell((key>>8)&0xFFFFFF);
  458. else
  459. loadngc((key>>16)&0xFFFF);
  460. }
  461. break;
  462. }
  463. }
  464. if(notflat)
  465. goto loop;
  466. }
  467. int
  468. ism(int index)
  469. {
  470. int i;
  471. for(i=0; i<NMrec; i++)
  472. if(mindex[i].ngc == index)
  473. return 1;
  474. return 0;
  475. }
  476. char*
  477. alpha(char *s, char *t)
  478. {
  479. int n;
  480. n = strlen(t);
  481. if(strncmp(s, t, n)==0 && (s[n]<'a' || 'z'<s[n]))
  482. return skipbl(s+n);
  483. return 0;
  484. }
  485. char*
  486. text(char *s, char *t)
  487. {
  488. int n;
  489. n = strlen(t);
  490. if(strncmp(s, t, n)==0 && (s[n]==0 || s[n]==' ' || s[n]=='\t'))
  491. return skipbl(s+n);
  492. return 0;
  493. }
  494. int
  495. cull(char *s, int keep, int dobbox)
  496. {
  497. int i, j, nobj, keepthis;
  498. Record *or;
  499. char *t;
  500. int dogrtr, doless, dom, dosao, dongc, doabell;
  501. int mgrtr, mless;
  502. char obj[100];
  503. memset(obj, 0, sizeof(obj));
  504. nobj = 0;
  505. dogrtr = 0;
  506. doless = 0;
  507. dom = 0;
  508. dongc = 0;
  509. dosao = 0;
  510. doabell = 0;
  511. mgrtr = mless= 0;
  512. if(dobbox)
  513. goto Cull;
  514. for(;;){
  515. if(s[0] == '>'){
  516. dogrtr = 1;
  517. mgrtr = 10 * strtod(s+1, &t);
  518. if(mgrtr==0 && t==s+1){
  519. fprint(2, "bad magnitude\n");
  520. return 0;
  521. }
  522. s = skipbl(t);
  523. continue;
  524. }
  525. if(s[0] == '<'){
  526. doless = 1;
  527. mless = 10 * strtod(s+1, &t);
  528. if(mless==0 && t==s+1){
  529. fprint(2, "bad magnitude\n");
  530. return 0;
  531. }
  532. s = skipbl(t);
  533. continue;
  534. }
  535. if((t = text(s, "m")) ){
  536. dom = 1;
  537. s = t;
  538. continue;
  539. }
  540. if((t = text(s, "sao"))){
  541. dosao = 1;
  542. s = t;
  543. continue;
  544. }
  545. if((t = text(s, "ngc"))){
  546. dongc = 1;
  547. s = t;
  548. continue;
  549. }
  550. if((t = text(s, "abell"))){
  551. doabell = 1;
  552. s = t;
  553. continue;
  554. }
  555. for(i=0; names[i].name; i++)
  556. if((t = alpha(s, names[i].name))){
  557. if(nobj > 100){
  558. fprint(2, "too many object types\n");
  559. return 0;
  560. }
  561. obj[nobj++] = names[i].type;
  562. s = t;
  563. goto Continue;
  564. }
  565. break;
  566. Continue:;
  567. }
  568. if(*s){
  569. fprint(2, "syntax error in object list\n");
  570. return 0;
  571. }
  572. Cull:
  573. flatten();
  574. copy();
  575. reset();
  576. if(dom)
  577. mopen();
  578. if(dosao)
  579. saoopen();
  580. if(dongc || nobj)
  581. ngcopen();
  582. if(doabell)
  583. abellopen();
  584. for(i=0,or=orec; i<norec; i++,or++){
  585. keepthis = !keep;
  586. if(dobbox && inbbox(or->ngc.ra, or->ngc.dec))
  587. keepthis = keep;
  588. if(doless && or->ngc.mag <= mless)
  589. keepthis = keep;
  590. if(dogrtr && or->ngc.mag >= mgrtr)
  591. keepthis = keep;
  592. if(dom && (or->type==NGC && ism(or->ngc.ngc)))
  593. keepthis = keep;
  594. if(dongc && or->type==NGC)
  595. keepthis = keep;
  596. if(doabell && or->type==Abell)
  597. keepthis = keep;
  598. if(dosao && or->type==SAO)
  599. keepthis = keep;
  600. for(j=0; j<nobj; j++)
  601. if(or->type==NGC && or->ngc.type==obj[j])
  602. keepthis = keep;
  603. if(keepthis){
  604. grow();
  605. memmove(cur, or, sizeof(Record));
  606. }
  607. }
  608. return 1;
  609. }
  610. int
  611. compar(const void *va, const void *vb)
  612. {
  613. Record const *a=va, *b=vb;
  614. if(a->type == b->type)
  615. return a->index - b->index;
  616. return a->type - b->type;
  617. }
  618. void
  619. sort(void)
  620. {
  621. int i;
  622. Record *r, *s;
  623. if(nrec == 0)
  624. return;
  625. qsort(rec, nrec, sizeof(Record), compar);
  626. r = rec+1;
  627. s = rec;
  628. for(i=1; i<nrec; i++,r++){
  629. /* may have multiple instances of a planet in the scene */
  630. if(r->type==s->type && r->index==s->index && r->type!=Planet)
  631. continue;
  632. memmove(++s, r, sizeof(Record));
  633. }
  634. nrec = (s+1)-rec;
  635. }
  636. char greekbuf[128];
  637. char*
  638. togreek(char *s)
  639. {
  640. char *t;
  641. int i, n;
  642. Rune r;
  643. t = greekbuf;
  644. while(*s){
  645. for(i=1; i<=24; i++){
  646. n = strlen(greek[i]);
  647. if(strncmp(s, greek[i], n)==0 && (s[n]==' ' || s[n]=='\t')){
  648. s += n;
  649. t += runetochar(t, &greeklet[i]);
  650. goto Cont;
  651. }
  652. }
  653. n = chartorune(&r, s);
  654. for(i=0; i<n; i++)
  655. *t++ = *s++;
  656. Cont:;
  657. }
  658. *t = 0;
  659. return greekbuf;
  660. }
  661. char*
  662. fromgreek(char *s)
  663. {
  664. char *t;
  665. int i, n;
  666. Rune r;
  667. t = greekbuf;
  668. while(*s){
  669. n = chartorune(&r, s);
  670. for(i=1; i<=24; i++){
  671. if(r == greeklet[i]){
  672. strcpy(t, greek[i]);
  673. t += strlen(greek[i]);
  674. s += n;
  675. goto Cont;
  676. }
  677. }
  678. for(i=0; i<n; i++)
  679. *t++ = *s++;
  680. Cont:;
  681. }
  682. *t = 0;
  683. return greekbuf;
  684. }
  685. #ifdef OLD
  686. /*
  687. * Old version
  688. */
  689. int
  690. coords(int deg)
  691. {
  692. int i;
  693. int x, y;
  694. Record *or;
  695. int32_t dec, ra, ndec, nra;
  696. int rdeg;
  697. flatten();
  698. copy();
  699. reset();
  700. deg *= 2;
  701. for(i=0,or=orec; i<norec; i++,or++){
  702. if(or->type == Planet) /* must keep it here */
  703. loadplanet(or->index, or);
  704. dec = or->ngc.dec/MILLIARCSEC;
  705. ra = or->ngc.ra/MILLIARCSEC;
  706. rdeg = deg/cos((dec*PI)/180);
  707. for(y=-deg; y<=+deg; y++){
  708. ndec = dec*2+y;
  709. if(ndec/2>=90 || ndec/2<=-90)
  710. continue;
  711. /* fp errors hurt here, so we round 1' to the pole */
  712. if(ndec >= 0)
  713. ndec = ndec*500*60*60 + 60000;
  714. else
  715. ndec = ndec*500*60*60 - 60000;
  716. for(x=-rdeg; x<=+rdeg; x++){
  717. nra = ra*2+x;
  718. if(nra/2 < 0)
  719. nra += 360*2;
  720. if(nra/2 >= 360)
  721. nra -= 360*2;
  722. /* fp errors hurt here, so we round up 1' */
  723. nra = nra/2*MILLIARCSEC + 60000;
  724. loadpatch(patcha(angle(nra), angle(ndec)));
  725. }
  726. }
  727. }
  728. sort();
  729. return 1;
  730. }
  731. #endif
  732. /*
  733. * New version attempts to match the boundaries of the plot better.
  734. */
  735. int
  736. coords(int deg)
  737. {
  738. int i;
  739. int x, y, xx;
  740. Record *or;
  741. int32_t min, circle;
  742. double factor;
  743. flatten();
  744. circle = 360*MILLIARCSEC;
  745. deg *= MILLIARCSEC;
  746. /* find center */
  747. folded = 0;
  748. bbox(0, 0, 0);
  749. /* now expand */
  750. factor = cos(angle((decmax+decmin)/2));
  751. if(factor < .2)
  752. factor = .2;
  753. factor = floor(1/factor);
  754. folded = 0;
  755. bbox(factor*deg, deg, 1);
  756. Bprint(&bout, "%s to ", hms(angle(ramin)));
  757. Bprint(&bout, "%s\n", hms(angle(ramax)));
  758. Bprint(&bout, "%s to ", dms(angle(decmin)));
  759. Bprint(&bout, "%s\n", dms(angle(decmax)));
  760. copy();
  761. reset();
  762. for(i=0,or=orec; i<norec; i++,or++)
  763. if(or->type == Planet) /* must keep it here */
  764. loadplanet(or->index, or);
  765. min = ramin;
  766. if(ramin > ramax)
  767. min -= circle;
  768. for(x=min; x<=ramax; x+=250*60*60){
  769. xx = x;
  770. if(xx < 0)
  771. xx += circle;
  772. for(y=decmin; y<=decmax; y+=250*60*60)
  773. if(-circle/4 < y && y < circle/4)
  774. loadpatch(patcha(angle(xx), angle(y)));
  775. }
  776. sort();
  777. cull(nil, 1, 1);
  778. return 1;
  779. }
  780. void
  781. pplate(char *flags)
  782. {
  783. int i;
  784. int32_t c;
  785. int na, rah, ram, d1, d2;
  786. double r0;
  787. int ra, dec;
  788. int32_t ramin, ramax, decmin, decmax; /* all in degrees */
  789. Record *r;
  790. int folded;
  791. Angle racenter, deccenter, rasize, decsize, a[4];
  792. Picture *pic;
  793. rasize = -1.0;
  794. decsize = -1.0;
  795. na = 0;
  796. for(;;){
  797. while(*flags==' ')
  798. flags++;
  799. if(('0'<=*flags && *flags<='9') || *flags=='+' || *flags=='-'){
  800. if(na >= 3)
  801. goto err;
  802. a[na++] = getra(flags);
  803. while(*flags && *flags!=' ')
  804. flags++;
  805. continue;
  806. }
  807. if(*flags){
  808. err:
  809. Bprint(&bout, "syntax error in plate\n");
  810. return;
  811. }
  812. break;
  813. }
  814. switch(na){
  815. case 0:
  816. break;
  817. case 1:
  818. rasize = a[0];
  819. decsize = rasize;
  820. break;
  821. case 2:
  822. rasize = a[0];
  823. decsize = a[1];
  824. break;
  825. case 3:
  826. case 4:
  827. racenter = a[0];
  828. deccenter = a[1];
  829. rasize = a[2];
  830. if(na == 4)
  831. decsize = a[3];
  832. else
  833. decsize = rasize;
  834. if(rasize<0.0 || decsize<0.0){
  835. Bprint(&bout, "negative sizes\n");
  836. return;
  837. }
  838. goto done;
  839. }
  840. folded = 0;
  841. /* convert to milliarcsec */
  842. c = 1000*60*60;
  843. Again:
  844. if(nrec == 0){
  845. Bprint(&bout, "empty\n");
  846. return;
  847. }
  848. ramin = 0x7FFFFFFF;
  849. ramax = -0x7FFFFFFF;
  850. decmin = 0x7FFFFFFF;
  851. decmax = -0x7FFFFFFF;
  852. for(r=rec,i=0; i<nrec; i++,r++){
  853. if(r->type == Patch){
  854. radec(r->index, &rah, &ram, &dec);
  855. ra = 15*rah+ram/4;
  856. r0 = c/cos(RAD(dec));
  857. ra *= c;
  858. dec *= c;
  859. if(dec == 0)
  860. d1 = c, d2 = c;
  861. else if(dec < 0)
  862. d1 = c, d2 = 0;
  863. else
  864. d1 = 0, d2 = c;
  865. }else if(r->type==SAO || r->type==NGC || r->type==Abell){
  866. ra = r->ngc.ra;
  867. dec = r->ngc.dec;
  868. d1 = 0, d2 = 0, r0 = 0;
  869. }else if(r->type==NGCN){
  870. loadngc(r->index);
  871. continue;
  872. }else if(r->type==NamedSAO){
  873. loadsao(r->index);
  874. continue;
  875. }else if(r->type==NamedNGC){
  876. loadngc(r->index);
  877. continue;
  878. }else if(r->type==NamedAbell){
  879. loadabell(r->index);
  880. continue;
  881. }else
  882. continue;
  883. if(dec+d2 > decmax)
  884. decmax = dec+d2;
  885. if(dec-d1 < decmin)
  886. decmin = dec-d1;
  887. if(folded){
  888. ra -= 180*c;
  889. if(ra < 0)
  890. ra += 360*c;
  891. }
  892. if(ra+r0 > ramax)
  893. ramax = ra+r0;
  894. if(ra < ramin)
  895. ramin = ra;
  896. }
  897. if(!folded && ramax-ramin>270*c){
  898. folded = 1;
  899. goto Again;
  900. }
  901. racenter = angle(ramin+(ramax-ramin)/2);
  902. deccenter = angle(decmin+(decmax-decmin)/2);
  903. if(rasize<0 || decsize<0){
  904. rasize = angle(ramax-ramin)*cos(deccenter);
  905. decsize = angle(decmax-decmin);
  906. }
  907. done:
  908. if(DEG(rasize)>1.1 || DEG(decsize)>1.1){
  909. Bprint(&bout, "plate too big: %s", ms(rasize));
  910. Bprint(&bout, " x %s\n", ms(decsize));
  911. Bprint(&bout, "trimming to 30'x30'\n");
  912. rasize = RAD(0.5);
  913. decsize = RAD(0.5);
  914. }
  915. Bprint(&bout, "%s %s ", hms(racenter), dms(deccenter));
  916. Bprint(&bout, "%s", ms(rasize));
  917. Bprint(&bout, " x %s\n", ms(decsize));
  918. Bflush(&bout);
  919. flatten();
  920. pic = image(racenter, deccenter, rasize, decsize);
  921. if(pic == 0)
  922. return;
  923. Bprint(&bout, "plate %s locn %d %d %d %d\n", pic->name, pic->minx, pic->miny, pic->maxx, pic->maxy);
  924. Bflush(&bout);
  925. displaypic(pic);
  926. }
  927. void
  928. lookup(char *s, int doreset)
  929. {
  930. int i, j, k;
  931. int rah, ram, deg;
  932. char *starts, *inputline=s, *t, *u;
  933. Record *r;
  934. int32_t n;
  935. double x;
  936. Angle ra;
  937. lowercase(s);
  938. s = skipbl(s);
  939. if(*s == 0)
  940. goto Print;
  941. if((t = alpha(s, "flat"))){
  942. if(*t){
  943. fprint(2, "flat takes no arguments\n");
  944. return;
  945. }
  946. if(nrec == 0){
  947. fprint(2, "no records\n");
  948. return;
  949. }
  950. flatten();
  951. goto Print;
  952. }
  953. if((t = alpha(s, "print"))){
  954. if(*t){
  955. fprint(2, "print takes no arguments\n");
  956. return;
  957. }
  958. for(i=0,r=rec; i<nrec; i++,r++)
  959. prrec(r);
  960. return;
  961. }
  962. if((t = alpha(s, "add"))){
  963. lookup(t, 0);
  964. return;
  965. }
  966. if((t = alpha(s, "sao"))){
  967. n = strtoul(t, &u, 10);
  968. if(n<=0 || n>NSAO)
  969. goto NotFound;
  970. t = skipbl(u);
  971. if(*t){
  972. fprint(2, "syntax error in sao\n");
  973. return;
  974. }
  975. if(doreset)
  976. reset();
  977. if(!loadsao(n))
  978. goto NotFound;
  979. goto Print;
  980. }
  981. if((t = alpha(s, "ngc"))){
  982. n = strtoul(t, &u, 10);
  983. if(n<=0 || n>NNGC)
  984. goto NotFound;
  985. t = skipbl(u);
  986. if(*t){
  987. fprint(2, "syntax error in ngc\n");
  988. return;
  989. }
  990. if(doreset)
  991. reset();
  992. if(!loadngc(n))
  993. goto NotFound;
  994. goto Print;
  995. }
  996. if((t = alpha(s, "ic"))){
  997. n = strtoul(t, &u, 10);
  998. if(n<=0 || n>NIC)
  999. goto NotFound;
  1000. t = skipbl(u);
  1001. if(*t){
  1002. fprint(2, "syntax error in ic\n");
  1003. return;
  1004. }
  1005. if(doreset)
  1006. reset();
  1007. if(!loadngc(n+NNGC))
  1008. goto NotFound;
  1009. goto Print;
  1010. }
  1011. if((t = alpha(s, "abell"))){
  1012. n = strtoul(t, &u, 10);
  1013. if(n<=0 || n>NAbell)
  1014. goto NotFound;
  1015. if(doreset)
  1016. reset();
  1017. if(!loadabell(n))
  1018. goto NotFound;
  1019. goto Print;
  1020. }
  1021. if((t = alpha(s, "m"))){
  1022. n = strtoul(t, &u, 10);
  1023. if(n<=0 || n>NM)
  1024. goto NotFound;
  1025. mopen();
  1026. for(j=n-1; mindex[j].m<n; j++)
  1027. ;
  1028. if(doreset)
  1029. reset();
  1030. while(mindex[j].m == n){
  1031. if(mindex[j].ngc){
  1032. grow();
  1033. cur->type = NGCN;
  1034. cur->index = mindex[j].ngc;
  1035. }
  1036. j++;
  1037. }
  1038. goto Print;
  1039. }
  1040. for(i=1; i<=Ncon; i++)
  1041. if((t = alpha(s, constel[i]))){
  1042. if(*t){
  1043. fprint(2, "syntax error in constellation\n");
  1044. return;
  1045. }
  1046. constelopen();
  1047. seek(condb, 4L*conindex[i-1], 0);
  1048. j = conindex[i]-conindex[i-1];
  1049. Eread(condb, "con", con, 4*j);
  1050. if(doreset)
  1051. reset();
  1052. for(k=0; k<j; k++){
  1053. grow();
  1054. cur->type = PatchC;
  1055. cur->index = Long(&con[k]);
  1056. }
  1057. goto Print;
  1058. }
  1059. if((t = alpha(s, "expand"))){
  1060. n = 0;
  1061. if(*t){
  1062. if(*t<'0' && '9'<*t){
  1063. Expanderr:
  1064. fprint(2, "syntax error in expand\n");
  1065. return;
  1066. }
  1067. n = strtoul(t, &u, 10);
  1068. t = skipbl(u);
  1069. if(*t)
  1070. goto Expanderr;
  1071. }
  1072. coords(n);
  1073. goto Print;
  1074. }
  1075. if((t = alpha(s, "plot"))){
  1076. if(nrec == 0){
  1077. Bprint(&bout, "empty\n");
  1078. return;
  1079. }
  1080. plot(t);
  1081. return;
  1082. }
  1083. if((t = alpha(s, "astro"))){
  1084. astro(t, 0);
  1085. return;
  1086. }
  1087. if((t = alpha(s, "plate"))){
  1088. pplate(t);
  1089. return;
  1090. }
  1091. if((t = alpha(s, "gamma"))){
  1092. while(*t==' ')
  1093. t++;
  1094. u = t;
  1095. x = strtod(t, &u);
  1096. if(u > t)
  1097. gam.gamma = x;
  1098. Bprint(&bout, "%.2f\n", gam.gamma);
  1099. return;
  1100. }
  1101. if((t = alpha(s, "keep"))){
  1102. if(!cull(t, 1, 0))
  1103. return;
  1104. goto Print;
  1105. }
  1106. if((t = alpha(s, "drop"))){
  1107. if(!cull(t, 0, 0))
  1108. return;
  1109. goto Print;
  1110. }
  1111. for(i=0; planet[i].name[0]; i++){
  1112. if((t = alpha(s, planet[i].name))){
  1113. if(doreset)
  1114. reset();
  1115. loadplanet(i, nil);
  1116. goto Print;
  1117. }
  1118. }
  1119. for(i=0; names[i].name; i++){
  1120. if((t = alpha(s, names[i].name))){
  1121. if(*t){
  1122. fprint(2, "syntax error in type\n");
  1123. return;
  1124. }
  1125. if(doreset)
  1126. reset();
  1127. loadtype(names[i].type);
  1128. goto Print;
  1129. }
  1130. }
  1131. switch(s[0]){
  1132. case '"':
  1133. starts = ++s;
  1134. while(*s != '"')
  1135. if(*s++ == 0){
  1136. fprint(2, "bad star name\n");
  1137. return;
  1138. }
  1139. *s = 0;
  1140. if(doreset)
  1141. reset();
  1142. j = nrec;
  1143. saoopen();
  1144. starts = fromgreek(starts);
  1145. for(i=0; i<NName; i++)
  1146. if(equal(starts, name[i].name)){
  1147. grow();
  1148. if(name[i].sao){
  1149. rec[j].type = NamedSAO;
  1150. rec[j].index = name[i].sao;
  1151. }
  1152. if(name[i].ngc){
  1153. rec[j].type = NamedNGC;
  1154. rec[j].index = name[i].ngc;
  1155. }
  1156. if(name[i].abell){
  1157. rec[j].type = NamedAbell;
  1158. rec[j].index = name[i].abell;
  1159. }
  1160. strcpy(rec[j].named.name, name[i].name);
  1161. j++;
  1162. }
  1163. if(parsename(starts))
  1164. for(i=0; i<NBayer; i++)
  1165. if(bayer[i].name[0]==parsed[0] &&
  1166. (bayer[i].name[1]==parsed[1] || parsed[1]==0) &&
  1167. bayer[i].name[2]==parsed[2]){
  1168. grow();
  1169. rec[j].type = NamedSAO;
  1170. rec[j].index = bayer[i].sao;
  1171. strncpy(rec[j].named.name, starts, sizeof(rec[j].named.name));
  1172. j++;
  1173. }
  1174. if(j == 0){
  1175. *s = '"';
  1176. goto NotFound;
  1177. }
  1178. break;
  1179. case '0': case '1': case '2': case '3': case '4':
  1180. case '5': case '6': case '7': case '8': case '9':
  1181. strtoul(s, &t, 10);
  1182. if(*t != 'h'){
  1183. BadCoords:
  1184. fprint(2, "bad coordinates %s\n", inputline);
  1185. break;
  1186. }
  1187. ra = DEG(getra(s));
  1188. while(*s && *s!=' ' && *s!='\t')
  1189. s++;
  1190. rah = ra/15;
  1191. ra = ra-rah*15;
  1192. ram = ra*4;
  1193. deg = strtol(s, &t, 10);
  1194. if(t == s)
  1195. goto BadCoords;
  1196. /* degree sign etc. is optional */
  1197. if((uint8_t)*t == L'°')
  1198. deg = DEG(getra(s));
  1199. if(doreset)
  1200. reset();
  1201. if(abs(deg)>=90 || rah>=24)
  1202. goto BadCoords;
  1203. if(!loadpatch(patch(rah, ram, deg)))
  1204. goto NotFound;
  1205. break;
  1206. default:
  1207. fprint(2, "unknown command %s\n", inputline);
  1208. return;
  1209. }
  1210. Print:
  1211. if(nrec == 0)
  1212. Bprint(&bout, "empty\n");
  1213. else if(nrec <= 2)
  1214. for(i=0; i<nrec; i++)
  1215. prrec(rec+i);
  1216. else
  1217. Bprint(&bout, "%ld items\n", nrec);
  1218. return;
  1219. NotFound:
  1220. fprint(2, "%s not found\n", inputline);
  1221. return;
  1222. }
  1223. char *ngctypes[] =
  1224. {
  1225. [Galaxy] = "Gx",
  1226. [PlanetaryN] = "Pl",
  1227. [OpenCl] = "OC",
  1228. [GlobularCl] = "Gb",
  1229. [DiffuseN] = "Nb",
  1230. [NebularCl] = "C+N",
  1231. [Asterism] = "Ast",
  1232. [Knot] = "Kt",
  1233. [Triple] = "***",
  1234. [Double] = "D*",
  1235. [Single] = "*",
  1236. [Uncertain] = "?",
  1237. [Nonexistent] = "-",
  1238. [Unknown] = " ",
  1239. [PlateDefect] = "PD",
  1240. };
  1241. char*
  1242. ngcstring(int d)
  1243. {
  1244. if(d<Galaxy || d>PlateDefect)
  1245. return "can't happen";
  1246. return ngctypes[d];
  1247. }
  1248. int16_t descindex[NINDEX];
  1249. void
  1250. printnames(Record *r)
  1251. {
  1252. int i, ok, done;
  1253. done = 0;
  1254. for(i=0; i<NName; i++){ /* stupid linear search! */
  1255. ok = 0;
  1256. if(r->type==SAO && r->index==name[i].sao)
  1257. ok = 1;
  1258. if(r->type==NGC && r->ngc.ngc==name[i].ngc)
  1259. ok = 1;
  1260. if(r->type==Abell && r->abell.abell==name[i].abell)
  1261. ok = 1;
  1262. if(ok){
  1263. if(done++ == 0)
  1264. Bprint(&bout, "\t");
  1265. Bprint(&bout, " \"%s\"", togreek(name[i].name));
  1266. }
  1267. }
  1268. if(done)
  1269. Bprint(&bout, "\n");
  1270. }
  1271. int
  1272. equal(char *s1, char *s2)
  1273. {
  1274. int c;
  1275. while(*s1){
  1276. if(*s1==' '){
  1277. while(*s1==' ')
  1278. s1++;
  1279. continue;
  1280. }
  1281. while(*s2==' ')
  1282. s2++;
  1283. c=*s2;
  1284. if('A'<=*s2 && *s2<='Z')
  1285. c^=' ';
  1286. if(*s1!=c)
  1287. return 0;
  1288. s1++, s2++;
  1289. }
  1290. return 1;
  1291. }
  1292. int
  1293. parsename(char *s)
  1294. {
  1295. char *blank;
  1296. int i;
  1297. blank = strchr(s, ' ');
  1298. if(blank==0 || strchr(blank+1, ' ') || strlen(blank+1)!=3)
  1299. return 0;
  1300. blank++;
  1301. parsed[0] = parsed[1] = parsed[2] = 0;
  1302. if('0'<=s[0] && s[0]<='9'){
  1303. i = atoi(s);
  1304. parsed[0] = i;
  1305. if(i > 100)
  1306. return 0;
  1307. }else{
  1308. for(i=1; i<=24; i++)
  1309. if(strncmp(greek[i], s, strlen(greek[i]))==0){
  1310. parsed[0]=100+i;
  1311. goto out;
  1312. }
  1313. return 0;
  1314. out:
  1315. if('0'<=s[strlen(greek[i])] && s[strlen(greek[i])]<='9')
  1316. parsed[1]=s[strlen(greek[i])]-'0';
  1317. }
  1318. for(i=1; i<=88; i++)
  1319. if(strcmp(constel[i], blank)==0){
  1320. parsed[2] = i;
  1321. return 1;
  1322. }
  1323. return 0;
  1324. }
  1325. char*
  1326. dist_grp(int dg)
  1327. {
  1328. switch(dg){
  1329. default:
  1330. return "unknown";
  1331. case 1:
  1332. return "13.3-14.0";
  1333. case 2:
  1334. return "14.1-14.8";
  1335. case 3:
  1336. return "14.9-15.6";
  1337. case 4:
  1338. return "15.7-16.4";
  1339. case 5:
  1340. return "16.5-17.2";
  1341. case 6:
  1342. return "17.3-18.0";
  1343. case 7:
  1344. return ">18.0";
  1345. }
  1346. }
  1347. char*
  1348. rich_grp(int dg)
  1349. {
  1350. switch(dg){
  1351. default:
  1352. return "unknown";
  1353. case 0:
  1354. return "30-40";
  1355. case 1:
  1356. return "50-79";
  1357. case 2:
  1358. return "80-129";
  1359. case 3:
  1360. return "130-199";
  1361. case 4:
  1362. return "200-299";
  1363. case 5:
  1364. return ">=300";
  1365. }
  1366. }
  1367. char*
  1368. nameof(Record *r)
  1369. {
  1370. NGCrec *n;
  1371. SAOrec *s;
  1372. Abellrec *a;
  1373. static char buf[128];
  1374. int i;
  1375. switch(r->type){
  1376. default:
  1377. return nil;
  1378. case SAO:
  1379. s = &r->sao;
  1380. if(s->name[0] == 0)
  1381. return nil;
  1382. if(s->name[0] >= 100){
  1383. i = snprint(buf, sizeof buf, "%C", greeklet[s->name[0]-100]);
  1384. if(s->name[1])
  1385. i += snprint(buf+i, sizeof buf-i, "%d", s->name[1]);
  1386. }else
  1387. i = snprint(buf, sizeof buf, " %d", s->name[0]);
  1388. snprint(buf+i, sizeof buf-i, " %s", constel[(uintptr_t)s->name[2]]);
  1389. break;
  1390. case NGC:
  1391. n = &r->ngc;
  1392. if(n->type >= Uncertain)
  1393. return nil;
  1394. if(n->ngc <= NNGC)
  1395. snprint(buf, sizeof buf, "NGC%4d ", n->ngc);
  1396. else
  1397. snprint(buf, sizeof buf, "IC%4d ", n->ngc-NNGC);
  1398. break;
  1399. case Abell:
  1400. a = &r->abell;
  1401. snprint(buf, sizeof buf, "Abell%4d", a->abell);
  1402. break;
  1403. }
  1404. return buf;
  1405. }
  1406. void
  1407. prrec(Record *r)
  1408. {
  1409. NGCrec *n;
  1410. SAOrec *s;
  1411. Abellrec *a;
  1412. Planetrec *p;
  1413. int i, rah, ram, dec, nn;
  1414. int32_t key;
  1415. if(r) switch(r->type){
  1416. default:
  1417. fprint(2, "can't prrec type %d\n", r->type);
  1418. exits("type");
  1419. case Planet:
  1420. p = &r->planet;
  1421. Bprint(&bout, "%s", p->name);
  1422. Bprint(&bout, "\t%s %s",
  1423. hms(angle(p->ra)),
  1424. dms(angle(p->dec)));
  1425. Bprint(&bout, " %3.2f° %3.2f°",
  1426. p->az/(double)MILLIARCSEC, p->alt/(double)MILLIARCSEC);
  1427. Bprint(&bout, " %s",
  1428. ms(angle(p->semidiam)));
  1429. if(r->index <= 1)
  1430. Bprint(&bout, " %g", p->phase);
  1431. Bprint(&bout, "\n");
  1432. break;
  1433. case NGC:
  1434. n = &r->ngc;
  1435. if(n->ngc <= NNGC)
  1436. Bprint(&bout, "NGC%4d ", n->ngc);
  1437. else
  1438. Bprint(&bout, "IC%4d ", n->ngc-NNGC);
  1439. Bprint(&bout, "%s ", ngcstring(n->type));
  1440. if(n->mag == UNKNOWNMAG)
  1441. Bprint(&bout, "----");
  1442. else
  1443. Bprint(&bout, "%.1f%c", n->mag/10.0, n->magtype);
  1444. Bprint(&bout, "\t%s %s\t%c%.1f'\n",
  1445. hm(angle(n->ra)),
  1446. dm(angle(n->dec)),
  1447. n->diamlim,
  1448. DEG(angle(n->diam))*60.);
  1449. prdesc(n->desc, desctab, descindex);
  1450. printnames(r);
  1451. break;
  1452. case Abell:
  1453. a = &r->abell;
  1454. Bprint(&bout, "Abell%4d %.1f %.2f° %dMpc", a->abell, a->mag10/10.0,
  1455. DEG(angle(a->rad)), a->dist);
  1456. Bprint(&bout, "\t%s %s\t%.2f %.2f\n",
  1457. hm(angle(a->ra)),
  1458. dm(angle(a->dec)),
  1459. DEG(angle(a->glat)),
  1460. DEG(angle(a->glong)));
  1461. Bprint(&bout, "\tdist grp: %s rich grp: %s %d galaxies/°²\n",
  1462. dist_grp(a->distgrp),
  1463. rich_grp(a->richgrp),
  1464. a->pop);
  1465. printnames(r);
  1466. break;
  1467. case SAO:
  1468. s = &r->sao;
  1469. Bprint(&bout, "SAO%6ld ", r->index);
  1470. if(s->mag==UNKNOWNMAG)
  1471. Bprint(&bout, "---");
  1472. else
  1473. Bprint(&bout, "%.1f", s->mag/10.0);
  1474. if(s->mpg==UNKNOWNMAG)
  1475. Bprint(&bout, ",---");
  1476. else
  1477. Bprint(&bout, ",%.1f", s->mpg/10.0);
  1478. Bprint(&bout, " %s %s %.4fs %.3f\"",
  1479. hms(angle(s->ra)),
  1480. dms(angle(s->dec)),
  1481. DEG(angle(s->dra))*(4*60),
  1482. DEG(angle(s->ddec))*(60*60));
  1483. Bprint(&bout, " %.3s %c %.2s %ld %d",
  1484. s->spec, s->code, s->compid, s->hd, s->hdcode);
  1485. if(s->name[0])
  1486. Bprint(&bout, " \"%s\"", nameof(r));
  1487. Bprint(&bout, "\n");
  1488. printnames(r);
  1489. break;
  1490. case Patch:
  1491. radec(r->index, &rah, &ram, &dec);
  1492. Bprint(&bout, "%dh%dm %d°", rah, ram, dec);
  1493. key = r->patch.key[0];
  1494. Bprint(&bout, " %s", constel[key&0xFF]);
  1495. if((key>>=8) & 0xFF)
  1496. Bprint(&bout, " %s", constel[key&0xFF]);
  1497. if((key>>=8) & 0xFF)
  1498. Bprint(&bout, " %s", constel[key&0xFF]);
  1499. if((key>>=8) & 0xFF)
  1500. Bprint(&bout, " %s", constel[key&0xFF]);
  1501. for(i=1; i<r->patch.nkey; i++){
  1502. key = r->patch.key[i];
  1503. switch(key&0x3F){
  1504. case SAO:
  1505. Bprint(&bout, " SAO%ld", (key>>8)&0xFFFFFF);
  1506. break;
  1507. case Abell:
  1508. Bprint(&bout, " Abell%ld", (key>>8)&0xFFFFFF);
  1509. break;
  1510. default: /* NGC */
  1511. nn = (key>>16)&0xFFFF;
  1512. if(nn > NNGC)
  1513. Bprint(&bout, " IC%d", nn-NNGC);
  1514. else
  1515. Bprint(&bout, " NGC%d", nn);
  1516. Bprint(&bout, "(%s)", ngcstring(key&0x3F));
  1517. break;
  1518. }
  1519. }
  1520. Bprint(&bout, "\n");
  1521. break;
  1522. case NGCN:
  1523. if(r->index <= NNGC)
  1524. Bprint(&bout, "NGC%ld\n", r->index);
  1525. else
  1526. Bprint(&bout, "IC%ld\n", r->index-NNGC);
  1527. break;
  1528. case NamedSAO:
  1529. Bprint(&bout, "SAO%ld \"%s\"\n", r->index, togreek(r->named.name));
  1530. break;
  1531. case NamedNGC:
  1532. if(r->index <= NNGC)
  1533. Bprint(&bout, "NGC%ld \"%s\"\n", r->index, togreek(r->named.name));
  1534. else
  1535. Bprint(&bout, "IC%ld \"%s\"\n", r->index-NNGC, togreek(r->named.name));
  1536. break;
  1537. case NamedAbell:
  1538. Bprint(&bout, "Abell%ld \"%s\"\n", r->index, togreek(r->named.name));
  1539. break;
  1540. case PatchC:
  1541. radec(r->index, &rah, &ram, &dec);
  1542. Bprint(&bout, "%dh%dm %d\n", rah, ram, dec);
  1543. break;
  1544. }
  1545. }