plot.c 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953
  1. #include <u.h>
  2. #include <libc.h>
  3. #include <bio.h>
  4. #include <draw.h>
  5. #include <event.h>
  6. #include <ctype.h>
  7. #include "map.h"
  8. #undef RAD
  9. #undef TWOPI
  10. #include "sky.h"
  11. /* convert to milliarcsec */
  12. static long c = MILLIARCSEC; /* 1 degree */
  13. static long m5 = 1250*60*60; /* 5 minutes of ra */
  14. DAngle ramin;
  15. DAngle ramax;
  16. DAngle decmin;
  17. DAngle decmax;
  18. int folded;
  19. Image *grey;
  20. Image *alphagrey;
  21. Image *green;
  22. Image *lightblue;
  23. Image *lightgrey;
  24. Image *ocstipple;
  25. Image *suncolor;
  26. Image *mooncolor;
  27. Image *shadowcolor;
  28. Image *mercurycolor;
  29. Image *venuscolor;
  30. Image *marscolor;
  31. Image *jupitercolor;
  32. Image *saturncolor;
  33. Image *uranuscolor;
  34. Image *neptunecolor;
  35. Image *plutocolor;
  36. Image *cometcolor;
  37. Planetrec *planet;
  38. long mapx0, mapy0;
  39. long mapra, mapdec;
  40. double mylat, mylon, mysid;
  41. double mapscale;
  42. double maps;
  43. int (*projection)(struct place*, double*, double*);
  44. char *fontname = "/lib/font/bit/lucida/unicode.6.font";
  45. /* types Coord and Loc correspond to types in map(3) thus:
  46. Coord == struct coord;
  47. Loc == struct place, except longitudes are measured
  48. positive east for Loc and west for struct place
  49. */
  50. typedef struct Xyz Xyz;
  51. typedef struct coord Coord;
  52. typedef struct Loc Loc;
  53. struct Xyz{
  54. double x,y,z;
  55. };
  56. struct Loc{
  57. Coord nlat, elon;
  58. };
  59. Xyz north = { 0, 0, 1 };
  60. int
  61. plotopen(void)
  62. {
  63. if(display != nil)
  64. return 1;
  65. display = initdisplay(nil, nil, drawerror);
  66. if(display == nil){
  67. fprint(2, "initdisplay failed: %r\n");
  68. return -1;
  69. }
  70. grey = allocimage(display, Rect(0, 0, 1, 1), CMAP8, 1, 0x777777FF);
  71. lightgrey = allocimage(display, Rect(0, 0, 1, 1), CMAP8, 1, 0xAAAAAAFF);
  72. alphagrey = allocimage(display, Rect(0, 0, 2, 2), RGBA32, 1, 0x77777777);
  73. green = allocimage(display, Rect(0, 0, 1, 1), CMAP8, 1, 0x00AA00FF);
  74. lightblue = allocimage(display, Rect(0, 0, 1, 1), CMAP8, 1, 0x009EEEFF);
  75. ocstipple = allocimage(display, Rect(0, 0, 2, 2), CMAP8, 1, 0xAAAAAAFF);
  76. draw(ocstipple, Rect(0, 0, 1, 1), display->black, nil, ZP);
  77. draw(ocstipple, Rect(1, 1, 2, 2), display->black, nil, ZP);
  78. suncolor = allocimage(display, Rect(0, 0, 1, 1), RGBA32, 1, 0xFFFF77FF);
  79. mooncolor = allocimage(display, Rect(0, 0, 1, 1), RGBA32, 1, 0xAAAAAAFF);
  80. shadowcolor = allocimage(display, Rect(0, 0, 1, 1), RGBA32, 1, 0x00000055);
  81. mercurycolor = allocimage(display, Rect(0, 0, 1, 1), RGBA32, 1, 0xFFAAAAFF);
  82. venuscolor = allocimage(display, Rect(0, 0, 1, 1), RGBA32, 1, 0xAAAAFFFF);
  83. marscolor = allocimage(display, Rect(0, 0, 1, 1), RGBA32, 1, 0xFF5555FF);
  84. jupitercolor = allocimage(display, Rect(0, 0, 1, 1), RGBA32, 1, 0xFFFFAAFF);
  85. saturncolor = allocimage(display, Rect(0, 0, 1, 1), RGBA32, 1, 0xAAFFAAFF);
  86. uranuscolor = allocimage(display, Rect(0, 0, 1, 1), RGBA32, 1, 0x77DDDDFF);
  87. neptunecolor = allocimage(display, Rect(0, 0, 1, 1), RGBA32, 1, 0x77FF77FF);
  88. plutocolor = allocimage(display, Rect(0, 0, 1, 1), RGBA32, 1, 0x7777FFFF);
  89. cometcolor = allocimage(display, Rect(0, 0, 1, 1), RGBA32, 1, 0xAAAAFFFF);
  90. font = openfont(display, fontname);
  91. if(font == nil)
  92. fprint(2, "warning: no font %s: %r\n", fontname);
  93. return 1;
  94. }
  95. /*
  96. * Function heavens() for setting up observer-eye-view
  97. * sky charts, plus subsidiary functions.
  98. * Written by Doug McIlroy.
  99. */
  100. /* heavens(nlato, wlono, nlatc, wlonc) sets up a map(3)-style
  101. coordinate change (by calling orient()) and returns a
  102. projection function heavens for calculating a star map
  103. centered on nlatc,wlonc and rotated so it will appear
  104. upright as seen by a ground observer at nlato,wlono.
  105. all coordinates (north latitude and west longitude)
  106. are in degrees.
  107. */
  108. Coord
  109. mkcoord(double degrees)
  110. {
  111. Coord c;
  112. c.l = degrees*PI/180;
  113. c.s = sin(c.l);
  114. c.c = cos(c.l);
  115. return c;
  116. }
  117. Xyz
  118. ptov(struct place p)
  119. {
  120. Xyz v;
  121. v.z = p.nlat.s;
  122. v.x = p.nlat.c * p.wlon.c;
  123. v.y = -p.nlat.c * p.wlon.s;
  124. return v;
  125. }
  126. double
  127. dot(Xyz a, Xyz b)
  128. {
  129. return a.x*b.x + a.y*b.y + a.z*b.z;
  130. }
  131. Xyz
  132. cross(Xyz a, Xyz b)
  133. {
  134. Xyz v;
  135. v.x = a.y*b.z - a.z*b.y;
  136. v.y = a.z*b.x - a.x*b.z;
  137. v.z = a.x*b.y - a.y*b.x;
  138. return v;
  139. }
  140. double
  141. len(Xyz a)
  142. {
  143. return sqrt(dot(a, a));
  144. }
  145. /* An azimuth vector from a to b is a tangent to
  146. the sphere at a pointing along the (shorter)
  147. great-circle direction to b. It lies in the
  148. plane of the vectors a and b, is perpendicular
  149. to a, and has a positive compoent along b,
  150. provided a and b span a 2-space. Otherwise
  151. it is null. (aXb)Xa, where X denotes cross
  152. product, is such a vector. */
  153. Xyz
  154. azvec(Xyz a, Xyz b)
  155. {
  156. return cross(cross(a,b), a);
  157. }
  158. /* Find the azimuth of point b as seen
  159. from point a, given that a is distinct
  160. from either pole and from b */
  161. double
  162. azimuth(Xyz a, Xyz b)
  163. {
  164. Xyz aton = azvec(a,north);
  165. Xyz atob = azvec(a,b);
  166. double lenaton = len(aton);
  167. double lenatob = len(atob);
  168. double az = acos(dot(aton,atob)/(lenaton*lenatob));
  169. if(dot(b,cross(north,a)) < 0)
  170. az = -az;
  171. return az;
  172. }
  173. /* Find the rotation (3rd argument of orient() in the
  174. map projection package) for the map described
  175. below. The return is radians; it must be converted
  176. to degrees for orient().
  177. */
  178. double
  179. rot(struct place center, struct place zenith)
  180. {
  181. Xyz cen = ptov(center);
  182. Xyz zen = ptov(zenith);
  183. if(cen.z > 1-FUZZ) /* center at N pole */
  184. return PI + zenith.wlon.l;
  185. if(cen.z < FUZZ-1) /* at S pole */
  186. return -zenith.wlon.l;
  187. if(fabs(dot(cen,zen)) > 1-FUZZ) /* at zenith */
  188. return 0;
  189. return azimuth(cen, zen);
  190. }
  191. int (*
  192. heavens(double zlatdeg, double zlondeg, double clatdeg, double clondeg))(Loc*, double*, double*)
  193. {
  194. struct place center;
  195. struct place zenith;
  196. center.nlat = mkcoord(clatdeg);
  197. center.wlon = mkcoord(clondeg);
  198. zenith.nlat = mkcoord(zlatdeg);
  199. zenith.wlon = mkcoord(zlondeg);
  200. projection = stereographic();
  201. orient(clatdeg, clondeg, rot(center, zenith)*180/PI);
  202. return projection;
  203. }
  204. int
  205. maptoxy(long ra, long dec, double *x, double *y)
  206. {
  207. double lat, lon;
  208. struct place pl;
  209. lat = angle(dec);
  210. lon = angle(ra);
  211. pl.nlat.l = lat;
  212. pl.nlat.s = sin(lat);
  213. pl.nlat.c = cos(lat);
  214. pl.wlon.l = lon;
  215. pl.wlon.s = sin(lon);
  216. pl.wlon.c = cos(lon);
  217. normalize(&pl);
  218. return projection(&pl, x, y);
  219. }
  220. /* end of 'heavens' section */
  221. int
  222. setmap(long ramin, long ramax, long decmin, long decmax, Rectangle r, int zenithup)
  223. {
  224. int c;
  225. double minx, maxx, miny, maxy;
  226. c = 1000*60*60;
  227. mapra = ramax/2+ramin/2;
  228. mapdec = decmax/2+decmin/2;
  229. if(zenithup)
  230. projection = heavens(mylat, mysid, (double)mapdec/c, (double)mapra/c);
  231. else{
  232. orient((double)mapdec/c, (double)mapra/c, 0.);
  233. projection = stereographic();
  234. }
  235. mapx0 = (r.max.x+r.min.x)/2;
  236. mapy0 = (r.max.y+r.min.y)/2;
  237. maps = ((double)Dy(r))/(double)(decmax-decmin);
  238. if(maptoxy(ramin, decmin, &minx, &miny) < 0)
  239. return -1;
  240. if(maptoxy(ramax, decmax, &maxx, &maxy) < 0)
  241. return -1;
  242. /*
  243. * It's tricky to get the scale right. This noble attempt scales
  244. * to fit the lengths of the sides of the rectangle.
  245. */
  246. mapscale = Dx(r)/(minx-maxx);
  247. if(mapscale > Dy(r)/(maxy-miny))
  248. mapscale = Dy(r)/(maxy-miny);
  249. /*
  250. * near the pole It's not a rectangle, though, so this scales
  251. * to fit the corners of the trapezoid (a triangle at the pole).
  252. */
  253. mapscale *= (cos(angle(mapdec))+1.)/2;
  254. if(maxy < miny){
  255. /* upside down, between zenith and pole */
  256. fprint(2, "reverse plot\n");
  257. mapscale = -mapscale;
  258. }
  259. return 1;
  260. }
  261. Point
  262. map(long ra, long dec)
  263. {
  264. double x, y;
  265. Point p;
  266. if(maptoxy(ra, dec, &x, &y) > 0){
  267. p.x = mapscale*x + mapx0;
  268. p.y = mapscale*-y + mapy0;
  269. }else{
  270. p.x = -100;
  271. p.y = -100;
  272. }
  273. return p;
  274. }
  275. int
  276. dsize(int mag) /* mag is 10*magnitude; return disc size */
  277. {
  278. double d;
  279. mag += 25; /* make mags all positive; sirius is -1.6m */
  280. d = (130-mag)/10;
  281. /* if plate scale is huge, adjust */
  282. if(maps < 100.0/MILLIARCSEC)
  283. d *= .71;
  284. if(maps < 50.0/MILLIARCSEC)
  285. d *= .71;
  286. return d;
  287. }
  288. void
  289. drawname(Image *scr, Image *col, char *s, int ra, int dec)
  290. {
  291. Point p;
  292. if(font == nil)
  293. return;
  294. p = addpt(map(ra, dec), Pt(4, -1)); /* font has huge ascent */
  295. string(scr, p, col, ZP, font, s);
  296. }
  297. int
  298. npixels(DAngle diam)
  299. {
  300. Point p0, p1;
  301. diam = DEG(angle(diam)*MILLIARCSEC); /* diam in milliarcsec */
  302. diam /= 2; /* radius */
  303. /* convert to plate scale */
  304. /* BUG: need +100 because we sometimes crash in library if we plot the exact center */
  305. p0 = map(mapra+100, mapdec);
  306. p1 = map(mapra+100+diam, mapdec);
  307. return hypot(p0.x-p1.x, p0.y-p1.y);
  308. }
  309. void
  310. drawdisc(Image *scr, DAngle semidiam, int ring, Image *color, Point pt, char *s)
  311. {
  312. int d;
  313. d = npixels(semidiam*2);
  314. if(d < 5)
  315. d = 5;
  316. fillellipse(scr, pt, d, d, color, ZP);
  317. if(ring == 1)
  318. ellipse(scr, pt, 5*d/2, d/2, 0, color, ZP);
  319. if(ring == 2)
  320. ellipse(scr, pt, d, d, 0, grey, ZP);
  321. if(s){
  322. d = stringwidth(font, s);
  323. pt.x -= d/2;
  324. pt.y -= font->height/2 + 1;
  325. string(scr, pt, display->black, ZP, font, s);
  326. }
  327. }
  328. void
  329. drawplanet(Image *scr, Planetrec *p, Point pt)
  330. {
  331. if(strcmp(p->name, "sun") == 0){
  332. drawdisc(scr, p->semidiam, 0, suncolor, pt, nil);
  333. return;
  334. }
  335. if(strcmp(p->name, "moon") == 0){
  336. drawdisc(scr, p->semidiam, 0, mooncolor, pt, nil);
  337. return;
  338. }
  339. if(strcmp(p->name, "shadow") == 0){
  340. drawdisc(scr, p->semidiam, 2, shadowcolor, pt, nil);
  341. return;
  342. }
  343. if(strcmp(p->name, "mercury") == 0){
  344. drawdisc(scr, p->semidiam, 0, mercurycolor, pt, "m");
  345. return;
  346. }
  347. if(strcmp(p->name, "venus") == 0){
  348. drawdisc(scr, p->semidiam, 0, venuscolor, pt, "v");
  349. return;
  350. }
  351. if(strcmp(p->name, "mars") == 0){
  352. drawdisc(scr, p->semidiam, 0, marscolor, pt, "M");
  353. return;
  354. }
  355. if(strcmp(p->name, "jupiter") == 0){
  356. drawdisc(scr, p->semidiam, 0, jupitercolor, pt, "J");
  357. return;
  358. }
  359. if(strcmp(p->name, "saturn") == 0){
  360. drawdisc(scr, p->semidiam, 1, saturncolor, pt, "S");
  361. return;
  362. }
  363. if(strcmp(p->name, "uranus") == 0){
  364. drawdisc(scr, p->semidiam, 0, uranuscolor, pt, "U");
  365. return;
  366. }
  367. if(strcmp(p->name, "neptune") == 0){
  368. drawdisc(scr, p->semidiam, 0, neptunecolor, pt, "N");
  369. return;
  370. }
  371. if(strcmp(p->name, "pluto") == 0){
  372. drawdisc(scr, p->semidiam, 0, plutocolor, pt, "P");
  373. return;
  374. }
  375. if(strcmp(p->name, "comet") == 0){
  376. drawdisc(scr, p->semidiam, 0, cometcolor, pt, "C");
  377. return;
  378. }
  379. pt.x -= stringwidth(font, p->name)/2;
  380. pt.y -= font->height/2;
  381. string(scr, pt, grey, ZP, font, p->name);
  382. }
  383. void
  384. tolast(char *name)
  385. {
  386. int i, nlast;
  387. Record *r, rr;
  388. /* stop early to simplify inner loop adjustment */
  389. nlast = 0;
  390. for(i=0,r=rec; i<nrec-nlast; i++,r++)
  391. if(r->type == Planet)
  392. if(name==nil || strcmp(r->planet.name, name)==0){
  393. rr = *r;
  394. memmove(rec+i, rec+i+1, (nrec-i-1)*sizeof(Record));
  395. rec[nrec-1] = rr;
  396. --i;
  397. --r;
  398. nlast++;
  399. }
  400. }
  401. int
  402. bbox(long extrara, long extradec, int quantize)
  403. {
  404. int i;
  405. Record *r;
  406. int ra, dec;
  407. int rah, ram, d1, d2;
  408. double r0;
  409. ramin = 0x7FFFFFFF;
  410. ramax = -0x7FFFFFFF;
  411. decmin = 0x7FFFFFFF;
  412. decmax = -0x7FFFFFFF;
  413. for(i=0,r=rec; i<nrec; i++,r++){
  414. if(r->type == Patch){
  415. radec(r->index, &rah, &ram, &dec);
  416. ra = 15*rah+ram/4;
  417. r0 = c/cos(dec*PI/180);
  418. ra *= c;
  419. dec *= c;
  420. if(dec == 0)
  421. d1 = c, d2 = c;
  422. else if(dec < 0)
  423. d1 = c, d2 = 0;
  424. else
  425. d1 = 0, d2 = c;
  426. }else if(r->type==SAO || r->type==NGC || r->type==Planet || r->type==Abell){
  427. ra = r->ngc.ra;
  428. dec = r->ngc.dec;
  429. d1 = 0, d2 = 0, r0 = 0;
  430. }else
  431. continue;
  432. if(dec+d2+extradec > decmax)
  433. decmax = dec+d2+extradec;
  434. if(dec-d1-extradec < decmin)
  435. decmin = dec-d1-extradec;
  436. if(folded){
  437. ra -= 180*c;
  438. if(ra < 0)
  439. ra += 360*c;
  440. }
  441. if(ra+r0+extrara > ramax)
  442. ramax = ra+r0+extrara;
  443. if(ra-extrara < ramin)
  444. ramin = ra-extrara;
  445. }
  446. if(decmax > 90*c)
  447. decmax = 90*c;
  448. if(decmin < -90*c)
  449. decmin = -90*c;
  450. if(ramin < 0)
  451. ramin += 360*c;
  452. if(ramax >= 360*c)
  453. ramax -= 360*c;
  454. if(quantize){
  455. /* quantize to degree boundaries */
  456. ramin -= ramin%m5;
  457. if(ramax%m5 != 0)
  458. ramax += m5-(ramax%m5);
  459. if(decmin > 0)
  460. decmin -= decmin%c;
  461. else
  462. decmin -= c - (-decmin)%c;
  463. if(decmax > 0){
  464. if(decmax%c != 0)
  465. decmax += c-(decmax%c);
  466. }else if(decmax < 0){
  467. if(decmax%c != 0)
  468. decmax += ((-decmax)%c);
  469. }
  470. }
  471. if(folded){
  472. if(ramax-ramin > 270*c){
  473. fprint(2, "ra range too wide %ld°\n", (ramax-ramin)/c);
  474. return -1;
  475. }
  476. }else if(ramax-ramin > 270*c){
  477. folded = 1;
  478. return bbox(0, 0, quantize);
  479. }
  480. return 1;
  481. }
  482. int
  483. inbbox(DAngle ra, DAngle dec)
  484. {
  485. int min;
  486. if(dec < decmin)
  487. return 0;
  488. if(dec > decmax)
  489. return 0;
  490. min = ramin;
  491. if(ramin > ramax){ /* straddling 0h0m */
  492. min -= 360*c;
  493. if(ra > 180*c)
  494. ra -= 360*c;
  495. }
  496. if(ra < min)
  497. return 0;
  498. if(ra > ramax)
  499. return 0;
  500. return 1;
  501. }
  502. int
  503. gridra(long mapdec)
  504. {
  505. mapdec = abs(mapdec)+c/2;
  506. mapdec /= c;
  507. if(mapdec < 60)
  508. return m5;
  509. if(mapdec < 80)
  510. return 2*m5;
  511. if(mapdec < 85)
  512. return 4*m5;
  513. return 8*m5;
  514. }
  515. #define GREY (nogrey? display->white : grey)
  516. void
  517. plot(char *flags)
  518. {
  519. int i, j, k;
  520. char *t;
  521. long x, y;
  522. int ra, dec;
  523. int m;
  524. Point p, pts[10];
  525. Record *r;
  526. Rectangle rect, r1;
  527. int dx, dy, nogrid, textlevel, nogrey, zenithup;
  528. Image *scr;
  529. char *name, buf[32];
  530. double v;
  531. if(plotopen() < 0)
  532. return;
  533. nogrid = 0;
  534. nogrey = 0;
  535. textlevel = 1;
  536. dx = 512;
  537. dy = 512;
  538. zenithup = 0;
  539. for(;;){
  540. if(t = alpha(flags, "nogrid")){
  541. nogrid = 1;
  542. flags = t;
  543. continue;
  544. }
  545. if((t = alpha(flags, "zenith")) || (t = alpha(flags, "zenithup")) ){
  546. zenithup = 1;
  547. flags = t;
  548. continue;
  549. }
  550. if((t = alpha(flags, "notext")) || (t = alpha(flags, "nolabel")) ){
  551. textlevel = 0;
  552. flags = t;
  553. continue;
  554. }
  555. if((t = alpha(flags, "alltext")) || (t = alpha(flags, "alllabel")) ){
  556. textlevel = 2;
  557. flags = t;
  558. continue;
  559. }
  560. if(t = alpha(flags, "dx")){
  561. dx = strtol(t, &t, 0);
  562. if(dx < 100){
  563. fprint(2, "dx %d too small (min 100) in plot\n", dx);
  564. return;
  565. }
  566. flags = skipbl(t);
  567. continue;
  568. }
  569. if(t = alpha(flags, "dy")){
  570. dy = strtol(t, &t, 0);
  571. if(dy < 100){
  572. fprint(2, "dy %d too small (min 100) in plot\n", dy);
  573. return;
  574. }
  575. flags = skipbl(t);
  576. continue;
  577. }
  578. if((t = alpha(flags, "nogrey")) || (t = alpha(flags, "nogray"))){
  579. nogrey = 1;
  580. flags = skipbl(t);
  581. continue;
  582. }
  583. if(*flags){
  584. fprint(2, "syntax error in plot\n");
  585. return;
  586. }
  587. break;
  588. }
  589. flatten();
  590. folded = 0;
  591. if(bbox(0, 0, 1) < 0)
  592. return;
  593. if(ramax-ramin<100 || decmax-decmin<100){
  594. fprint(2, "plot too small\n");
  595. return;
  596. }
  597. scr = allocimage(display, Rect(0, 0, dx, dy), RGB24, 0, DBlack);
  598. if(scr == nil){
  599. fprint(2, "can't allocate image: %r\n");
  600. return;
  601. }
  602. rect = scr->r;
  603. rect.min.x += 16;
  604. rect = insetrect(rect, 40);
  605. if(setmap(ramin, ramax, decmin, decmax, rect, zenithup) < 0){
  606. fprint(2, "can't set up map coordinates\n");
  607. return;
  608. }
  609. if(!nogrid){
  610. for(x=ramin; ; ){
  611. for(j=0; j<nelem(pts); j++){
  612. /* use double to avoid overflow */
  613. v = (double)j / (double)(nelem(pts)-1);
  614. v = decmin + v*(decmax-decmin);
  615. pts[j] = map(x, v);
  616. }
  617. bezspline(scr, pts, nelem(pts), Endsquare, Endsquare, 0, GREY, ZP);
  618. ra = x;
  619. if(folded){
  620. ra -= 180*c;
  621. if(ra < 0)
  622. ra += 360*c;
  623. }
  624. p = pts[0];
  625. p.x -= stringwidth(font, hm5(angle(ra)))/2;
  626. string(scr, p, GREY, ZP, font, hm5(angle(ra)));
  627. p = pts[nelem(pts)-1];
  628. p.x -= stringwidth(font, hm5(angle(ra)))/2;
  629. p.y -= font->height;
  630. string(scr, p, GREY, ZP, font, hm5(angle(ra)));
  631. if(x == ramax)
  632. break;
  633. x += gridra(mapdec);
  634. if(x > ramax)
  635. x = ramax;
  636. }
  637. for(y=decmin; y<=decmax; y+=c){
  638. for(j=0; j<nelem(pts); j++){
  639. /* use double to avoid overflow */
  640. v = (double)j / (double)(nelem(pts)-1);
  641. v = ramin + v*(ramax-ramin);
  642. pts[j] = map(v, y);
  643. }
  644. bezspline(scr, pts, nelem(pts), Endsquare, Endsquare, 0, GREY, ZP);
  645. p = pts[0];
  646. p.x += 3;
  647. p.y -= font->height/2;
  648. string(scr, p, GREY, ZP, font, deg(angle(y)));
  649. p = pts[nelem(pts)-1];
  650. p.x -= 3+stringwidth(font, deg(angle(y)));
  651. p.y -= font->height/2;
  652. string(scr, p, GREY, ZP, font, deg(angle(y)));
  653. }
  654. }
  655. /* reorder to get planets in front of stars */
  656. tolast(nil);
  657. tolast("moon"); /* moon is in front of everything... */
  658. tolast("shadow"); /* ... except the shadow */
  659. for(i=0,r=rec; i<nrec; i++,r++){
  660. dec = r->ngc.dec;
  661. ra = r->ngc.ra;
  662. if(folded){
  663. ra -= 180*c;
  664. if(ra < 0)
  665. ra += 360*c;
  666. }
  667. if(textlevel){
  668. name = nameof(r);
  669. if(name==nil && textlevel>1 && r->type==SAO){
  670. snprint(buf, sizeof buf, "SAO%ld", r->index);
  671. name = buf;
  672. }
  673. if(name)
  674. drawname(scr, nogrey? display->white : alphagrey, name, ra, dec);
  675. }
  676. if(r->type == Planet){
  677. drawplanet(scr, &r->planet, map(ra, dec));
  678. continue;
  679. }
  680. if(r->type == SAO){
  681. m = r->sao.mag;
  682. if(m == UNKNOWNMAG)
  683. m = r->sao.mpg;
  684. if(m == UNKNOWNMAG)
  685. continue;
  686. m = dsize(m);
  687. if(m < 3)
  688. fillellipse(scr, map(ra, dec), m, m, nogrey? display->white : lightgrey, ZP);
  689. else{
  690. ellipse(scr, map(ra, dec), m+1, m+1, 0, display->black, ZP);
  691. fillellipse(scr, map(ra, dec), m, m, display->white, ZP);
  692. }
  693. continue;
  694. }
  695. if(r->type == Abell){
  696. ellipse(scr, addpt(map(ra, dec), Pt(-3, 2)), 2, 1, 0, lightblue, ZP);
  697. ellipse(scr, addpt(map(ra, dec), Pt(3, 2)), 2, 1, 0, lightblue, ZP);
  698. ellipse(scr, addpt(map(ra, dec), Pt(0, -2)), 1, 2, 0, lightblue, ZP);
  699. continue;
  700. }
  701. switch(r->ngc.type){
  702. case Galaxy:
  703. j = npixels(r->ngc.diam);
  704. if(j < 4)
  705. j = 4;
  706. if(j > 10)
  707. k = j/3;
  708. else
  709. k = j/2;
  710. ellipse(scr, map(ra, dec), j, k, 0, lightblue, ZP);
  711. break;
  712. case PlanetaryN:
  713. p = map(ra, dec);
  714. j = npixels(r->ngc.diam);
  715. if(j < 3)
  716. j = 3;
  717. ellipse(scr, p, j, j, 0, green, ZP);
  718. line(scr, Pt(p.x, p.y+j+1), Pt(p.x, p.y+j+4),
  719. Endsquare, Endsquare, 0, green, ZP);
  720. line(scr, Pt(p.x, p.y-(j+1)), Pt(p.x, p.y-(j+4)),
  721. Endsquare, Endsquare, 0, green, ZP);
  722. line(scr, Pt(p.x+j+1, p.y), Pt(p.x+j+4, p.y),
  723. Endsquare, Endsquare, 0, green, ZP);
  724. line(scr, Pt(p.x-(j+1), p.y), Pt(p.x-(j+4), p.y),
  725. Endsquare, Endsquare, 0, green, ZP);
  726. break;
  727. case DiffuseN:
  728. case NebularCl:
  729. p = map(ra, dec);
  730. j = npixels(r->ngc.diam);
  731. if(j < 4)
  732. j = 4;
  733. r1.min = Pt(p.x-j, p.y-j);
  734. r1.max = Pt(p.x+j, p.y+j);
  735. if(r->ngc.type != DiffuseN)
  736. draw(scr, r1, ocstipple, ocstipple, ZP);
  737. line(scr, Pt(p.x-j, p.y-j), Pt(p.x+j, p.y-j),
  738. Endsquare, Endsquare, 0, green, ZP);
  739. line(scr, Pt(p.x-j, p.y+j), Pt(p.x+j, p.y+j),
  740. Endsquare, Endsquare, 0, green, ZP);
  741. line(scr, Pt(p.x-j, p.y-j), Pt(p.x-j, p.y+j),
  742. Endsquare, Endsquare, 0, green, ZP);
  743. line(scr, Pt(p.x+j, p.y-j), Pt(p.x+j, p.y+j),
  744. Endsquare, Endsquare, 0, green, ZP);
  745. break;
  746. case OpenCl:
  747. p = map(ra, dec);
  748. j = npixels(r->ngc.diam);
  749. if(j < 4)
  750. j = 4;
  751. fillellipse(scr, p, j, j, ocstipple, ZP);
  752. break;
  753. case GlobularCl:
  754. j = npixels(r->ngc.diam);
  755. if(j < 4)
  756. j = 4;
  757. p = map(ra, dec);
  758. ellipse(scr, p, j, j, 0, lightgrey, ZP);
  759. line(scr, Pt(p.x-(j-1), p.y), Pt(p.x+j, p.y),
  760. Endsquare, Endsquare, 0, lightgrey, ZP);
  761. line(scr, Pt(p.x, p.y-(j-1)), Pt(p.x, p.y+j),
  762. Endsquare, Endsquare, 0, lightgrey, ZP);
  763. break;
  764. }
  765. }
  766. flushimage(display, 1);
  767. displayimage(scr);
  768. }
  769. int
  770. runcommand(char *command, int p[2])
  771. {
  772. switch(rfork(RFPROC|RFFDG|RFNOWAIT)){
  773. case -1:
  774. return -1;
  775. default:
  776. break;
  777. case 0:
  778. dup(p[1], 1);
  779. close(p[0]);
  780. close(p[1]);
  781. execl("/bin/rc", "rc", "-c", command, nil);
  782. fprint(2, "can't exec %s: %r", command);
  783. exits(nil);
  784. }
  785. return 1;
  786. }
  787. void
  788. parseplanet(char *line, Planetrec *p)
  789. {
  790. char *fld[6];
  791. int i, nfld;
  792. char *s;
  793. if(line[0] == '\0')
  794. return;
  795. line[10] = '\0'; /* terminate name */
  796. s = strrchr(line, ' ');
  797. if(s == nil)
  798. s = line;
  799. else
  800. s++;
  801. strcpy(p->name, s);
  802. for(i=0; s[i]!='\0'; i++)
  803. p->name[i] = tolower(s[i]);
  804. p->name[i] = '\0';
  805. nfld = getfields(line+11, fld, nelem(fld), 1, " ");
  806. p->ra = dangle(getra(fld[0]));
  807. p->dec = dangle(getra(fld[1]));
  808. p->az = atof(fld[2])*MILLIARCSEC;
  809. p->alt = atof(fld[3])*MILLIARCSEC;
  810. p->semidiam = atof(fld[4])*1000;
  811. if(nfld > 5)
  812. p->phase = atof(fld[5]);
  813. else
  814. p->phase = 0;
  815. }
  816. void
  817. astro(char *flags, int initial)
  818. {
  819. int p[2];
  820. int i, n, np;
  821. char cmd[256], buf[4096], *lines[20], *fld[10];
  822. snprint(cmd, sizeof cmd, "/bin/astro -p %s", flags);
  823. if(pipe(p) < 0){
  824. fprint(2, "can't pipe: %r\n");
  825. return;
  826. }
  827. if(runcommand(cmd, p) < 0){
  828. close(p[0]);
  829. close(p[1]);
  830. fprint(2, "can't run astro: %r");
  831. return;
  832. }
  833. close(p[1]);
  834. n = readn(p[0], buf, sizeof buf-1);
  835. if(n <= 0){
  836. fprint(2, "no data from astro\n");
  837. return;
  838. }
  839. if(!initial)
  840. Bwrite(&bout, buf, n);
  841. buf[n] = '\0';
  842. np = getfields(buf, lines, nelem(lines), 0, "\n");
  843. if(np <= 1){
  844. fprint(2, "astro: not enough output\n");
  845. return;
  846. }
  847. Bprint(&bout, "%s\n", lines[0]);
  848. Bflush(&bout);
  849. /* get latitude and longitude */
  850. if(getfields(lines[0], fld, nelem(fld), 1, " ") < 8)
  851. fprint(2, "astro: can't read longitude: too few fields\n");
  852. else{
  853. mysid = getra(fld[5])*180./PI;
  854. mylat = getra(fld[6])*180./PI;
  855. mylon = getra(fld[7])*180./PI;
  856. }
  857. /*
  858. * Each time we run astro, we generate a new planet list
  859. * so multiple appearances of a planet may exist as we plot
  860. * its motion over time.
  861. */
  862. planet = malloc(NPlanet*sizeof planet[0]);
  863. if(planet == nil){
  864. fprint(2, "astro: malloc failed: %r\n");
  865. exits("malloc");
  866. }
  867. memset(planet, 0, NPlanet*sizeof planet[0]);
  868. for(i=1; i<np; i++)
  869. parseplanet(lines[i], &planet[i-1]);
  870. }