datum.c 12 KB

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