2
/****************************************************************************
6
* AUTHOR(S): Laura Toma, Bowdoin College - ltoma@bowdoin.edu
7
* Yi Zhuang - yzhuang@bowdoin.edu
9
* Ported to GRASS by William Richard -
10
* wkrichar@bowdoin.edu or willster3021@gmail.com
11
* Markus Metz: surface interpolation
15
* PURPOSE: To calculate the viewshed (the visible cells in the
16
* raster) for the given viewpoint (observer) location. The
17
* visibility model is the following: Two points in the raster are
18
* considered visible to each other if the cells where they belong are
19
* visible to each other. Two cells are visible to each other if the
20
* line-of-sight that connects their centers does not intersect the
21
* terrain. The terrain is NOT viewed as a tesselation of flat cells,
22
* i.e. if the line-of-sight does not pass through the cell center,
23
* elevation is determined using bilinear interpolation.
24
* The viewshed algorithm is efficient both in
25
* terms of CPU operations and I/O operations. It has worst-case
26
* complexity O(n lg n) in the RAM model and O(sort(n)) in the
27
* I/O-model. For the algorithm and all the other details see the
28
* paper: "Computing Visibility on * Terrains in External Memory" by
29
* Herman Haverkort, Laura Toma and Yi Zhuang.
31
* COPYRIGHT: (C) 2008 by the GRASS Development Team
33
* This program is free software under the GNU General Public License
34
* (>=v2). Read the file COPYING that comes with GRASS for details.
36
*****************************************************************************/
41
#include <grass/gis.h>
42
#include <grass/glocale.h>
46
#include "visibility.h"
51
/* ------------------------------------------------------------ */
52
/* viewpoint functions */
53
void print_viewpoint(Viewpoint vp)
55
G_debug(3, "vp=(%d, %d, %.1f) ", vp.row, vp.col, vp.elev);
59
/* ------------------------------------------------------------ */
60
void set_viewpoint_coord(Viewpoint * vp, dimensionType row, dimensionType col)
68
/* ------------------------------------------------------------ */
69
void set_viewpoint_elev(Viewpoint * vp, float elev)
76
/* ------------------------------------------------------------ */
78
void copy_viewpoint(Viewpoint * a, Viewpoint b)
88
/* ------------------------------------------------------------ */
89
/* MemoryVisibilityGrid functions */
91
/* create and return a grid of the sizes specified in the header */
92
MemoryVisibilityGrid *create_inmem_visibilitygrid(GridHeader hd, Viewpoint vp)
95
MemoryVisibilityGrid *visgrid;
97
visgrid = (MemoryVisibilityGrid *) G_malloc(sizeof(MemoryVisibilityGrid));
102
/* create the grid */
103
visgrid->grid = create_empty_grid();
104
assert(visgrid->grid);
106
/* create the header */
107
visgrid->grid->hd = (GridHeader *) G_malloc(sizeof(GridHeader));
109
assert(visgrid->grid->hd);
112
copy_header(visgrid->grid->hd, hd);
114
/* allocate the Grid data */
115
alloc_grid_data(visgrid->grid);
117
/*allocate viewpoint */
118
visgrid->vp = (Viewpoint *) G_malloc(sizeof(Viewpoint));
121
copy_viewpoint(visgrid->vp, vp);
129
/* ------------------------------------------------------------ */
130
void free_inmem_visibilitygrid(MemoryVisibilityGrid * visgrid)
136
destroy_grid(visgrid->grid);
148
/* ------------------------------------------------------------ */
149
/*set all values of visgrid's Grid to the given value */
150
void set_inmem_visibilitygrid(MemoryVisibilityGrid * visgrid, float val)
153
assert(visgrid && visgrid->grid && visgrid->grid->hd &&
154
visgrid->grid->grid_data);
158
for (i = 0; i < visgrid->grid->hd->nrows; i++) {
159
assert(visgrid->grid->grid_data[i]);
160
for (j = 0; j < visgrid->grid->hd->ncols; j++) {
161
visgrid->grid->grid_data[i][j] = val;
169
/* ------------------------------------------------------------ */
170
/*set the (i,j) value of visgrid's Grid to the given value */
171
void add_result_to_inmem_visibilitygrid(MemoryVisibilityGrid * visgrid,
172
dimensionType i, dimensionType j,
176
assert(visgrid && visgrid->grid && visgrid->grid->hd &&
177
visgrid->grid->grid_data);
178
assert(i < visgrid->grid->hd->nrows);
179
assert(j < visgrid->grid->hd->ncols);
180
assert(visgrid->grid->grid_data[i]);
182
visgrid->grid->grid_data[i][j] = val;
189
/* ------------------------------------------------------------ */
190
/* The following functions are used to convert the visibility results
191
recorded during the viewshed computation into the output grid into
192
tehe output required by the user.
194
x is assumed to be the visibility value computed for a cell during the
195
viewshed computation.
197
The value computed during the viewshed is the following:
199
x is NODATA if the cell is NODATA;
202
x is INVISIBLE if the cell is invisible;
204
x is the vertical angle of the cell wrt the viewpoint if the cell is
205
visible---the angle is a value in (0,180).
207
int is_visible(float x)
209
/* if GRASS is on, we cannot guarantee that NODATA is negative; so
211
int isnull = Rast_is_null_value(&x, G_SURFACE_TYPE);
218
int is_invisible_not_nodata(float x)
221
return ((int)x == (int)INVISIBLE);
224
int is_invisible_nodata(float x)
227
return (!is_visible(x)) && (!is_invisible_not_nodata(x));
230
/* ------------------------------------------------------------ */
231
/* This function is called when the program runs in
232
viewOptions.outputMode == OUTPUT_BOOL. */
233
float booleanVisibilityOutput(float x)
235
/* NODATA and INVISIBLE are both negative values */
239
return BOOL_INVISIBLE;
242
/* ------------------------------------------------------------ */
243
/* This function is called when the program runs in
244
viewOptions.outputMode == OUTPUT_ANGLE. In this case x represents
246
float angleVisibilityOutput(float x)
253
/* ------------------------------------------------------------ */
254
/* visgrid is the structure that records the visibility information
255
after the sweep is done. Use it to write the visibility output
256
grid and then distroy it.
258
void save_inmem_visibilitygrid(MemoryVisibilityGrid * visgrid,
259
ViewOptions viewOptions, Viewpoint vp)
262
if (viewOptions.outputMode == OUTPUT_BOOL)
263
save_grid_to_GRASS(visgrid->grid, viewOptions.outputfname, CELL_TYPE,
265
else if (viewOptions.outputMode == OUTPUT_ANGLE)
266
save_grid_to_GRASS(visgrid->grid, viewOptions.outputfname, FCELL_TYPE,
269
/* elevation output */
270
save_vis_elev_to_GRASS(visgrid->grid, viewOptions.inputfname,
271
viewOptions.outputfname,
272
vp.elev + viewOptions.obsElev);
274
free_inmem_visibilitygrid(visgrid);
281
/* ------------------------------------------------------------ */
282
/* IOVisibilityGrid functions */
283
/* ------------------------------------------------------------ */
285
/* ------------------------------------------------------------ */
286
/*create grid from given header and viewpoint */
287
IOVisibilityGrid *init_io_visibilitygrid(GridHeader hd, Viewpoint vp)
289
IOVisibilityGrid *visgrid;
291
visgrid = (IOVisibilityGrid *) G_malloc(sizeof(IOVisibilityGrid));
296
visgrid->hd = (GridHeader *) G_malloc(sizeof(GridHeader));
299
copy_header(visgrid->hd, hd);
302
visgrid->vp = (Viewpoint *) G_malloc(sizeof(Viewpoint));
305
copy_viewpoint(visgrid->vp, vp);
308
visgrid->visStr = new AMI_STREAM < VisCell > ();
309
assert(visgrid->visStr);
316
/* ------------------------------------------------------------ */
318
void free_io_visibilitygrid(IOVisibilityGrid * grid)
336
/* ------------------------------------------------------------ */
337
/*write cell to stream */
338
void add_result_to_io_visibilitygrid(IOVisibilityGrid * visgrid,
342
assert(visgrid && cell);
346
assert(visgrid->visStr);
347
ae = visgrid->visStr->write_item(*cell);
348
assert(ae == AMI_ERROR_NO_ERROR);
353
/* ------------------------------------------------------------ */
354
/*compare function, (i,j) grid order */
355
int IJCompare::compare(const VisCell & a, const VisCell & b)
372
/* ------------------------------------------------------------ */
373
/*sort stream in grid order */
374
void sort_io_visibilitygrid(IOVisibilityGrid * visGrid)
378
assert(visGrid->visStr);
379
if (visGrid->visStr->stream_len() == 0)
382
AMI_STREAM < VisCell > *sortedStr;
386
ae = AMI_sort(visGrid->visStr, &sortedStr, &cmpObj, 1);
387
assert(ae == AMI_ERROR_NO_ERROR);
391
visGrid->visStr = sortedStr;
396
/* ------------------------------------------------------------ */
398
save_io_visibilitygrid(IOVisibilityGrid * visgrid,
399
ViewOptions viewOptions, Viewpoint vp)
402
if (viewOptions.outputMode == OUTPUT_BOOL)
403
save_io_visibilitygrid_to_GRASS(visgrid, viewOptions.outputfname,
404
CELL_TYPE, booleanVisibilityOutput);
406
else if (viewOptions.outputMode == OUTPUT_ANGLE)
407
save_io_visibilitygrid_to_GRASS(visgrid, viewOptions.outputfname,
408
FCELL_TYPE, angleVisibilityOutput);
410
/* elevation output */
411
save_io_vis_and_elev_to_GRASS(visgrid, viewOptions.inputfname,
412
viewOptions.outputfname,
413
vp.elev + viewOptions.obsElev);
415
/*free visibiliyty grid */
416
free_io_visibilitygrid(visgrid);