datum.c 12 KB

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