main.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417
  1. /****************************************************************************
  2. *
  3. * MODULE: r.los
  4. * AUTHOR(S): Kewan Q. Khawaja, Intelligent Engineering Systems Laboratory, M.I.T. (original contributor)
  5. * Markus Neteler <neteler itc.it> (original contributor)
  6. * Ron Yorston <rmy tigress co uk>, Glynn Clements <glynn gclements.plus.com>,
  7. * Hamish Bowman <hamish_b yahoo.com>, Jan-Oliver Wagner <jan intevation.de>
  8. * PURPOSE: line of sight
  9. * COPYRIGHT: (C) 1999-2007 by the GRASS Development Team
  10. *
  11. * This program is free software under the GNU General Public
  12. * License (>=v2). Read the file COPYING that comes with GRASS
  13. * for details.
  14. *
  15. *****************************************************************************/
  16. /****************************************************************
  17. * main.c
  18. *
  19. * This is the main program for line-of-sight analysis.
  20. * It takes a digital elevation map and identifies all
  21. * the grid cells that are visible from a user specified
  22. * observer location. Other input parameters to the
  23. * program include the height of the observer above the
  24. * ground, a map marking areas of interest in which the
  25. * analysis is desired, and a maximum range for the line
  26. * of sight.
  27. *
  28. ****************************************************************/
  29. #include <stdlib.h>
  30. #include <unistd.h>
  31. #include <math.h>
  32. #include <fcntl.h>
  33. #include <grass/gis.h>
  34. #include <grass/raster.h>
  35. #include <grass/segment.h>
  36. #include <grass/gprojects.h>
  37. #include <grass/glocale.h>
  38. #include "cmd_line.h"
  39. #include "point.h"
  40. #include "local_proto.h"
  41. #define COLOR_SHIFT 155.0
  42. #define COLOR_MAX 255.0
  43. #define SEARCH_PT_INCLINATION SEARCH_PT->inclination
  44. #define NEXT_SEARCH_PT SEARCH_PT->next
  45. struct Cell_head window; /* database window */
  46. struct point *DELAYED_DELETE;
  47. double east;
  48. double north;
  49. double obs_elev;
  50. double max_dist;
  51. char *elev_layer;
  52. char *patt_layer;
  53. char *out_layer;
  54. int main(int argc, char *argv[])
  55. {
  56. int row_viewpt, col_viewpt, nrows, ncols, a, b, row, patt_flag;
  57. int segment_no, flip, xmax, ymax, sign_on_y, sign_on_x;
  58. int submatrix_rows, submatrix_cols, lenth_data_item;
  59. int patt = 0, in_fd, out_fd, patt_fd = 0;
  60. int old, new;
  61. double slope_1, slope_2, max_vert_angle = 0.0, color_factor;
  62. const char *old_mapset, *patt_mapset = NULL;
  63. FCELL *value;
  64. const char *search_mapset, *current_mapset;
  65. const char *in_name, *out_name, *patt_name = NULL;
  66. struct Categories cats;
  67. struct Cell_head cellhd_elev, cellhd_patt;
  68. extern struct Cell_head window;
  69. CELL *cell;
  70. FCELL *fcell, data, viewpt_elev;
  71. SEGMENT seg_in, seg_out, seg_patt;
  72. struct point *heads[16], *SEARCH_PT;
  73. struct GModule *module;
  74. struct Option *opt1, *opt2, *opt3, *opt5, *opt6, *opt7;
  75. struct Flag *curvature;
  76. struct History history;
  77. char title[128];
  78. double aa, e2;
  79. G_gisinit(argv[0]);
  80. module = G_define_module();
  81. G_add_keyword(_("raster"));
  82. G_add_keyword(_("viewshed"));
  83. G_add_keyword(_("line of sight"));
  84. module->description = _("Line-of-sight raster analysis program.");
  85. /* Define the different options */
  86. opt1 = G_define_standard_option(G_OPT_R_ELEV);
  87. opt1->key = "input";
  88. opt7 = G_define_standard_option(G_OPT_R_OUTPUT);
  89. opt3 = G_define_option();
  90. opt3->key = "coordinate";
  91. opt3->type = TYPE_STRING;
  92. opt3->required = YES;
  93. opt3->key_desc = "x,y";
  94. opt3->description = _("Coordinate identifying the viewing position");
  95. opt2 = G_define_standard_option(G_OPT_R_COVER);
  96. opt2->key = "patt_map";
  97. opt2->required = NO;
  98. opt2->description = _("Binary (1/0) raster map to use as a mask");
  99. opt5 = G_define_option();
  100. opt5->key = "obs_elev";
  101. opt5->type = TYPE_DOUBLE;
  102. opt5->required = NO;
  103. opt5->answer = "1.75";
  104. opt5->description = _("Viewing position height above the ground");
  105. opt6 = G_define_option();
  106. opt6->key = "max_dist";
  107. opt6->type = TYPE_DOUBLE;
  108. opt6->required = NO;
  109. opt6->answer = "10000";
  110. opt6->options = "0-5000000"; /* observer can be in a plane, too */
  111. opt6->description = _("Maximum distance from the viewing point (meters)");
  112. /* http://mintaka.sdsu.edu/GF/explain/atmos_refr/horizon.html */
  113. curvature = G_define_flag();
  114. curvature->key = 'c';
  115. curvature->description =
  116. _("Consider earth curvature (current ellipsoid)");
  117. if (G_parser(argc, argv))
  118. exit(EXIT_FAILURE);
  119. /* initialize delayed point deletion */
  120. DELAYED_DELETE = NULL;
  121. G_scan_easting(opt3->answers[0], &east, G_projection());
  122. G_scan_northing(opt3->answers[1], &north, G_projection());
  123. sscanf(opt5->answer, "%lf", &obs_elev);
  124. sscanf(opt6->answer, "%lf", &max_dist);
  125. elev_layer = opt1->answer;
  126. patt_layer = opt2->answer;
  127. out_layer = opt7->answer;
  128. G_get_window(&window);
  129. current_mapset = G_mapset();
  130. /* set flag to indicate presence of areas of interest */
  131. if (patt_layer == NULL)
  132. patt_flag = FALSE;
  133. else
  134. patt_flag = TRUE;
  135. if ((G_projection() == PROJECTION_LL))
  136. G_fatal_error(_("Lat/Long support is not (yet) implemented for this module."));
  137. /* check if specified observer location inside window */
  138. if (east < window.west || east > window.east
  139. || north > window.north || north < window.south)
  140. G_fatal_error(_("Specified observer coordinate is outside current region bounds."));
  141. search_mapset = "";
  142. old_mapset = G_find_raster2(elev_layer, search_mapset);
  143. /* check if elevation layer present in database */
  144. if (old_mapset == NULL)
  145. G_fatal_error(_("Raster map <%s> not found"), elev_layer);
  146. /* if pattern layer used, check if present in database */
  147. if (patt_flag == TRUE) {
  148. patt_mapset = G_find_raster(patt_layer, search_mapset);
  149. if (patt_mapset == NULL)
  150. G_fatal_error(_("Raster map <%s> not found"), patt_layer);
  151. }
  152. /* read header info for elevation layer */
  153. Rast_get_cellhd(elev_layer, old_mapset, &cellhd_elev);
  154. /* if pattern layer present, read in its header info */
  155. if (patt_flag == TRUE) {
  156. Rast_get_cellhd(patt_layer, patt_mapset, &cellhd_patt);
  157. /* allocate buffer space for row-io to layer */
  158. cell = Rast_allocate_buf(CELL_TYPE);
  159. }
  160. /* allocate buffer space for row-io to layer */
  161. fcell = Rast_allocate_buf(FCELL_TYPE);
  162. /* find number of rows and columns in elevation map */
  163. nrows = Rast_window_rows();
  164. ncols = Rast_window_cols();
  165. /* open elevation overlay file for reading */
  166. old = Rast_open_old(elev_layer, old_mapset);
  167. /* open cell layer for writing output */
  168. new = Rast_open_new(out_layer, FCELL_TYPE);
  169. /* if pattern layer specified, open it for reading */
  170. if (patt_flag == TRUE) {
  171. patt = Rast_open_old(patt_layer, patt_mapset);
  172. if (Rast_get_map_type(patt) != CELL_TYPE)
  173. G_fatal_error(_("Pattern map should be a binary 0/1 CELL map"));
  174. }
  175. /* parameters for map submatrices */
  176. lenth_data_item = sizeof(FCELL);
  177. submatrix_rows = nrows / 4 + 1;
  178. submatrix_cols = ncols / 4 + 1;
  179. /* create segmented format files for elevation layer, */
  180. /* output layer and pattern layer (if present) */
  181. in_name = G_tempfile();
  182. in_fd = creat(in_name, 0666);
  183. segment_format(in_fd, nrows, ncols,
  184. submatrix_rows, submatrix_cols, lenth_data_item);
  185. close(in_fd);
  186. out_name = G_tempfile();
  187. out_fd = creat(out_name, 0666);
  188. segment_format(out_fd, nrows, ncols,
  189. submatrix_rows, submatrix_cols, lenth_data_item);
  190. close(out_fd);
  191. if (patt_flag == TRUE) {
  192. patt_name = G_tempfile();
  193. patt_fd = creat(patt_name, 0666);
  194. segment_format(patt_fd, nrows, ncols,
  195. submatrix_rows, submatrix_cols, sizeof(CELL));
  196. close(patt_fd);
  197. }
  198. if (curvature->answer) {
  199. /* try to get the radius the standard GRASS way from the libs */
  200. G_get_ellipsoid_parameters(&aa, &e2);
  201. if (aa == 0) {
  202. /* since there was a problem, take a hardcoded radius :( */
  203. G_warning(_("Problem to obtain current ellipsoid parameters, using sphere (6370997.0)"));
  204. aa = 6370997.00;
  205. }
  206. G_debug(3, "radius: %f", aa);
  207. }
  208. G_message(_("Using maximum distance from the viewing point (meters): %f"),
  209. max_dist);
  210. /* open, initialize and segment all files */
  211. in_fd = open(in_name, 2);
  212. segment_init(&seg_in, in_fd, 4);
  213. out_fd = open(out_name, 2);
  214. segment_init(&seg_out, out_fd, 4);
  215. if (patt_flag == TRUE) {
  216. patt_fd = open(patt_name, 2);
  217. segment_init(&seg_patt, patt_fd, 4);
  218. for (row = 0; row < nrows; row++) {
  219. Rast_get_row(patt, cell, row, CELL_TYPE);
  220. segment_put_row(&seg_patt, cell, row);
  221. }
  222. }
  223. for (row = 0; row < nrows; row++) {
  224. Rast_get_row(old, fcell, row, FCELL_TYPE);
  225. segment_put_row(&seg_in, fcell, row);
  226. }
  227. /* calc map array coordinates for viewing point */
  228. row_viewpt = (window.north - north) / window.ns_res;
  229. col_viewpt = (east - window.west) / window.ew_res;
  230. /* read elevation of viewing point */
  231. value = &viewpt_elev;
  232. segment_get(&seg_in, value, row_viewpt, col_viewpt);
  233. viewpt_elev += obs_elev;
  234. /* DO LOS ANALYSIS FOR SIXTEEN SEGMENTS */
  235. for (segment_no = 1; segment_no <= 16; segment_no++) {
  236. sign_on_y = 1 - (segment_no - 1) / 8 * 2;
  237. if (segment_no > 4 && segment_no < 13)
  238. sign_on_x = -1;
  239. else
  240. sign_on_x = 1;
  241. /* calc slopes for bounding rays of a segment */
  242. if (segment_no == 1 || segment_no == 4 || segment_no == 5 ||
  243. segment_no == 8 || segment_no == 9 || segment_no == 12 ||
  244. segment_no == 13 || segment_no == 16) {
  245. slope_1 = 0.0;
  246. slope_2 = 0.5;
  247. }
  248. else {
  249. slope_1 = 0.5;
  250. slope_2 = 1.0;
  251. }
  252. if (segment_no == 1 || segment_no == 2 || segment_no == 7 ||
  253. segment_no == 8 || segment_no == 9 || segment_no == 10 ||
  254. segment_no == 15 || segment_no == 16)
  255. flip = 0;
  256. else
  257. flip = 1;
  258. /* calculate max and min 'x' and 'y' */
  259. a = ((ncols - 1) * (sign_on_x + 1) / 2 - sign_on_x * col_viewpt);
  260. b = (1 - sign_on_y) / 2 * (nrows - 1) + sign_on_y * row_viewpt;
  261. if (flip == 0) {
  262. xmax = a;
  263. ymax = b;
  264. }
  265. else {
  266. xmax = b;
  267. ymax = a;
  268. }
  269. /* perform analysis for every segment */
  270. heads[segment_no - 1] = segment(segment_no, xmax, ymax,
  271. slope_1, slope_2, flip, sign_on_y,
  272. sign_on_x, viewpt_elev, &seg_in,
  273. &seg_out, &seg_patt, row_viewpt,
  274. col_viewpt, patt_flag,
  275. curvature->answer, aa);
  276. G_percent(segment_no, 16, 5);
  277. } /* end of for-loop over segments */
  278. /* loop over all segment lists to find maximum vertical */
  279. /* angle of any point when viewed from observer location */
  280. for (segment_no = 1; segment_no <= 16; segment_no++) {
  281. SEARCH_PT = heads[segment_no - 1];
  282. while (SEARCH_PT != NULL) {
  283. if (fabs(SEARCH_PT_INCLINATION) > max_vert_angle)
  284. max_vert_angle = fabs(SEARCH_PT_INCLINATION);
  285. SEARCH_PT = NEXT_SEARCH_PT;
  286. }
  287. }
  288. /* calculate factor to be multiplied to every vertical */
  289. /* angle for suitable color variation on output map */
  290. /* color_factor = decide_color_range(max_vert_angle * 57.3,
  291. COLOR_SHIFT, COLOR_MAX); */
  292. color_factor = 1.0; /* to give true angle? */
  293. /* mark visible points for all segments on outputmap */
  294. for (segment_no = 1; segment_no <= 16; segment_no++) {
  295. mark_visible_points(heads[segment_no - 1], &seg_out,
  296. row_viewpt, col_viewpt, color_factor,
  297. COLOR_SHIFT);
  298. }
  299. /* mark viewpt on output map */
  300. data = 180;
  301. value = &data;
  302. segment_put(&seg_out, value, row_viewpt, col_viewpt);
  303. /* write pending updates by segment_put() to outputmap */
  304. segment_flush(&seg_out);
  305. /* convert output submatrices to full cell overlay */
  306. for (row = 0; row < nrows; row++) {
  307. int col;
  308. segment_get_row(&seg_out, fcell, row);
  309. for (col = 0; col < ncols; col++)
  310. /* set to NULL if beyond max_dist (0) or blocked view (1) */
  311. if (fcell[col] == 0 || fcell[col] == 1)
  312. Rast_set_null_value(&fcell[col], 1, FCELL_TYPE);
  313. Rast_put_row(new, fcell, FCELL_TYPE);
  314. }
  315. segment_release(&seg_in); /* release memory */
  316. segment_release(&seg_out);
  317. if (patt_flag == TRUE)
  318. segment_release(&seg_patt);
  319. close(in_fd); /* close all files */
  320. close(out_fd);
  321. unlink(in_name); /* remove temp files as well */
  322. unlink(out_name);
  323. Rast_close(old);
  324. Rast_close(new);
  325. if (patt_flag == TRUE) {
  326. close(patt_fd);
  327. Rast_close(patt);
  328. }
  329. /* create category file for output map */
  330. Rast_read_cats(out_layer, current_mapset, &cats);
  331. Rast_set_cats_fmt("$1 degree$?s", 1.0, 0.0, 0.0, 0.0, &cats);
  332. Rast_write_cats(out_layer, &cats);
  333. sprintf(title, "Line of sight %.2fm above %s", obs_elev, opt3->answer);
  334. Rast_put_cell_title(out_layer, title);
  335. Rast_write_units(out_layer, "degrees");
  336. Rast_short_history(out_layer, "raster", &history);
  337. Rast_command_history(&history);
  338. Rast_write_history(out_layer, &history);
  339. /* release that last tiny bit of memory ... */
  340. if ( DELAYED_DELETE != NULL ) {
  341. G_free ( DELAYED_DELETE );
  342. }
  343. exit(EXIT_SUCCESS);
  344. }