datum.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432
  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. const char *projshare = getenv("GRASS_PROJSHARE");
  166. if (!projshare) {
  167. G_warning(_("Failed to detect nadgrids path, GRASS_PROJSHARE not defined"));
  168. returnval = -1;
  169. }
  170. else {
  171. G_asprintf(params, "nadgrids=%s%c%s", projshare, HOST_DIRSEP,
  172. G_find_key_value("nadgrids", projinfo));
  173. returnval = 2;
  174. }
  175. }
  176. else if (G_find_key_value("towgs84", projinfo) != NULL) {
  177. G_asprintf(params, "towgs84=%s",
  178. G_find_key_value("towgs84", projinfo));
  179. returnval = 2;
  180. }
  181. else if (G_find_key_value("dx", projinfo) != NULL
  182. && G_find_key_value("dy", projinfo) != NULL
  183. && G_find_key_value("dz", projinfo) != NULL) {
  184. G_asprintf(params, "towgs84=%s,%s,%s",
  185. G_find_key_value("dx", projinfo),
  186. G_find_key_value("dy", projinfo),
  187. G_find_key_value("dz", projinfo));
  188. returnval = 2;
  189. }
  190. else
  191. *params = NULL;
  192. return returnval;
  193. }
  194. /**
  195. * \brief Internal function to find all possible sets of
  196. * transformation parameters for a particular datum
  197. *
  198. * \param inputname String containing the datum name we
  199. * are going to look up parameters for
  200. *
  201. * \return Pointer to struct gpj_datum_transform_list (a linked
  202. * list containing transformation parameters),
  203. * or NULL if no suitable parameters were found.
  204. **/
  205. struct gpj_datum_transform_list *GPJ_get_datum_transform_by_name(const char
  206. *inputname)
  207. {
  208. FILE *fd;
  209. char file[GPATH_MAX];
  210. char buf[1024];
  211. int line;
  212. struct gpj_datum_transform_list *current = NULL, *outputlist = NULL;
  213. struct gpj_datum dstruct;
  214. int count = 0;
  215. GPJ_get_datum_by_name(inputname, &dstruct);
  216. if (dstruct.dx < 99999 && dstruct.dy < 99999 && dstruct.dz < 99999) {
  217. /* Include the old-style dx dy dz parameters from datum.table at the
  218. * start of the list, unless these have been set to all 99999 to
  219. * indicate only entries in datumtransform.table should be used */
  220. if (current == NULL)
  221. current = outputlist =
  222. G_malloc(sizeof(struct gpj_datum_transform_list));
  223. else
  224. current = current->next =
  225. G_malloc(sizeof(struct gpj_datum_transform_list));
  226. G_asprintf(&(current->params), "towgs84=%.3f,%.3f,%.3f", dstruct.dx,
  227. dstruct.dy, dstruct.dz);
  228. G_asprintf(&(current->where_used), "whole %s region", inputname);
  229. G_asprintf(&(current->comment),
  230. "Default 3-Parameter Transformation (May not be optimum for "
  231. "older datums; use this only if no more appropriate options "
  232. "are available.)");
  233. count++;
  234. current->count = count;
  235. current->next = NULL;
  236. }
  237. GPJ_free_datum(&dstruct);
  238. /* Now check for additional parameters in datumtransform.table */
  239. sprintf(file, "%s%s", G_gisbase(), DATUMTRANSFORMTABLE);
  240. fd = fopen(file, "r");
  241. if (!fd) {
  242. G_warning(_("Unable to open datum table file <%s>"), file);
  243. return outputlist;
  244. }
  245. for (line = 1; G_getl2(buf, sizeof(buf), fd); line++) {
  246. char name[100], params[1024], where_used[1024], comment[1024];
  247. G_strip(buf);
  248. if (*buf == '\0' || *buf == '#')
  249. continue;
  250. if (sscanf(buf, "%99s \"%1023[^\"]\" \"%1023[^\"]\" \"%1023[^\"]\"",
  251. name, params, where_used, comment) != 4) {
  252. G_warning(_("Error in datum table file <%s>, line %d"), file,
  253. line);
  254. continue;
  255. }
  256. if (G_strcasecmp(inputname, name) == 0) {
  257. /* If the datum name in this line matches the one we are
  258. * looking for, add an entry to the linked list */
  259. if (current == NULL)
  260. current = outputlist =
  261. G_malloc(sizeof(struct gpj_datum_transform_list));
  262. else
  263. current = current->next =
  264. G_malloc(sizeof(struct gpj_datum_transform_list));
  265. current->params = G_store(params);
  266. current->where_used = G_store(where_used);
  267. current->comment = G_store(comment);
  268. count++;
  269. current->count = count;
  270. current->next = NULL;
  271. }
  272. }
  273. fclose(fd);
  274. return outputlist;
  275. }
  276. /**
  277. * \brief Free the memory used by a gpj_datum_transform_list struct
  278. *
  279. * \param item gpj_datum_transform_list struct to be freed
  280. **/
  281. void GPJ_free_datum_transform(struct gpj_datum_transform_list *item)
  282. {
  283. G_free(item->params);
  284. G_free(item->where_used);
  285. G_free(item->comment);
  286. G_free(item);
  287. return;
  288. }
  289. /**
  290. * \brief Read the current GRASS datum.table from disk and store in
  291. * memory
  292. *
  293. * The datum information is stored in a datum_list linked list structure.
  294. *
  295. * \return Pointer to first datum_list element in linked list, or NULL
  296. * if unable to open datum.table file
  297. **/
  298. struct datum_list *read_datum_table(void)
  299. {
  300. FILE *fd;
  301. char file[GPATH_MAX];
  302. char buf[4096];
  303. int line;
  304. struct datum_list *current = NULL, *outputlist = NULL;
  305. int count = 0;
  306. sprintf(file, "%s%s", G_gisbase(), DATUMTABLE);
  307. fd = fopen(file, "r");
  308. if (!fd) {
  309. G_warning(_("Unable to open datum table file <%s>"), file);
  310. return NULL;
  311. }
  312. for (line = 1; G_getl2(buf, sizeof(buf), fd); line++) {
  313. char name[100], descr[1024], ellps[100];
  314. double dx, dy, dz;
  315. G_strip(buf);
  316. if (*buf == '\0' || *buf == '#')
  317. continue;
  318. if (sscanf(buf, "%s \"%1023[^\"]\" %s dx=%lf dy=%lf dz=%lf",
  319. name, descr, ellps, &dx, &dy, &dz) != 6) {
  320. G_warning(_("Error in datum table file <%s>, line %d"), file,
  321. line);
  322. continue;
  323. }
  324. if (current == NULL)
  325. current = outputlist = G_malloc(sizeof(struct datum_list));
  326. else
  327. current = current->next = G_malloc(sizeof(struct datum_list));
  328. current->name = G_store(name);
  329. current->longname = G_store(descr);
  330. current->ellps = G_store(ellps);
  331. current->dx = dx;
  332. current->dy = dy;
  333. current->dz = dz;
  334. current->next = NULL;
  335. count++;
  336. }
  337. fclose(fd);
  338. return outputlist;
  339. }
  340. /**
  341. * \brief Free the memory used for the strings in a gpj_datum struct
  342. *
  343. * \param dstruct gpj_datum struct to be freed
  344. **/
  345. void GPJ_free_datum(struct gpj_datum *dstruct)
  346. {
  347. G_free(dstruct->name);
  348. G_free(dstruct->longname);
  349. G_free(dstruct->ellps);
  350. return;
  351. }
  352. /**
  353. * \brief Free the memory used by a datum_list linked list structure
  354. *
  355. * \param dstruct datum_list struct to be freed
  356. **/
  357. void free_datum_list(struct datum_list *dstruct)
  358. {
  359. struct datum_list *old;
  360. while (dstruct != NULL) {
  361. G_free(dstruct->name);
  362. G_free(dstruct->longname);
  363. G_free(dstruct->ellps);
  364. old = dstruct;
  365. dstruct = old->next;
  366. G_free(old);
  367. }
  368. return;
  369. }