ellipse.c 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330
  1. /*!
  2. \file lib/proj/ellipse.c
  3. \brief GProj library - Functions for reading datum parameters from the location database
  4. \author 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 <ctype.h>
  12. #include <string.h>
  13. #include <stdlib.h>
  14. #include <math.h> /* for sqrt() */
  15. #include <grass/gis.h>
  16. #include <grass/glocale.h>
  17. #include <grass/gprojects.h>
  18. #include "local_proto.h"
  19. static int get_a_e2_rf(const char *, const char *, double *, double *,
  20. double *);
  21. /*!
  22. * \brief Get the ellipsoid parameters from the database.
  23. *
  24. * If the PROJECTION_FILE exists in the PERMANENT mapset, read info from
  25. * that file, otherwise return WGS 84 values.
  26. *
  27. * Dies with diagnostic if there is an error.
  28. *
  29. * \param[out] a semi-major axis
  30. * \param[out] e2 first eccentricity squared
  31. * \param[out] rf reciprocal of the ellipsoid flattening term
  32. *
  33. * \return 1 on success
  34. * \return 0 default values used.
  35. */
  36. int GPJ_get_ellipsoid_params(double *a, double *e2, double *rf)
  37. {
  38. int ret;
  39. struct Key_Value *proj_keys = G_get_projinfo();
  40. if (proj_keys == NULL)
  41. proj_keys = G_create_key_value();
  42. ret = GPJ__get_ellipsoid_params(proj_keys, a, e2, rf);
  43. G_free_key_value(proj_keys);
  44. return ret;
  45. }
  46. /*!
  47. * \brief Get the ellipsoid parameters from proj keys structure.
  48. *
  49. * If the PROJECTION_FILE exists in the PERMANENT mapset, read info from
  50. * that file, otherwise return WGS 84 values.
  51. *
  52. * Dies with diagnostic if there is an error.
  53. *
  54. * \param proj_keys proj definition
  55. * \param[out] a semi-major axis
  56. * \param[out] e2 first eccentricity squared
  57. * \param[out] rf reciprocal of the ellipsoid flattening term
  58. *
  59. * \return 1 on success
  60. * \return 0 default values used.
  61. */
  62. int GPJ__get_ellipsoid_params(const struct Key_Value *proj_keys,
  63. double *a, double *e2, double *rf)
  64. {
  65. struct gpj_ellps estruct;
  66. struct gpj_datum dstruct;
  67. const char *str, *str3;
  68. char *str1, *ellps;
  69. str = G_find_key_value("datum", proj_keys);
  70. if ((str != NULL) && (GPJ_get_datum_by_name(str, &dstruct) > 0)) {
  71. /* If 'datum' key is present, look up correct ellipsoid
  72. * from datum.table */
  73. ellps = G_store(dstruct.ellps);
  74. GPJ_free_datum(&dstruct);
  75. }
  76. else
  77. /* else use ellipsoid defined in PROJ_INFO */
  78. ellps = G_store(G_find_key_value("ellps", proj_keys));
  79. if (ellps != NULL && *ellps) {
  80. if (GPJ_get_ellipsoid_by_name(ellps, &estruct) < 0)
  81. G_fatal_error(_("Invalid ellipsoid <%s> in file"), ellps);
  82. *a = estruct.a;
  83. *e2 = estruct.es;
  84. *rf = estruct.rf;
  85. GPJ_free_ellps(&estruct);
  86. G_free(ellps);
  87. return 1;
  88. }
  89. else {
  90. if (ellps) /* *ellps = '\0' */
  91. G_free(ellps);
  92. str3 = G_find_key_value("a", proj_keys);
  93. if (str3 != NULL) {
  94. char *str4;
  95. G_asprintf(&str4, "a=%s", str3);
  96. if ((str3 = G_find_key_value("es", proj_keys)) != NULL)
  97. G_asprintf(&str1, "e=%s", str3);
  98. else if ((str3 = G_find_key_value("f", proj_keys)) != NULL)
  99. G_asprintf(&str1, "f=1/%s", str3);
  100. else if ((str3 = G_find_key_value("rf", proj_keys)) != NULL)
  101. G_asprintf(&str1, "f=1/%s", str3);
  102. else if ((str3 = G_find_key_value("b", proj_keys)) != NULL)
  103. G_asprintf(&str1, "b=%s", str3);
  104. else
  105. G_fatal_error(_("No secondary ellipsoid descriptor "
  106. "(rf, es or b) in file"));
  107. if (get_a_e2_rf(str4, str1, a, e2, rf) == 0)
  108. G_fatal_error(_("Invalid ellipsoid descriptors "
  109. "(a, rf, es or b) in file"));
  110. return 1;
  111. }
  112. else {
  113. str = G_find_key_value("proj", proj_keys);
  114. if ((str == NULL) || (strcmp(str, "ll") == 0)) {
  115. *a = 6378137.0;
  116. *e2 = .006694385;
  117. *rf = 298.257223563;
  118. return 0;
  119. }
  120. else {
  121. G_fatal_error(_("No ellipsoid info given in file"));
  122. }
  123. }
  124. }
  125. return 1;
  126. }
  127. /*!
  128. * \brief Looks up ellipsoid in ellipsoid table and returns the a, e2
  129. * parameters for the ellipsoid.
  130. *
  131. * \param name ellipsoid name
  132. * \param[out] estruct ellipsoid
  133. *
  134. * \return 1 on success
  135. * \return -1 if not found in table
  136. */
  137. int GPJ_get_ellipsoid_by_name(const char *name, struct gpj_ellps *estruct)
  138. {
  139. struct ellps_list *list, *listhead;
  140. list = listhead = read_ellipsoid_table(0);
  141. while (list != NULL) {
  142. if (G_strcasecmp(name, list->name) == 0) {
  143. estruct->name = G_store(list->name);
  144. estruct->longname = G_store(list->longname);
  145. estruct->a = list->a;
  146. estruct->es = list->es;
  147. estruct->rf = list->rf;
  148. free_ellps_list(listhead);
  149. return 1;
  150. }
  151. list = list->next;
  152. }
  153. free_ellps_list(listhead);
  154. return -1;
  155. }
  156. int get_a_e2_rf(const char *s1, const char *s2, double *a, double *e2,
  157. double *recipf)
  158. {
  159. double b, f;
  160. if (sscanf(s1, "a=%lf", a) != 1)
  161. return 0;
  162. if (*a <= 0.0)
  163. return 0;
  164. if (sscanf(s2, "e=%lf", e2) == 1) {
  165. f = 1.0 - sqrt(1.0 - *e2);
  166. *recipf = 1.0 / f;
  167. return (*e2 >= 0.0);
  168. }
  169. if (sscanf(s2, "f=1/%lf", recipf) == 1) {
  170. if (*recipf <= 0.0)
  171. return 0;
  172. f = 1.0 / *recipf;
  173. *e2 = f * (2 - f);
  174. return (*e2 >= 0.0);
  175. }
  176. if (sscanf(s2, "b=%lf", &b) == 1) {
  177. if (b <= 0.0)
  178. return 0;
  179. if (b == *a) {
  180. f = 0.0;
  181. *e2 = 0.0;
  182. }
  183. else {
  184. f = (*a - b) / *a;
  185. *e2 = f * (2 - f);
  186. }
  187. *recipf = 1.0 / f;
  188. return (*e2 >= 0.0);
  189. }
  190. return 0;
  191. }
  192. struct ellps_list *read_ellipsoid_table(int fatal)
  193. {
  194. FILE *fd;
  195. char file[GPATH_MAX];
  196. char buf[4096];
  197. char name[100], descr[1024], buf1[1024], buf2[1024];
  198. char badlines[1024];
  199. int line;
  200. int err;
  201. struct ellps_list *current = NULL, *outputlist = NULL;
  202. double a, e2, rf;
  203. int count = 0;
  204. sprintf(file, "%s%s", G_gisbase(), ELLIPSOIDTABLE);
  205. fd = fopen(file, "r");
  206. if (!fd) {
  207. (fatal ? G_fatal_error : G_warning)(
  208. _("Unable to open ellipsoid table file <%s>"), file);
  209. return NULL;
  210. }
  211. err = 0;
  212. *badlines = 0;
  213. for (line = 1; G_getl2(buf, sizeof buf, fd); line++) {
  214. G_strip(buf);
  215. if (*buf == 0 || *buf == '#')
  216. continue;
  217. if (sscanf(buf, "%s \"%1023[^\"]\" %s %s", name, descr, buf1, buf2)
  218. != 4) {
  219. err++;
  220. sprintf(buf, " %d", line);
  221. if (*badlines)
  222. strcat(badlines, ",");
  223. strcat(badlines, buf);
  224. continue;
  225. }
  226. if (get_a_e2_rf(buf1, buf2, &a, &e2, &rf)
  227. || get_a_e2_rf(buf2, buf1, &a, &e2, &rf)) {
  228. if (current == NULL)
  229. current = outputlist = G_malloc(sizeof(struct ellps_list));
  230. else
  231. current = current->next = G_malloc(sizeof(struct ellps_list));
  232. current->name = G_store(name);
  233. current->longname = G_store(descr);
  234. current->a = a;
  235. current->es = e2;
  236. current->rf = rf;
  237. current->next = NULL;
  238. count++;
  239. }
  240. else {
  241. err++;
  242. sprintf(buf, " %d", line);
  243. if (*badlines)
  244. strcat(badlines, ",");
  245. strcat(badlines, buf);
  246. continue;
  247. }
  248. }
  249. fclose(fd);
  250. if (!err)
  251. return outputlist;
  252. (fatal ? G_fatal_error : G_warning)(
  253. n_(
  254. ("Line%s of ellipsoid table file <%s> is invalid"),
  255. ("Lines%s of ellipsoid table file <%s> are invalid"),
  256. err),
  257. badlines, file);
  258. return outputlist;
  259. }
  260. /*!
  261. \brief Free ellipsoid data structure.
  262. \param estruct data structure to be freed
  263. */
  264. void GPJ_free_ellps(struct gpj_ellps *estruct)
  265. {
  266. G_free(estruct->name);
  267. G_free(estruct->longname);
  268. return;
  269. }
  270. void free_ellps_list(struct ellps_list *elist)
  271. {
  272. struct ellps_list *old;
  273. while (elist != NULL) {
  274. G_free(elist->name);
  275. G_free(elist->longname);
  276. old = elist;
  277. elist = old->next;
  278. G_free(old);
  279. }
  280. return;
  281. }