grass.cpp 29 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016
  1. /****************************************************************************
  2. *
  3. * MODULE: r.viewshed
  4. *
  5. * AUTHOR(S): Laura Toma, Bowdoin College - ltoma@bowdoin.edu
  6. * Yi Zhuang - yzhuang@bowdoin.edu
  7. *
  8. * Ported to GRASS by William Richard -
  9. * wkrichar@bowdoin.edu or willster3021@gmail.com
  10. * Markus Metz: surface interpolation
  11. *
  12. * Date: april 2011
  13. *
  14. * PURPOSE: To calculate the viewshed (the visible cells in the
  15. * raster) for the given viewpoint (observer) location. The
  16. * visibility model is the following: Two points in the raster are
  17. * considered visible to each other if the cells where they belong are
  18. * visible to each other. Two cells are visible to each other if the
  19. * line-of-sight that connects their centers does not intersect the
  20. * terrain. The terrain is NOT viewed as a tesselation of flat cells,
  21. * i.e. if the line-of-sight does not pass through the cell center,
  22. * elevation is determined using bilinear interpolation.
  23. * The viewshed algorithm is efficient both in
  24. * terms of CPU operations and I/O operations. It has worst-case
  25. * complexity O(n lg n) in the RAM model and O(sort(n)) in the
  26. * I/O-model. For the algorithm and all the other details see the
  27. * paper: "Computing Visibility on * Terrains in External Memory" by
  28. * Herman Haverkort, Laura Toma and Yi Zhuang.
  29. *
  30. * COPYRIGHT: (C) 2008 by the GRASS Development Team
  31. *
  32. * This program is free software under the GNU General Public License
  33. * (>=v2). Read the file COPYING that comes with GRASS for details.
  34. *
  35. *****************************************************************************/
  36. #include <stdlib.h>
  37. #include <stdio.h>
  38. extern "C"
  39. {
  40. #include <grass/config.h>
  41. #include <grass/gis.h>
  42. #include <grass/glocale.h>
  43. }
  44. #include "grass.h"
  45. #include "visibility.h"
  46. /* ------------------------------------------------------------ */
  47. /* If viewOptions.doCurv is on then adjust the passed height for
  48. curvature of the earth; otherwise return the passed height
  49. unchanged.
  50. If viewOptions.doRefr is on then adjust the curved height for
  51. the effect of atmospheric refraction too.
  52. */
  53. surface_type adjust_for_curvature(Viewpoint vp, double row,
  54. double col, surface_type h,
  55. ViewOptions viewOptions, GridHeader *hd)
  56. {
  57. if (!viewOptions.doCurv)
  58. return h;
  59. assert(viewOptions.ellps_a != 0);
  60. /* distance must be in meters because ellps_a is in meters */
  61. double dist = G_distance(Rast_col_to_easting(vp.col + 0.5, &(hd->window)),
  62. Rast_row_to_northing(vp.row + 0.5, &(hd->window)),
  63. Rast_col_to_easting(col + 0.5, &(hd->window)),
  64. Rast_row_to_northing(row + 0.5, &(hd->window)));
  65. double adjustment = (dist * dist) / (2.0 * viewOptions.ellps_a);
  66. if (!viewOptions.doRefr)
  67. return h - adjustment;
  68. return h - (adjustment * (1.0 - viewOptions.refr_coef));
  69. }
  70. /* ************************************************************ */
  71. /*return a GridHeader that has all the relevant data filled in */
  72. GridHeader *read_header(char *rastName, Cell_head * region)
  73. {
  74. assert(rastName);
  75. /*allocate the grid header to fill */
  76. GridHeader *hd = (GridHeader *) G_malloc(sizeof(GridHeader));
  77. assert(hd);
  78. /*get the num rows and cols from GRASS */
  79. int nrows, ncols;
  80. nrows = Rast_window_rows();
  81. ncols = Rast_window_cols();
  82. /*check for loss of prescion */
  83. if (nrows <= maxDimension && ncols <= maxDimension) {
  84. hd->nrows = (dimensionType) nrows;
  85. hd->ncols = (dimensionType) ncols;
  86. }
  87. else {
  88. G_warning("ERROR: nrows (%d) > maxDimension (%d) AND/OR ncols (%d) > maxDimension (%d)",
  89. nrows, maxDimension, ncols, maxDimension);
  90. G_fatal_error(_("Computational region too large. Use smaller area or lower raster resolution"));
  91. }
  92. /*fill in rest of header */
  93. hd->xllcorner = Rast_col_to_easting(0, region);
  94. hd->yllcorner = Rast_row_to_northing(0, region);
  95. /* Cell_head stores 2 resolutions, while GridHeader only stores 1 */
  96. // make sure the two Cell_head resolutions are equal
  97. if (fabs(region->ew_res - region->ns_res) > .001) {
  98. G_warning(_("East-west resolution does not equal north-south resolution. "
  99. "The viewshed computation assumes the cells are square, so in "
  100. "this case this may result in innacuracies."));
  101. // exit(EXIT_FAILURE);
  102. }
  103. hd->ew_res = region->ew_res;
  104. hd->ns_res = region->ns_res;
  105. //store the null value of the map
  106. Rast_set_null_value(&(hd->nodata_value), 1, G_SURFACE_TYPE);
  107. G_verbose_message("Nodata value set to %f", hd->nodata_value);
  108. return hd;
  109. }
  110. /* calculate ENTER and EXIT event elevation (bilinear interpolation) */
  111. surface_type calculate_event_elevation(AEvent e, int nrows, int ncols,
  112. dimensionType vprow, dimensionType vpcol,
  113. G_SURFACE_T **inrast, RASTER_MAP_TYPE data_type)
  114. {
  115. int row1, col1;
  116. surface_type event_elev;
  117. G_SURFACE_T elev1, elev2, elev3, elev4;
  118. calculate_event_row_col(e, vprow, vpcol, &row1, &col1);
  119. if (row1 >= 0 && row1 < nrows && col1 >= 0 && col1 < ncols) {
  120. elev1 = inrast[row1 - e.row + 1][col1];
  121. elev2 = inrast[row1 - e.row + 1][e.col];
  122. elev3 = inrast[1][col1];
  123. elev4 = inrast[1][e.col];
  124. if (Rast_is_null_value(&elev1, data_type) ||
  125. Rast_is_null_value(&elev2, data_type) ||
  126. Rast_is_null_value(&elev3, data_type) ||
  127. Rast_is_null_value(&elev4, data_type))
  128. event_elev = inrast[1][e.col];
  129. else {
  130. event_elev = (elev1 + elev2 + elev3 + elev4) / 4.;
  131. }
  132. }
  133. else
  134. event_elev = inrast[1][e.col];
  135. return event_elev;
  136. }
  137. /* ************************************************************ */
  138. /* input: an array capable to hold the max number of events, a raster
  139. name, a viewpoint and the viewOptions; action: figure out all events
  140. in the input file, and write them to the event list. data is
  141. allocated and initialized with all the cells on the same row as the
  142. viewpoint. it returns the number of events. initialize and fill
  143. AEvent* with all the events for the map. Used when solving in
  144. memory, so the AEvent* should fit in memory. */
  145. size_t
  146. init_event_list_in_memory(AEvent * eventList, char *rastName,
  147. Viewpoint * vp, GridHeader * hd,
  148. ViewOptions viewOptions, surface_type ***data,
  149. MemoryVisibilityGrid * visgrid)
  150. {
  151. G_message(_("Computing events..."));
  152. assert(eventList && vp && visgrid);
  153. //GRASS should be defined
  154. /*alloc data ; data is used to store all the cells on the same row
  155. as the viewpoint. */
  156. *data = (surface_type **)G_malloc(3 * sizeof(surface_type *));
  157. assert(*data);
  158. (*data)[0] = (surface_type *)G_malloc(3 * Rast_window_cols() * sizeof(surface_type));
  159. assert((*data)[0]);
  160. (*data)[1] = (*data)[0] + Rast_window_cols();
  161. (*data)[2] = (*data)[1] + Rast_window_cols();
  162. /*get the mapset name */
  163. const char *mapset;
  164. mapset = G_find_raster(rastName, "");
  165. if (mapset == NULL)
  166. G_fatal_error(_("Raster map [%s] not found"), rastName);
  167. /*open map */
  168. int infd;
  169. if ((infd = Rast_open_old(rastName, mapset)) < 0)
  170. G_fatal_error(_("Cannot open raster file [%s]"), rastName);
  171. /*get the data_type */
  172. RASTER_MAP_TYPE data_type;
  173. /* data_type = G_raster_map_type(rastName, mapset); */
  174. data_type = G_SURFACE_TYPE;
  175. /*buffer to hold 3 rows */
  176. G_SURFACE_T **inrast;
  177. int nrows = Rast_window_rows();
  178. int ncols = Rast_window_cols();
  179. inrast = (G_SURFACE_T **)G_malloc(3 * sizeof(G_SURFACE_T *));
  180. assert(inrast);
  181. inrast[0] = (G_SURFACE_T *)Rast_allocate_buf(data_type);
  182. assert(inrast[0]);
  183. inrast[1] = (G_SURFACE_T *)Rast_allocate_buf(data_type);
  184. assert(inrast[1]);
  185. inrast[2] = (G_SURFACE_T *)Rast_allocate_buf(data_type);
  186. assert(inrast[2]);
  187. Rast_set_null_value(inrast[0], ncols, data_type);
  188. Rast_set_null_value(inrast[1], ncols, data_type);
  189. Rast_set_null_value(inrast[2], ncols, data_type);
  190. int isnull = 0;
  191. /*keep track of the number of events added, to be returned later */
  192. size_t nevents = 0;
  193. /*scan through the raster data */
  194. dimensionType i, j;
  195. double ax, ay;
  196. AEvent e;
  197. /* read first row */
  198. Rast_get_row(infd, inrast[2], 0, data_type);
  199. e.angle = -1;
  200. for (i = 0; i < nrows; i++) {
  201. /*read in the raster row */
  202. G_SURFACE_T *tmprast = inrast[0];
  203. inrast[0] = inrast[1];
  204. inrast[1] = inrast[2];
  205. inrast[2] = tmprast;
  206. if (i < nrows - 1)
  207. Rast_get_row(infd, inrast[2], i + 1, data_type);
  208. else
  209. Rast_set_null_value(inrast[2], ncols, data_type);
  210. G_percent(i, nrows, 2);
  211. /*fill event list with events from this row */
  212. for (j = 0; j < Rast_window_cols(); j++) {
  213. e.row = i;
  214. e.col = j;
  215. /*read the elevation value into the event */
  216. isnull = Rast_is_null_value(&(inrast[1][j]), data_type);
  217. e.elev[1] = inrast[1][j];
  218. /* adjust for curvature */
  219. e.elev[1] = adjust_for_curvature(*vp, i, j, e.elev[1], viewOptions, hd);
  220. /*write it into the row of data going through the viewpoint */
  221. if (i == vp->row) {
  222. (*data)[0][j] = e.elev[1];
  223. (*data)[1][j] = e.elev[1];
  224. (*data)[2][j] = e.elev[1];
  225. }
  226. /* set the viewpoint, and don't insert it into eventlist */
  227. if (i == vp->row && j == vp->col) {
  228. set_viewpoint_elev(vp, e.elev[1] + viewOptions.obsElev);
  229. if (viewOptions.tgtElev > 0)
  230. vp->target_offset = viewOptions.tgtElev;
  231. else
  232. vp->target_offset = 0.;
  233. if (isnull) {
  234. /*what to do when viewpoint is NODATA ? */
  235. G_warning(_("Viewpoint is NODATA."));
  236. G_message(_("Will assume its elevation is = %f"),
  237. vp->elev);
  238. }
  239. add_result_to_inmem_visibilitygrid(visgrid, i, j,
  240. 180);
  241. continue;
  242. }
  243. /*don't insert in eventlist nodata cell events */
  244. if (isnull) {
  245. /* record this cell as being NODATA; this is necessary so
  246. that we can distingush invisible events, from nodata
  247. events in the output */
  248. add_result_to_inmem_visibilitygrid(visgrid, i, j,
  249. hd->nodata_value);
  250. continue;
  251. }
  252. /* if point is outside maxDist, do NOT include it as an
  253. event */
  254. if (is_point_outside_max_dist
  255. (*vp, *hd, i, j, viewOptions.maxDist))
  256. continue;
  257. /* if it got here it is not the viewpoint, not NODATA, and
  258. within max distance from viewpoint; generate its 3 events
  259. and insert them */
  260. /* get ENTER elevation */
  261. e.eventType = ENTERING_EVENT;
  262. e.elev[0] = calculate_event_elevation(e, nrows, ncols,
  263. vp->row, vp->col, inrast, data_type);
  264. /* adjust for curvature */
  265. if (viewOptions.doCurv) {
  266. calculate_event_position(e, vp->row, vp->col, &ay, &ax);
  267. e.elev[0] = adjust_for_curvature(*vp, ay, ax, e.elev[0], viewOptions, hd);
  268. }
  269. /* get EXIT elevation */
  270. e.eventType = EXITING_EVENT;
  271. e.elev[2] = calculate_event_elevation(e, nrows, ncols,
  272. vp->row, vp->col, inrast, data_type);
  273. /* adjust for curvature */
  274. if (viewOptions.doCurv) {
  275. calculate_event_position(e, vp->row, vp->col, &ay, &ax);
  276. e.elev[2] = adjust_for_curvature(*vp, ay, ax, e.elev[2], viewOptions, hd);
  277. }
  278. /*write adjusted elevation into the row of data going through the viewpoint */
  279. if (i == vp->row) {
  280. (*data)[0][j] = e.elev[0];
  281. (*data)[1][j] = e.elev[1];
  282. (*data)[2][j] = e.elev[2];
  283. }
  284. /*put event into event list */
  285. e.eventType = ENTERING_EVENT;
  286. calculate_event_position(e, vp->row, vp->col, &ay, &ax);
  287. e.angle = calculate_angle(ax, ay, vp->col, vp->row);
  288. eventList[nevents] = e;
  289. nevents++;
  290. e.eventType = CENTER_EVENT;
  291. calculate_event_position(e, vp->row, vp->col, &ay, &ax);
  292. e.angle = calculate_angle(ax, ay, vp->col, vp->row);
  293. eventList[nevents] = e;
  294. nevents++;
  295. e.eventType = EXITING_EVENT;
  296. calculate_event_position(e, vp->row, vp->col, &ay, &ax);
  297. e.angle = calculate_angle(ax, ay, vp->col, vp->row);
  298. eventList[nevents] = e;
  299. nevents++;
  300. }
  301. }
  302. G_percent(nrows, nrows, 2);
  303. Rast_close(infd);
  304. G_free(inrast[0]);
  305. G_free(inrast[1]);
  306. G_free(inrast[2]);
  307. G_free(inrast);
  308. return nevents;
  309. }
  310. /* ************************************************************ */
  311. /* input: an arcascii file, a grid header and a viewpoint; action:
  312. figure out all events in the input file, and write them to the
  313. stream. It assumes the file pointer is positioned rigth after the
  314. grid header so that this function can read all grid elements.
  315. if data is not NULL, it creates an array that stores all events on
  316. the same row as the viewpoint.
  317. */
  318. AMI_STREAM < AEvent > *init_event_list(char *rastName, Viewpoint * vp,
  319. GridHeader * hd,
  320. ViewOptions viewOptions,
  321. surface_type ***data,
  322. IOVisibilityGrid * visgrid)
  323. {
  324. G_message(_("Computing events..."));
  325. assert(rastName && vp && hd && visgrid);
  326. if (data != NULL) {
  327. /*data is used to store all the cells on the same row as the
  328. //viewpoint. */
  329. *data = (surface_type **)G_malloc(3 * sizeof(surface_type *));
  330. assert(*data);
  331. (*data)[0] = (surface_type *)G_malloc(3 * Rast_window_cols() * sizeof(surface_type));
  332. assert((*data)[0]);
  333. (*data)[1] = (*data)[0] + Rast_window_cols();
  334. (*data)[2] = (*data)[1] + Rast_window_cols();
  335. }
  336. /*create the event stream that will hold the events */
  337. AMI_STREAM < AEvent > *eventList = new AMI_STREAM < AEvent > ();
  338. assert(eventList);
  339. /*determine which mapset we are in */
  340. const char *mapset;
  341. mapset = G_find_raster(rastName, "");
  342. if (mapset == NULL)
  343. G_fatal_error(_("Raster map [%s] not found"), rastName);
  344. /*open map */
  345. int infd;
  346. if ((infd = Rast_open_old(rastName, mapset)) < 0)
  347. G_fatal_error(_("Cannot open raster file [%s]"), rastName);
  348. RASTER_MAP_TYPE data_type;
  349. /* data_type = G_raster_map_type(rastName, mapset); */
  350. data_type = G_SURFACE_TYPE;
  351. G_SURFACE_T **inrast;
  352. int nrows = Rast_window_rows();
  353. int ncols = Rast_window_cols();
  354. inrast = (G_SURFACE_T **)G_malloc(3 * sizeof(G_SURFACE_T *));
  355. assert(inrast);
  356. inrast[0] = (G_SURFACE_T *)Rast_allocate_buf(data_type);
  357. assert(inrast[0]);
  358. inrast[1] = (G_SURFACE_T *)Rast_allocate_buf(data_type);
  359. assert(inrast[1]);
  360. inrast[2] = (G_SURFACE_T *)Rast_allocate_buf(data_type);
  361. assert(inrast[2]);
  362. Rast_set_null_value(inrast[0], ncols, data_type);
  363. Rast_set_null_value(inrast[1], ncols, data_type);
  364. Rast_set_null_value(inrast[2], ncols, data_type);
  365. /*scan through the raster data */
  366. int isnull = 0;
  367. dimensionType i, j;
  368. double ax, ay;
  369. AEvent e;
  370. /* read first row */
  371. Rast_get_row(infd, inrast[2], 0, data_type);
  372. e.angle = -1;
  373. /*start scanning through the grid */
  374. for (i = 0; i < nrows; i++) {
  375. G_percent(i, nrows, 2);
  376. /*read in the raster row */
  377. G_SURFACE_T *tmprast = inrast[0];
  378. inrast[0] = inrast[1];
  379. inrast[1] = inrast[2];
  380. inrast[2] = tmprast;
  381. if (i < nrows - 1)
  382. Rast_get_row(infd, inrast[2], i + 1, data_type);
  383. else
  384. Rast_set_null_value(inrast[2], ncols, data_type);
  385. /*fill event list with events from this row */
  386. for (j = 0; j < ncols; j++) {
  387. e.row = i;
  388. e.col = j;
  389. /*read the elevation value into the event */
  390. isnull = Rast_is_null_value(&(inrast[1][j]), data_type);
  391. e.elev[1] = inrast[1][j];
  392. /* adjust for curvature */
  393. e.elev[1] = adjust_for_curvature(*vp, i, j, e.elev[1], viewOptions, hd);
  394. if (data != NULL) {
  395. /*write the row of data going through the viewpoint */
  396. if (i == vp->row) {
  397. (*data)[0][j] = e.elev[1];
  398. (*data)[1][j] = e.elev[1];
  399. (*data)[2][j] = e.elev[1];
  400. }
  401. }
  402. /* set the viewpoint */
  403. if (i == vp->row && j == vp->col) {
  404. set_viewpoint_elev(vp, e.elev[1] + viewOptions.obsElev);
  405. /*what to do when viewpoint is NODATA */
  406. if (is_nodata(hd, e.elev[1])) {
  407. G_warning("Viewpoint is NODATA.");
  408. G_message("Will assume its elevation is %.f", e.elev[1]);
  409. };
  410. if (viewOptions.tgtElev > 0)
  411. vp->target_offset = viewOptions.tgtElev;
  412. else
  413. vp->target_offset = 0.;
  414. /* add viewpoint to visibility grid */
  415. VisCell visCell = { i, j, 180 };
  416. add_result_to_io_visibilitygrid(visgrid, &visCell);
  417. /*don't insert viewpoint into eventlist */
  418. continue;
  419. }
  420. /*don't insert the nodata cell events */
  421. if (is_nodata(hd, e.elev[1])) {
  422. /* record this cell as being NODATA. ; this is necessary so
  423. that we can distingush invisible events, from nodata
  424. events in the output */
  425. VisCell visCell = { i, j, hd->nodata_value };
  426. add_result_to_io_visibilitygrid(visgrid, &visCell);
  427. continue;
  428. }
  429. /* if point is outside maxDist, do NOT include it as an
  430. event */
  431. if (is_point_outside_max_dist
  432. (*vp, *hd, i, j, viewOptions.maxDist))
  433. continue;
  434. /* get ENTER elevation */
  435. e.eventType = ENTERING_EVENT;
  436. e.elev[0] = calculate_event_elevation(e, nrows, ncols,
  437. vp->row, vp->col, inrast, data_type);
  438. /* adjust for curvature */
  439. if (viewOptions.doCurv) {
  440. calculate_event_position(e, vp->row, vp->col, &ay, &ax);
  441. e.elev[0] = adjust_for_curvature(*vp, ay, ax, e.elev[0], viewOptions, hd);
  442. }
  443. /* get EXIT elevation */
  444. e.eventType = EXITING_EVENT;
  445. e.elev[2] = calculate_event_elevation(e, nrows, ncols,
  446. vp->row, vp->col, inrast, data_type);
  447. /* adjust for curvature */
  448. if (viewOptions.doCurv) {
  449. calculate_event_position(e, vp->row, vp->col, &ay, &ax);
  450. e.elev[2] = adjust_for_curvature(*vp, ay, ax, e.elev[2], viewOptions, hd);
  451. }
  452. if (data != NULL) {
  453. /*write the row of data going through the viewpoint */
  454. if (i == vp->row) {
  455. (*data)[0][j] = e.elev[0];
  456. (*data)[1][j] = e.elev[1];
  457. (*data)[2][j] = e.elev[2];
  458. }
  459. }
  460. /*put event into event list */
  461. e.eventType = ENTERING_EVENT;
  462. calculate_event_position(e, vp->row, vp->col, &ay, &ax);
  463. e.angle = calculate_angle(ax, ay, vp->col, vp->row);
  464. eventList->write_item(e);
  465. e.eventType = CENTER_EVENT;
  466. calculate_event_position(e, vp->row, vp->col, &ay, &ax);
  467. e.angle = calculate_angle(ax, ay, vp->col, vp->row);
  468. eventList->write_item(e);
  469. e.eventType = EXITING_EVENT;
  470. calculate_event_position(e, vp->row, vp->col, &ay, &ax);
  471. e.angle = calculate_angle(ax, ay, vp->col, vp->row);
  472. eventList->write_item(e);
  473. } /* for j */
  474. } /* for i */
  475. G_percent(nrows, nrows, 2);
  476. Rast_close(infd);
  477. G_free(inrast[0]);
  478. G_free(inrast[1]);
  479. G_free(inrast[2]);
  480. G_free(inrast);
  481. G_debug(1, "nbEvents = %lu", (unsigned long)eventList->stream_len());
  482. G_debug(1, "Event stream length: %lu x %dB (%lu MB)",
  483. (unsigned long)eventList->stream_len(), (int)sizeof(AEvent),
  484. (unsigned long)(((long long)(eventList->stream_len() *
  485. sizeof(AEvent))) >> 20));
  486. return eventList;
  487. }
  488. /* ************************************************************ */
  489. /* saves the grid into a GRASS raster. Loops through all elements x
  490. in row-column order and writes fun(x) to file. */
  491. void
  492. save_grid_to_GRASS(Grid * grid, char *filename, RASTER_MAP_TYPE type,
  493. OutputMode mode)
  494. {
  495. G_important_message(_("Writing output raster map..."));
  496. assert(grid && filename);
  497. /*open the new raster */
  498. int outfd;
  499. outfd = Rast_open_new(filename, type);
  500. /*get the buffer to store values to read and write to each row */
  501. void *outrast;
  502. outrast = Rast_allocate_buf(type);
  503. assert(outrast);
  504. dimensionType i, j;
  505. for (i = 0; i < Rast_window_rows(); i++) {
  506. G_percent(i, Rast_window_rows(), 5);
  507. for (j = 0; j < Rast_window_cols(); j++) {
  508. if (is_invisible_nodata(grid->grid_data[i][j])) {
  509. writeNodataValue(outrast, j, type);
  510. }
  511. else if (mode == OUTPUT_BOOL) {
  512. ((CELL *) outrast)[j] = (CELL) booleanVisibilityOutput(grid->grid_data[i][j]);
  513. }
  514. else if (mode == OUTPUT_ANGLE) {
  515. if (is_visible(grid->grid_data[i][j])) {
  516. ((FCELL *) outrast)[j] = (FCELL) angleVisibilityOutput(grid->grid_data[i][j]);
  517. }
  518. else {
  519. writeNodataValue(outrast, j, FCELL_TYPE);
  520. }
  521. }
  522. } /* for j */
  523. Rast_put_row(outfd, outrast, type);
  524. } /* for i */
  525. G_percent(1, 1, 1);
  526. G_free(outrast);
  527. Rast_close(outfd);
  528. return;
  529. }
  530. /* ************************************************************ */
  531. /* using the visibility information recorded in visgrid, it creates an
  532. output viewshed raster with name outfname; for every point p that
  533. is visible in the grid, the corresponding value in the output
  534. raster is elevation(p) - viewpoint_elevation(p); the elevation
  535. values are read from elevfname raster */
  536. void
  537. save_vis_elev_to_GRASS(Grid * visgrid, char *elevfname, char *visfname,
  538. float vp_elev)
  539. {
  540. G_message(_("Saving grid to <%s>"), visfname);
  541. assert(visgrid && elevfname && visfname);
  542. /*get the mapset name */
  543. const char *mapset;
  544. mapset = G_find_raster(elevfname, "");
  545. if (mapset == NULL)
  546. G_fatal_error(_("Raster map [%s] not found"), elevfname);
  547. /*open elevation map */
  548. int elevfd;
  549. if ((elevfd = Rast_open_old(elevfname, mapset)) < 0)
  550. G_fatal_error(_("Cannot open raster file [%s]"), elevfname);
  551. /*get elevation data_type */
  552. RASTER_MAP_TYPE elev_data_type;
  553. elev_data_type = Rast_map_type(elevfname, mapset);
  554. /* create the visibility raster of same type */
  555. int visfd;
  556. visfd = Rast_open_new(visfname, elev_data_type);
  557. /*get the buffers to store each row */
  558. void *elevrast;
  559. elevrast = Rast_allocate_buf(elev_data_type);
  560. assert(elevrast);
  561. void *visrast;
  562. visrast = Rast_allocate_buf(elev_data_type);
  563. assert(visrast);
  564. dimensionType i, j;
  565. double elev = 0, viewshed_value;
  566. for (i = 0; i < Rast_window_rows(); i++) {
  567. /* get the row from elevation */
  568. Rast_get_row(elevfd, elevrast, i, elev_data_type);
  569. for (j = 0; j < Rast_window_cols(); j++) {
  570. /* read the current elevation value */
  571. int isNull = 0;
  572. switch (elev_data_type) {
  573. case CELL_TYPE:
  574. isNull = Rast_is_c_null_value(&((CELL *) elevrast)[j]);
  575. elev = (double)(((CELL *) elevrast)[j]);
  576. break;
  577. case FCELL_TYPE:
  578. isNull = Rast_is_f_null_value(&((FCELL *) elevrast)[j]);
  579. elev = (double)(((FCELL *) elevrast)[j]);
  580. break;
  581. case DCELL_TYPE:
  582. isNull = Rast_is_d_null_value(&((DCELL *) elevrast)[j]);
  583. elev = (double)(((DCELL *) elevrast)[j]);
  584. break;
  585. }
  586. if (is_visible(visgrid->grid_data[i][j])) {
  587. /* elevation cannot be null */
  588. assert(!isNull);
  589. /* write elev - viewpoint_elevation */
  590. viewshed_value = elev - vp_elev;
  591. writeValue(visrast, j, viewshed_value, elev_data_type);
  592. }
  593. else if (is_invisible_not_nodata(visgrid->grid_data[i][j])) {
  594. /* elevation cannot be null */
  595. assert(!isNull);
  596. /* write INVISIBLE */
  597. /*
  598. viewshed_value = INVISIBLE;
  599. writeValue(visrast, j, viewshed_value, elev_data_type);
  600. */
  601. /* write NODATA */
  602. writeNodataValue(visrast, j, elev_data_type);
  603. }
  604. else {
  605. /* nodata */
  606. assert(isNull);
  607. /* write NODATA */
  608. writeNodataValue(visrast, j, elev_data_type);
  609. }
  610. } /* for j */
  611. Rast_put_row(visfd, visrast, elev_data_type);
  612. } /* for i */
  613. Rast_close(elevfd);
  614. Rast_close(visfd);
  615. return;
  616. }
  617. /* helper function to deal with GRASS writing to a row buffer */
  618. void writeValue(void *bufrast, int j, double x, RASTER_MAP_TYPE data_type)
  619. {
  620. switch (data_type) {
  621. case CELL_TYPE:
  622. ((CELL *) bufrast)[j] = (CELL) x;
  623. break;
  624. case FCELL_TYPE:
  625. ((FCELL *) bufrast)[j] = (FCELL) x;
  626. break;
  627. case DCELL_TYPE:
  628. ((DCELL *) bufrast)[j] = (DCELL) x;
  629. break;
  630. default:
  631. G_fatal_error(_("Unknown data type"));
  632. }
  633. }
  634. void writeNodataValue(void *bufrast, int j, RASTER_MAP_TYPE data_type)
  635. {
  636. switch (data_type) {
  637. case CELL_TYPE:
  638. Rast_set_c_null_value(&((CELL *) bufrast)[j], 1);
  639. break;
  640. case FCELL_TYPE:
  641. Rast_set_f_null_value(&((FCELL *) bufrast)[j], 1);
  642. break;
  643. case DCELL_TYPE:
  644. Rast_set_d_null_value(&((DCELL *) bufrast)[j], 1);
  645. break;
  646. default:
  647. G_fatal_error(_("Unknown data type"));
  648. }
  649. }
  650. /* ************************************************************ */
  651. /* write the visibility grid to GRASS. assume all cells that are not
  652. in stream are NOT visible. assume stream is sorted in (i,j) order.
  653. for each value x it writes to grass fun(x) */
  654. void
  655. save_io_visibilitygrid_to_GRASS(IOVisibilityGrid * visgrid,
  656. char *fname, RASTER_MAP_TYPE type,
  657. float (*fun) (float))
  658. {
  659. G_message(_("Saving grid to <%s>"), fname);
  660. assert(fname && visgrid);
  661. /* open the output raster and set up its row buffer */
  662. int visfd;
  663. visfd = Rast_open_new(fname, type);
  664. void *visrast;
  665. visrast = Rast_allocate_buf(type);
  666. assert(visrast);
  667. /*set up reading data from visibility stream */
  668. AMI_STREAM < VisCell > *vstr = visgrid->visStr;
  669. off_t streamLen, counter = 0;
  670. streamLen = vstr->stream_len();
  671. vstr->seek(0);
  672. /*read the first element */
  673. AMI_err ae;
  674. VisCell *curResult = NULL;
  675. if (streamLen > 0) {
  676. ae = vstr->read_item(&curResult);
  677. assert(ae == AMI_ERROR_NO_ERROR);
  678. counter++;
  679. }
  680. dimensionType i, j;
  681. for (i = 0; i < Rast_window_rows(); i++) {
  682. for (j = 0; j < Rast_window_cols(); j++) {
  683. if (curResult->row == i && curResult->col == j) {
  684. /*cell is recodred in the visibility stream: it must be
  685. either visible, or NODATA */
  686. if (is_visible(curResult->angle))
  687. writeValue(visrast, j, fun(curResult->angle), type);
  688. else
  689. writeNodataValue(visrast, j, type);
  690. /*read next element of stream */
  691. if (counter < streamLen) {
  692. ae = vstr->read_item(&curResult);
  693. assert(ae == AMI_ERROR_NO_ERROR);
  694. counter++;
  695. }
  696. }
  697. else {
  698. /* this cell is not in stream, so it is invisible */
  699. writeNodataValue(visrast, j, type);
  700. }
  701. } /* for j */
  702. Rast_put_row(visfd, visrast, type);
  703. } /* for i */
  704. Rast_close(visfd);
  705. }
  706. /* ************************************************************ */
  707. /* using the visibility information recorded in visgrid, it creates
  708. an output viewshed raster with name outfname; for every point p
  709. that is visible in the grid, the corresponding value in the output
  710. raster is elevation(p) - viewpoint_elevation(p); the elevation
  711. values are read from elevfname raster. assume stream is sorted in
  712. (i,j) order. */
  713. void
  714. save_io_vis_and_elev_to_GRASS(IOVisibilityGrid * visgrid, char *elevfname,
  715. char *visfname, float vp_elev)
  716. {
  717. G_message(_("Saving grid to <%s>"), visfname);
  718. assert(visfname && visgrid);
  719. /*get mapset name and data type */
  720. const char *mapset;
  721. mapset = G_find_raster(elevfname, "");
  722. if (mapset == NULL)
  723. G_fatal_error(_("Opening <%s>: cannot find raster"), elevfname);
  724. /*open elevation map */
  725. int elevfd;
  726. if ((elevfd = Rast_open_old(elevfname, mapset)) < 0)
  727. G_fatal_error(_("Cannot open raster file [%s]"), elevfname);
  728. /*get elevation data_type */
  729. RASTER_MAP_TYPE elev_data_type;
  730. elev_data_type = Rast_map_type(elevfname, mapset);
  731. /* open visibility raster */
  732. int visfd;
  733. visfd = Rast_open_new(visfname, elev_data_type);
  734. /*get the buffers to store each row */
  735. void *elevrast;
  736. elevrast = Rast_allocate_buf(elev_data_type);
  737. assert(elevrast);
  738. void *visrast;
  739. visrast = Rast_allocate_buf(elev_data_type);
  740. assert(visrast);
  741. /*set up stream reading stuff */
  742. off_t streamLen, counter = 0;
  743. AMI_err ae;
  744. VisCell *curResult = NULL;
  745. AMI_STREAM < VisCell > *vstr = visgrid->visStr;
  746. streamLen = vstr->stream_len();
  747. vstr->seek(0);
  748. /*read the first element */
  749. if (streamLen > 0) {
  750. ae = vstr->read_item(&curResult);
  751. assert(ae == AMI_ERROR_NO_ERROR);
  752. counter++;
  753. }
  754. dimensionType i, j;
  755. double elev = 0, viewshed_value;
  756. for (i = 0; i < Rast_window_rows(); i++) {
  757. Rast_get_row(elevfd, elevrast, i, elev_data_type);
  758. for (j = 0; j < Rast_window_cols(); j++) {
  759. /* read the current elevation value */
  760. int isNull = 0;
  761. switch (elev_data_type) {
  762. case CELL_TYPE:
  763. isNull = Rast_is_c_null_value(&((CELL *) elevrast)[j]);
  764. elev = (double)(((CELL *) elevrast)[j]);
  765. break;
  766. case FCELL_TYPE:
  767. isNull = Rast_is_f_null_value(&((FCELL *) elevrast)[j]);
  768. elev = (double)(((FCELL *) elevrast)[j]);
  769. break;
  770. case DCELL_TYPE:
  771. isNull = Rast_is_d_null_value(&((DCELL *) elevrast)[j]);
  772. elev = (double)(((DCELL *) elevrast)[j]);
  773. break;
  774. }
  775. if (curResult->row == i && curResult->col == j) {
  776. /*cell is recodred in the visibility stream: it must be
  777. either visible, or NODATA */
  778. if (is_visible(curResult->angle))
  779. writeValue(visrast, j, elev - vp_elev, elev_data_type);
  780. else
  781. writeNodataValue(visrast, j, elev_data_type);
  782. /*read next element of stream */
  783. if (counter < streamLen) {
  784. ae = vstr->read_item(&curResult);
  785. assert(ae == AMI_ERROR_NO_ERROR);
  786. counter++;
  787. }
  788. }
  789. else {
  790. /* this cell is not in stream, so it is invisible */
  791. writeNodataValue(visrast, j, elev_data_type);
  792. }
  793. } /* for j */
  794. Rast_put_row(visfd, visrast, elev_data_type);
  795. } /* for i */
  796. Rast_close(elevfd);
  797. Rast_close(visfd);
  798. return;
  799. }