datum.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410
  1. /**
  2. \file 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 = 1;
  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->next != NULL) {
  85. count++;
  86. old = list;
  87. list = list->next;
  88. G_free(old);
  89. }
  90. G_free(list);
  91. return count;
  92. }
  93. /**
  94. *
  95. * \brief Extract the datum transformation-related parameters for
  96. * the current location.
  97. *
  98. * This function can be used to test if a location's co-ordinate
  99. * system set-up supports datum transformation.
  100. *
  101. * \param name Pointer to a pointer which will have memory
  102. * allocated and into which a string containing the
  103. * datum name (if present) will be placed. Otherwise
  104. * set to NULL.
  105. *
  106. * \param params Pointer to a pointer which will have memory
  107. * allocated and into which a string containing
  108. * the datum parameters (if present) will
  109. * be placed. Otherwise set to NULL.
  110. *
  111. * \return -1 error or no datum information found,
  112. * 1 only datum name found, 2 params found
  113. *
  114. **/
  115. int GPJ_get_datum_params(char **name, char **params)
  116. {
  117. int ret;
  118. struct Key_Value *proj_keys = G_get_projinfo();
  119. ret = GPJ__get_datum_params(proj_keys, name, params);
  120. G_free_key_value(proj_keys);
  121. return ret;
  122. }
  123. /**
  124. *
  125. * \brief Extract the datum transformation-related parameters from a
  126. * set of general PROJ_INFO parameters.
  127. *
  128. * This function can be used to test if a location's co-ordinate
  129. * system set-up supports datum transformation.
  130. *
  131. * \param projinfo Set of key_value pairs containing
  132. * projection information in PROJ_INFO file
  133. * format
  134. *
  135. * \param datumname Pointer to a pointer which will have memory
  136. * allocated and into which a string containing the
  137. * datum name (if present) will be placed. Otherwise
  138. * set to NULL.
  139. *
  140. * \param params Pointer to a pointer which will have memory
  141. * allocated and into which a string containing
  142. * the datum parameters (if present) will
  143. * be placed. Otherwise set to NULL.
  144. *
  145. * \return -1 error or no datum information found,
  146. * 1 only datum name found, 2 params found
  147. *
  148. **/
  149. int GPJ__get_datum_params(struct Key_Value *projinfo,
  150. char **datumname, char **params)
  151. {
  152. int returnval = -1;
  153. if (NULL != G_find_key_value("datum", projinfo)) {
  154. *datumname = G_store(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. returnval = 2;
  162. }
  163. else if (G_find_key_value("nadgrids", projinfo) != NULL) {
  164. const char *gisbase = G_gisbase();
  165. G_asprintf(params, "nadgrids=%s%s/%s", gisbase, GRIDDIR,
  166. G_find_key_value("nadgrids", projinfo));
  167. returnval = 2;
  168. }
  169. else if (G_find_key_value("towgs84", projinfo) != NULL) {
  170. G_asprintf(params, "towgs84=%s",
  171. G_find_key_value("towgs84", projinfo));
  172. returnval = 2;
  173. }
  174. else if (G_find_key_value("dx", projinfo) != NULL
  175. && G_find_key_value("dy", projinfo) != NULL
  176. && G_find_key_value("dz", projinfo) != NULL) {
  177. G_asprintf(params, "towgs84=%s,%s,%s",
  178. G_find_key_value("dx", projinfo),
  179. G_find_key_value("dy", projinfo),
  180. G_find_key_value("dz", projinfo));
  181. returnval = 2;
  182. }
  183. else
  184. *params = NULL;
  185. return returnval;
  186. }
  187. /**
  188. * \brief Internal function to find all possible sets of
  189. * transformation parameters for a particular datum
  190. *
  191. * \param inputname String containing the datum name we
  192. * are going to look up parameters for
  193. *
  194. * \return Pointer to struct gpj_datum_transform_list (a linked
  195. * list containing transformation parameters),
  196. * or NULL if no suitable parameters were found.
  197. **/
  198. struct gpj_datum_transform_list *GPJ_get_datum_transform_by_name(const char
  199. *inputname)
  200. {
  201. FILE *fd;
  202. char file[GPATH_MAX];
  203. char buf[1024];
  204. int line;
  205. struct gpj_datum_transform_list *current = NULL, *outputlist = NULL;
  206. struct gpj_datum dstruct;
  207. int count = 0;
  208. GPJ_get_datum_by_name(inputname, &dstruct);
  209. if (dstruct.dx < 99999 && dstruct.dy < 99999 && dstruct.dz < 99999) {
  210. /* Include the old-style dx dy dz parameters from datum.table at the
  211. * start of the list, unless these have been set to all 99999 to
  212. * indicate only entries in datumtransform.table should be used */
  213. if (current == NULL)
  214. current = outputlist =
  215. G_malloc(sizeof(struct gpj_datum_transform_list));
  216. else
  217. current = current->next =
  218. G_malloc(sizeof(struct gpj_datum_transform_list));
  219. G_asprintf(&(current->params), "towgs84=%.3f,%.3f,%.3f", dstruct.dx,
  220. dstruct.dy, dstruct.dz);
  221. G_asprintf(&(current->where_used), "whole %s region", inputname);
  222. G_asprintf(&(current->comment),
  223. "Default 3-Parameter Transformation (May not be optimum for "
  224. "older datums; use this only if no more appropriate options "
  225. "are available.)");
  226. count++;
  227. current->count = count;
  228. current->next = NULL;
  229. }
  230. GPJ_free_datum(&dstruct);
  231. /* Now check for additional parameters in datumtransform.table */
  232. sprintf(file, "%s%s", G_gisbase(), DATUMTRANSFORMTABLE);
  233. fd = fopen(file, "r");
  234. if (!fd) {
  235. G_warning(_("Unable to open datum table file <%s>"), file);
  236. return outputlist;
  237. }
  238. for (line = 1; G_getl2(buf, sizeof(buf), fd); line++) {
  239. char name[100], params[1024], where_used[1024], comment[1024];
  240. G_strip(buf);
  241. if (*buf == '\0' || *buf == '#')
  242. continue;
  243. if (sscanf(buf, "%99s \"%1023[^\"]\" \"%1023[^\"]\" \"%1023[^\"]\"",
  244. name, params, where_used, comment) != 4) {
  245. G_warning(_("Error in datum table file <%s>, line %d"), file,
  246. line);
  247. continue;
  248. }
  249. if (G_strcasecmp(inputname, name) == 0) {
  250. /* If the datum name in this line matches the one we are
  251. * looking for, add an entry to the linked list */
  252. if (current == NULL)
  253. current = outputlist =
  254. G_malloc(sizeof(struct gpj_datum_transform_list));
  255. else
  256. current = current->next =
  257. G_malloc(sizeof(struct gpj_datum_transform_list));
  258. current->params = G_store(params);
  259. current->where_used = G_store(where_used);
  260. current->comment = G_store(comment);
  261. count++;
  262. current->count = count;
  263. current->next = NULL;
  264. }
  265. }
  266. fclose(fd);
  267. return outputlist;
  268. }
  269. /**
  270. * \brief Read the current GRASS datum.table from disk and store in
  271. * memory
  272. *
  273. * The datum information is stored in a datum_list linked list structure.
  274. *
  275. * \return Pointer to first datum_list element in linked list, or NULL
  276. * if unable to open datum.table file
  277. **/
  278. struct datum_list *read_datum_table(void)
  279. {
  280. FILE *fd;
  281. char file[GPATH_MAX];
  282. char buf[4096];
  283. int line;
  284. struct datum_list *current = NULL, *outputlist = NULL;
  285. int count = 0;
  286. sprintf(file, "%s%s", G_gisbase(), DATUMTABLE);
  287. fd = fopen(file, "r");
  288. if (!fd) {
  289. G_warning(_("Unable to open datum table file <%s>"), file);
  290. return NULL;
  291. }
  292. for (line = 1; G_getl2(buf, sizeof(buf), fd); line++) {
  293. char name[100], descr[1024], ellps[100];
  294. double dx, dy, dz;
  295. G_strip(buf);
  296. if (*buf == '\0' || *buf == '#')
  297. continue;
  298. if (sscanf(buf, "%s \"%1023[^\"]\" %s dx=%lf dy=%lf dz=%lf",
  299. name, descr, ellps, &dx, &dy, &dz) != 6) {
  300. G_warning(_("Error in datum table file <%s>, line %d"), file,
  301. line);
  302. continue;
  303. }
  304. if (current == NULL)
  305. current = outputlist = G_malloc(sizeof(struct datum_list));
  306. else
  307. current = current->next = G_malloc(sizeof(struct datum_list));
  308. current->name = G_store(name);
  309. current->longname = G_store(descr);
  310. current->ellps = G_store(ellps);
  311. current->dx = dx;
  312. current->dy = dy;
  313. current->dz = dz;
  314. current->next = NULL;
  315. count++;
  316. }
  317. fclose(fd);
  318. return outputlist;
  319. }
  320. /**
  321. * \brief Free the memory used for the strings in a gpj_datum struct
  322. *
  323. * \param dstruct gpj_datum struct to be freed
  324. **/
  325. void GPJ_free_datum(struct gpj_datum *dstruct)
  326. {
  327. G_free(dstruct->name);
  328. G_free(dstruct->longname);
  329. G_free(dstruct->ellps);
  330. return;
  331. }
  332. /**
  333. * \brief Free the memory used by a datum_list linked list structure
  334. *
  335. * \param dstruct datum_list struct to be freed
  336. **/
  337. void free_datum_list(struct datum_list *dstruct)
  338. {
  339. struct datum_list *old;
  340. while (dstruct != NULL) {
  341. G_free(dstruct->name);
  342. G_free(dstruct->longname);
  343. G_free(dstruct->ellps);
  344. old = dstruct;
  345. dstruct = old->next;
  346. G_free(old);
  347. }
  348. return;
  349. }