map.c 25 KB

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