main.c 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344
  1. /*
  2. * Copyright (C) 2000 by the GRASS Development Team
  3. * Author: Bob Covill <bcovill@tekmap.ns.ca>
  4. *
  5. * This Program is free software under the GPL (>=v2)
  6. * Read the file COPYING coming with GRASS for details
  7. *
  8. */
  9. #include <stdlib.h>
  10. #include <grass/gis.h>
  11. #include <grass/raster.h>
  12. #include <grass/glocale.h>
  13. #include "local_proto.h"
  14. int clr;
  15. struct Colors colors;
  16. static double dist, e, n;
  17. int main(int argc, char *argv[])
  18. {
  19. char *name, *outfile;
  20. const char *unit;
  21. int unit_id;
  22. double factor;
  23. int fd, projection;
  24. FILE *fp, *coor_fp;
  25. double res;
  26. char *null_string;
  27. char ebuf[256], nbuf[256], label[512], formatbuff[256];
  28. char b1[100], b2[100];
  29. int n;
  30. int havefirst = FALSE;
  31. int coords = 0, i, k = -1;
  32. double e1, e2, n1, n2;
  33. RASTER_MAP_TYPE data_type;
  34. struct Cell_head window;
  35. struct
  36. {
  37. struct Option *opt1, *profile, *res, *output, *null_str, *coord_file, *units;
  38. struct Flag *g, *c, *m;
  39. }
  40. parm;
  41. struct GModule *module;
  42. G_gisinit(argv[0]);
  43. /* Set description */
  44. module = G_define_module();
  45. G_add_keyword(_("raster"));
  46. G_add_keyword(_("profile"));
  47. module->description =
  48. _("Outputs the raster map layer values lying on user-defined line(s).");
  49. parm.opt1 = G_define_standard_option(G_OPT_R_INPUT);
  50. parm.output = G_define_standard_option(G_OPT_F_OUTPUT);
  51. parm.output->required = NO;
  52. parm.output->answer = "-";
  53. parm.output->description =
  54. _("Name of file for output (use output=- for stdout)");
  55. parm.profile = G_define_standard_option(G_OPT_M_COORDS);
  56. parm.profile->required = NO;
  57. parm.profile->multiple = YES;
  58. parm.profile->description = _("Profile coordinate pairs");
  59. parm.coord_file = G_define_standard_option(G_OPT_F_INPUT);
  60. parm.coord_file->key = "file";
  61. parm.coord_file->required = NO;
  62. parm.coord_file->label =
  63. _("Name of input file containing coordinate pairs");
  64. parm.coord_file->description =
  65. _("Use instead of the 'coordinates' option. "
  66. "\"-\" reads from stdin.");
  67. parm.res = G_define_option();
  68. parm.res->key = "resolution";
  69. parm.res->type = TYPE_DOUBLE;
  70. parm.res->required = NO;
  71. parm.res->description =
  72. _("Resolution along profile (default = current region resolution)");
  73. parm.null_str = G_define_standard_option(G_OPT_M_NULL_VALUE);
  74. parm.null_str->answer = "*";
  75. parm.g = G_define_flag();
  76. parm.g->key = 'g';
  77. parm.g->description =
  78. _("Output easting and northing in first two columns of four column output");
  79. parm.c = G_define_flag();
  80. parm.c->key = 'c';
  81. parm.c->description =
  82. _("Output RRR:GGG:BBB color values for each profile point");
  83. parm.units = G_define_standard_option(G_OPT_M_UNITS);
  84. parm.units->options = "meters,kilometers,feet,miles";
  85. parm.units->label = parm.units->description;
  86. parm.units->description = _("If units are not specified, current location units are used. "
  87. "Meters are used by default in geographic (latlon) locations.");
  88. if (G_parser(argc, argv))
  89. exit(EXIT_FAILURE);
  90. clr = 0;
  91. if (parm.c->answer)
  92. clr = 1; /* color output */
  93. null_string = parm.null_str->answer;
  94. if ((parm.profile->answer && parm.coord_file->answer) ||
  95. (!parm.profile->answer && !parm.coord_file->answer))
  96. G_fatal_error(_("Either use profile option or coordinate_file "
  97. " option, but not both"));
  98. G_get_window(&window);
  99. projection = G_projection();
  100. /* get conversion factor and units name */
  101. if (parm.units->answer) {
  102. unit_id = G_units(parm.units->answer);
  103. factor = 1. / G_meters_to_units_factor(unit_id);
  104. unit = G_get_units_name(unit_id, 1, 0);
  105. }
  106. /* keep meters in case of latlon */
  107. else if (projection == PROJECTION_LL) {
  108. factor = 1;
  109. unit = "meters";
  110. }
  111. else {
  112. /* get conversion factor to current units */
  113. unit = G_database_unit_name(1);
  114. factor = G_database_units_to_meters_factor();
  115. }
  116. if (parm.res->answer) {
  117. res = atof(parm.res->answer);
  118. /* Catch bad resolution ? */
  119. if (res <= 0)
  120. G_fatal_error(_("Illegal resolution %g [%s]"), res / factor, unit);
  121. }
  122. else {
  123. /* Do average of EW and NS res */
  124. res = (window.ew_res + window.ns_res) / 2;
  125. }
  126. G_message(_("Using resolution: %g [%s]"), res / factor, unit);
  127. G_begin_distance_calculations();
  128. /* Open Input File for reading */
  129. /* Get Input Name */
  130. name = parm.opt1->answer;
  131. if (parm.g->answer)
  132. coords = 1;
  133. /* Open Raster File */
  134. fd = Rast_open_old(name, "");
  135. /* initialize color structure */
  136. if (clr)
  137. Rast_read_colors(name, "", &colors);
  138. /* Open ASCII file for output or stdout */
  139. outfile = parm.output->answer;
  140. if ((strcmp("-", outfile)) == 0) {
  141. fp = stdout;
  142. }
  143. else if (NULL == (fp = fopen(outfile, "w")))
  144. G_fatal_error(_("Unable to open file <%s>"), outfile);
  145. /* Get Raster Type */
  146. data_type = Rast_get_map_type(fd);
  147. /* Done with file */
  148. /* Show message giving output format */
  149. G_message(_("Output columns:"));
  150. if (coords == 1)
  151. sprintf(formatbuff,
  152. _("Easting, Northing, Along track dist. [%s], Elevation"), unit);
  153. else
  154. sprintf(formatbuff, _("Along track dist. [%s], Elevation"), unit);
  155. if (clr)
  156. strcat(formatbuff, _(" RGB color"));
  157. G_message("%s", formatbuff);
  158. /* Get Profile Start Coords */
  159. if (parm.coord_file->answer) {
  160. if (strcmp("-", parm.coord_file->answer) == 0)
  161. coor_fp = stdin;
  162. else
  163. coor_fp = fopen(parm.coord_file->answer, "r");
  164. if (coor_fp == NULL)
  165. G_fatal_error(_("Could not open <%s>"), parm.coord_file->answer);
  166. for (n = 1; input(b1, ebuf, b2, nbuf, label, coor_fp); n++) {
  167. G_debug(4, "stdin line %d: ebuf=[%s] nbuf=[%s]", n, ebuf, nbuf);
  168. if (!G_scan_easting(ebuf, &e2, G_projection()) ||
  169. !G_scan_northing(nbuf, &n2, G_projection()))
  170. G_fatal_error(_("Invalid coordinates %s %s"), ebuf, nbuf);
  171. if (havefirst)
  172. do_profile(e1, e2, n1, n2, coords, res, fd, data_type,
  173. fp, null_string, unit, factor);
  174. e1 = e2;
  175. n1 = n2;
  176. havefirst = TRUE;
  177. }
  178. if (coor_fp != stdin)
  179. fclose(coor_fp);
  180. }
  181. else {
  182. /* Coords given on the Command Line using the profile= option */
  183. for (i = 0; parm.profile->answers[i]; i += 2) {
  184. /* Test for number coordinate pairs */
  185. k = i;
  186. }
  187. if (k == 0) {
  188. /* Only one coordinate pair supplied */
  189. G_scan_easting(parm.profile->answers[0], &e1, G_projection());
  190. G_scan_northing(parm.profile->answers[1], &n1, G_projection());
  191. e2 = e1;
  192. n2 = n1;
  193. /* Get profile info */
  194. do_profile(e1, e2, n1, n2, coords, res, fd, data_type, fp,
  195. null_string, unit, factor);
  196. }
  197. else {
  198. for (i = 0; i <= k - 2; i += 2) {
  199. G_scan_easting(parm.profile->answers[i], &e1, G_projection());
  200. G_scan_northing(parm.profile->answers[i + 1], &n1,
  201. G_projection());
  202. G_scan_easting(parm.profile->answers[i + 2], &e2,
  203. G_projection());
  204. G_scan_northing(parm.profile->answers[i + 3], &n2,
  205. G_projection());
  206. /* Get profile info */
  207. do_profile(e1, e2, n1, n2, coords, res, fd, data_type,
  208. fp, null_string, unit, factor);
  209. }
  210. }
  211. }
  212. Rast_close(fd);
  213. fclose(fp);
  214. if (clr)
  215. Rast_free_colors(&colors);
  216. exit(EXIT_SUCCESS);
  217. } /* Done with main */
  218. /* Calculate the Profile Now */
  219. /* Establish parameters */
  220. int do_profile(double e1, double e2, double n1, double n2,
  221. int coords, double res, int fd, int data_type, FILE * fp,
  222. char *null_string, const char *unit, double factor)
  223. {
  224. double rows, cols, LEN;
  225. double Y, X, k;
  226. cols = e1 - e2;
  227. rows = n1 - n2;
  228. LEN = G_distance(e1, n1, e2, n2);
  229. G_message(_("Approx. transect length: %f [%s]"), LEN / factor, unit);
  230. if (!G_point_in_region(e2, n2))
  231. G_warning(_("Endpoint coordinates are outside of current region settings"));
  232. /* Calculate Azimuth of Line */
  233. if (rows == 0 && cols == 0) {
  234. /* Special case for no movement */
  235. e = e1;
  236. n = n1;
  237. read_rast(e, n, dist / factor, fd, coords, data_type, fp, null_string);
  238. }
  239. k = res / hypot(rows, cols);
  240. Y = k * rows;
  241. X = k * cols;
  242. if (Y < 0)
  243. Y = Y * -1.;
  244. if (X < 0)
  245. X = X * -1.;
  246. if (e != 0.0 && (e != e1 || n != n1)) {
  247. dist -= G_distance(e, n, e1, n1);
  248. }
  249. if (rows >= 0 && cols < 0) {
  250. /* SE Quad or due east */
  251. for (e = e1, n = n1; e < e2 || n > n2; e += X, n -= Y) {
  252. read_rast(e, n, dist / factor, fd, coords, data_type, fp, null_string);
  253. /* d+=res; */
  254. dist += G_distance(e - X, n + Y, e, n);
  255. }
  256. }
  257. if (rows < 0 && cols <= 0) {
  258. /* NE Quad or due north */
  259. for (e = e1, n = n1; e < e2 || n < n2; e += X, n += Y) {
  260. read_rast(e, n, dist / factor, fd, coords, data_type, fp, null_string);
  261. /* d+=res; */
  262. dist += G_distance(e - X, n - Y, e, n);
  263. }
  264. }
  265. if (rows > 0 && cols >= 0) {
  266. /* SW Quad or due south */
  267. for (e = e1, n = n1; e > e2 || n > n2; e -= X, n -= Y) {
  268. read_rast(e, n, dist / factor, fd, coords, data_type, fp, null_string);
  269. /* d+=res; */
  270. dist += G_distance(e + X, n + Y, e, n);
  271. }
  272. }
  273. if (rows <= 0 && cols > 0) {
  274. /* NW Quad or due west */
  275. for (e = e1, n = n1; e > e2 || n < n2; e -= X, n += Y) {
  276. read_rast(e, n, dist / factor, fd, coords, data_type, fp, null_string);
  277. /* d+=res; */
  278. dist += G_distance(e + X, n - Y, e, n);
  279. }
  280. }
  281. /*
  282. * return dist;
  283. */
  284. return 0;
  285. } /* done with do_profile */