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