/Proj4/cs2cs.c

http://github.com/route-me/route-me · C · 446 lines · 320 code · 47 blank · 79 comment · 126 complexity · 974fade99cc6e0080b79a69b9ae55e76 MD5 · raw file

  1. /******************************************************************************
  2. * $Id: cs2cs.c,v 1.10 2006/10/10 15:24:05 fwarmerdam Exp $
  3. *
  4. * Project: PROJ.4
  5. * Purpose: Mainline program sort of like ``proj'' for converting between
  6. * two coordinate systems.
  7. * Author: Frank Warmerdam, warmerda@home.com
  8. *
  9. ******************************************************************************
  10. * Copyright (c) 2000, Frank Warmerdam
  11. *
  12. * Permission is hereby granted, free of charge, to any person obtaining a
  13. * copy of this software and associated documentation files (the "Software"),
  14. * to deal in the Software without restriction, including without limitation
  15. * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  16. * and/or sell copies of the Software, and to permit persons to whom the
  17. * Software is furnished to do so, subject to the following conditions:
  18. *
  19. * The above copyright notice and this permission notice shall be included
  20. * in all copies or substantial portions of the Software.
  21. *
  22. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
  23. * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  24. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  25. * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  26. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  27. * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  28. * DEALINGS IN THE SOFTWARE.
  29. ******************************************************************************
  30. *
  31. * $Log: cs2cs.c,v $
  32. * Revision 1.10 2006/10/10 15:24:05 fwarmerdam
  33. * Increase MAX_LINE to 1000 per request from Dan Scheirer.
  34. *
  35. * Revision 1.9 2006/03/30 14:35:09 fwarmerdam
  36. * bug 1145: avoid warnings on VC8.
  37. *
  38. * Revision 1.8 2004/10/28 16:05:37 fwarmerdam
  39. * avoid using global variables from DLL
  40. *
  41. * Revision 1.7 2003/03/25 17:53:13 warmerda
  42. * modified so that -f formats are used for Z as well
  43. *
  44. * Revision 1.6 2002/12/09 16:01:02 warmerda
  45. * added prime meridian support
  46. *
  47. * Revision 1.5 2002/11/19 20:33:42 warmerda
  48. * cleanup before exit to facilitate memory leak testing
  49. *
  50. * Revision 1.4 2001/04/05 19:32:19 warmerda
  51. * use projPJ, and pj_is_latlong()
  52. *
  53. * Revision 1.3 2001/04/05 04:23:28 warmerda
  54. * use pj_latlong_from_proj
  55. *
  56. * Revision 1.2 2001/02/03 18:36:55 warmerda
  57. * removed some unavailable options from usage string
  58. *
  59. * Revision 1.1 2000/07/06 23:32:27 warmerda
  60. * New
  61. *
  62. */
  63. #include "projects.h"
  64. #include <stdio.h>
  65. #include <stdlib.h>
  66. #include <ctype.h>
  67. #include <string.h>
  68. #include <math.h>
  69. #include "emess.h"
  70. #define MAX_LINE 1000
  71. #define MAX_PARGS 100
  72. static projPJ fromProj, toProj;
  73. static int
  74. reversein = 0, /* != 0 reverse input arguments */
  75. reverseout = 0, /* != 0 reverse output arguments */
  76. echoin = 0, /* echo input data to output line */
  77. tag = '#'; /* beginning of line tag character */
  78. static char
  79. *oform = (char *)0, /* output format for x-y or decimal degrees */
  80. *oterr = "*\t*", /* output line for unprojectable input */
  81. *usage =
  82. "%s\nusage: %s [ -eEfIlrstvwW [args] ] [ +opts[=arg] ]\n"
  83. " [+to [+opts[=arg] [ files ]\n";
  84. static struct FACTORS facs;
  85. static double (*informat)(const char *,
  86. char **); /* input data deformatter function */
  87. /************************************************************************/
  88. /* process() */
  89. /* */
  90. /* File processing function. */
  91. /************************************************************************/
  92. static void process(FILE *fid)
  93. {
  94. char line[MAX_LINE+3], *s, pline[40];
  95. projUV data;
  96. for (;;) {
  97. double z;
  98. ++emess_dat.File_line;
  99. if (!(s = fgets(line, MAX_LINE, fid)))
  100. break;
  101. if (!strchr(s, '\n')) { /* overlong line */
  102. int c;
  103. (void)strcat(s, "\n");
  104. /* gobble up to newline */
  105. while ((c = fgetc(fid)) != EOF && c != '\n') ;
  106. }
  107. if (*s == tag) {
  108. fputs(line, stdout);
  109. continue;
  110. }
  111. if (reversein) {
  112. data.v = (*informat)(s, &s);
  113. data.u = (*informat)(s, &s);
  114. } else {
  115. data.u = (*informat)(s, &s);
  116. data.v = (*informat)(s, &s);
  117. }
  118. z = strtod( s, &s );
  119. if (data.v == HUGE_VAL)
  120. data.u = HUGE_VAL;
  121. if (!*s && (s > line)) --s; /* assumed we gobbled \n */
  122. if ( echoin) {
  123. int t;
  124. t = *s;
  125. *s = '\0';
  126. (void)fputs(line, stdout);
  127. *s = t;
  128. putchar('\t');
  129. }
  130. if (data.u != HUGE_VAL) {
  131. if( pj_transform( fromProj, toProj, 1, 0,
  132. &(data.u), &(data.v), &z ) != 0 )
  133. {
  134. data.u = HUGE_VAL;
  135. data.v = HUGE_VAL;
  136. }
  137. }
  138. if (data.u == HUGE_VAL) /* error output */
  139. fputs(oterr, stdout);
  140. else if (pj_is_latlong(toProj) && !oform) { /*ascii DMS output */
  141. if (reverseout) {
  142. fputs(rtodms(pline, data.v, 'N', 'S'), stdout);
  143. putchar('\t');
  144. fputs(rtodms(pline, data.u, 'E', 'W'), stdout);
  145. } else {
  146. fputs(rtodms(pline, data.u, 'E', 'W'), stdout);
  147. putchar('\t');
  148. fputs(rtodms(pline, data.v, 'N', 'S'), stdout);
  149. }
  150. } else { /* x-y or decimal degree ascii output */
  151. if ( pj_is_latlong(toProj) ) {
  152. data.v *= RAD_TO_DEG;
  153. data.u *= RAD_TO_DEG;
  154. }
  155. if (reverseout) {
  156. printf(oform,data.v); putchar('\t');
  157. printf(oform,data.u);
  158. } else {
  159. printf(oform,data.u); putchar('\t');
  160. printf(oform,data.v);
  161. }
  162. }
  163. putchar(' ');
  164. if( oform != NULL )
  165. printf( oform, z );
  166. else
  167. printf( "%.3f", z );
  168. fputs("\n", stdout );
  169. }
  170. }
  171. /************************************************************************/
  172. /* main() */
  173. /************************************************************************/
  174. int main(int argc, char **argv)
  175. {
  176. char *arg, **eargv = argv, *from_argv[MAX_PARGS], *to_argv[MAX_PARGS],
  177. **iargv = argv;
  178. FILE *fid;
  179. int from_argc=0, to_argc=0, iargc = argc, eargc = 0, c, mon = 0;
  180. int have_to_flag = 0, inverse = 0, i;
  181. if (emess_dat.Prog_name = strrchr(*argv,DIR_CHAR))
  182. ++emess_dat.Prog_name;
  183. else emess_dat.Prog_name = *argv;
  184. inverse = ! strncmp(emess_dat.Prog_name, "inv", 3);
  185. if (argc <= 1 ) {
  186. (void)fprintf(stderr, usage, pj_get_release(), emess_dat.Prog_name);
  187. exit (0);
  188. }
  189. /* process run line arguments */
  190. while (--argc > 0) { /* collect run line arguments */
  191. if(**++argv == '-') for(arg = *argv;;) {
  192. switch(*++arg) {
  193. case '\0': /* position of "stdin" */
  194. if (arg[-1] == '-') eargv[eargc++] = "-";
  195. break;
  196. case 'v': /* monitor dump of initialization */
  197. mon = 1;
  198. continue;
  199. case 'I': /* alt. method to spec inverse */
  200. inverse = 1;
  201. continue;
  202. case 'E': /* echo ascii input to ascii output */
  203. echoin = 1;
  204. continue;
  205. case 't': /* set col. one char */
  206. if (arg[1]) tag = *++arg;
  207. else emess(1,"missing -t col. 1 tag");
  208. continue;
  209. case 'l': /* list projections, ellipses or units */
  210. if (!arg[1] || arg[1] == 'p' || arg[1] == 'P') {
  211. /* list projections */
  212. struct PJ_LIST *lp;
  213. int do_long = arg[1] == 'P', c;
  214. char *str;
  215. for (lp = pj_get_list_ref() ; lp->id ; ++lp) {
  216. (void)printf("%s : ", lp->id);
  217. if (do_long) /* possibly multiline description */
  218. (void)puts(*lp->descr);
  219. else { /* first line, only */
  220. str = *lp->descr;
  221. while ((c = *str++) && c != '\n')
  222. putchar(c);
  223. putchar('\n');
  224. }
  225. }
  226. } else if (arg[1] == '=') { /* list projection 'descr' */
  227. struct PJ_LIST *lp;
  228. arg += 2;
  229. for (lp = pj_get_list_ref() ; lp->id ; ++lp)
  230. if (!strcmp(lp->id, arg)) {
  231. (void)printf("%9s : %s\n", lp->id, *lp->descr);
  232. break;
  233. }
  234. } else if (arg[1] == 'e') { /* list ellipses */
  235. struct PJ_ELLPS *le;
  236. for (le = pj_get_ellps_ref(); le->id ; ++le)
  237. (void)printf("%9s %-16s %-16s %s\n",
  238. le->id, le->major, le->ell, le->name);
  239. } else if (arg[1] == 'u') { /* list units */
  240. struct PJ_UNITS *lu;
  241. for (lu = pj_get_units_ref(); lu->id ; ++lu)
  242. (void)printf("%12s %-20s %s\n",
  243. lu->id, lu->to_meter, lu->name);
  244. } else if (arg[1] == 'd') { /* list datums */
  245. struct PJ_DATUMS *ld;
  246. printf("__datum_id__ __ellipse___ __definition/comments______________________________\n" );
  247. for (ld = pj_get_datums_ref(); ld->id ; ++ld)
  248. {
  249. printf("%12s %-12s %-30s\n",
  250. ld->id, ld->ellipse_id, ld->defn);
  251. if( ld->comments != NULL && strlen(ld->comments) > 0 )
  252. printf( "%25s %s\n", " ", ld->comments );
  253. }
  254. } else if( arg[1] == 'm') { /* list prime meridians */
  255. struct PJ_PRIME_MERIDIANS *lpm;
  256. for (lpm = pj_get_prime_meridians_ref(); lpm->id ; ++lpm)
  257. (void)printf("%12s %-30s\n",
  258. lpm->id, lpm->defn);
  259. } else
  260. emess(1,"invalid list option: l%c",arg[1]);
  261. exit(0);
  262. continue; /* artificial */
  263. case 'e': /* error line alternative */
  264. if (--argc <= 0)
  265. noargument:
  266. emess(1,"missing argument for -%c",*arg);
  267. oterr = *++argv;
  268. continue;
  269. case 'W': /* specify seconds precision */
  270. case 'w': /* -W for constant field width */
  271. if ((c = arg[1]) != 0 && isdigit(c)) {
  272. set_rtodms(c - '0', *arg == 'W');
  273. ++arg;
  274. } else
  275. emess(1,"-W argument missing or non-digit");
  276. continue;
  277. case 'f': /* alternate output format degrees or xy */
  278. if (--argc <= 0) goto noargument;
  279. oform = *++argv;
  280. continue;
  281. case 'r': /* reverse input */
  282. reversein = 1;
  283. continue;
  284. case 's': /* reverse output */
  285. reverseout = 1;
  286. continue;
  287. default:
  288. emess(1, "invalid option: -%c",*arg);
  289. break;
  290. }
  291. break;
  292. } else if (strcmp(*argv,"+to") == 0 ) {
  293. have_to_flag = 1;
  294. } else if (**argv == '+') { /* + argument */
  295. if( have_to_flag )
  296. {
  297. if( to_argc < MAX_PARGS )
  298. to_argv[to_argc++] = *argv + 1;
  299. else
  300. emess(1,"overflowed + argument table");
  301. }
  302. else
  303. {
  304. if (from_argc < MAX_PARGS)
  305. from_argv[from_argc++] = *argv + 1;
  306. else
  307. emess(1,"overflowed + argument table");
  308. }
  309. } else /* assumed to be input file name(s) */
  310. eargv[eargc++] = *argv;
  311. }
  312. if (eargc == 0 ) /* if no specific files force sysin */
  313. eargv[eargc++] = "-";
  314. /*
  315. * If the user has requested inverse, then just reverse the
  316. * coordinate systems.
  317. */
  318. if( inverse )
  319. {
  320. int argcount;
  321. for( i = 0; i < MAX_PARGS; i++ )
  322. {
  323. char *arg;
  324. arg = from_argv[i];
  325. from_argv[i] = to_argv[i];
  326. to_argv[i] = arg;
  327. }
  328. argcount = from_argc;
  329. from_argc = to_argc;
  330. to_argc = argcount;
  331. }
  332. if (!(fromProj = pj_init(from_argc, from_argv)))
  333. {
  334. printf( "Using from definition: " );
  335. for( i = 0; i < from_argc; i++ )
  336. printf( "%s ", from_argv[i] );
  337. printf( "\n" );
  338. emess(3,"projection initialization failure\ncause: %s",
  339. pj_strerrno(pj_errno));
  340. }
  341. if( to_argc == 0 )
  342. {
  343. if (!(toProj = pj_latlong_from_proj( fromProj )))
  344. {
  345. printf( "Using to definition: " );
  346. for( i = 0; i < to_argc; i++ )
  347. printf( "%s ", to_argv[i] );
  348. printf( "\n" );
  349. emess(3,"projection initialization failure\ncause: %s",
  350. pj_strerrno(pj_errno));
  351. }
  352. }
  353. else if (!(toProj = pj_init(to_argc, to_argv)))
  354. {
  355. printf( "Using to definition: " );
  356. for( i = 0; i < to_argc; i++ )
  357. printf( "%s ", to_argv[i] );
  358. printf( "\n" );
  359. emess(3,"projection initialization failure\ncause: %s",
  360. pj_strerrno(pj_errno));
  361. }
  362. if (mon) {
  363. printf( "%c ---- From Coordinate System ----\n", tag );
  364. pj_pr_list(fromProj);
  365. printf( "%c ---- To Coordinate System ----\n", tag );
  366. pj_pr_list(toProj);
  367. }
  368. /* set input formating control */
  369. if( !fromProj->is_latlong )
  370. informat = strtod;
  371. else {
  372. informat = dmstor;
  373. }
  374. if( !toProj->is_latlong && !oform )
  375. oform = "%.2f";
  376. /* process input file list */
  377. for ( ; eargc-- ; ++eargv) {
  378. if (**eargv == '-') {
  379. fid = stdin;
  380. emess_dat.File_name = "<stdin>";
  381. } else {
  382. if ((fid = fopen(*eargv, "rt")) == NULL) {
  383. emess(-2, *eargv, "input file");
  384. continue;
  385. }
  386. emess_dat.File_name = *eargv;
  387. }
  388. emess_dat.File_line = 0;
  389. process(fid);
  390. fclose(fid);
  391. emess_dat.File_name = 0;
  392. }
  393. if( fromProj != NULL )
  394. pj_free( fromProj );
  395. if( toProj != NULL )
  396. pj_free( toProj );
  397. pj_deallocate_grids();
  398. exit(0); /* normal completion */
  399. }