datum.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431
  1. /**
  2. \file lib/proj/datum.c
  3. \brief GProj library - Functions for reading datum parameters from the location database
  4. \author Andreas Lange <andreas.lange rhein-main.de>, Paul Kelly <paul-grass stjohnspoint.co.uk>
  5. (C) 2003-2008 by the GRASS Development Team
  6. This program is free software under the GNU General Public
  7. License (>=v2). Read the file COPYING that comes with GRASS
  8. for details.
  9. **/
  10. #include <unistd.h>
  11. #include <string.h>
  12. #include <ctype.h>
  13. #include <stdlib.h>
  14. #include <grass/gis.h>
  15. #include <grass/glocale.h>
  16. #include <grass/gprojects.h>
  17. #include "local_proto.h"
  18. /**
  19. * \brief Look up a string in datum.table file to see if it is a valid datum
  20. * name and if so place its information into a gpj_datum struct
  21. *
  22. * \param name String containing datum name to look up
  23. * \param dstruct gpj_datum struct into which datum parameters will be placed
  24. * if found
  25. *
  26. * \return 1 if datum found, -1 if not
  27. **/
  28. int GPJ_get_datum_by_name(const char *name, struct gpj_datum *dstruct)
  29. {
  30. struct datum_list *list, *listhead;
  31. list = listhead = read_datum_table();
  32. while (list != NULL) {
  33. if (G_strcasecmp(name, list->name) == 0) {
  34. dstruct->name = G_store(list->name);
  35. dstruct->longname = G_store(list->longname);
  36. dstruct->ellps = G_store(list->ellps);
  37. dstruct->dx = list->dx;
  38. dstruct->dy = list->dy;
  39. dstruct->dz = list->dz;
  40. free_datum_list(listhead);
  41. return 1;
  42. }
  43. list = list->next;
  44. }
  45. free_datum_list(listhead);
  46. return -1;
  47. }
  48. /**
  49. * \brief "Last resort" function to retrieve a "default" set of datum
  50. * parameters for a datum (N.B. there really is no such thing as a
  51. * catch-all default!)
  52. *
  53. * Kind of a "last resort" function as there really is no such thing
  54. * as a default set of datum transformation parameters. Only should
  55. * really be used where user interaction to choose a set of parameters
  56. * is not desirable. Use of this function is not likely to result in
  57. * selection of the optimum set of datum transformation parameters
  58. * for the location
  59. *
  60. * \param name String containing GRASS datum name for which default
  61. * parameters are to be retrieved
  62. *
  63. * \param params Pointer to a pointer which will have memory
  64. * allocated and into which a string containing
  65. * the datum parameters (if present) will
  66. * be placed
  67. *
  68. * \return The number of possible parameter sets GRASS knows
  69. * about for this datum
  70. *
  71. **/
  72. int GPJ_get_default_datum_params_by_name(const char *name, char **params)
  73. {
  74. struct gpj_datum_transform_list *list, *old;
  75. int count = 0;
  76. list = GPJ_get_datum_transform_by_name(name);
  77. if (list == NULL) {
  78. *params = NULL;
  79. return -1;
  80. }
  81. /* Take the first parameter set in the list as the default
  82. * (will normally be a 3-parameter transformation) */
  83. *params = G_store(list->params);
  84. while (list != NULL) {
  85. count++;
  86. old = list;
  87. list = list->next;
  88. GPJ_free_datum_transform(old);
  89. }
  90. return count;
  91. }
  92. /**
  93. *
  94. * \brief Extract the datum transformation-related parameters for
  95. * the current location.
  96. *
  97. * This function can be used to test if a location's co-ordinate
  98. * system set-up supports datum transformation.
  99. *
  100. * \param name Pointer to a pointer which will have memory
  101. * allocated and into which a string containing the
  102. * datum name (if present) will be placed. Otherwise
  103. * set to NULL.
  104. *
  105. * \param params Pointer to a pointer which will have memory
  106. * allocated and into which a string containing
  107. * the datum parameters (if present) will
  108. * be placed. Otherwise set to NULL.
  109. *
  110. * \return -1 error or no datum information found,
  111. * 1 only datum name found, 2 params found
  112. *
  113. **/
  114. int GPJ_get_datum_params(char **name, char **params)
  115. {
  116. int ret;
  117. struct Key_Value *proj_keys = G_get_projinfo();
  118. ret = GPJ__get_datum_params(proj_keys, name, params);
  119. G_free_key_value(proj_keys);
  120. return ret;
  121. }
  122. /**
  123. *
  124. * \brief Extract the datum transformation-related parameters from a
  125. * set of general PROJ_INFO parameters.
  126. *
  127. * This function can be used to test if a location's co-ordinate
  128. * system set-up supports datum transformation.
  129. *
  130. * \param projinfo Set of key_value pairs containing
  131. * projection information in PROJ_INFO file
  132. * format
  133. *
  134. * \param datumname Pointer to a pointer which will have memory
  135. * allocated and into which a string containing the
  136. * datum name (if present) will be placed. Otherwise
  137. * set to NULL.
  138. *
  139. * \param params Pointer to a pointer which will have memory
  140. * allocated and into which a string containing
  141. * the datum parameters (if present) will
  142. * be placed. Otherwise set to NULL.
  143. *
  144. * \return -1 error or no datum information found,
  145. * 1 only datum name found, 2 params found
  146. *
  147. **/
  148. int GPJ__get_datum_params(const struct Key_Value *projinfo,
  149. char **datumname, char **params)
  150. {
  151. int returnval = -1;
  152. if (NULL != G_find_key_value("datum", projinfo)) {
  153. *datumname = G_store(G_find_key_value("datum", projinfo));
  154. G_debug(3, "GPJ__get_datum_params: datumname: <%s>", G_find_key_value("datum", projinfo));
  155. returnval = 1;
  156. }
  157. else
  158. *datumname = NULL;
  159. if (G_find_key_value("datumparams", projinfo) != NULL) {
  160. *params = G_store(G_find_key_value("datumparams", projinfo));
  161. G_debug(3, "GPJ__get_datum_params: datumparams: <%s>", G_find_key_value("datumparams", projinfo));
  162. returnval = 2;
  163. }
  164. else if (G_find_key_value("nadgrids", projinfo) != NULL) {
  165. /* 1. beware of '@', do not create something like
  166. * /usr/share/proj/@null, correct is @null or
  167. * @/usr/share/proj/null
  168. * 2. do not add path to the grid, there might already be a
  169. * path, and it is safer to use pj_set_finder with PROJ.4 in
  170. * datum.c */
  171. G_asprintf(params, "nadgrids=%s", G_find_key_value("nadgrids", projinfo));
  172. returnval = 2;
  173. }
  174. else if (G_find_key_value("towgs84", projinfo) != NULL) {
  175. G_asprintf(params, "towgs84=%s",
  176. G_find_key_value("towgs84", projinfo));
  177. returnval = 2;
  178. }
  179. else if (G_find_key_value("dx", projinfo) != NULL
  180. && G_find_key_value("dy", projinfo) != NULL
  181. && G_find_key_value("dz", projinfo) != NULL) {
  182. G_asprintf(params, "towgs84=%s,%s,%s",
  183. G_find_key_value("dx", projinfo),
  184. G_find_key_value("dy", projinfo),
  185. G_find_key_value("dz", projinfo));
  186. returnval = 2;
  187. }
  188. else
  189. *params = NULL;
  190. return returnval;
  191. }
  192. /**
  193. * \brief Internal function to find all possible sets of
  194. * transformation parameters for a particular datum
  195. *
  196. * \param inputname String containing the datum name we
  197. * are going to look up parameters for
  198. *
  199. * \return Pointer to struct gpj_datum_transform_list (a linked
  200. * list containing transformation parameters),
  201. * or NULL if no suitable parameters were found.
  202. **/
  203. struct gpj_datum_transform_list *GPJ_get_datum_transform_by_name(const char
  204. *inputname)
  205. {
  206. FILE *fd;
  207. char file[GPATH_MAX];
  208. char buf[1024];
  209. int line;
  210. struct gpj_datum_transform_list *current = NULL, *outputlist = NULL;
  211. struct gpj_datum dstruct;
  212. int count = 0;
  213. GPJ_get_datum_by_name(inputname, &dstruct);
  214. if (dstruct.dx < 99999 && dstruct.dy < 99999 && dstruct.dz < 99999) {
  215. /* Include the old-style dx dy dz parameters from datum.table at the
  216. * start of the list, unless these have been set to all 99999 to
  217. * indicate only entries in datumtransform.table should be used */
  218. if (current == NULL)
  219. current = outputlist =
  220. G_malloc(sizeof(struct gpj_datum_transform_list));
  221. else
  222. current = current->next =
  223. G_malloc(sizeof(struct gpj_datum_transform_list));
  224. G_asprintf(&(current->params), "towgs84=%.3f,%.3f,%.3f", dstruct.dx,
  225. dstruct.dy, dstruct.dz);
  226. G_asprintf(&(current->where_used), "whole %s region", inputname);
  227. G_asprintf(&(current->comment),
  228. "Default 3-Parameter Transformation (May not be optimum for "
  229. "older datums; use this only if no more appropriate options "
  230. "are available.)");
  231. count++;
  232. current->count = count;
  233. current->next = NULL;
  234. }
  235. GPJ_free_datum(&dstruct);
  236. /* Now check for additional parameters in datumtransform.table */
  237. sprintf(file, "%s%s", G_gisbase(), DATUMTRANSFORMTABLE);
  238. fd = fopen(file, "r");
  239. if (!fd) {
  240. G_warning(_("Unable to open datum table file <%s>"), file);
  241. return outputlist;
  242. }
  243. for (line = 1; G_getl2(buf, sizeof(buf), fd); line++) {
  244. char name[100], params[1024], where_used[1024], comment[1024];
  245. G_strip(buf);
  246. if (*buf == '\0' || *buf == '#')
  247. continue;
  248. if (sscanf(buf, "%99s \"%1023[^\"]\" \"%1023[^\"]\" \"%1023[^\"]\"",
  249. name, params, where_used, comment) != 4) {
  250. G_warning(_("Error in datum table file <%s>, line %d"), file,
  251. line);
  252. continue;
  253. }
  254. if (G_strcasecmp(inputname, name) == 0) {
  255. /* If the datum name in this line matches the one we are
  256. * looking for, add an entry to the linked list */
  257. if (current == NULL)
  258. current = outputlist =
  259. G_malloc(sizeof(struct gpj_datum_transform_list));
  260. else
  261. current = current->next =
  262. G_malloc(sizeof(struct gpj_datum_transform_list));
  263. current->params = G_store(params);
  264. current->where_used = G_store(where_used);
  265. current->comment = G_store(comment);
  266. count++;
  267. current->count = count;
  268. current->next = NULL;
  269. }
  270. }
  271. fclose(fd);
  272. return outputlist;
  273. }
  274. /**
  275. * \brief Free the memory used by a gpj_datum_transform_list struct
  276. *
  277. * \param item gpj_datum_transform_list struct to be freed
  278. **/
  279. void GPJ_free_datum_transform(struct gpj_datum_transform_list *item)
  280. {
  281. G_free(item->params);
  282. G_free(item->where_used);
  283. G_free(item->comment);
  284. G_free(item);
  285. return;
  286. }
  287. /**
  288. * \brief Read the current GRASS datum.table from disk and store in
  289. * memory
  290. *
  291. * The datum information is stored in a datum_list linked list structure.
  292. *
  293. * \return Pointer to first datum_list element in linked list, or NULL
  294. * if unable to open datum.table file
  295. **/
  296. struct datum_list *read_datum_table(void)
  297. {
  298. FILE *fd;
  299. char file[GPATH_MAX];
  300. char buf[4096];
  301. int line;
  302. struct datum_list *current = NULL, *outputlist = NULL;
  303. int count = 0;
  304. sprintf(file, "%s%s", G_gisbase(), DATUMTABLE);
  305. fd = fopen(file, "r");
  306. if (!fd) {
  307. G_warning(_("Unable to open datum table file <%s>"), file);
  308. return NULL;
  309. }
  310. for (line = 1; G_getl2(buf, sizeof(buf), fd); line++) {
  311. char name[100], descr[1024], ellps[100];
  312. double dx, dy, dz;
  313. G_strip(buf);
  314. if (*buf == '\0' || *buf == '#')
  315. continue;
  316. if (sscanf(buf, "%s \"%1023[^\"]\" %s dx=%lf dy=%lf dz=%lf",
  317. name, descr, ellps, &dx, &dy, &dz) != 6) {
  318. G_warning(_("Error in datum table file <%s>, line %d"), file,
  319. line);
  320. continue;
  321. }
  322. if (current == NULL)
  323. current = outputlist = G_malloc(sizeof(struct datum_list));
  324. else
  325. current = current->next = G_malloc(sizeof(struct datum_list));
  326. current->name = G_store(name);
  327. current->longname = G_store(descr);
  328. current->ellps = G_store(ellps);
  329. current->dx = dx;
  330. current->dy = dy;
  331. current->dz = dz;
  332. current->next = NULL;
  333. count++;
  334. }
  335. fclose(fd);
  336. return outputlist;
  337. }
  338. /**
  339. * \brief Free the memory used for the strings in a gpj_datum struct
  340. *
  341. * \param dstruct gpj_datum struct to be freed
  342. **/
  343. void GPJ_free_datum(struct gpj_datum *dstruct)
  344. {
  345. G_free(dstruct->name);
  346. G_free(dstruct->longname);
  347. G_free(dstruct->ellps);
  348. return;
  349. }
  350. /**
  351. * \brief Free the memory used by a datum_list linked list structure
  352. *
  353. * \param dstruct datum_list struct to be freed
  354. **/
  355. void free_datum_list(struct datum_list *dstruct)
  356. {
  357. struct datum_list *old;
  358. while (dstruct != NULL) {
  359. G_free(dstruct->name);
  360. G_free(dstruct->longname);
  361. G_free(dstruct->ellps);
  362. old = dstruct;
  363. dstruct = old->next;
  364. G_free(old);
  365. }
  366. return;
  367. }