main.c 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341
  1. /* ====================================================================
  2. * PROGRAM: m.cogo
  3. * AUTHOR: Eric G. Miller <egm2@jps.net>
  4. * DATE: September 29, 2001
  5. * PURPOSE: Translates simple COordinate GeOmetry with a format of
  6. * "[label] <bearing> <distance>" to "X Y [label]".
  7. *
  8. * Example: "P0001 S 88-44-56 W 6.7195"
  9. * "-6.7178980970 -0.1467153972 P0001"
  10. *
  11. * The input formats are very limited.
  12. * --------------------------------------------------------------------
  13. * COPYRIGHT: (C) 2000 by the GRASS Development Team
  14. *
  15. * This program is free software under the GNU General Public
  16. * License (>=v2). Read the file COPYING that comes with GRASS
  17. * for details.
  18. */
  19. #include <stdio.h>
  20. #include <stdlib.h>
  21. #include <math.h>
  22. #include <string.h>
  23. #include <grass/gis.h>
  24. #include <grass/glocale.h>
  25. #define DEG2RAD(a) ((a) * M_PI / 180.0)
  26. #define RAD2DEG(a) ((a) * 180.0 / M_PI)
  27. #define DMS2DD(d,m,s) ((d) + ((m) / 60.0) + ((s) / 3600.0))
  28. #define FORMAT_1 " %s %1[NS] %d%c%d%c%lf %1[EW] %lf "
  29. #define FORMAT_2 " %1[NS] %d%c%d%c%lf %1[EW] %lf "
  30. #define FORMAT_3 " %lf %lf %s "
  31. struct survey_record
  32. {
  33. char label[20];
  34. int haslabel;
  35. char n_s[2];
  36. char e_w[2];
  37. int deg;
  38. int min;
  39. double sec;
  40. double dist;
  41. double rads;
  42. double dd;
  43. double x;
  44. double y;
  45. };
  46. static void print_coordinates(FILE *outfile, struct survey_record *in)
  47. {
  48. if (in->haslabel == YES)
  49. fprintf(outfile, "%.15g %.15g %s\n", in->x, in->y, in->label);
  50. else
  51. fprintf(outfile, "%.15g %.15g\n", in->x, in->y);
  52. }
  53. static void print_cogo(FILE *outfile, struct survey_record *in)
  54. {
  55. if (in->haslabel == YES)
  56. fprintf(outfile, "%s %s %02d:%02d:%02.9g %s %.13g\n",
  57. in->label, in->n_s, in->deg, in->min, in->sec,
  58. in->e_w, in->dist);
  59. else
  60. fprintf(outfile, "%s %02d:%02d:%02.9g %s %.13g\n",
  61. in->n_s, in->deg, in->min, in->sec, in->e_w, in->dist);
  62. }
  63. static const char *next_line(FILE *infile)
  64. {
  65. static char line[512];
  66. const char *cptr;
  67. memset(line, 0, sizeof(line));
  68. /* TODO: update to G_getl2(), but this fn needs to return pointer to string not ok/EOF int */
  69. cptr = fgets(line, 512, infile);
  70. return cptr;
  71. }
  72. static int parse_forward(const char *in, struct survey_record *out)
  73. {
  74. char dummy1;
  75. int status;
  76. if (out->haslabel == YES) {
  77. status =
  78. sscanf(in, FORMAT_1, out->label, out->n_s, &out->deg, &dummy1,
  79. &out->min, &dummy1, &out->sec, out->e_w, &out->dist);
  80. }
  81. else {
  82. status = sscanf(in, FORMAT_2, out->n_s, &out->deg, &dummy1,
  83. &out->min, &dummy1, &out->sec, out->e_w, &out->dist);
  84. }
  85. if ((status != 9 && out->haslabel == YES) ||
  86. (status != 8 && out->haslabel == NO))
  87. return 0;
  88. out->dd = DMS2DD(out->deg, out->min, out->sec);
  89. if (out->n_s[0] == 'N') {
  90. if (out->e_w[0] == 'E') {
  91. out->dd = 90.0 - out->dd;
  92. }
  93. else if (out->e_w[0] == 'W') {
  94. out->dd = 90.0 + out->dd;
  95. }
  96. else {
  97. return 0;
  98. }
  99. }
  100. else if (out->n_s[0] == 'S') {
  101. if (out->e_w[0] == 'E') {
  102. out->dd = 270 + out->dd;
  103. }
  104. else if (out->e_w[0] == 'W') {
  105. out->dd = 270 - out->dd;
  106. }
  107. else {
  108. return 0;
  109. }
  110. }
  111. else {
  112. return 0;
  113. }
  114. out->rads = DEG2RAD(out->dd);
  115. out->x += out->dist * cos(out->rads);
  116. out->y += out->dist * sin(out->rads);
  117. return status;
  118. }
  119. static int parse_reverse(const char *in, struct survey_record *out)
  120. {
  121. double x, y;
  122. int status;
  123. status = sscanf(in, FORMAT_3, &x, &y, out->label);
  124. if (status < 2)
  125. return 0;
  126. else if (status == 2)
  127. out->haslabel = NO;
  128. else
  129. out->haslabel = YES;
  130. G_debug(5, "IN: x=%f y=%f out->x=%f out->y=%f", x, y, out->x, out->y);
  131. out->rads = atan2(y - out->y, x - out->x);
  132. out->dist = hypot(x - out->x, y - out->y);
  133. out->x = x;
  134. out->y = y;
  135. out->dd = RAD2DEG(out->rads);
  136. G_debug(5, "OUT: out->dd=%f out->dist=%f", out->dd, out->dist);
  137. if (out->rads >= 0.0) {
  138. out->n_s[0] = 'N';
  139. out->n_s[1] = '\0';
  140. }
  141. else {
  142. out->n_s[0] = 'S';
  143. out->n_s[1] = '\0';
  144. }
  145. if (fabs(out->rads) >= M_PI_2) {
  146. out->e_w[0] = 'W';
  147. out->e_w[1] = '\0';
  148. }
  149. else {
  150. out->e_w[0] = 'E';
  151. out->e_w[1] = '\0';
  152. }
  153. if (out->n_s[0] == 'N') {
  154. if (out->e_w[0] == 'W') {
  155. out->dd = out->dd - 90.0;
  156. }
  157. else {
  158. out->dd = 90.0 - out->dd;
  159. }
  160. }
  161. else {
  162. if (out->e_w[0] == 'W') {
  163. out->dd = fabs(out->dd) - 90.0;
  164. }
  165. else {
  166. out->dd = 90.0 - fabs(out->dd);
  167. }
  168. }
  169. out->deg = (int)(out->dd);
  170. out->min = (int)((out->dd - out->deg) * 60.0);
  171. out->sec = (out->dd - out->deg - out->min / 60.0) * 3600.0;
  172. return status;
  173. }
  174. int main(int argc, char **argv)
  175. {
  176. struct Option *input;
  177. struct Option *output;
  178. struct Option *coords;
  179. struct Flag *format;
  180. struct Flag *reverse;
  181. struct Flag *close;
  182. struct GModule *module;
  183. FILE *infile, *outfile;
  184. struct survey_record record, first_record;
  185. const char *cptr;
  186. char *ss;
  187. unsigned long linenum = 0, dataline = 0;
  188. int (*parse_line) (const char *, struct survey_record *);
  189. void (*print_func) (FILE *, struct survey_record *);
  190. G_gisinit(argv[0]);
  191. module = G_define_module();
  192. G_add_keyword(_("miscellaneous"));
  193. G_add_keyword(_("distance"));
  194. module->label = _("A simple utility for converting bearing and "
  195. "distance measurements to coordinates and vice versa.");
  196. module->description = _("It assumes a cartesian coordinate system");
  197. format = G_define_flag();
  198. format->key = 'l';
  199. format->description = _("Lines are labelled");
  200. reverse = G_define_flag();
  201. reverse->key = 'r';
  202. reverse->description =
  203. _("Convert from coordinates to bearing and distance");
  204. close = G_define_flag();
  205. close->key = 'c';
  206. close->description =
  207. _("Repeat the starting coordinate at the end to close a loop");
  208. input = G_define_standard_option(G_OPT_F_INPUT);
  209. input->required = NO;
  210. input->answer = "-";
  211. output = G_define_standard_option(G_OPT_F_OUTPUT);
  212. output->required = NO;
  213. output->answer = "-";
  214. coords = G_define_standard_option(G_OPT_M_COORDS);
  215. coords->description = _("Starting coordinate pair");
  216. coords->answer = "0.0,0.0";
  217. if (G_parser(argc, argv) != 0)
  218. exit(EXIT_FAILURE);
  219. if (input->answer && input->answer[0] != '-') {
  220. infile = fopen(input->answer, "r");
  221. if (infile == NULL)
  222. G_fatal_error(_("Couldn't open COGO file <%s>"), input->answer);
  223. }
  224. else {
  225. infile = stdin;
  226. }
  227. if (output->answer && output->answer[0] != '-') {
  228. outfile = fopen(output->answer, "w");
  229. if (outfile == NULL)
  230. G_fatal_error(_("Couldn't open output file <%s>"),
  231. output->answer);
  232. }
  233. else {
  234. outfile = stdout;
  235. }
  236. record.label[0] = '\0';
  237. if (format->answer) {
  238. record.haslabel = YES;
  239. }
  240. else {
  241. record.haslabel = NO;
  242. }
  243. if (reverse->answer) {
  244. parse_line = parse_reverse;
  245. print_func = print_cogo;
  246. }
  247. else {
  248. parse_line = parse_forward;
  249. print_func = print_coordinates;
  250. }
  251. if (coords->answer) {
  252. record.x = strtod(coords->answers[0], &ss);
  253. if (ss == coords->answers[0])
  254. G_fatal_error(_("Converting starting coordinate pair"));
  255. record.y = strtod(coords->answers[1], &ss);
  256. if (ss == coords->answers[1])
  257. G_fatal_error(_("Converting starting coordinate pair"));
  258. }
  259. else {
  260. record.x = record.y = 0.0;
  261. }
  262. while ((cptr = next_line(infile))) {
  263. linenum++;
  264. if ((cptr[0] == '#') || (cptr[0] == '\0') || (cptr[0] == '\n')) {
  265. /* remove \n check once module is updated to use G_getl2() */
  266. continue; /* line is a comment or blank */
  267. }
  268. if (!parse_line(cptr, &record)) {
  269. G_warning(_("Input parse error on line %lu"), linenum);
  270. continue;
  271. }
  272. dataline++;
  273. if (dataline == 1)
  274. first_record = record;
  275. print_func(outfile, &record);
  276. }
  277. if (close->answer)
  278. print_func(outfile, &first_record);
  279. if (infile != stdin)
  280. fclose(infile);
  281. if (outfile != stdout)
  282. fclose(stdout);
  283. exit(EXIT_SUCCESS);
  284. }