map.c 25 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229
  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 <stdio.h>
  12. #include "map.h"
  13. #include "iplot.h"
  14. #define NVERT 20 /* max number of vertices in a -v polygon */
  15. #define HALFWIDTH 8192 /* output scaled to fit in -HALFWIDTH,HALFWIDTH */
  16. #define LONGLINES (HALFWIDTH*4) /* permissible segment lengths */
  17. #define SHORTLINES (HALFWIDTH/8)
  18. #define SCALERATIO 10 /* of abs to rel data (see map(5)) */
  19. #define RESOL 2. /* coarsest resolution for tracing grid (degrees) */
  20. #define TWO_THRD 0.66666666666666667
  21. int normproj(double, double, double *, double *);
  22. int posproj(double, double, double *, double *);
  23. int picut(struct place *, struct place *, double *);
  24. double reduce(double);
  25. int16_t getshort(FILE *);
  26. char *mapindex(char *);
  27. proj projection;
  28. static char *mapdir = "/lib/map"; /* default map directory */
  29. struct file {
  30. char *name;
  31. char *color;
  32. char *style;
  33. };
  34. static struct file dfltfile = {
  35. "world", BLACK, SOLID /* default map */
  36. };
  37. static struct file *file = &dfltfile; /* list of map files */
  38. static int nfile = 1; /* length of list */
  39. static char *currcolor = BLACK; /* current color */
  40. static char *gridcolor = BLACK;
  41. static char *bordcolor = BLACK;
  42. extern struct index index[];
  43. int halfwidth = HALFWIDTH;
  44. static int (*cut)(struct place *, struct place *, double *);
  45. static int (*limb)(double*, double*, double);
  46. static void dolimb(void);
  47. static int onlimb;
  48. static int poles;
  49. static double orientation[3] = { 90., 0., 0. }; /* -o option */
  50. static oriented; /* nonzero if -o option occurred */
  51. static upright; /* 1 if orientation[0]==90, -1 if -90, else 0*/
  52. static int delta = 1; /* -d setting */
  53. static double limits[4] = { /* -l parameters */
  54. -90., 90., -180., 180.
  55. };
  56. static double klimits[4] = { /* -k parameters */
  57. -90., 90., -180., 180.
  58. };
  59. static int limcase;
  60. static double rlimits[4]; /* limits expressed in radians */
  61. static double lolat, hilat, lolon, hilon;
  62. static double window[4] = { /* option -w */
  63. -90., 90., -180., 180.
  64. };
  65. static windowed; /* nozero if option -w */
  66. static struct vert { double x, y; } v[NVERT+2]; /*clipping polygon*/
  67. static struct edge { double a, b, c; } e[NVERT]; /* coeffs for linear inequality */
  68. static int nvert; /* number of vertices in clipping polygon */
  69. static double rwindow[4]; /* window, expressed in radians */
  70. static double params[2]; /* projection params */
  71. /* bounds on output values before scaling; found by coarse survey */
  72. static double xmin = 100.;
  73. static double xmax = -100.;
  74. static double ymin = 100.;
  75. static double ymax = -100.;
  76. static double xcent, ycent;
  77. static double xoff, yoff;
  78. double xrange, yrange;
  79. static int left = -HALFWIDTH;
  80. static int right = HALFWIDTH;
  81. static int bottom = -HALFWIDTH;
  82. static int top = HALFWIDTH;
  83. static int longlines = SHORTLINES; /* drop longer segments */
  84. static int shortlines = SHORTLINES;
  85. static int bflag = 1; /* 0 for option -b */
  86. static int s1flag = 0; /* 1 for option -s1 */
  87. static int s2flag = 0; /* 1 for option -s2 */
  88. static int rflag = 0; /* 1 for option -r */
  89. static int kflag = 0; /* 1 if option -k occurred */
  90. static int xflag = 0; /* 1 for option -x */
  91. int vflag = 1; /* -1 if option -v occurred */
  92. static double position[3]; /* option -p */
  93. static double center[3] = {0., 0., 0.}; /* option -c */
  94. static struct coord crot; /* option -c */
  95. static double grid[3] = { 10., 10., RESOL }; /* option -g */
  96. static double dlat, dlon; /* resolution for tracing grid in lat and lon */
  97. static double scaling; /* to compute final integer output */
  98. static struct file *track; /* options -t and -u */
  99. static int ntrack; /* number of tracks present */
  100. static char *symbolfile; /* option -y */
  101. void clamp(double *px, double v);
  102. void clipinit(void);
  103. double diddle(struct place *, double, double);
  104. double diddle(struct place *, double, double);
  105. void dobounds(double, double, double, double, int);
  106. void dogrid(double, double, double, double);
  107. int duple(struct place *, double);
  108. double fmax(double, double);
  109. double fmin(double, double);
  110. void getdata(char *);
  111. int gridpt(double, double, int);
  112. int inpoly(double, double);
  113. int inwindow(struct place *);
  114. void pathnames(void);
  115. int pnorm(double);
  116. void radbds(double *w, double *rw);
  117. void revlon(struct place *, double);
  118. void satellite(struct file *);
  119. int seeable(double, double);
  120. void windlim(void);
  121. void realcut(void);
  122. int
  123. option(char *s)
  124. {
  125. if(s[0]=='-' && (s[1]<'0'||s[1]>'9'))
  126. return(s[1]!='.'&&s[1]!=0);
  127. else
  128. return(0);
  129. }
  130. void
  131. conv(int k, struct coord *g)
  132. {
  133. g->l = (0.0001/SCALERATIO)*k;
  134. sincos(g);
  135. }
  136. int
  137. main(int argc, char *argv[])
  138. {
  139. int i,k;
  140. char *s, *t, *style;
  141. double x, y;
  142. double lat, lon;
  143. double *wlim;
  144. double dd;
  145. if(sizeof(int16_t)!=2)
  146. abort(); /* getshort() won't work */
  147. s = getenv("MAP");
  148. if(s)
  149. file[0].name = s;
  150. s = getenv("MAPDIR");
  151. if(s)
  152. mapdir = s;
  153. if(argc<=1)
  154. error("usage: map projection params options");
  155. for(k=0;index[k].name;k++) {
  156. s = index[k].name;
  157. t = argv[1];
  158. while(*s == *t){
  159. if(*s==0) goto found;
  160. s++;
  161. t++;
  162. }
  163. }
  164. fprintf(stderr,"projections:\n");
  165. for(i=0;index[i].name;i++) {
  166. fprintf(stderr,"%s",index[i].name);
  167. for(k=0; k<index[i].npar; k++)
  168. fprintf(stderr," p%d", k);
  169. fprintf(stderr,"\n");
  170. }
  171. exits("error");
  172. found:
  173. argv += 2;
  174. argc -= 2;
  175. cut = index[k].cut;
  176. limb = index[k].limb;
  177. poles = index[k].poles;
  178. for(i=0;i<index[k].npar;i++) {
  179. if(i>=argc||option(argv[i])) {
  180. fprintf(stderr,"%s needs %d params\n",index[k].name,index[k].npar);
  181. exits("error");
  182. }
  183. params[i] = atof(argv[i]);
  184. }
  185. argv += i;
  186. argc -= i;
  187. while(argc>0&&option(argv[0])) {
  188. argc--;
  189. argv++;
  190. switch(argv[-1][1]) {
  191. case 'm':
  192. if(file == &dfltfile) {
  193. file = 0;
  194. nfile = 0;
  195. }
  196. while(argc && !option(*argv)) {
  197. file = realloc(file,(nfile+1)*sizeof(*file));
  198. file[nfile].name = *argv;
  199. file[nfile].color = currcolor;
  200. file[nfile].style = SOLID;
  201. nfile++;
  202. argv++;
  203. argc--;
  204. }
  205. break;
  206. case 'b':
  207. bflag = 0;
  208. for(nvert=0;nvert<NVERT&&argc>=2;nvert++) {
  209. if(option(*argv))
  210. break;
  211. v[nvert].x = atof(*argv++);
  212. argc--;
  213. if(option(*argv))
  214. break;
  215. v[nvert].y = atof(*argv++);
  216. argc--;
  217. }
  218. if(nvert>=NVERT)
  219. error("too many clipping vertices");
  220. break;
  221. case 'g':
  222. gridcolor = currcolor;
  223. for(i=0;i<3&&argc>i&&!option(argv[i]);i++)
  224. grid[i] = atof(argv[i]);
  225. switch(i) {
  226. case 0:
  227. grid[0] = grid[1] = 0.;
  228. break;
  229. case 1:
  230. grid[1] = grid[0];
  231. }
  232. argc -= i;
  233. argv += i;
  234. break;
  235. case 't':
  236. style = SOLID;
  237. goto casetu;
  238. case 'u':
  239. style = DOTDASH;
  240. casetu:
  241. while(argc && !option(*argv)) {
  242. track = realloc(track,(ntrack+1)*sizeof(*track));
  243. track[ntrack].name = *argv;
  244. track[ntrack].color = currcolor;
  245. track[ntrack].style = style;
  246. ntrack++;
  247. argv++;
  248. argc--;
  249. }
  250. break;
  251. case 'r':
  252. rflag++;
  253. break;
  254. case 's':
  255. switch(argv[-1][2]) {
  256. case '1':
  257. s1flag++;
  258. break;
  259. case 0: /* compatibility */
  260. case '2':
  261. s2flag++;
  262. }
  263. break;
  264. case 'o':
  265. for(i=0;i<3&&i<argc&&!option(argv[i]);i++)
  266. orientation[i] = atof(argv[i]);
  267. oriented++;
  268. argv += i;
  269. argc -= i;
  270. break;
  271. case 'l':
  272. bordcolor = currcolor;
  273. for(i=0;i<argc&&i<4&&!option(argv[i]);i++)
  274. limits[i] = atof(argv[i]);
  275. argv += i;
  276. argc -= i;
  277. break;
  278. case 'k':
  279. kflag++;
  280. for(i=0;i<argc&&i<4&&!option(argv[i]);i++)
  281. klimits[i] = atof(argv[i]);
  282. argv += i;
  283. argc -= i;
  284. break;
  285. case 'd':
  286. if(argc>0&&!option(argv[0])) {
  287. delta = atoi(argv[0]);
  288. argv++;
  289. argc--;
  290. }
  291. break;
  292. case 'w':
  293. bordcolor = currcolor;
  294. windowed++;
  295. for(i=0;i<argc&&i<4&&!option(argv[i]);i++)
  296. window[i] = atof(argv[i]);
  297. argv += i;
  298. argc -= i;
  299. break;
  300. case 'c':
  301. for(i=0;i<3&&argc>i&&!option(argv[i]);i++)
  302. center[i] = atof(argv[i]);
  303. argc -= i;
  304. argv += i;
  305. break;
  306. case 'p':
  307. for(i=0;i<3&&argc>i&&!option(argv[i]);i++)
  308. position[i] = atof(argv[i]);
  309. argc -= i;
  310. argv += i;
  311. if(i!=3||position[2]<=0)
  312. error("incomplete positioning");
  313. break;
  314. case 'y':
  315. if(argc>0&&!option(argv[0])) {
  316. symbolfile = argv[0];
  317. argc--;
  318. argv++;
  319. }
  320. break;
  321. case 'v':
  322. if(index[k].limb == 0)
  323. error("-v does not apply here");
  324. vflag = -1;
  325. break;
  326. case 'x':
  327. xflag = 1;
  328. break;
  329. case 'C':
  330. if(argc && !option(*argv)) {
  331. currcolor = colorcode(*argv);
  332. argc--;
  333. argv++;
  334. }
  335. break;
  336. }
  337. }
  338. if(argc>0)
  339. error("error in arguments");
  340. pathnames();
  341. clamp(&limits[0],-90.);
  342. clamp(&limits[1],90.);
  343. clamp(&klimits[0],-90.);
  344. clamp(&klimits[1],90.);
  345. clamp(&window[0],-90.);
  346. clamp(&window[1],90.);
  347. radbds(limits,rlimits);
  348. limcase = limits[2]<-180.?0:
  349. limits[3]>180.?2:
  350. 1;
  351. if(
  352. window[0]>=window[1]||
  353. window[2]>=window[3]||
  354. window[0]>90.||
  355. window[1]<-90.||
  356. window[2]>180.||
  357. window[3]<-180.)
  358. error("unreasonable window");
  359. windlim();
  360. radbds(window,rwindow);
  361. upright = orientation[0]==90? 1: orientation[0]==-90? -1: 0;
  362. if(index[k].spheroid && !upright)
  363. error("can't tilt the spheroid");
  364. if(limits[2]>limits[3])
  365. limits[3] += 360;
  366. if(!oriented)
  367. orientation[2] = (limits[2]+limits[3])/2;
  368. orient(orientation[0],orientation[1],orientation[2]);
  369. projection = (*index[k].prog)(params[0],params[1]);
  370. if(projection == 0)
  371. error("unreasonable projection parameters");
  372. clipinit();
  373. grid[0] = fabs(grid[0]);
  374. grid[1] = fabs(grid[1]);
  375. if(!kflag)
  376. for(i=0;i<4;i++)
  377. klimits[i] = limits[i];
  378. if(klimits[2]>klimits[3])
  379. klimits[3] += 360;
  380. lolat = limits[0];
  381. hilat = limits[1];
  382. lolon = limits[2];
  383. hilon = limits[3];
  384. if(lolon>=hilon||lolat>=hilat||lolat<-90.||hilat>90.)
  385. error("unreasonable limits");
  386. wlim = kflag? klimits: window;
  387. dlat = fmin(hilat-lolat,wlim[1]-wlim[0])/16;
  388. dlon = fmin(hilon-lolon,wlim[3]-wlim[2])/32;
  389. dd = fmax(dlat,dlon);
  390. while(grid[2]>fmin(dlat,dlon)/2)
  391. grid[2] /= 2;
  392. realcut();
  393. if(nvert<=0) {
  394. for(lat=klimits[0];lat<klimits[1]+dd-FUZZ;lat+=dd) {
  395. if(lat>klimits[1])
  396. lat = klimits[1];
  397. for(lon=klimits[2];lon<klimits[3]+dd-FUZZ;lon+=dd) {
  398. i = (kflag?posproj:normproj)
  399. (lat,lon+(lon<klimits[3]?FUZZ:-FUZZ),
  400. &x,&y);
  401. if(i*vflag <= 0)
  402. continue;
  403. if(x<xmin) xmin = x;
  404. if(x>xmax) xmax = x;
  405. if(y<ymin) ymin = y;
  406. if(y>ymax) ymax = y;
  407. }
  408. }
  409. } else {
  410. for(i=0; i<nvert; i++) {
  411. x = v[i].x;
  412. y = v[i].y;
  413. if(x<xmin) xmin = x;
  414. if(x>xmax) xmax = x;
  415. if(y<ymin) ymin = y;
  416. if(y>ymax) ymax = y;
  417. }
  418. }
  419. xrange = xmax - xmin;
  420. yrange = ymax - ymin;
  421. if(xrange<=0||yrange<=0)
  422. error("map seems to be empty");
  423. scaling = 2; /*plotting area from -1 to 1*/
  424. if(position[2]!=0) {
  425. if(posproj(position[0]-.5,position[1],&xcent,&ycent)==0||
  426. posproj(position[0]+.5,position[1],&x,&y)==0)
  427. error("unreasonable position");
  428. scaling /= (position[2]*hypot(x-xcent,y-ycent));
  429. if(posproj(position[0],position[1],&xcent,&ycent)==0)
  430. error("unreasonable position");
  431. } else {
  432. scaling /= (xrange>yrange?xrange:yrange);
  433. xcent = (xmin+xmax)/2;
  434. ycent = (ymin+ymax)/2;
  435. }
  436. xoff = center[0]/scaling;
  437. yoff = center[1]/scaling;
  438. crot.l = center[2]*RAD;
  439. sincos(&crot);
  440. scaling *= HALFWIDTH*0.9;
  441. if(symbolfile)
  442. getsyms(symbolfile);
  443. if(!s2flag) {
  444. openpl();
  445. erase();
  446. }
  447. range(left,bottom,right,top);
  448. comment("grid","");
  449. colorx(gridcolor);
  450. pen(DOTTED);
  451. if(grid[0]>0.)
  452. for(lat=ceil(lolat/grid[0])*grid[0];
  453. lat<=hilat;lat+=grid[0])
  454. dogrid(lat,lat,lolon,hilon);
  455. if(grid[1]>0.)
  456. for(lon=ceil(lolon/grid[1])*grid[1];
  457. lon<=hilon;lon+=grid[1])
  458. dogrid(lolat,hilat,lon,lon);
  459. comment("border","");
  460. colorx(bordcolor);
  461. pen(SOLID);
  462. if(bflag) {
  463. dolimb();
  464. dobounds(lolat,hilat,lolon,hilon,0);
  465. dobounds(window[0],window[1],window[2],window[3],1);
  466. }
  467. lolat = floor(limits[0]/10)*10;
  468. hilat = ceil(limits[1]/10)*10;
  469. lolon = floor(limits[2]/10)*10;
  470. hilon = ceil(limits[3]/10)*10;
  471. if(lolon>hilon)
  472. hilon += 360.;
  473. /*do tracks first so as not to lose the standard input*/
  474. for(i=0;i<ntrack;i++) {
  475. longlines = LONGLINES;
  476. satellite(&track[i]);
  477. longlines = shortlines;
  478. }
  479. for(i=0;i<nfile;i++) {
  480. comment("mapfile",file[i].name);
  481. colorx(file[i].color);
  482. pen(file[i].style);
  483. getdata(file[i].name);
  484. }
  485. move(right,bottom);
  486. if(!s1flag)
  487. closepl();
  488. return 0;
  489. }
  490. /* Out of perverseness (really to recover from a dubious,
  491. but documented, convention) the returns from projection
  492. functions (-1 unplottable, 0 wrong sheet, 1 good) are
  493. recoded into -1 wrong sheet, 0 unplottable, 1 good. */
  494. int
  495. fixproj(struct place *g, double *x, double *y)
  496. {
  497. int i = (*projection)(g,x,y);
  498. return i<0? 0: i==0? -1: 1;
  499. }
  500. int
  501. normproj(double lat, double lon, double *x, double *y)
  502. {
  503. int i;
  504. struct place geog;
  505. latlon(lat,lon,&geog);
  506. /*
  507. printp(&geog);
  508. */
  509. normalize(&geog);
  510. if(!inwindow(&geog))
  511. return(-1);
  512. i = fixproj(&geog,x,y);
  513. if(rflag)
  514. *x = -*x;
  515. /*
  516. printp(&geog);
  517. fprintf(stderr,"%d %.3f %.3f\n",i,*x,*y);
  518. */
  519. return(i);
  520. }
  521. int
  522. posproj(double lat, double lon, double *x, double *y)
  523. {
  524. int i;
  525. struct place geog;
  526. latlon(lat,lon,&geog);
  527. normalize(&geog);
  528. i = fixproj(&geog,x,y);
  529. if(rflag)
  530. *x = -*x;
  531. return(i);
  532. }
  533. int
  534. inwindow(struct place *geog)
  535. {
  536. if(geog->nlat.l<rwindow[0]-FUZZ||
  537. geog->nlat.l>rwindow[1]+FUZZ||
  538. geog->wlon.l<rwindow[2]-FUZZ||
  539. geog->wlon.l>rwindow[3]+FUZZ)
  540. return(0);
  541. else return(1);
  542. }
  543. int
  544. inlimits(struct place *g)
  545. {
  546. if(rlimits[0]-FUZZ>g->nlat.l||
  547. rlimits[1]+FUZZ<g->nlat.l)
  548. return(0);
  549. switch(limcase) {
  550. case 0:
  551. if(rlimits[2]+TWOPI-FUZZ>g->wlon.l&&
  552. rlimits[3]+FUZZ<g->wlon.l)
  553. return(0);
  554. break;
  555. case 1:
  556. if(rlimits[2]-FUZZ>g->wlon.l||
  557. rlimits[3]+FUZZ<g->wlon.l)
  558. return(0);
  559. break;
  560. case 2:
  561. if(rlimits[2]>g->wlon.l&&
  562. rlimits[3]-TWOPI+FUZZ<g->wlon.l)
  563. return(0);
  564. break;
  565. }
  566. return(1);
  567. }
  568. int32_t patch[18][36];
  569. void
  570. getdata(char *mapfile)
  571. {
  572. char *indexfile;
  573. int kx,ky,c;
  574. int k;
  575. int32_t b;
  576. int32_t *p;
  577. int ip, jp;
  578. int n;
  579. struct place g;
  580. int i, j;
  581. double lat, lon;
  582. int conn;
  583. FILE *ifile, *xfile;
  584. indexfile = mapindex(mapfile);
  585. xfile = fopen(indexfile,"r");
  586. if(xfile==NULL)
  587. filerror("can't find map index", indexfile);
  588. free(indexfile);
  589. for(i=0,p=patch[0];i<18*36;i++,p++)
  590. *p = 1;
  591. while(!feof(xfile) && fscanf(xfile,"%d%d%ld",&i,&j,&b)==3)
  592. patch[i+9][j+18] = b;
  593. fclose(xfile);
  594. ifile = fopen(mapfile,"r");
  595. if(ifile==NULL)
  596. filerror("can't find map data", mapfile);
  597. for(lat=lolat;lat<hilat;lat+=10.)
  598. for(lon=lolon;lon<hilon;lon+=10.) {
  599. if(!seeable(lat,lon))
  600. continue;
  601. i = pnorm(lat);
  602. j = pnorm(lon);
  603. if((b=patch[i+9][j+18])&1)
  604. continue;
  605. fseek(ifile,b,0);
  606. while((ip=getc(ifile))>=0&&(jp=getc(ifile))>=0){
  607. if(ip!=(i&0377)||jp!=(j&0377))
  608. break;
  609. n = getshort(ifile);
  610. conn = 0;
  611. if(n > 0) { /* absolute coordinates */
  612. kx = ky = 0; /* set */
  613. for(k=0;k<n;k++){
  614. kx = SCALERATIO*getshort(ifile);
  615. ky = SCALERATIO*getshort(ifile);
  616. if (((k%delta) != 0) && (k != (n-1)))
  617. continue;
  618. conv(kx,&g.nlat);
  619. conv(ky,&g.wlon);
  620. conn = plotpt(&g,conn);
  621. }
  622. } else { /* differential, scaled by SCALERATI0 */
  623. n = -n;
  624. kx = SCALERATIO*getshort(ifile);
  625. ky = SCALERATIO*getshort(ifile);
  626. for(k=0; k<n; k++) {
  627. c = getc(ifile);
  628. if(c&0200) c|= ~0177;
  629. kx += c;
  630. c = getc(ifile);
  631. if(c&0200) c|= ~0177;
  632. ky += c;
  633. if(k%delta!=0&&k!=n-1)
  634. continue;
  635. conv(kx,&g.nlat);
  636. conv(ky,&g.wlon);
  637. conn = plotpt(&g,conn);
  638. }
  639. }
  640. if(k==1) {
  641. conv(kx,&g.nlat);
  642. conv(ky,&g.wlon);
  643. plotpt(&g,conn);
  644. }
  645. }
  646. }
  647. fclose(ifile);
  648. }
  649. int
  650. seeable(double lat0, double lon0)
  651. {
  652. double x, y;
  653. double lat, lon;
  654. for(lat=lat0;lat<=lat0+10;lat+=2*grid[2])
  655. for(lon=lon0;lon<=lon0+10;lon+=2*grid[2])
  656. if(normproj(lat,lon,&x,&y)*vflag>0)
  657. return(1);
  658. return(0);
  659. }
  660. void
  661. satellite(struct file *t)
  662. {
  663. char sym[50];
  664. char lbl[50];
  665. double scale;
  666. register conn;
  667. double lat,lon;
  668. struct place place;
  669. static FILE *ifile = stdin;
  670. if(t->name[0]!='-'||t->name[1]!=0) {
  671. fclose(ifile);
  672. if((ifile=fopen(t->name,"r"))==NULL)
  673. filerror("can't find track", t->name);
  674. }
  675. comment("track",t->name);
  676. colorx(t->color);
  677. pen(t->style);
  678. for(;;) {
  679. conn = 0;
  680. while(!feof(ifile) && fscanf(ifile,"%lf%lf",&lat,&lon)==2){
  681. latlon(lat,lon,&place);
  682. if(fscanf(ifile,"%1s",lbl) == 1) {
  683. if(strchr("+-.0123456789",*lbl)==0)
  684. break;
  685. ungetc(*lbl,ifile);
  686. }
  687. conn = plotpt(&place,conn);
  688. }
  689. if(feof(ifile))
  690. return;
  691. fscanf(ifile,"%[^\n]",lbl+1);
  692. switch(*lbl) {
  693. case '"':
  694. if(plotpt(&place,conn))
  695. text(lbl+1);
  696. break;
  697. case ':':
  698. case '!':
  699. if(sscanf(lbl+1,"%s %lf",sym,&scale) <= 1)
  700. scale = 1;
  701. if(plotpt(&place,conn?conn:-1)) {
  702. int r = *lbl=='!'?0:rflag?-1:1;
  703. pen(SOLID);
  704. if(putsym(&place,sym,scale,r) == 0)
  705. text(lbl);
  706. pen(t->style);
  707. }
  708. break;
  709. default:
  710. if(plotpt(&place,conn))
  711. text(lbl);
  712. break;
  713. }
  714. }
  715. }
  716. int
  717. pnorm(double x)
  718. {
  719. int i;
  720. i = x/10.;
  721. i %= 36;
  722. if(i>=18) return(i-36);
  723. if(i<-18) return(i+36);
  724. return(i);
  725. }
  726. void
  727. error(char *s)
  728. {
  729. fprintf(stderr,"map: \r\n%s\n",s);
  730. exits("error");
  731. }
  732. void
  733. filerror(char *s, char *f)
  734. {
  735. fprintf(stderr,"\r\n%s %s\n",s,f);
  736. exits("error");
  737. }
  738. char *
  739. mapindex(char *s)
  740. {
  741. char *t = malloc(strlen(s)+3);
  742. strcpy(t,s);
  743. strcat(t,".x");
  744. return t;
  745. }
  746. #define NOPT 32767
  747. static ox = NOPT, oy = NOPT;
  748. int
  749. cpoint(int xi, int yi, int conn)
  750. {
  751. int dx = abs(ox-xi);
  752. int dy = abs(oy-yi);
  753. if(!xflag && (xi<left||xi>=right || yi<bottom||yi>=top)) {
  754. ox = oy = NOPT;
  755. return 0;
  756. }
  757. if(conn == -1) /* isolated plotting symbol */
  758. {}
  759. else if(!conn)
  760. point(xi,yi);
  761. else {
  762. if(dx+dy>longlines) {
  763. ox = oy = NOPT; /* don't leap across cuts */
  764. return 0;
  765. }
  766. if(dx || dy)
  767. vec(xi,yi);
  768. }
  769. ox = xi, oy = yi;
  770. return dx+dy<=2? 2: 1; /* 2=very near; see dogrid */
  771. }
  772. struct place oldg;
  773. int
  774. plotpt(struct place *g, int conn)
  775. {
  776. int kx,ky;
  777. int ret;
  778. double cutlon;
  779. if(!inlimits(g)) {
  780. return(0);
  781. }
  782. normalize(g);
  783. if(!inwindow(g)) {
  784. return(0);
  785. }
  786. switch((*cut)(g,&oldg,&cutlon)) {
  787. case 2:
  788. if(conn) {
  789. ret = duple(g,cutlon)|duple(g,cutlon);
  790. oldg = *g;
  791. return(ret);
  792. }
  793. case 0:
  794. conn = 0;
  795. default: /* prevent diags about bad return value */
  796. case 1:
  797. oldg = *g;
  798. ret = doproj(g,&kx,&ky);
  799. if(ret==0 || !onlimb && ret*vflag<=0)
  800. return(0);
  801. ret = cpoint(kx,ky,conn);
  802. return ret;
  803. }
  804. }
  805. int
  806. doproj(struct place *g, int *kx, int *ky)
  807. {
  808. int i;
  809. double x,y,x1,y1;
  810. /*fprintf(stderr,"dopr1 %f %f \n",g->nlat.l,g->wlon.l);*/
  811. i = fixproj(g,&x,&y);
  812. if(i == 0)
  813. return(0);
  814. if(rflag)
  815. x = -x;
  816. /*fprintf(stderr,"dopr2 %f %f\n",x,y);*/
  817. if(!inpoly(x,y)) {
  818. return 0;
  819. }
  820. x1 = x - xcent;
  821. y1 = y - ycent;
  822. x = (x1*crot.c - y1*crot.s + xoff)*scaling;
  823. y = (x1*crot.s + y1*crot.c + yoff)*scaling;
  824. *kx = x + (x>0?.5:-.5);
  825. *ky = y + (y>0?.5:-.5);
  826. return(i);
  827. }
  828. int
  829. duple(struct place *g, double cutlon)
  830. {
  831. int kx,ky;
  832. int okx,oky;
  833. struct place ig;
  834. revlon(g,cutlon);
  835. revlon(&oldg,cutlon);
  836. ig = *g;
  837. invert(&ig);
  838. if(!inlimits(&ig))
  839. return(0);
  840. if(doproj(g,&kx,&ky)*vflag<=0 ||
  841. doproj(&oldg,&okx,&oky)*vflag<=0)
  842. return(0);
  843. cpoint(okx,oky,0);
  844. cpoint(kx,ky,1);
  845. return(1);
  846. }
  847. void
  848. revlon(struct place *g, double cutlon)
  849. {
  850. g->wlon.l = reduce(cutlon-reduce(g->wlon.l-cutlon));
  851. sincos(&g->wlon);
  852. }
  853. /* recognize problems of cuts
  854. * move a point across cut to side of its predecessor
  855. * if its very close to the cut
  856. * return(0) if cut interrupts the line
  857. * return(1) if line is to be drawn normally
  858. * return(2) if line is so close to cut as to
  859. * be properly drawn on both sheets
  860. */
  861. int
  862. picut(struct place *g, struct place *og, double *cutlon)
  863. {
  864. *cutlon = PI;
  865. return(ckcut(g,og,PI));
  866. }
  867. int
  868. nocut(struct place *g, struct place *og, double *cutlon)
  869. {
  870. USED(g, og, cutlon);
  871. /*
  872. #pragma ref g
  873. #pragma ref og
  874. #pragma ref cutlon
  875. */
  876. return(1);
  877. }
  878. int
  879. ckcut(struct place *g1, struct place *g2, double lon)
  880. {
  881. double d1, d2;
  882. double f1, f2;
  883. int kx,ky;
  884. d1 = reduce(g1->wlon.l -lon);
  885. d2 = reduce(g2->wlon.l -lon);
  886. if((f1=fabs(d1))<FUZZ)
  887. d1 = diddle(g1,lon,d2);
  888. if((f2=fabs(d2))<FUZZ) {
  889. d2 = diddle(g2,lon,d1);
  890. if(doproj(g2,&kx,&ky)*vflag>0)
  891. cpoint(kx,ky,0);
  892. }
  893. if(f1<FUZZ&&f2<FUZZ)
  894. return(2);
  895. if(f1>PI*TWO_THRD||f2>PI*TWO_THRD)
  896. return(1);
  897. return(d1*d2>=0);
  898. }
  899. double
  900. diddle(struct place *g, double lon, double d)
  901. {
  902. double d1;
  903. d1 = FUZZ/2;
  904. if(d<0)
  905. d1 = -d1;
  906. g->wlon.l = reduce(lon+d1);
  907. sincos(&g->wlon);
  908. return(d1);
  909. }
  910. double
  911. reduce(double lon)
  912. {
  913. if(lon>PI)
  914. lon -= 2*PI;
  915. else if(lon<-PI)
  916. lon += 2*PI;
  917. return(lon);
  918. }
  919. double tetrapt = 35.26438968; /* atan(1/sqrt(2)) */
  920. void
  921. dogrid(double lat0, double lat1, double lon0, double lon1)
  922. {
  923. double slat,slon,tlat,tlon;
  924. register int conn, oconn;
  925. slat = tlat = slon = tlon = 0;
  926. if(lat1>lat0)
  927. slat = tlat = fmin(grid[2],dlat);
  928. else
  929. slon = tlon = fmin(grid[2],dlon);;
  930. conn = oconn = 0;
  931. while(lat0<=lat1&&lon0<=lon1) {
  932. conn = gridpt(lat0,lon0,conn);
  933. if(projection==Xguyou&&slat>0) {
  934. if(lat0<-45&&lat0+slat>-45)
  935. conn = gridpt(-45.,lon0,conn);
  936. else if(lat0<45&&lat0+slat>45)
  937. conn = gridpt(45.,lon0,conn);
  938. } else if(projection==Xtetra&&slat>0) {
  939. if(lat0<-tetrapt&&lat0+slat>-tetrapt) {
  940. gridpt(-tetrapt-.001,lon0,conn);
  941. conn = gridpt(-tetrapt+.001,lon0,0);
  942. }
  943. else if(lat0<tetrapt&&lat0+slat>tetrapt) {
  944. gridpt(tetrapt-.001,lon0,conn);
  945. conn = gridpt(tetrapt+.001,lon0,0);
  946. }
  947. }
  948. if(conn==0 && oconn!=0) {
  949. if(slat+slon>.05) {
  950. lat0 -= slat; /* steps too big */
  951. lon0 -= slon; /* or near bdry */
  952. slat /= 2;
  953. slon /= 2;
  954. conn = oconn = gridpt(lat0,lon0,conn);
  955. } else
  956. oconn = 0;
  957. } else {
  958. if(conn==2) {
  959. slat = tlat;
  960. slon = tlon;
  961. conn = 1;
  962. }
  963. oconn = conn;
  964. }
  965. lat0 += slat;
  966. lon0 += slon;
  967. }
  968. gridpt(lat1,lon1,conn);
  969. }
  970. static gridinv; /* nonzero when doing window bounds */
  971. int
  972. gridpt(double lat, double lon, int conn)
  973. {
  974. struct place g;
  975. /*fprintf(stderr,"%f %f\n",lat,lon);*/
  976. latlon(lat,lon,&g);
  977. if(gridinv)
  978. invert(&g);
  979. return(plotpt(&g,conn));
  980. }
  981. /* win=0 ordinary grid lines, win=1 window lines */
  982. void
  983. dobounds(double lolat, double hilat, double lolon, double hilon, int win)
  984. {
  985. gridinv = win;
  986. if(lolat>-90 || win && (poles&1)!=0)
  987. dogrid(lolat+FUZZ,lolat+FUZZ,lolon,hilon);
  988. if(hilat<90 || win && (poles&2)!=0)
  989. dogrid(hilat-FUZZ,hilat-FUZZ,lolon,hilon);
  990. if(hilon-lolon<360 || win && cut==picut) {
  991. dogrid(lolat,hilat,lolon+FUZZ,lolon+FUZZ);
  992. dogrid(lolat,hilat,hilon-FUZZ,hilon-FUZZ);
  993. }
  994. gridinv = 0;
  995. }
  996. static void
  997. dolimb(void)
  998. {
  999. double lat, lon;
  1000. double res = fmin(dlat, dlon)/4;
  1001. int conn = 0;
  1002. int newconn;
  1003. if(limb == 0)
  1004. return;
  1005. onlimb = gridinv = 1;
  1006. for(;;) {
  1007. newconn = (*limb)(&lat, &lon, res);
  1008. if(newconn == -1)
  1009. break;
  1010. conn = gridpt(lat, lon, conn*newconn);
  1011. }
  1012. onlimb = gridinv = 0;
  1013. }
  1014. void
  1015. radbds(double *w, double *rw)
  1016. {
  1017. int i;
  1018. for(i=0;i<4;i++)
  1019. rw[i] = w[i]*RAD;
  1020. rw[0] -= FUZZ;
  1021. rw[1] += FUZZ;
  1022. rw[2] -= FUZZ;
  1023. rw[3] += FUZZ;
  1024. }
  1025. void
  1026. windlim(void)
  1027. {
  1028. double center = orientation[0];
  1029. double colat;
  1030. if(center>90)
  1031. center = 180 - center;
  1032. if(center<-90)
  1033. center = -180 - center;
  1034. if(fabs(center)>90)
  1035. error("unreasonable orientation");
  1036. colat = 90 - window[0];
  1037. if(center-colat>limits[0])
  1038. limits[0] = center - colat;
  1039. if(center+colat<limits[1])
  1040. limits[1] = center + colat;
  1041. }
  1042. int16_t
  1043. getshort(FILE *f)
  1044. {
  1045. int c, r;
  1046. c = getc(f);
  1047. r = (c | getc(f)<<8);
  1048. if (r&0x8000)
  1049. r |= ~0xFFFF; /* in case short > 16 bits */
  1050. return r;
  1051. }
  1052. double
  1053. fmin(double x, double y)
  1054. {
  1055. return(x<y?x:y);
  1056. }
  1057. double
  1058. fmax(double x, double y)
  1059. {
  1060. return(x>y?x:y);
  1061. }
  1062. void
  1063. clamp(double *px, double v)
  1064. {
  1065. *px = (v<0?fmax:fmin)(*px,v);
  1066. }
  1067. void
  1068. pathnames(void)
  1069. {
  1070. int i;
  1071. char *t, *indexfile, *name;
  1072. FILE *f, *fx;
  1073. for(i=0; i<nfile; i++) {
  1074. name = file[i].name;
  1075. if(*name=='/')
  1076. continue;
  1077. indexfile = mapindex(name);
  1078. /* ansi equiv of unix access() call */
  1079. f = fopen(name, "r");
  1080. fx = fopen(indexfile, "r");
  1081. if(f) fclose(f);
  1082. if(fx) fclose(fx);
  1083. free(indexfile);
  1084. if(f && fx)
  1085. continue;
  1086. t = malloc(strlen(name)+strlen(mapdir)+2);
  1087. strcpy(t,mapdir);
  1088. strcat(t,"/");
  1089. strcat(t,name);
  1090. file[i].name = t;
  1091. }
  1092. }
  1093. void
  1094. clipinit(void)
  1095. {
  1096. register i;
  1097. double s,t;
  1098. if(nvert<=0)
  1099. return;
  1100. for(i=0; i<nvert; i++) { /*convert latlon to xy*/
  1101. if(normproj(v[i].x,v[i].y,&v[i].x,&v[i].y)==0)
  1102. error("invisible clipping vertex");
  1103. }
  1104. if(nvert==2) { /*rectangle with diag specified*/
  1105. nvert = 4;
  1106. v[2] = v[1];
  1107. v[1].x=v[0].x, v[1].y=v[2].y, v[3].x=v[2].x, v[3].y=v[0].y;
  1108. }
  1109. v[nvert] = v[0];
  1110. v[nvert+1] = v[1];
  1111. s = 0;
  1112. for(i=1; i<=nvert; i++) { /*test for convexity*/
  1113. t = (v[i-1].x-v[i].x)*(v[i+1].y-v[i].y) -
  1114. (v[i-1].y-v[i].y)*(v[i+1].x-v[i].x);
  1115. if(t<-FUZZ && s>=0) s = 1;
  1116. if(t>FUZZ && s<=0) s = -1;
  1117. if(-FUZZ<=t&&t<=FUZZ || t*s>0) {
  1118. s = 0;
  1119. break;
  1120. }
  1121. }
  1122. if(s==0)
  1123. error("improper clipping polygon");
  1124. for(i=0; i<nvert; i++) { /*edge equation ax+by=c*/
  1125. e[i].a = s*(v[i+1].y - v[i].y);
  1126. e[i].b = s*(v[i].x - v[i+1].x);
  1127. e[i].c = s*(v[i].x*v[i+1].y - v[i].y*v[i+1].x);
  1128. }
  1129. }
  1130. int
  1131. inpoly(double x, double y)
  1132. {
  1133. register i;
  1134. for(i=0; i<nvert; i++) {
  1135. register struct edge *ei = &e[i];
  1136. double val = x*ei->a + y*ei->b - ei->c;
  1137. if(val>10*FUZZ)
  1138. return(0);
  1139. }
  1140. return 1;
  1141. }
  1142. void
  1143. realcut()
  1144. {
  1145. struct place g;
  1146. double lat;
  1147. if(cut != picut) /* punt on unusual cuts */
  1148. return;
  1149. for(lat=window[0]; lat<=window[1]; lat+=grid[2]) {
  1150. g.wlon.l = PI;
  1151. sincos(&g.wlon);
  1152. g.nlat.l = lat*RAD;
  1153. sincos(&g.nlat);
  1154. if(!inwindow(&g)) {
  1155. break;
  1156. }
  1157. invert(&g);
  1158. if(inlimits(&g)) {
  1159. return;
  1160. }
  1161. }
  1162. longlines = shortlines = LONGLINES;
  1163. cut = nocut; /* not necessary; small eff. gain */
  1164. }