main.c 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323
  1. /****************************************************************************
  2. *
  3. * MODULE: d.profile
  4. * AUTHOR(S): Dave Johnson (original contributor)
  5. * DBA Systems, Inc. 10560 Arrowhead Drive Fairfax, VA 22030
  6. * Markus Neteler <neteler itc.it>,
  7. * Bernhard Reiter <bernhard intevation.de>,
  8. * Huidae Cho <grass4u gmail.com>,
  9. * Eric G. Miller <egm2 jps.net>,
  10. * Glynn Clements <glynn gclements.plus.com>
  11. * PURPOSE: user chooses transects path, and profile of raster data drawn
  12. * COPYRIGHT: (C) 1999-2007 by the GRASS Development Team
  13. *
  14. * This program is free software under the GNU General Public
  15. * License (>=v2). Read the file COPYING that comes with GRASS
  16. * for details.
  17. *
  18. *****************************************************************************/
  19. #include <stdio.h>
  20. #include <stdlib.h>
  21. #include <math.h>
  22. #include <grass/gis.h>
  23. #include <grass/raster.h>
  24. #include <grass/display.h>
  25. #include <grass/glocale.h>
  26. static char *mapname;
  27. static double min, max;
  28. struct point
  29. {
  30. double x, y;
  31. double d;
  32. };
  33. static void get_region_range(int fd)
  34. {
  35. DCELL *buf = Rast_allocate_d_buf();
  36. int nrows = Rast_window_rows();
  37. int ncols = Rast_window_cols();
  38. int row, col;
  39. min = 1e300;
  40. max = -1e300;
  41. for (row = 0; row < nrows; row++) {
  42. Rast_get_d_row(fd, buf, row);
  43. for (col = 0; col < ncols; col++) {
  44. if (min > buf[col])
  45. min = buf[col];
  46. if (max < buf[col])
  47. max = buf[col];
  48. }
  49. }
  50. }
  51. static void get_map_range(void)
  52. {
  53. if (Rast_map_type(mapname, "") == CELL_TYPE) {
  54. struct Range range;
  55. CELL xmin, xmax;
  56. if (Rast_read_range(mapname, "", &range) <= 0)
  57. G_fatal_error(_("Unable to read range for %s"), mapname);
  58. Rast_get_range_min_max(&range, &xmin, &xmax);
  59. max = xmax;
  60. min = xmin;
  61. }
  62. else {
  63. struct FPRange fprange;
  64. if (Rast_read_fp_range(mapname, "", &fprange) <= 0)
  65. G_fatal_error(_("Unable to read FP range for %s"), mapname);
  66. Rast_get_fp_range_min_max(&fprange, &min, &max);
  67. }
  68. }
  69. static void plot_axes(void)
  70. {
  71. char str[64];
  72. double scale;
  73. double t, b, l, r;
  74. D_use_color(D_translate_color("red"));
  75. D_begin();
  76. D_move_abs(0, 1);
  77. D_cont_abs(0, 0);
  78. D_cont_abs(1, 0);
  79. D_end();
  80. D_stroke();
  81. D_use_color(D_translate_color(DEFAULT_FG_COLOR));
  82. /* set text size for y-axis labels */
  83. scale = fabs(D_get_u_to_d_yconv());
  84. D_text_size(scale * 0.04, scale * 0.05);
  85. /* plot y-axis label (bottom) */
  86. sprintf(str, "%.1f", min);
  87. D_get_text_box(str, &t, &b, &l, &r);
  88. D_pos_abs(-0.02 - (r - l), 0 - (t - b) / 2);
  89. D_text(str);
  90. /* plot y-axis label (top) */
  91. sprintf(str, "%.1f", max);
  92. D_get_text_box(str, &t, &b, &l, &r);
  93. D_pos_abs(-0.02 - (r - l), 1 - (t - b) / 2);
  94. D_text(str);
  95. }
  96. static int get_cell(DCELL *result, int fd, double x, double y)
  97. {
  98. static DCELL *row1, *row2;
  99. static int cur_row = -1;
  100. static int row, col;
  101. DCELL *tmp;
  102. if (!row1) {
  103. row1 = Rast_allocate_d_buf();
  104. row2 = Rast_allocate_d_buf();
  105. }
  106. col = (int)floor(x - 0.5);
  107. row = (int)floor(y - 0.5);
  108. x -= col + 0.5;
  109. y -= row + 0.5;
  110. if (row < 0 || row + 1 >= Rast_window_rows() ||
  111. col < 0 || col + 1 >= Rast_window_cols()) {
  112. Rast_set_d_null_value(result, 1);
  113. return 0;
  114. }
  115. if (cur_row != row) {
  116. if (cur_row == row + 1) {
  117. tmp = row1; row1 = row2; row2 = tmp;
  118. Rast_get_d_row(fd, row1, row);
  119. }
  120. else if (cur_row == row - 1) {
  121. tmp = row1; row1 = row2; row2 = tmp;
  122. Rast_get_d_row(fd, row2, row + 1);
  123. }
  124. else {
  125. Rast_get_d_row(fd, row1, row);
  126. Rast_get_d_row(fd, row2, row + 1);
  127. }
  128. cur_row = row;
  129. }
  130. if (Rast_is_d_null_value(&row1[col]) || Rast_is_d_null_value(&row1[col+1]) ||
  131. Rast_is_d_null_value(&row2[col]) || Rast_is_d_null_value(&row2[col+1])) {
  132. Rast_set_d_null_value(result, 1);
  133. return 0;
  134. }
  135. *result = Rast_interp_bilinear(x, y,
  136. row1[col], row1[col+1],
  137. row2[col], row2[col+1]);
  138. return 1;
  139. }
  140. int main(int argc, char **argv)
  141. {
  142. struct GModule *module;
  143. struct Option *map, *profile;
  144. struct Flag *stored;
  145. struct Cell_head window;
  146. struct point *points = NULL;
  147. int num_points, max_points = 0;
  148. double length;
  149. double t, b, l, r;
  150. int fd;
  151. int i;
  152. double sx;
  153. int last;
  154. /* Initialize the GIS calls */
  155. G_gisinit(argv[0]);
  156. /* Set description */
  157. module = G_define_module();
  158. G_add_keyword(_("display"));
  159. G_add_keyword(_("profile"));
  160. G_add_keyword(_("raster"));
  161. module->description = _("Plots profile of a transect.");
  162. /* set up command line */
  163. map = G_define_standard_option(G_OPT_R_INPUT);
  164. map->description = _("Raster map to be profiled");
  165. profile = G_define_option();
  166. profile->key = "profile";
  167. profile->type = TYPE_DOUBLE;
  168. profile->required = YES;
  169. profile->multiple = YES;
  170. profile->key_desc = "east,north";
  171. profile->description = _("Profile coordinate pairs");
  172. stored = G_define_flag();
  173. stored->key = 'r';
  174. stored->description = _("Use map's range recorded range");
  175. if (G_parser(argc, argv))
  176. exit(EXIT_FAILURE);
  177. mapname = map->answer;
  178. fd = Rast_open_old(mapname, "");
  179. if (stored->answer)
  180. get_map_range();
  181. else
  182. get_region_range(fd);
  183. G_get_window(&window);
  184. num_points = 0;
  185. length = 0;
  186. for (i = 0; profile->answers[i]; i += 2) {
  187. struct point *p;
  188. double x, y;
  189. if (num_points >= max_points) {
  190. max_points = num_points + 100;
  191. points = G_realloc(points, max_points * sizeof(struct point));
  192. }
  193. p = &points[num_points];
  194. G_scan_easting( profile->answers[i+0], &x, G_projection());
  195. G_scan_northing(profile->answers[i+1], &y, G_projection());
  196. p->x = Rast_easting_to_col (x, &window);
  197. p->y = Rast_northing_to_row(y, &window);
  198. if (num_points > 0) {
  199. const struct point *prev = &points[num_points-1];
  200. double dx = fabs(p->x - prev->x);
  201. double dy = fabs(p->y - prev->y);
  202. double d = sqrt(dx * dx + dy * dy);
  203. length += d;
  204. p->d = length;
  205. }
  206. num_points++;
  207. }
  208. points[0].d = 0;
  209. if (num_points < 2)
  210. G_fatal_error(_("At least two points are required"));
  211. /* establish connection with graphics driver */
  212. if (D_open_driver() != 0)
  213. G_fatal_error(_("No graphics device selected. "
  214. "Use d.mon to select graphics device."));
  215. D_setup2(1, 0, 1.05, -0.05, -0.15, 1.05);
  216. plot_axes();
  217. D_use_color(D_translate_color(DEFAULT_FG_COLOR));
  218. D_get_src(&t, &b, &l, &r);
  219. t -= 0.1 * (t - b);
  220. b += 0.1 * (t - b);
  221. l += 0.1 * (r - l);
  222. r -= 0.1 * (r - l);
  223. D_begin();
  224. i = 0;
  225. last = 0;
  226. for (sx = 0; sx < 1; sx += D_get_d_to_u_xconv()) {
  227. double d = length * (sx - l);
  228. const struct point *p, *next;
  229. double k, sy, x, y;
  230. DCELL v;
  231. for (;;) {
  232. p = &points[i];
  233. next = &points[i + 1];
  234. k = (d - p->d) / (next->d - p->d);
  235. if (k < 1)
  236. break;
  237. i++;
  238. }
  239. x = p->x * (1 - k) + next->x * k;
  240. y = p->y * (1 - k) + next->y * k;
  241. if (!get_cell(&v, fd, x, y)) {
  242. last = 0;
  243. continue;
  244. }
  245. sy = (v - min) / (max - min);
  246. if (last)
  247. D_cont_abs(sx, sy);
  248. else
  249. D_move_abs(sx, sy);
  250. last = 1;
  251. }
  252. D_end();
  253. D_stroke();
  254. D_close_driver();
  255. exit(EXIT_SUCCESS);
  256. }