plot.c 21 KB

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