123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310 |
- /****************************************************************************
- *
- * MODULE: r.viewshed
- *
- * AUTHOR(S): Laura Toma, Bowdoin College - ltoma@bowdoin.edu
- * Yi Zhuang - yzhuang@bowdoin.edu
- * Ported to GRASS by William Richard -
- * wkrichar@bowdoin.edu or willster3021@gmail.com
- * Markus Metz: surface interpolation
- *
- * Date: april 2011
- *
- * PURPOSE: To calculate the viewshed (the visible cells in the
- * raster) for the given viewpoint (observer) location. The
- * visibility model is the following: Two points in the raster are
- * considered visible to each other if the cells where they belong are
- * visible to each other. Two cells are visible to each other if the
- * line-of-sight that connects their centers does not intersect the
- * terrain. The terrain is NOT viewed as a tesselation of flat cells,
- * i.e. if the line-of-sight does not pass through the cell center,
- * elevation is determined using bilinear interpolation.
- * The viewshed algorithm is efficient both in
- * terms of CPU operations and I/O operations. It has worst-case
- * complexity O(n lg n) in the RAM model and O(sort(n)) in the
- * I/O-model. For the algorithm and all the other details see the
- * paper: "Computing Visibility on * Terrains in External Memory" by
- * Herman Haverkort, Laura Toma and Yi Zhuang.
- *
- * COPYRIGHT: (C) 2008 by the GRASS Development Team
- *
- * This program is free software under the GNU General Public License
- * (>=v2). Read the file COPYING that comes with GRASS for details.
- *
- *****************************************************************************/
- #include <math.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <assert.h>
- extern "C"
- {
- #include <grass/gis.h>
- #include <grass/glocale.h>
- }
- #include "grass.h"
- #include "statusstructure.h"
- /*SMALLEST_GRADIENT is defined in rbbst.h */
- /* ------------------------------------------------------------ */
- /*find the vertical angle in degrees between the viewpoint and the
- point represented by the StatusNode. Assumes all values (except
- gradient) in sn have been filled. The value returned is in [0,
- 180]. A value of 0 is directly below the specified viewing position,
- 90 is due horizontal, and 180 is directly above the observer.
- If doCurv is set we need to consider the curvature of the
- earth */
- float get_vertical_angle(Viewpoint vp, StatusNode sn, surface_type elev, int doCurv)
- {
- /*determine the difference in elevation, based on the curvature */
- double diffElev;
- diffElev = vp.elev - elev;
- /*calculate and return the angle in degrees */
- assert(fabs(sn.dist2vp) > 0.001);
- /* 0 above, 180 below */
- if (diffElev >= 0.0)
- return (atan(sqrt(sn.dist2vp) / diffElev) * (180 / M_PI));
- else
- return (atan(fabs(diffElev) / sqrt(sn.dist2vp)) * (180 / M_PI) + 90);
- /* 180 above, 0 below */
- if (diffElev >= 0.0)
- return (atan(diffElev / sqrt(sn.dist2vp)) * (180 / M_PI) + 90);
- else
- return (atan(sqrt(sn.dist2vp) / fabs(diffElev)) * (180 / M_PI));
- }
- /* ------------------------------------------------------------ */
- /*return an estimate of the size of active structure */
- long long get_active_str_size_bytes(GridHeader * hd)
- {
- long long sizeBytes;
- G_verbose_message(_("Estimated size active structure:"));
- G_verbose_message(_(" (key=%d, ptr=%d, total node=%d B)"),
- (int)sizeof(TreeValue),
- (int)sizeof(TreeNode *), (int)sizeof(TreeNode));
- sizeBytes = sizeof(TreeNode) * std::max(hd->ncols, hd->nrows);
- G_verbose_message(_(" Total= %lld B"), sizeBytes);
- return sizeBytes;
- }
- /* ------------------------------------------------------------ */
- /*given a StatusNode, fill in its dist2vp and gradient */
- void calculate_dist_n_gradient(StatusNode * sn, double elev,
- Viewpoint * vp, GridHeader hd)
- {
- assert(sn && vp);
- /*sqrt is expensive
- //sn->dist2vp = sqrt((float) ( pow(sn->row - vp->row,2.0) +
- // pow(sn->col - vp->col,2.0)));
- //sn->gradient = (sn->elev - vp->elev)/(sn->dist2vp); */
-
- double diffElev = elev - vp->elev;
-
- if (G_projection() == PROJECTION_LL) {
- double dist = G_distance(Rast_col_to_easting(sn->col + 0.5, &(hd.window)),
- Rast_row_to_northing(sn->row + 0.5, &(hd.window)),
- Rast_col_to_easting(vp->col + 0.5, &(hd.window)),
- Rast_row_to_northing(vp->row + 0.5, &(hd.window)));
- sn->dist2vp = dist * dist;
- }
- else {
- double dx = ((double)sn->col - vp->col) * hd.ew_res;
- double dy = ((double)sn->row - vp->row) * hd.ns_res;
-
- sn->dist2vp = (dx * dx) + (dy * dy);
- }
- if (diffElev == 0) {
- sn->gradient[1] = 0;
- return;
- }
- /* PI / 2 above, - PI / 2 below, like r.los */
- sn->gradient[1] = atan(diffElev / sqrt(sn->dist2vp));
- return;
- /* PI above, 0 below. slower than r.los - like */
- if (diffElev >= 0.0)
- sn->gradient[1] = (atan(diffElev / sqrt(sn->dist2vp)) + M_PI / 2);
- else
- sn->gradient[1] = (atan(sqrt(sn->dist2vp) / fabs(diffElev)));
- return;
- /* a little bit faster but not accurate enough */
- sn->gradient[1] = (diffElev * diffElev) / (sn->dist2vp);
- /*maintain sign */
- if (elev < vp->elev)
- sn->gradient[1] = -sn->gradient[1];
-
- return;
- }
- /* ------------------------------------------------------------ */
- /* calculate gradient for ENTERING or EXITING event */
- void calculate_event_gradient(StatusNode * sn, int e_idx,
- double row, double col, double elev,
- Viewpoint * vp, GridHeader hd)
- {
- assert(sn && vp);
- /*sqrt is expensive
- //sn->dist2vp = sqrt((float) ( pow(sn->row - vp->row,2.0) +
- // pow(sn->col - vp->col,2.0)));
- //sn->gradient = (sn->elev - vp->elev)/(sn->dist2vp); */
-
- double diffElev = elev - vp->elev;
- double dist2vp;
- if (G_projection() == PROJECTION_LL) {
- double dist = G_distance(Rast_col_to_easting(col + 0.5, &(hd.window)),
- Rast_row_to_northing(row + 0.5, &(hd.window)),
- Rast_col_to_easting(vp->col + 0.5, &(hd.window)),
- Rast_row_to_northing(vp->row + 0.5, &(hd.window)));
- dist2vp = dist * dist;
- }
- else {
- double dx = (col - vp->col) * hd.ew_res;
- double dy = (row - vp->row) * hd.ns_res;
-
- dist2vp = (dx * dx) + (dy * dy);
- }
- /* PI / 2 above, - PI / 2 below */
- sn->gradient[e_idx] = atan(diffElev / sqrt(dist2vp));
- return;
- /* PI above, 0 below. slower than r.los - like */
- if (diffElev >= 0.0)
- sn->gradient[e_idx] = (atan(diffElev / sqrt(dist2vp)) + M_PI / 2);
- else
- sn->gradient[e_idx] = (atan(sqrt(dist2vp) / fabs(diffElev)));
- return;
- /* faster but not accurate enough */
- sn->gradient[e_idx] = (diffElev * diffElev) / (dist2vp);
- /*maintain sign */
- if (elev < vp->elev)
- sn->gradient[e_idx] = -sn->gradient[e_idx];
- return;
- }
- /* ------------------------------------------------------------ */
- /*create an empty status list */
- StatusList *create_status_struct()
- {
- StatusList *sl;
- sl = (StatusList *) G_malloc(sizeof(StatusList));
- assert(sl);
- TreeValue tv;
- tv.gradient[0] = SMALLEST_GRADIENT;
- tv.gradient[1] = SMALLEST_GRADIENT;
- tv.gradient[2] = SMALLEST_GRADIENT;
- tv.angle[0] = 0;
- tv.angle[1] = 0;
- tv.angle[2] = 0;
- tv.key = 0;
- tv.maxGradient = SMALLEST_GRADIENT;
- sl->rbt = create_tree(tv);
- return sl;
- }
- /* ------------------------------------------------------------ */
- /*delete a status structure */
- void delete_status_structure(StatusList * sl)
- {
- assert(sl);
- delete_tree(sl->rbt);
- G_free(sl);
- return;
- }
- /* ------------------------------------------------------------ */
- /*delete the statusNode with the given key */
- void delete_from_status_struct(StatusList * sl, double dist2vp)
- {
- assert(sl);
- delete_from(sl->rbt, dist2vp);
- return;
- }
- /* ------------------------------------------------------------ */
- /*insert the element into the status structure */
- void insert_into_status_struct(StatusNode sn, StatusList * sl)
- {
- assert(sl);
- TreeValue tv;
- tv.key = sn.dist2vp;
- tv.gradient[0] = sn.gradient[0];
- tv.gradient[1] = sn.gradient[1];
- tv.gradient[2] = sn.gradient[2];
- tv.angle[0] = sn.angle[0];
- tv.angle[1] = sn.angle[1];
- tv.angle[2] = sn.angle[2];
- tv.maxGradient = SMALLEST_GRADIENT;
- insert_into(sl->rbt, tv);
- return;
- }
- /* ------------------------------------------------------------ */
- /*find the node with max Gradient within the distance (from viewpoint)
- //given */
- double find_max_gradient_in_status_struct(StatusList * sl, double dist, double angle, double gradient)
- {
- assert(sl);
- /*note: if there is nothing in the status struccture, it means this
- cell is VISIBLE */
- if (is_empty(sl))
- return SMALLEST_GRADIENT;
- /*it is also possible that the status structure is not empty, but
- there are no events with key < dist ---in this case it returns
- SMALLEST_GRADIENT; */
- return find_max_gradient_within_key(sl->rbt, dist, angle, gradient);
- }
- /*returns true if it is empty */
- int is_empty(StatusList * sl)
- {
- assert(sl);
- return (is_empty(sl->rbt) ||
- sl->rbt->root->value.maxGradient == SMALLEST_GRADIENT);
- }
|