/Proj4/pj_init.c

http://github.com/route-me/route-me · C · 434 lines · 244 code · 55 blank · 135 comment · 116 complexity · 0b27f5927aa5290611f5c6665c0e0134 MD5 · raw file

  1. /******************************************************************************
  2. * $Id: pj_init.c,v 1.19 2007/11/26 00:21:59 fwarmerdam Exp $
  3. *
  4. * Project: PROJ.4
  5. * Purpose: Initialize projection object from string definition. Includes
  6. * pj_init(), pj_init_plus() and pj_free() function.
  7. * Author: Gerald Evenden, Frank Warmerdam <warmerdam@pobox.com>
  8. *
  9. ******************************************************************************
  10. * Copyright (c) 1995, Gerald Evenden
  11. * Copyright (c) 2002, Frank Warmerdam <warmerdam@pobox.com>
  12. *
  13. * Permission is hereby granted, free of charge, to any person obtaining a
  14. * copy of this software and associated documentation files (the "Software"),
  15. * to deal in the Software without restriction, including without limitation
  16. * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  17. * and/or sell copies of the Software, and to permit persons to whom the
  18. * Software is furnished to do so, subject to the following conditions:
  19. *
  20. * The above copyright notice and this permission notice shall be included
  21. * in all copies or substantial portions of the Software.
  22. *
  23. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
  24. * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  25. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  26. * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  27. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  28. * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  29. * DEALINGS IN THE SOFTWARE.
  30. ******************************************************************************
  31. *
  32. * $Log: pj_init.c,v $
  33. * Revision 1.19 2007/11/26 00:21:59 fwarmerdam
  34. * Modified PJ structure to hold a_orig, es_orig, ellipsoid definition before
  35. * adjustment for spherical projections.
  36. * Modified pj_datum_transform() to use the original ellipsoid parameters,
  37. * not the ones adjusted for spherical projections.
  38. * Modified pj_datum_transform() to not attempt any datum shift via
  39. * geocentric coordinates if the source *or* destination are raw ellipsoids
  40. * (ie. PJD_UNKNOWN). All per PROJ bug #1602, GDAL bug #2025.
  41. *
  42. * Revision 1.18 2006/10/12 21:04:39 fwarmerdam
  43. * Added experimental +lon_wrap argument to set a "center point" for
  44. * longitude wrapping of longitude values coming out of pj_transform().
  45. *
  46. * Revision 1.17 2006/09/22 23:06:24 fwarmerdam
  47. * remote static start variable in pj_init (bug 1283)
  48. *
  49. * Revision 1.16 2004/09/08 15:23:37 warmerda
  50. * added new error for unknown prime meridians
  51. *
  52. * Revision 1.15 2004/05/05 01:45:41 warmerda
  53. * Made sword even longer.
  54. *
  55. * Revision 1.14 2004/05/05 01:45:00 warmerda
  56. * Make sword buffer larger so long +towgs84 parameters don't get split.
  57. *
  58. * Revision 1.13 2003/09/16 03:46:21 warmerda
  59. * dont use default ellps if any earth model info is set: bug 386
  60. *
  61. * Revision 1.12 2003/08/21 02:15:59 warmerda
  62. * improve MAX_ARG checking
  63. *
  64. * Revision 1.11 2003/06/09 21:23:16 warmerda
  65. * ensure start is initialized at very beginning of pj_init()
  66. *
  67. * Revision 1.10 2003/03/16 16:38:24 warmerda
  68. * Modified get_opt() to terminate reading the definition when a new
  69. * definition (a word starting with '<') is encountered, in addition to when
  70. * the definition terminator '<>' is encountered, so that unterminated
  71. * definitions like those in the distributed esri file will work properly.
  72. * http://bugzilla.remotesensing.org/show_bug.cgi?id=302
  73. *
  74. * Revision 1.9 2002/12/14 20:15:02 warmerda
  75. * added geocentric support, updated headers
  76. *
  77. */
  78. #define PJ_LIB__
  79. #include "projects.h"
  80. #include <stdio.h>
  81. #include <string.h>
  82. #include <errno.h>
  83. PJ_CVSID("$Id: pj_init.c,v 1.19 2007/11/26 00:21:59 fwarmerdam Exp $");
  84. extern FILE *pj_open_lib(char *, char *);
  85. /************************************************************************/
  86. /* get_opt() */
  87. /************************************************************************/
  88. static paralist *
  89. get_opt(paralist **start, FILE *fid, char *name, paralist *next) {
  90. char sword[302], *word = sword+1;
  91. int first = 1, len, c;
  92. len = strlen(name);
  93. *sword = 't';
  94. while (fscanf(fid, "%300s", word) == 1) {
  95. if (*word == '#') /* skip comments */
  96. while((c = fgetc(fid)) != EOF && c != '\n') ;
  97. else if (*word == '<') { /* control name */
  98. if (first && !strncmp(name, word + 1, len)
  99. && word[len + 1] == '>')
  100. first = 0;
  101. else if (!first && *word == '<') {
  102. while((c = fgetc(fid)) != EOF && c != '\n') ;
  103. break;
  104. }
  105. } else if (!first && !pj_param(*start, sword).i) {
  106. /* don't default ellipse if datum, ellps or any earth model
  107. information is set. */
  108. if( strncmp(word,"ellps=",6) != 0
  109. || (!pj_param(*start, "tdatum").i
  110. && !pj_param(*start, "tellps").i
  111. && !pj_param(*start, "ta").i
  112. && !pj_param(*start, "tb").i
  113. && !pj_param(*start, "trf").i
  114. && !pj_param(*start, "tf").i) )
  115. {
  116. next = next->next = pj_mkparam(word);
  117. }
  118. }
  119. }
  120. if (errno == 25)
  121. errno = 0;
  122. return next;
  123. }
  124. /************************************************************************/
  125. /* get_defaults() */
  126. /************************************************************************/
  127. static paralist *
  128. get_defaults(paralist **start, paralist *next, char *name) {
  129. FILE *fid;
  130. fid = pj_open_lib("proj_def.dat", "rt");
  131. if (fid) {
  132. next = get_opt(start, fid, "general", next);
  133. rewind(fid);
  134. next = get_opt(start, fid, name, next);
  135. (void)fclose(fid);
  136. }
  137. if (errno)
  138. errno = 0; /* don't care if can't open file */
  139. return next;
  140. }
  141. /************************************************************************/
  142. /* get_init() */
  143. /************************************************************************/
  144. static paralist *
  145. get_init(paralist **start, paralist *next, char *name) {
  146. char fname[MAX_PATH_FILENAME+ID_TAG_MAX+3], *opt;
  147. FILE *fid;
  148. (void)strncpy(fname, name, MAX_PATH_FILENAME + ID_TAG_MAX + 1);
  149. opt = strrchr(fname, ':');
  150. if (opt)
  151. *opt++ = '\0';
  152. else { pj_errno = -3; return(0); }
  153. fid = pj_open_lib(fname, "rt");
  154. if (fid)
  155. next = get_opt(start, fid, opt, next);
  156. else
  157. return(0);
  158. (void)fclose(fid);
  159. if (errno == 25)
  160. errno = 0; /* unknown problem with some sys errno<-25 */
  161. return next;
  162. }
  163. /************************************************************************/
  164. /* pj_init_plus() */
  165. /* */
  166. /* Same as pj_init() except it takes one argument string with */
  167. /* individual arguments preceeded by '+', such as "+proj=utm */
  168. /* +zone=11 +ellps=WGS84". */
  169. /************************************************************************/
  170. PJ *
  171. pj_init_plus( const char *definition )
  172. {
  173. #define MAX_ARG 200
  174. char *argv[MAX_ARG];
  175. char *defn_copy;
  176. int argc = 0, i;
  177. PJ *result;
  178. /* make a copy that we can manipulate */
  179. defn_copy = (char *) pj_malloc( strlen(definition)+1 );
  180. strcpy( defn_copy, definition );
  181. /* split into arguments based on '+' and trim white space */
  182. for( i = 0; defn_copy[i] != '\0'; i++ )
  183. {
  184. switch( defn_copy[i] )
  185. {
  186. case '+':
  187. if( i == 0 || defn_copy[i-1] == '\0' )
  188. {
  189. if( argc+1 == MAX_ARG )
  190. {
  191. pj_errno = -44;
  192. return NULL;
  193. }
  194. argv[argc++] = defn_copy + i + 1;
  195. }
  196. break;
  197. case ' ':
  198. case '\t':
  199. case '\n':
  200. defn_copy[i] = '\0';
  201. break;
  202. default:
  203. /* do nothing */;
  204. }
  205. }
  206. /* perform actual initialization */
  207. result = pj_init( argc, argv );
  208. pj_dalloc( defn_copy );
  209. return result;
  210. }
  211. /************************************************************************/
  212. /* pj_init() */
  213. /* */
  214. /* Main entry point for initialing a PJ projections */
  215. /* definition. Note that the projection specific function is */
  216. /* called to do the initial allocation so it can be created */
  217. /* large enough to hold projection specific parameters. */
  218. /************************************************************************/
  219. PJ *
  220. pj_init(int argc, char **argv) {
  221. char *s, *name;
  222. paralist *start = NULL;
  223. PJ *(*proj)(PJ *);
  224. paralist *curr = 0;
  225. int i;
  226. PJ *PIN = 0;
  227. errno = pj_errno = 0;
  228. start = NULL;
  229. /* put arguments into internal linked list */
  230. if (argc <= 0) { pj_errno = -1; goto bum_call; }
  231. for (i = 0; i < argc; ++i)
  232. if (i)
  233. curr = curr->next = pj_mkparam(argv[i]);
  234. else
  235. start = curr = pj_mkparam(argv[i]);
  236. if (pj_errno) goto bum_call;
  237. /* check if +init present */
  238. if (pj_param(start, "tinit").i) {
  239. paralist *last = curr;
  240. if (!(curr = get_init(&start, curr, pj_param(start, "sinit").s)))
  241. goto bum_call;
  242. if (curr == last) { pj_errno = -2; goto bum_call; }
  243. }
  244. /* find projection selection */
  245. if (!(name = pj_param(start, "sproj").s))
  246. { pj_errno = -4; goto bum_call; }
  247. for (i = 0; (s = pj_list[i].id) && strcmp(name, s) ; ++i) ;
  248. if (!s) { pj_errno = -5; goto bum_call; }
  249. /* set defaults, unless inhibited */
  250. if (!pj_param(start, "bno_defs").i)
  251. get_defaults(&start, curr, name);
  252. proj = (PJ *(*)(PJ *)) pj_list[i].proj;
  253. /* allocate projection structure */
  254. if (!(PIN = (*proj)(0))) goto bum_call;
  255. PIN->params = start;
  256. PIN->is_latlong = 0;
  257. PIN->is_geocent = 0;
  258. PIN->long_wrap_center = 0.0;
  259. /* set datum parameters */
  260. if (pj_datum_set(start, PIN)) goto bum_call;
  261. /* set ellipsoid/sphere parameters */
  262. if (pj_ell_set(start, &PIN->a, &PIN->es)) goto bum_call;
  263. PIN->a_orig = PIN->a;
  264. PIN->es_orig = PIN->es;
  265. PIN->e = sqrt(PIN->es);
  266. PIN->ra = 1. / PIN->a;
  267. PIN->one_es = 1. - PIN->es;
  268. if (PIN->one_es == 0.) { pj_errno = -6; goto bum_call; }
  269. PIN->rone_es = 1./PIN->one_es;
  270. /* Now that we have ellipse information check for WGS84 datum */
  271. if( PIN->datum_type == PJD_3PARAM
  272. && PIN->datum_params[0] == 0.0
  273. && PIN->datum_params[1] == 0.0
  274. && PIN->datum_params[2] == 0.0
  275. && PIN->a == 6378137.0
  276. && ABS(PIN->es - 0.006694379990) < 0.000000000050 )/*WGS84/GRS80*/
  277. {
  278. PIN->datum_type = PJD_WGS84;
  279. }
  280. /* set PIN->geoc coordinate system */
  281. PIN->geoc = (PIN->es && pj_param(start, "bgeoc").i);
  282. /* over-ranging flag */
  283. PIN->over = pj_param(start, "bover").i;
  284. /* longitude center for wrapping */
  285. PIN->long_wrap_center = pj_param(start, "rlon_wrap").f;
  286. /* central meridian */
  287. PIN->lam0=pj_param(start, "rlon_0").f;
  288. /* central latitude */
  289. PIN->phi0 = pj_param(start, "rlat_0").f;
  290. /* false easting and northing */
  291. PIN->x0 = pj_param(start, "dx_0").f;
  292. PIN->y0 = pj_param(start, "dy_0").f;
  293. /* general scaling factor */
  294. if (pj_param(start, "tk_0").i)
  295. PIN->k0 = pj_param(start, "dk_0").f;
  296. else if (pj_param(start, "tk").i)
  297. PIN->k0 = pj_param(start, "dk").f;
  298. else
  299. PIN->k0 = 1.;
  300. if (PIN->k0 <= 0.) {
  301. pj_errno = -31;
  302. goto bum_call;
  303. }
  304. /* set units */
  305. s = 0;
  306. name = pj_param(start, "sunits").s;
  307. if (name) {
  308. for (i = 0; (s = pj_units[i].id) && strcmp(name, s) ; ++i) ;
  309. if (!s) { pj_errno = -7; goto bum_call; }
  310. s = pj_units[i].to_meter;
  311. }
  312. if (s || (s = pj_param(start, "sto_meter").s)) {
  313. PIN->to_meter = strtod(s, &s);
  314. if (*s == '/') /* ratio number */
  315. PIN->to_meter /= strtod(++s, 0);
  316. PIN->fr_meter = 1. / PIN->to_meter;
  317. } else
  318. PIN->to_meter = PIN->fr_meter = 1.;
  319. /* prime meridian */
  320. s = 0;
  321. name = pj_param(start, "spm").s;
  322. if (name) {
  323. const char *value = NULL;
  324. char *next_str = NULL;
  325. for (i = 0; pj_prime_meridians[i].id != NULL; ++i )
  326. {
  327. if( strcmp(name,pj_prime_meridians[i].id) == 0 )
  328. {
  329. value = pj_prime_meridians[i].defn;
  330. break;
  331. }
  332. }
  333. if( value == NULL
  334. && (dmstor(name,&next_str) != 0.0 || *name == '0')
  335. && *next_str == '\0' )
  336. value = name;
  337. if (!value) { pj_errno = -46; goto bum_call; }
  338. PIN->from_greenwich = dmstor(value,NULL);
  339. }
  340. else
  341. PIN->from_greenwich = 0.0;
  342. /* projection specific initialization */
  343. if (!(PIN = (*proj)(PIN)) || errno || pj_errno) {
  344. bum_call: /* cleanup error return */
  345. if (!pj_errno)
  346. pj_errno = errno;
  347. if (PIN)
  348. pj_free(PIN);
  349. else
  350. for ( ; start; start = curr) {
  351. curr = start->next;
  352. pj_dalloc(start);
  353. }
  354. PIN = 0;
  355. }
  356. return PIN;
  357. }
  358. /************************************************************************/
  359. /* pj_free() */
  360. /* */
  361. /* This is the application callable entry point for destroying */
  362. /* a projection definition. It does work generic to all */
  363. /* projection types, and then calls the projection specific */
  364. /* free function (P->pfree()) to do local work. This maps to */
  365. /* the FREEUP code in the individual projection source files. */
  366. /************************************************************************/
  367. void
  368. pj_free(PJ *P) {
  369. if (P) {
  370. paralist *t, *n;
  371. /* free parameter list elements */
  372. for (t = P->params; t; t = n) {
  373. n = t->next;
  374. pj_dalloc(t);
  375. }
  376. /* free projection parameters */
  377. P->pfree(P);
  378. }
  379. }