plot.c 21 KB

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