[GRASS-SVN] r49483 - in grass/trunk/raster: . r.viewshed
svn_grass at osgeo.org
svn_grass at osgeo.org
Fri Dec 2 04:56:39 EST 2011
Author: mmetz
Date: 2011-12-02 01:56:38 -0800 (Fri, 02 Dec 2011)
New Revision: 49483
Added:
grass/trunk/raster/r.viewshed/
grass/trunk/raster/r.viewshed/distribute.cpp
grass/trunk/raster/r.viewshed/eventlist.cpp
grass/trunk/raster/r.viewshed/grass.cpp
grass/trunk/raster/r.viewshed/grid.cpp
grass/trunk/raster/r.viewshed/main.cpp
grass/trunk/raster/r.viewshed/rbbst.cpp
grass/trunk/raster/r.viewshed/statusstructure.cpp
grass/trunk/raster/r.viewshed/viewshed.cpp
grass/trunk/raster/r.viewshed/visibility.cpp
Removed:
grass/trunk/raster/r.viewshed/distribute.cc
grass/trunk/raster/r.viewshed/eventlist.cc
grass/trunk/raster/r.viewshed/grass.cc
grass/trunk/raster/r.viewshed/grid.cc
grass/trunk/raster/r.viewshed/main.cc
grass/trunk/raster/r.viewshed/rbbst.cc
grass/trunk/raster/r.viewshed/statusstructure.cc
grass/trunk/raster/r.viewshed/viewshed.cc
grass/trunk/raster/r.viewshed/visibility.cc
Modified:
grass/trunk/raster/r.viewshed/BUGS
grass/trunk/raster/r.viewshed/Makefile
grass/trunk/raster/r.viewshed/grass.h
grass/trunk/raster/r.viewshed/grid.h
Log:
add r.viewshed to trunk
Modified: grass/trunk/raster/r.viewshed/BUGS
===================================================================
--- grass-addons/raster/r.viewshed/BUGS 2011-12-02 09:30:54 UTC (rev 49482)
+++ grass/trunk/raster/r.viewshed/BUGS 2011-12-02 09:56:38 UTC (rev 49483)
@@ -1,6 +1,5 @@
BUGS
-* http://trac.osgeo.org/grass/ticket/390
- r.viewshed precision bug
-
* areas outside of LOS should be NULL, not zero
+ really? there is a difference between invisible areas
+ and areas whose visibility is unknown (zero != NULL)
Modified: grass/trunk/raster/r.viewshed/Makefile
===================================================================
--- grass-addons/raster/r.viewshed/Makefile 2011-12-02 09:30:54 UTC (rev 49482)
+++ grass/trunk/raster/r.viewshed/Makefile 2011-12-02 09:56:38 UTC (rev 49483)
@@ -1,50 +1,17 @@
-# Path to the module directory, i.e. the grass sourcecode main path.
-# Relative or absolute.
MODULE_TOPDIR = ../../
PGM = r.viewshed
-# Includes the grass make-System.
+LIBES = $(RASTERLIB) $(GISLIB) $(IOSTREAMLIB) $(MATHLIB)
+DEPENDENCIES = $(RASTERDEP) $(GISDEP) $(IOSTREAMDEP)
+
include $(MODULE_TOPDIR)/include/Make/Module.make
-SOURCES = main.cc distribute.cc eventlist.cc grid.cc grass.cc viewshed.cc \
- rbbst.cc statusstructure.cc visibility.cc
-HEADERS = distribute.h eventlist.h grid.h grass.h viewshed.h \
- rbbst.h statusstructure.h visibility.h
+EXTRA_CFLAGS = -DUSER=\"$(USER)\" -Wno-sign-compare
+LINK = $(CXX)
-OBJARCH=OBJ.$(ARCH)
-OBJ := $(patsubst %.cc,$(OBJARCH)/%.o,$(SOURCES))
+ifneq ($(strip $(CXX)),)
+default: cmd
+endif
-LIBS = $(GISLIB) $(IOSTREAMLIB)
-DEPLIBS = $(DEPGISLIB) $(IOSTREAMDEP)
-
-# Using GNU c++ compiler.
-CXX = g++
-
-# Set compiler and load flags.
-# (See 'man g++' for help).
-CXXFLAGS += -O3 -DNO_STATS #-DNDEBUG
-CXXFLAGS += $(WARNING_FLAGS) -DUSER=\"$(USER)\" -D__GRASS__
-# CXXFLAGS += -DPEARL
-CXXFLAGS += -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -fmessage-length=0
-CXXFLAGS += -ffast-math -funroll-loops
-
-
-WARNING_FLAGS = -Wall -Wformat -Wparentheses -Wpointer-arith -Wno-conversion \
- -Wreturn-type \
- -Wcomment -Wno-sign-compare -Wno-unused
-#-Wimplicit-int -Wimplicit-function-declaration
-
-# Make rules.
-# Default is the 'default' target for the grass make system.
-$(OBJARCH)/%.o:%.cc
- $(CXX) -c $(CXXFLAGS) $< -o $@
-
-
-default: $(BIN)/$(PGM)$(EXE)
- $(MAKE) htmlcmd
- $(MAKE) mancmd
-
-$(BIN)/$(PGM)$(EXE): $(OBJ) $(DEPLIBS)
- $(CXX) $(LDFLAGS) -o $@ $(OBJ) $(LIBS)
Deleted: grass/trunk/raster/r.viewshed/distribute.cc
===================================================================
--- grass-addons/raster/r.viewshed/distribute.cc 2011-12-02 09:30:54 UTC (rev 49482)
+++ grass/trunk/raster/r.viewshed/distribute.cc 2011-12-02 09:56:38 UTC (rev 49483)
@@ -1,1170 +0,0 @@
-
-/****************************************************************************
- *
- * MODULE: r.viewshed
- *
- * AUTHOR(S): Laura Toma, Bowdoin College - ltoma at bowdoin.edu
- * Yi Zhuang - yzhuang at bowdoin.edu
-
- * Ported to GRASS by William Richard -
- * wkrichar at bowdoin.edu or willster3021 at 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 <assert.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <math.h>
-
-extern "C"
-{
-#include <grass/config.h>
-#include <grass/gis.h>
-#include <grass/glocale.h>
-}
-
-/* include IOSTREAM header */
-#include <grass/iostream/ami.h>
-
-
-/*note: MAX_STREAM_OPEN defined in IOStream/include/ami_stream.h, which
- is included by ami.h */
-
-#include "distribute.h"
-#include "viewshed.h"
-#include "visibility.h"
-#include "eventlist.h"
-#include "statusstructure.h"
-#include "grass.h"
-
-
-#define DISTRIBDEBUG if(0)
-#define SOLVEINMEMDEBUG if(0)
-#define DEBUGINIT if(0)
-#define PRINTWARNING if(0)
-#define BND_DEBUG if(0)
-
-
-#define ANGLE_FACTOR 1
-#define EPSILON GRASS_EPSILON
-#define PRINT_DISTRIBUTE if(0)
-
-
-
-////////////////////////////////////////////////////////////////////////
-/* distribution sweep: write results to visgrid.
- */
-IOVisibilityGrid *distribute_and_sweep(char *inputfname,
- GridHeader * hd,
- Viewpoint * vp,
- ViewOptions viewOptions)
-{
-
- assert(inputfname && hd && vp);
- G_message(_("Start distributed sweeping."));
-
- /* ------------------------------ */
- /*initialize the visibility grid */
- IOVisibilityGrid *visgrid;
-
- visgrid = init_io_visibilitygrid(*hd, *vp);
- G_debug(1, "distribute_and_sweep: visgrid=%s", visgrid->visStr->name());
-
-
- /* ------------------------------ */
- /*construct event list corresp to the input file and viewpoint */
- Rtimer initEventTime;
-
- rt_start(initEventTime);
- AMI_STREAM < AEvent > *eventList;
-
- eventList = init_event_list(inputfname, vp, hd,
- viewOptions, NULL, visgrid);
-
- assert(eventList);
- eventList->seek(0);
- rt_stop(initEventTime);
- G_debug(1, "distribute_and_sweep: eventlist=%s", eventList->sprint());
-
-
- /* ------------------------------ */
- /*sort the events concentrically */
- Rtimer sortEventTime;
-
- rt_start(sortEventTime);
- G_debug(1, "Sorting events by distance from viewpoint..");
-
- sort_event_list_by_distance(&eventList, *vp);
- G_debug(1, "..sorting done.");
-
- /* debugging */
- /*sortCheck(eventList, *vp); */
- eventList->seek(0); /*this does not seem to be ensured by sort */
- rt_stop(sortEventTime);
- G_debug(1, "distribute_and_sweep: eventlist=%s", eventList->sprint());
-
-
-
- /* ------------------------------ */
- /* start distribution */
- long nvis; /*number of cells visible. Returned by distribute_sector */
-
- Rtimer sweepTime;
-
- rt_start(sweepTime);
- /*distribute recursively the events and write results to visgrid.
- invariant: distribute_sector deletes its eventlist */
- nvis = distribute_sector(eventList, NULL, 0, ANGLE_FACTOR * 2 * M_PI,
- visgrid, vp, hd, viewOptions);
- rt_stop(sweepTime);
-
-
- /* ------------------------------ */
- /*cleanup */
- G_message(_("Distribution sweeping done."));
-
- G_verbose_message("Total cells %ld, visible cells %ld (%.1f percent).",
- (long)visgrid->hd->nrows * visgrid->hd->ncols,
- nvis,
- (float)((float)nvis * 100 /
- (float)(visgrid->hd->nrows * visgrid->hd->ncols)));
-
- print_viewshed_timings(initEventTime, sortEventTime, sweepTime);
-
- return visgrid;
-}
-
-
-
-
-
-
-//***********************************************************************
-/* distribute recursively the events and write results to
- visgrid. eventList is a list of events sorted by distance that fall
- within angle boundaries start_angle and end_angle; enterBndEvents
- is a stream that contains all the ENTER events that are not in this
- sector, but their corresponding Q or X events are in this sector.
-
- When problem is small enough, solve it in memory and write results to
- visgrid.
-
- invariant: distribute_sector deletes eventList and enterBndEvents
- */
-unsigned long distribute_sector(AMI_STREAM < AEvent > *eventList,
- AMI_STREAM < AEvent > *enterBndEvents,
- double start_angle, double end_angle,
- IOVisibilityGrid * visgrid, Viewpoint * vp,
- GridHeader *hd, ViewOptions viewOptions)
-{
-
-
- assert(eventList && visgrid && vp);
- /*enterBndEvents may be NULL first time */
-
- G_debug(2, "*** DISTRIBUTE sector [%.4f, %.4f] ***",
- start_angle, end_angle);
- G_debug(2, "initial_gradient: %lf", SMALLEST_GRADIENT);
- G_debug(2, "eventlist: %s", eventList->sprint());
- if (enterBndEvents)
- G_debug(2, "BndEvents: %s", enterBndEvents->sprint());
- PRINT_DISTRIBUTE LOG_avail_memo();
-
- unsigned long nvis = 0;
-
- /*******************************************************
- BASE CASE
- *******************************************************/
- if (eventList->stream_len() * sizeof(AEvent) <
- MM_manager.memory_available()) {
- if (enterBndEvents) {
- nvis += solve_in_memory(eventList, enterBndEvents,
- start_angle, end_angle, visgrid, hd,
- vp, viewOptions);
- return nvis;
- }
- else {
- /*we are here if the problem fits in memory, and
- //enterBNdEvents==NULL---this only happens the very first time;
- //technically at this point we should do one pass though the
- //data and collect the events that cross the 1st and 4th
- //quadrant; instead we force recursion, nect= 2 */
- }
- }
-
- /*else, must recurse */
- PRINT_DISTRIBUTE G_debug(2, "In EXTERNAL memory");
-
- /*compute number of sectors */
- int nsect = compute_n_sectors();
-
- assert(nsect > 1);
-
- /*an array of streams, one for each sector; sector[i] will keep all
- the cells that are completely inside sector i */
- AMI_STREAM < AEvent > *sector = new AMI_STREAM < AEvent >[nsect];
-
- /*the array of gradient values, one for each sector; the gradient is
- the gradient of the center of a cell that spans the sector
- completely */
- double *high = new double[nsect];
-
- for (int i = 0; i < nsect; i++)
- high[i] = SMALLEST_GRADIENT;
-
- /*an array of streams, one for each stream boundary; sectorBnd[0]
- will keep all the cells crossing into sector 0 from below; and so on. */
- AMI_STREAM < AEvent > *sectorBnd = new AMI_STREAM < AEvent >[nsect];
-
- /*keeps stats for each sector */
- long *total = new long[nsect];
- long *insert = new long[nsect];
- long *drop = new long[nsect];
- long *bndInsert = new long[nsect];
- long *bndDrop = new long[nsect];
-
- for (int i = 0; i < nsect; i++)
- total[i] = insert[i] = drop[i] = bndInsert[i] = bndDrop[i] = 0;
- long longEvents = 0;
-
- /*******************************************************
- CONCENTRIC SWEEP
- *******************************************************/
- AEvent *e;
- AMI_err ae;
- double exit_angle, enter_angle;
- int exit_s, s, enter_s;
- long boundaryEvents = 0;
- off_t nbEvents = eventList->stream_len();
-
- eventList->seek(0);
- for (off_t i = 0; i < nbEvents; i++) {
-
- /*get out one event at a time and process it according to its type */
- ae = eventList->read_item(&e);
- assert(ae == AMI_ERROR_NO_ERROR);
- assert(is_inside(e, start_angle, end_angle));
-
- /*compute its sector */
- s = get_event_sector(e->angle, start_angle, end_angle, nsect);
- /*detect boundary cases ==> precision issues */
- if (is_almost_on_boundary(e->angle, s, start_angle, end_angle, nsect)) {
- double ssize = (end_angle - start_angle) / nsect;
-
- boundaryEvents++;
-
- G_debug(2, "WARNING! event ");
- print_event(*e, 3);
- G_debug(2, "close to boundary");
- G_debug(2, "angle=%f close to sector boundaries=[%f, %f]",
- e->angle, s * ssize, (s + 1) * ssize);
- }
-
- G_debug(2, "event %7lu: ", (unsigned long)i);
- print_event(*e, 2);
- G_debug(2, "d=%8.1f, ",
- get_square_distance_from_viewpoint(*e, *vp));
- G_debug(2, "s=%3d ", s);
-
- assert(is_inside(s, nsect));
- total[s]++;
-
- /*insert event in sector if not occluded */
- insert_event_in_sector(e, s, §or[s], high[s], vp, insert, drop);
-
- switch (e->eventType) {
- case CENTER_EVENT:
- break;
-
- case ENTERING_EVENT:
- /*find its corresponding exit event and its sector */
- exit_angle = calculate_exit_angle(e->row, e->col, vp);
- exit_s =
- get_event_sector(exit_angle, start_angle, end_angle, nsect);
-
- G_debug(2, " ENTER (a=%.2f,s=%3d)---> EXIT (a=%.2f,s=%3d) ",
- e->angle, s, exit_angle, exit_s);
- /*note: exit_s can be -1 (outside) */
- if (exit_s == s) {
- /*short event, fit in sector s */
-
- }
- else if (exit_s == (s + 1) % nsect || (exit_s + 1) % nsect == s) {
- /*semi-short event; insert in sector s, and in sector boundary s+1
- NOTE: to avoid precision issues, the events are inserted
- when processing the EXIT_EVENT
- insertEventInSector(e, (s+1)%nsect, §orBnd[(s+1)%nsect],
- high[(s+1)%nsect], vp,bndInsert, bndDrop); */
-
- }
- else {
- /*long event; insert in sector s, and in sector boundary exit_s */
- process_long_cell(s, exit_s, nsect, vp, e, high);
- longEvents++;
- /*insertEventInSector(e, exit_s, §orBnd[exit_s], high[exit_s],
- // vp, bndInsert, bndDrop); */
- }
- break;
-
- case EXITING_EVENT:
- /*find its corresponding enter event and its sector */
- enter_angle = calculate_enter_angle(e->row, e->col, vp);
- enter_s =
- get_event_sector(enter_angle, start_angle, end_angle, nsect);
-
- G_debug(2, " EXIT (a=%.2f,s=%3d)--->ENTER (a=%.2f,s=%3d) ",
- e->angle, s, enter_angle, enter_s);
-
- /*don't need to check spanned sectors because it is done on its
- //ENTER event; actually...you do, because its enter event may
- //not be in this sector==> enter_s = -1 (outside) */
- if (enter_s == s) {
- /*short event, fit in sector */
- }
- else if (enter_s == (s + 1) % nsect || (enter_s + 1) % nsect == s) {
- /*semi-short event
- //the corresponding ENTER event must insert itself in sectorBnd[s] */
- e->eventType = ENTERING_EVENT;
-
- G_debug(2, "BND event ");
- print_event(*e, 2);
- G_debug(2, "in bndSector %d", s);
-
-
- insert_event_in_sector(e, s, §orBnd[s], high[s],
- vp, bndInsert, bndDrop);
-
- }
- else {
- /*long event */
- process_long_cell(enter_s, s, nsect, vp, e, high);
- longEvents++;
- /*the corresponding ENTER event must insert itself in sectorBnd[s] */
- e->eventType = ENTERING_EVENT;
-
- G_debug(2, "BND event ");
- print_event(*e, 2);
- G_debug(2, "in bndSector %d", s);
-
- insert_event_in_sector(e, s, §orBnd[s], high[s],
- vp, bndInsert, bndDrop);
- }
- break;
-
- } /*switch event-type */
-
- G_debug(2, "\n");
- } /*for event i */
-
-
- /*distribute the enterBnd events to the boundary streams of the
- //sectors; note: the boundary streams are not sorted by distance. */
- if (enterBndEvents)
- distribute_bnd_events(enterBndEvents, sectorBnd, nsect, vp,
- start_angle, end_angle, high, bndInsert,
- bndDrop);
-
- /*sanity checks */
- G_debug(2, "boundary events in distribution: %ld",
- boundaryEvents);
- print_sector_stats(nbEvents, nsect, high, total, insert, drop, sector,
- sectorBnd, bndInsert,
- longEvents, start_angle, end_angle);
- /*cleanup after sector stats */
- delete[]total;
- delete[]insert;
- delete[]drop;
- delete[]high;
- delete[]bndInsert;
- delete[]bndDrop;
-
- /*we finished processing this sector, delete the event list */
- delete eventList;
-
- if (enterBndEvents)
- delete enterBndEvents;
-
- /*save stream names of new sectors */
- char **sectorName = (char **)G_malloc(nsect * sizeof(char *));
- char **sectorBndName = (char **)G_malloc(nsect * sizeof(char *));
-
- assert(sectorName && sectorBndName);
- for (int i = 0; i < nsect; i++) {
- sector[i].name(§orName[i]);
- G_debug(2, "saving stream %d: %s\t", i, sectorName[i]);
-
- sector[i].persist(PERSIST_PERSISTENT);
- sectorBnd[i].name(§orBndName[i]);
- G_debug(2, "saving BndStr %d: %s", i,
- sectorBndName[i]);
- sectorBnd[i].persist(PERSIST_PERSISTENT);
- }
-
- /*delete [] sector;
- //does this call delete on every single stream?
- //for (int i=0; i< nsect; i++ ) delete sector[i]; */
- delete[]sector;
- delete[]sectorBnd;
- /*LOG_avail_memo(); */
-
-
- /*solve recursively each sector */
- for (int i = 0; i < nsect; i++) {
-
- /*recover stream */
- G_debug(3, "opening sector stream %s ", sectorName[i]);
-
- AMI_STREAM < AEvent > *str =
- new AMI_STREAM < AEvent > (sectorName[i]);
- assert(str);
- G_debug(3, " len=%lu",
- (unsigned long)str->stream_len());
- /*recover boundary stream */
- G_debug(3, "opening boundary sector stream %s ",
- sectorBndName[i]);
- AMI_STREAM < AEvent > *bndStr =
- new AMI_STREAM < AEvent > (sectorBndName[i]);
- assert(str);
- G_debug(3, " len=%lu",
- (unsigned long)bndStr->stream_len());
-
-
- nvis += distribute_sector(str, bndStr,
- start_angle +
- i * ((end_angle - start_angle) / nsect),
- start_angle + (i +
- 1) * ((end_angle -
- start_angle) / nsect),
- visgrid, vp, hd, viewOptions);
- }
-
- /*cleanup */
- G_free(sectorName);
- G_free(sectorBndName);
-
- G_debug(2, "Distribute sector [ %.4f, %.4f] done.",
- start_angle, end_angle);
-
- return nvis;
-}
-
-
-
-
-/***********************************************************************
- enterBndEvents is a stream of events that cross into the sector's
- (first) boundary; they must be distributed to the boundary streams
- of the sub-sectors of this sector. Note: the boundary streams of
- the sub-sectors may not be empty; as a result, events get appended
- at the end, and they will not be sorted by distance from the
- vp.
- */
-void
-distribute_bnd_events(AMI_STREAM < AEvent > *bndEvents,
- AMI_STREAM < AEvent > *sectorBnd, int nsect,
- Viewpoint * vp, double start_angle, double end_angle,
- double *high, long *insert, long *drop)
-{
-
- G_debug(3, "Distribute boundary of sector [ %.4f, %.4f] ",
- start_angle, end_angle);
- assert(bndEvents && sectorBnd && vp && high && insert && drop);
- AEvent *e;
- AMI_err ae;
- double exit_angle;
- int exit_s;
- off_t nbEvents = bndEvents->stream_len();
-
- bndEvents->seek(0);
- for (off_t i = 0; i < nbEvents; i++) {
-
- /*get out one event at a time */
- ae = bndEvents->read_item(&e);
- assert(ae == AMI_ERROR_NO_ERROR);
- /*must be outside, but better not check to avoid precision issues
- //assert(!is_inside(e, start_angle, end_angle));
-
- //each event must be an ENTER event that falls in a diff sector
- //than its EXIT */
- assert(e->eventType == ENTERING_EVENT);
-
- /*find its corresponding exit event and its sector */
- exit_angle = calculate_exit_angle(e->row, e->col, vp);
- exit_s = get_event_sector(exit_angle, start_angle, end_angle, nsect);
-
- /*exit_s cannot be outside sector; though we have to be careful
- //with precision */
- assert(is_inside(exit_s, nsect));
-
- /*insert this event in the boundary stream of this sub-sector */
- insert_event_in_sector(e, exit_s, §orBnd[exit_s], high[exit_s],
- vp, insert, drop);
-
- } /*for i */
-
- G_debug(3, "Distribute boundary of sector [ %.4f, %.4f] done.",
- start_angle, end_angle);
-
- return;
-}
-
-
-
-
-//***********************************************************************
-/* Solves a segment in memory. it is called by distribute() when
- sector fits in memory. eventList is the list of events in
- increasing order of distance from the viewpoint; enterBndEvents is
- the list of ENTER events that are outside the sector, whose
- corresponding EXIT events are inside the sector. start_angle and
- end_angle are the boundaries of the sector, and visgrid is the grid
- to which the visible/invisible cells must be written. The sector is
- solved by switching to radial sweep. */
-unsigned long solve_in_memory(AMI_STREAM < AEvent > *eventList,
- AMI_STREAM < AEvent > *enterBndEvents,
- double start_angle, double end_angle,
- IOVisibilityGrid * visgrid, GridHeader *hd,
- Viewpoint * vp, ViewOptions viewOptions)
-{
-
- assert(eventList && visgrid && vp);
- G_debug(2, "solve INTERNAL memory");
-
- unsigned long nvis = 0; /*number of visible cells */
-
- G_debug(2, "solve_in_memory: eventlist: %s", eventList->sprint());
- if (enterBndEvents)
- G_debug(2, "BndEvents: %s", enterBndEvents->sprint());
-
- if (eventList->stream_len() == 0) {
- delete eventList;
-
- if (enterBndEvents)
- delete enterBndEvents;
-
- return nvis;
- }
-
- /*sort the events radially */
- sort_event_list(&eventList);
-
- /*create the status structure */
- StatusList *status_struct = create_status_struct();
-
- /*initialize status structure with all ENTER events whose EXIT
- //events is inside the sector */
- AEvent *e;
- AMI_err ae;
- StatusNode sn;
- int inevents = 0;
-
- /*
- eventList->seek(0);
- double enter_angle;
- ae = eventList->read_item(&e);
- while (ae == AMI_ERROR_NO_ERROR) {
- if (e->eventType == EXITING_EVENT) {
- enter_angle = calculateEnterAngle(e->row, e->col, vp);
- //to get around precision problems, insert cell in active
- //structure when close to the boundary --- these may cause a
- //double insert, but subsequent ENTER events close to the
- //boundary will be careful not to insert
- if (!is_inside(enter_angle, start_angle, end_angle) ||
- is_almost_on_boundary(enter_angle, start_angle)) {
- DEBUGINIT {printf("inserting "); print_event(*e); printf("\n");}
- //this must span the first boundary of this sector; insert it
- //in status structure
- sn.col = e->col;
- sn.row = e->row;
- sn.elev = e->elev;
- calculateDistNGradient(&sn, vp);
- insertIntoStatusStruct(sn, status_struct);
- inevents++;
- }
- }
- ae = eventList->read_item(&e);
- }
- assert(ae == AMI_ERROR_END_OF_STREAM);
- */
- if (enterBndEvents) {
- double ax, ay;
-
- enterBndEvents->seek(0);
- inevents = enterBndEvents->stream_len();
- for (off_t i = 0; i < inevents; i++) {
- ae = enterBndEvents->read_item(&e);
- assert(ae == AMI_ERROR_NO_ERROR);
-
- G_debug(3, "INMEM init: initializing boundary ");
- print_event(*e, 3);
- G_debug(3, "\n");
-
- /*this must span the first boundary of this sector; insert it
- //in status structure */
- sn.col = e->col;
- sn.row = e->row;
-
- e->eventType = ENTERING_EVENT;
- calculate_event_position(*e, vp->row, vp->col, &ay, &ax);
- sn.angle[0] = calculate_angle(ax, ay, vp->col, vp->row);
- calculate_event_gradient(&sn, 0, ay, ax, e->elev[0], vp, *hd);
-
- e->eventType = CENTER_EVENT;
- calculate_event_position(*e, vp->row, vp->col, &ay, &ax);
- sn.angle[1] = calculate_angle(ax, ay, vp->col, vp->row);
- calculate_dist_n_gradient(&sn, e->elev[1], vp, *hd);
-
- e->eventType = EXITING_EVENT;
- calculate_event_position(*e, vp->row, vp->col, &ay, &ax);
- sn.angle[2] = calculate_angle(ax, ay, vp->col, vp->row);
- calculate_event_gradient(&sn, 2, ay, ax, e->elev[2], vp, *hd);
-
- if (sn.angle[0] > sn.angle[1])
- sn.angle[0] -= 2 * M_PI;
-
- //calculate_dist_n_gradient(&sn, vp);
- insert_into_status_struct(sn, status_struct);
- }
- }
-
- G_debug(2, "initialized active structure with %d events", inevents);
-
-
- /*sweep the event list */
- VisCell viscell;
- off_t nbEvents = eventList->stream_len();
-
- /*printf("nbEvents = %ld\n", (long) nbEvents); */
- eventList->seek(0);
- for (off_t i = 0; i < nbEvents; i++) {
- /*get out one event at a time and process it according to its type */
- ae = eventList->read_item(&e);
- assert(ae == AMI_ERROR_NO_ERROR);
-
- G_debug(3, "INMEM sweep: next event: ");
- print_event(*e, 3);
-
- sn.col = e->col;
- sn.row = e->row;
- //sn.elev = e->elev;
- /*calculate Distance to VP and Gradient */
- calculate_dist_n_gradient(&sn, e->elev[1] + vp->target_offset, vp, *hd);
-
- switch (e->eventType) {
- case ENTERING_EVENT:
- double ax, ay;
-
- /*insert node into structure */
- G_debug(3, "..ENTER-EVENT: insert");
-
- /*don't insert if its close to the boundary---the segment was
- //already inserted in initialization above
- //if (!is_almost_on_boundary(e->angle, start_angle))
- //insertIntoStatusStruct(sn,status_struct); */
- sn.angle[0] = calculate_enter_angle(sn.row, sn.col, vp);
- sn.angle[1] = calculate_angle(sn.col, sn.row, vp->col, vp->row);
- sn.angle[2] = calculate_exit_angle(sn.row, sn.col, vp);
-
- calculate_event_position(*e, vp->row, vp->col, &ay, &ax);
- //sn.angle[0] = calculate_angle(ax, ay, vp->col, vp->row);
- sn.angle[0] = e->angle;
- calculate_event_gradient(&sn, 0, ay, ax, e->elev[0], vp, *hd);
-
- e->eventType = CENTER_EVENT;
- calculate_event_position(*e, vp->row, vp->col, &ay, &ax);
- sn.angle[1] = calculate_angle(ax, ay, vp->col, vp->row);
- calculate_dist_n_gradient(&sn, e->elev[1], vp, *hd);
-
- e->eventType = EXITING_EVENT;
- calculate_event_position(*e, vp->row, vp->col, &ay, &ax);
- sn.angle[2] = calculate_angle(ax, ay, vp->col, vp->row);
- calculate_event_gradient(&sn, 2, ay, ax, e->elev[2], vp, *hd);
-
- e->eventType = ENTERING_EVENT;
-
- if (e->angle < M_PI) {
- if (sn.angle[0] > sn.angle[1])
- sn.angle[0] -= 2 * M_PI;
- }
- else {
- if (sn.angle[0] > sn.angle[1]) {
- sn.angle[1] += 2 * M_PI;
- sn.angle[2] += 2 * M_PI;
- }
- }
-
- insert_into_status_struct(sn, status_struct);
- break;
-
- case EXITING_EVENT:
- /*delete node out of status structure */
- SOLVEINMEMDEBUG {
- G_debug(3, "..EXIT-EVENT: delete");
- /*find its corresponding enter event and its sector */
- double enter_angle =
- calculate_enter_angle(e->row, e->col, vp);
- G_debug(3, " EXIT (a=%f)--->ENTER (a=%f) ", e->angle,
- enter_angle);
- }
- delete_from_status_struct(status_struct, sn.dist2vp);
- break;
-
- case CENTER_EVENT:
- SOLVEINMEMDEBUG {
- G_debug(3, "..QUERY-EVENT: query");
- }
- /*calculate visibility
-
- //note: if there is nothing in the status structure, it means
- //there is no prior event to occlude it, so this cell is
- //VISIBLE. this is taken care of in the status structure --- if
- //a query event comes when the structure is empty, the query
- //returns minimum gradient */
- double max;
-
- max =
- find_max_gradient_in_status_struct(status_struct, sn.dist2vp,
- e->angle, sn.gradient[1]);
-
- viscell.row = sn.row;
- viscell.col = sn.col;
-
- if (max <= sn.gradient[1]) {
- /*the point is visible */
- viscell.angle =
- get_vertical_angle(*vp, sn, e->elev[1] + vp->target_offset, viewOptions.doCurv);
- assert(viscell.angle > 0);
- /* viscell.vis = VISIBLE; */
- add_result_to_io_visibilitygrid(visgrid, &viscell);
- /*make sure nvis is correct */
- nvis++;
- }
- else {
- /* else the point is invisible; we do not write it to the
- //visibility stream, because we only record visible and nodata
- //values to the stream */
- /* viscell.vis = INVISIBLE; */
- /* add_result_to_io_visibilitygrid(visgrid, &viscell); */
- }
- break;
- }
- } /* for each event */
-
-
- G_debug(2, "in memory sweeping done.");
-
- G_debug(2, "Total cells %lu, visible cells %lu (%.1f percent).",
- (unsigned long)eventList->stream_len(), nvis,
- (float)((float)nvis * 100 / (float)(eventList->stream_len())));
-
- /*cleanup */
- delete_status_structure(status_struct);
-
-
-
- /*invariant: must delete its eventList */
- delete eventList;
-
- if (enterBndEvents)
- delete enterBndEvents;
-
- return nvis;
-}
-
-
-
-/***********************************************************************
- //returns 1 if enter angle is within epsilon from boundary angle*/
-int is_almost_on_boundary(double angle, double boundary_angle)
-{
- /*printf("is_almost_on_boundary: %f (%f) %f\n", angle, angle-2*M_PI, boundary_angle); */
- return (fabs(angle - boundary_angle) < EPSILON) ||
- (fabs(angle - 2 * M_PI - boundary_angle) < EPSILON);
-}
-
-
-/***********************************************************************
- // returns 1 if angle is within epsilon the boundaries of sector s*/
-int
-is_almost_on_boundary(double angle, int s, double start_angle,
- double end_angle, int nsect)
-{
- /*the boundaries of sector s */
- double ssize = (end_angle - start_angle) / nsect;
-
- return is_almost_on_boundary(angle, s * ssize) ||
- is_almost_on_boundary(angle, (s + 1) * ssize);
-}
-
-
-/***********************************************************************
- returns true if the event is inside the given sector */
-int is_inside(AEvent * e, double start_angle, double end_angle)
-{
- assert(e);
- return (e->angle >= (start_angle - EPSILON) &&
- e->angle <= (end_angle + EPSILON));
-}
-
-/***********************************************************************
- returns true if this angle is inside the given sector */
-int is_inside(double angle, double start_angle, double end_angle)
-{
- return (angle >= (start_angle - EPSILON) &&
- angle <= (end_angle + EPSILON));
-}
-
-
-
-/***********************************************************************
- return the start angle of the i-th sector. Assuming that
-[start..end] is split into nsectors */
-double
-get_sector_start(int i, double start_angle, double end_angle, int nsect)
-{
- assert(is_inside(i, nsect));
- return start_angle + i * ((end_angle - start_angle) / nsect);
-}
-
-
-
-/***********************************************************************
- return the start angle of the i-th sector. Assuming that
-[start..end] is split into nsectors */
-double get_sector_end(int i, double start_angle, double end_angle, int nsect)
-{
- assert(is_inside(i, nsect));
- return start_angle + (i + 1) * ((end_angle - start_angle) / nsect);
-}
-
-
-
-/***********************************************************************
- return 1 is s is inside sector; that is, if it is not -1 */
-int is_inside(int s, int nsect)
-{
- return (s >= 0 && s < nsect);
-}
-
-
-/***********************************************************************
- the event e spans sectors from start_s to end_s; Action: update
- high[] for each spanned sector. start_s and both_s can be -1, which
- means outside given sector---in that case long cell spans to the
- boundary of the sector.
- */
-void
-process_long_cell(int start_s, int end_s, int nsect,
- Viewpoint * vp, AEvent * e, double *high)
-{
-
- G_debug(4, "LONG CELL: spans [%3d, %3d] ", start_s, end_s);
- double ctrgrad = calculate_center_gradient(e, vp);
-
- /*ENTER event is outside */
- if (start_s == -1) {
- assert(e->eventType == EXITING_EVENT);
- assert(is_inside(end_s, nsect));
- /*span from 0 to end_s */
- for (int j = 0; j < end_s; j++) {
- if (high[j] < ctrgrad) {
- /*printf("update high[%d] from %.2f to %.2f ", j, high[j], ctrgrad); */
- high[j] = ctrgrad;
- }
- }
- return;
- }
-
- /*EXIT event is outside */
- if (end_s == -1) {
- assert(e->eventType == ENTERING_EVENT);
- assert(is_inside(start_s, nsect));
- /*span from start_s to nsect */
- for (int j = start_s + 1; j < nsect; j++) {
- if (high[j] < ctrgrad) {
- /*printf("update high[%d] from %.2f to %.2f ", j, high[j], ctrgrad); */
- high[j] = ctrgrad;
- }
- }
- return;
- }
-
- /*the usual scenario, both inside sector */
- if (start_s < end_s) {
- /*we must update high[] in start_s+1..end_s-1 */
- for (int j = start_s + 1; j < end_s; j++) {
- if (high[j] < ctrgrad) {
- /*printf("update high[%d] from %.2f to %.2f ", j, high[j], ctrgrad); */
- high[j] = ctrgrad;
- }
- }
- return;
- }
- else {
- /*start_s > end_s: we must insert in [start_s..nsect] and [0, end_s] */
- for (int j = start_s + 1; j < nsect; j++) {
- if (high[j] < ctrgrad) {
- /*printf("update high[%d] from %.2f to %.2f ", j, high[j], ctrgrad); */
- high[j] = ctrgrad;
- }
- }
- for (int j = 0; j < end_s; j++) {
- if (high[j] < ctrgrad) {
- /*printf("update high[%d] from %.2f to %.2f ", j, high[j], ctrgrad); */
- high[j] = ctrgrad;
- }
- }
- }
- return;
-}
-
-/***********************************************************************
- prints how many events were inserted and dropped in each sector */
-void
-print_sector_stats(off_t nevents, int nsect, double *high,
- long *total,
- long *insert, long *drop, AMI_STREAM < AEvent > *sector,
- AMI_STREAM < AEvent > *bndSector, long *bndInsert,
- long longEvents, double start_angle, double end_angle)
-{
-
-
- unsigned long totalSector = 0, totalDrop = 0, totalInsert = 0;
-
- for (int i = 0; i < nsect; i++) {
- assert(total[i] == insert[i] + drop[i]);
- assert(insert[i] == sector[i].stream_len());
-
- assert(bndInsert[i] == bndSector[i].stream_len());
-
- totalSector += total[i];
- totalDrop += drop[i];
- totalInsert += insert[i];
-
- }
- assert(totalSector == nevents);
-
- PRINT_DISTRIBUTE {
- G_debug(3, "-----nsectors=%d", nsect);
- for (int i = 0; i < nsect; i++) {
- G_debug(3, "\ts=%3d ", i);
- G_debug(3, "[%.4f, %.4f] ",
- get_sector_start(i, start_angle, end_angle, nsect),
- get_sector_end(i, start_angle, end_angle, nsect));
- G_debug(3, "high = %9.1f, ", high[i]);
- G_debug(3, "total = %10ld, ", total[i]);
- G_debug(3, "inserted = %10ld, ", insert[i]);
- G_debug(3, "dropped = %10ld, ", drop[i]);
- G_debug(3, "BOUNDARY = %5ld", bndInsert[i]);
- G_debug(3, "\n");
- }
- }
- G_debug(3, "Distribute [%.4f, %.4f]: nsect=%d, ",
- start_angle, end_angle, nsect);
- G_debug(3,
- "total events %lu, inserted %lu, dropped %lu, long events=%ld",
- totalSector, totalInsert, totalDrop, longEvents);
-
- return;
-}
-
-
-
-/***********************************************************************
- computes the number of sector for the distribution sweep; technically
- M/2B because you need 2 streams per sector */
-int compute_n_sectors()
-{
-
- long memSizeBytes = MM_manager.memory_available();
- unsigned int blockSizeBytes = UntypedStream::get_block_length();
-
- /*printf("computeNSect: block=%d, mem=%d\n", blockSizeBytes, (int)memSizeBytes); */
- int nsect = (int)(memSizeBytes / (2 * blockSizeBytes));
-
- /*be safe */
- if (nsect > 4)
- nsect = nsect / 2;
-
- /*if it happens that we are at the end of memory, set nsect=2;
- //technically, if there is not enough memory to hold two
- //blocks, the function should enter solve_in_memory; so there
- //is not enough memory to solve in memory nor to
- //distribute...this shoudl happen only under tests with very
- //very little memory. just set nsect=2 and hope that it
- //works */
-
- if (nsect == 0 || nsect == 1)
- nsect = 2;
- else {
- /*we'll have 2 streams for each sector open; subtract 10 to be safe */
- if (2 * nsect > MAX_STREAMS_OPEN - 10)
- nsect = (MAX_STREAMS_OPEN - 10) / 2;
- }
- G_debug(1, "nsectors set to %d", nsect);
-
- return nsect;
-}
-
-
-
-/***********************************************************************
- compute the sector that contains this angle; there are nsect
- sectors that span the angle interval [sstartAngle, sendAngle]. if
- angle falls outside, return -1*/
-int
-get_event_sector(double angle, double sstartAngle, double sendAngle,
- int nsect)
-{
-
- int s = -1;
-
- /*first protect against rounding errors
- //in the last sector */
- if (fabs(angle - sendAngle) < EPSILON)
- return nsect - 1;
-
- /*in the first sector */
- if (fabs(angle - sstartAngle) < EPSILON)
- return 0;
-
- double ssize = fabs(sstartAngle - sendAngle) / nsect;
-
- s = (int)((angle - sstartAngle) / ssize);
- /*printf("getsector: fit %.2f in (%.2f. %.2f)", angle, sstartAngle, sendAngle);
- //printf("ssize = %.2f, s=%d", ssize, s);
- //assert (s >= 0 && s < nsect); */
- if (s < 0 || s >= nsect) {
- /*falls outside --- this can happen when finding sector of pair
- //event; e.g. ENTER is inside sector, and its pair EXIT event
- //falls outside sector. */
- s = -1;
- }
- return s;
-}
-
-
-
-/***********************************************************************
- insert event in this sector */
-void insert_event_in_sector(AMI_STREAM < AEvent > *str, AEvent * e)
-{
-
- assert(str && e);
- AMI_err ae;
-
- ae = str->write_item(*e);
- assert(ae == AMI_ERROR_NO_ERROR);
-
- return;
-}
-
-
-/**********************************************************************
- insert event e into sector */
-void
-insert_event_in_sector_no_drop(AEvent * e, int s, AMI_STREAM < AEvent > *str,
- long *insert)
-{
-
- /*note: if on boundary, PRECISION ISSUES?? should insert both sectors? */
- DISTRIBDEBUG {
- print_event(*e, 2);
- G_debug(2, " insert in sector %3d", s);
- }
- AMI_err ae;
-
- ae = str->write_item(*e);
- assert(ae == AMI_ERROR_NO_ERROR);
- insert[s]++;
-
- return;
-}
-
-/**********************************************************************
- insert event e into sector if it is not occluded by high_s */
-void
-insert_event_in_sector(AEvent * e, int s, AMI_STREAM < AEvent > *str,
- double high_s, Viewpoint * vp, long *insert,
- long *drop)
-{
-
- /*note: if on boundary, PRECISION ISSUES?? should insert both sectors?
-
- //if not occluded by high_s insert it in its sector */
- if (!is_center_gradient_occluded(e, high_s, vp)) {
- insert[s]++;
- DISTRIBDEBUG {
- print_event(*e, 2);
- G_debug(2, " insert in sector %3d", s);
- }
- AMI_err ae;
-
- ae = str->write_item(*e);
- assert(ae == AMI_ERROR_NO_ERROR);
-
- }
- else {
- /*assert(calculateCenterGradient(e, vp) <= high[s]);
- //technically, if its a QUERY we should write it as invisible in
- //vis stream; but as an optimization, our vis stream only
- //records visible stuff. */
- DISTRIBDEBUG print_dropped(e, vp, high_s);
-
- drop[s]++;
- }
-
- return;
-}
-
-
-/***********************************************************************
- returns 1 if the center of event is occluded by the gradient, which
- is assumed to be in line with the event */
-int is_center_gradient_occluded(AEvent * e, double gradient, Viewpoint * vp)
-{
-
- assert(e && vp);
- double eg = calculate_center_gradient(e, vp);
-
- return (eg < gradient);
-}
-
-/***********************************************************************
-called when dropping an event e, high is the highest gradiant value
-//in its sector*/
-void print_dropped(AEvent * e, Viewpoint * vp, double high)
-{
-
- assert(e && vp);
- double eg = calculate_center_gradient(e, vp);
-
- G_debug(3, " dropping grad=%.2f, high=%.2f", eg, high);
-
- return;
-}
Copied: grass/trunk/raster/r.viewshed/distribute.cpp (from rev 49482, grass-addons/raster/r.viewshed/distribute.cc)
===================================================================
--- grass/trunk/raster/r.viewshed/distribute.cpp (rev 0)
+++ grass/trunk/raster/r.viewshed/distribute.cpp 2011-12-02 09:56:38 UTC (rev 49483)
@@ -0,0 +1,1170 @@
+
+/****************************************************************************
+ *
+ * MODULE: r.viewshed
+ *
+ * AUTHOR(S): Laura Toma, Bowdoin College - ltoma at bowdoin.edu
+ * Yi Zhuang - yzhuang at bowdoin.edu
+
+ * Ported to GRASS by William Richard -
+ * wkrichar at bowdoin.edu or willster3021 at 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 <assert.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <math.h>
+
+extern "C"
+{
+#include <grass/config.h>
+#include <grass/gis.h>
+#include <grass/glocale.h>
+}
+
+/* include IOSTREAM header */
+#include <grass/iostream/ami.h>
+
+
+/*note: MAX_STREAM_OPEN defined in IOStream/include/ami_stream.h, which
+ is included by ami.h */
+
+#include "distribute.h"
+#include "viewshed.h"
+#include "visibility.h"
+#include "eventlist.h"
+#include "statusstructure.h"
+#include "grass.h"
+
+
+#define DISTRIBDEBUG if(0)
+#define SOLVEINMEMDEBUG if(0)
+#define DEBUGINIT if(0)
+#define PRINTWARNING if(0)
+#define BND_DEBUG if(0)
+
+
+#define ANGLE_FACTOR 1
+#define EPSILON GRASS_EPSILON
+#define PRINT_DISTRIBUTE if(0)
+
+
+
+////////////////////////////////////////////////////////////////////////
+/* distribution sweep: write results to visgrid.
+ */
+IOVisibilityGrid *distribute_and_sweep(char *inputfname,
+ GridHeader * hd,
+ Viewpoint * vp,
+ ViewOptions viewOptions)
+{
+
+ assert(inputfname && hd && vp);
+ G_message(_("Start distributed sweeping."));
+
+ /* ------------------------------ */
+ /*initialize the visibility grid */
+ IOVisibilityGrid *visgrid;
+
+ visgrid = init_io_visibilitygrid(*hd, *vp);
+ G_debug(1, "distribute_and_sweep: visgrid=%s", visgrid->visStr->name());
+
+
+ /* ------------------------------ */
+ /*construct event list corresp to the input file and viewpoint */
+ Rtimer initEventTime;
+
+ rt_start(initEventTime);
+ AMI_STREAM < AEvent > *eventList;
+
+ eventList = init_event_list(inputfname, vp, hd,
+ viewOptions, NULL, visgrid);
+
+ assert(eventList);
+ eventList->seek(0);
+ rt_stop(initEventTime);
+ G_debug(1, "distribute_and_sweep: eventlist=%s", eventList->sprint());
+
+
+ /* ------------------------------ */
+ /*sort the events concentrically */
+ Rtimer sortEventTime;
+
+ rt_start(sortEventTime);
+ G_debug(1, "Sorting events by distance from viewpoint..");
+
+ sort_event_list_by_distance(&eventList, *vp);
+ G_debug(1, "..sorting done.");
+
+ /* debugging */
+ /*sortCheck(eventList, *vp); */
+ eventList->seek(0); /*this does not seem to be ensured by sort */
+ rt_stop(sortEventTime);
+ G_debug(1, "distribute_and_sweep: eventlist=%s", eventList->sprint());
+
+
+
+ /* ------------------------------ */
+ /* start distribution */
+ long nvis; /*number of cells visible. Returned by distribute_sector */
+
+ Rtimer sweepTime;
+
+ rt_start(sweepTime);
+ /*distribute recursively the events and write results to visgrid.
+ invariant: distribute_sector deletes its eventlist */
+ nvis = distribute_sector(eventList, NULL, 0, ANGLE_FACTOR * 2 * M_PI,
+ visgrid, vp, hd, viewOptions);
+ rt_stop(sweepTime);
+
+
+ /* ------------------------------ */
+ /*cleanup */
+ G_message(_("Distribution sweeping done."));
+
+ G_verbose_message("Total cells %ld, visible cells %ld (%.1f percent).",
+ (long)visgrid->hd->nrows * visgrid->hd->ncols,
+ nvis,
+ (float)((float)nvis * 100 /
+ (float)(visgrid->hd->nrows * visgrid->hd->ncols)));
+
+ print_viewshed_timings(initEventTime, sortEventTime, sweepTime);
+
+ return visgrid;
+}
+
+
+
+
+
+
+//***********************************************************************
+/* distribute recursively the events and write results to
+ visgrid. eventList is a list of events sorted by distance that fall
+ within angle boundaries start_angle and end_angle; enterBndEvents
+ is a stream that contains all the ENTER events that are not in this
+ sector, but their corresponding Q or X events are in this sector.
+
+ When problem is small enough, solve it in memory and write results to
+ visgrid.
+
+ invariant: distribute_sector deletes eventList and enterBndEvents
+ */
+unsigned long distribute_sector(AMI_STREAM < AEvent > *eventList,
+ AMI_STREAM < AEvent > *enterBndEvents,
+ double start_angle, double end_angle,
+ IOVisibilityGrid * visgrid, Viewpoint * vp,
+ GridHeader *hd, ViewOptions viewOptions)
+{
+
+
+ assert(eventList && visgrid && vp);
+ /*enterBndEvents may be NULL first time */
+
+ G_debug(2, "*** DISTRIBUTE sector [%.4f, %.4f] ***",
+ start_angle, end_angle);
+ G_debug(2, "initial_gradient: %lf", SMALLEST_GRADIENT);
+ G_debug(2, "eventlist: %s", eventList->sprint());
+ if (enterBndEvents)
+ G_debug(2, "BndEvents: %s", enterBndEvents->sprint());
+ PRINT_DISTRIBUTE LOG_avail_memo();
+
+ unsigned long nvis = 0;
+
+ /*******************************************************
+ BASE CASE
+ *******************************************************/
+ if (eventList->stream_len() * sizeof(AEvent) <
+ MM_manager.memory_available()) {
+ if (enterBndEvents) {
+ nvis += solve_in_memory(eventList, enterBndEvents,
+ start_angle, end_angle, visgrid, hd,
+ vp, viewOptions);
+ return nvis;
+ }
+ else {
+ /*we are here if the problem fits in memory, and
+ //enterBNdEvents==NULL---this only happens the very first time;
+ //technically at this point we should do one pass though the
+ //data and collect the events that cross the 1st and 4th
+ //quadrant; instead we force recursion, nect= 2 */
+ }
+ }
+
+ /*else, must recurse */
+ PRINT_DISTRIBUTE G_debug(2, "In EXTERNAL memory");
+
+ /*compute number of sectors */
+ int nsect = compute_n_sectors();
+
+ assert(nsect > 1);
+
+ /*an array of streams, one for each sector; sector[i] will keep all
+ the cells that are completely inside sector i */
+ AMI_STREAM < AEvent > *sector = new AMI_STREAM < AEvent >[nsect];
+
+ /*the array of gradient values, one for each sector; the gradient is
+ the gradient of the center of a cell that spans the sector
+ completely */
+ double *high = new double[nsect];
+
+ for (int i = 0; i < nsect; i++)
+ high[i] = SMALLEST_GRADIENT;
+
+ /*an array of streams, one for each stream boundary; sectorBnd[0]
+ will keep all the cells crossing into sector 0 from below; and so on. */
+ AMI_STREAM < AEvent > *sectorBnd = new AMI_STREAM < AEvent >[nsect];
+
+ /*keeps stats for each sector */
+ long *total = new long[nsect];
+ long *insert = new long[nsect];
+ long *drop = new long[nsect];
+ long *bndInsert = new long[nsect];
+ long *bndDrop = new long[nsect];
+
+ for (int i = 0; i < nsect; i++)
+ total[i] = insert[i] = drop[i] = bndInsert[i] = bndDrop[i] = 0;
+ long longEvents = 0;
+
+ /*******************************************************
+ CONCENTRIC SWEEP
+ *******************************************************/
+ AEvent *e;
+ AMI_err ae;
+ double exit_angle, enter_angle;
+ int exit_s, s, enter_s;
+ long boundaryEvents = 0;
+ off_t nbEvents = eventList->stream_len();
+
+ eventList->seek(0);
+ for (off_t i = 0; i < nbEvents; i++) {
+
+ /*get out one event at a time and process it according to its type */
+ ae = eventList->read_item(&e);
+ assert(ae == AMI_ERROR_NO_ERROR);
+ assert(is_inside(e, start_angle, end_angle));
+
+ /*compute its sector */
+ s = get_event_sector(e->angle, start_angle, end_angle, nsect);
+ /*detect boundary cases ==> precision issues */
+ if (is_almost_on_boundary(e->angle, s, start_angle, end_angle, nsect)) {
+ double ssize = (end_angle - start_angle) / nsect;
+
+ boundaryEvents++;
+
+ G_debug(2, "WARNING! event ");
+ print_event(*e, 3);
+ G_debug(2, "close to boundary");
+ G_debug(2, "angle=%f close to sector boundaries=[%f, %f]",
+ e->angle, s * ssize, (s + 1) * ssize);
+ }
+
+ G_debug(2, "event %7lu: ", (unsigned long)i);
+ print_event(*e, 2);
+ G_debug(2, "d=%8.1f, ",
+ get_square_distance_from_viewpoint(*e, *vp));
+ G_debug(2, "s=%3d ", s);
+
+ assert(is_inside(s, nsect));
+ total[s]++;
+
+ /*insert event in sector if not occluded */
+ insert_event_in_sector(e, s, §or[s], high[s], vp, insert, drop);
+
+ switch (e->eventType) {
+ case CENTER_EVENT:
+ break;
+
+ case ENTERING_EVENT:
+ /*find its corresponding exit event and its sector */
+ exit_angle = calculate_exit_angle(e->row, e->col, vp);
+ exit_s =
+ get_event_sector(exit_angle, start_angle, end_angle, nsect);
+
+ G_debug(2, " ENTER (a=%.2f,s=%3d)---> EXIT (a=%.2f,s=%3d) ",
+ e->angle, s, exit_angle, exit_s);
+ /*note: exit_s can be -1 (outside) */
+ if (exit_s == s) {
+ /*short event, fit in sector s */
+
+ }
+ else if (exit_s == (s + 1) % nsect || (exit_s + 1) % nsect == s) {
+ /*semi-short event; insert in sector s, and in sector boundary s+1
+ NOTE: to avoid precision issues, the events are inserted
+ when processing the EXIT_EVENT
+ insertEventInSector(e, (s+1)%nsect, §orBnd[(s+1)%nsect],
+ high[(s+1)%nsect], vp,bndInsert, bndDrop); */
+
+ }
+ else {
+ /*long event; insert in sector s, and in sector boundary exit_s */
+ process_long_cell(s, exit_s, nsect, vp, e, high);
+ longEvents++;
+ /*insertEventInSector(e, exit_s, §orBnd[exit_s], high[exit_s],
+ // vp, bndInsert, bndDrop); */
+ }
+ break;
+
+ case EXITING_EVENT:
+ /*find its corresponding enter event and its sector */
+ enter_angle = calculate_enter_angle(e->row, e->col, vp);
+ enter_s =
+ get_event_sector(enter_angle, start_angle, end_angle, nsect);
+
+ G_debug(2, " EXIT (a=%.2f,s=%3d)--->ENTER (a=%.2f,s=%3d) ",
+ e->angle, s, enter_angle, enter_s);
+
+ /*don't need to check spanned sectors because it is done on its
+ //ENTER event; actually...you do, because its enter event may
+ //not be in this sector==> enter_s = -1 (outside) */
+ if (enter_s == s) {
+ /*short event, fit in sector */
+ }
+ else if (enter_s == (s + 1) % nsect || (enter_s + 1) % nsect == s) {
+ /*semi-short event
+ //the corresponding ENTER event must insert itself in sectorBnd[s] */
+ e->eventType = ENTERING_EVENT;
+
+ G_debug(2, "BND event ");
+ print_event(*e, 2);
+ G_debug(2, "in bndSector %d", s);
+
+
+ insert_event_in_sector(e, s, §orBnd[s], high[s],
+ vp, bndInsert, bndDrop);
+
+ }
+ else {
+ /*long event */
+ process_long_cell(enter_s, s, nsect, vp, e, high);
+ longEvents++;
+ /*the corresponding ENTER event must insert itself in sectorBnd[s] */
+ e->eventType = ENTERING_EVENT;
+
+ G_debug(2, "BND event ");
+ print_event(*e, 2);
+ G_debug(2, "in bndSector %d", s);
+
+ insert_event_in_sector(e, s, §orBnd[s], high[s],
+ vp, bndInsert, bndDrop);
+ }
+ break;
+
+ } /*switch event-type */
+
+ G_debug(2, "\n");
+ } /*for event i */
+
+
+ /*distribute the enterBnd events to the boundary streams of the
+ //sectors; note: the boundary streams are not sorted by distance. */
+ if (enterBndEvents)
+ distribute_bnd_events(enterBndEvents, sectorBnd, nsect, vp,
+ start_angle, end_angle, high, bndInsert,
+ bndDrop);
+
+ /*sanity checks */
+ G_debug(2, "boundary events in distribution: %ld",
+ boundaryEvents);
+ print_sector_stats(nbEvents, nsect, high, total, insert, drop, sector,
+ sectorBnd, bndInsert,
+ longEvents, start_angle, end_angle);
+ /*cleanup after sector stats */
+ delete[]total;
+ delete[]insert;
+ delete[]drop;
+ delete[]high;
+ delete[]bndInsert;
+ delete[]bndDrop;
+
+ /*we finished processing this sector, delete the event list */
+ delete eventList;
+
+ if (enterBndEvents)
+ delete enterBndEvents;
+
+ /*save stream names of new sectors */
+ char **sectorName = (char **)G_malloc(nsect * sizeof(char *));
+ char **sectorBndName = (char **)G_malloc(nsect * sizeof(char *));
+
+ assert(sectorName && sectorBndName);
+ for (int i = 0; i < nsect; i++) {
+ sector[i].name(§orName[i]);
+ G_debug(2, "saving stream %d: %s\t", i, sectorName[i]);
+
+ sector[i].persist(PERSIST_PERSISTENT);
+ sectorBnd[i].name(§orBndName[i]);
+ G_debug(2, "saving BndStr %d: %s", i,
+ sectorBndName[i]);
+ sectorBnd[i].persist(PERSIST_PERSISTENT);
+ }
+
+ /*delete [] sector;
+ //does this call delete on every single stream?
+ //for (int i=0; i< nsect; i++ ) delete sector[i]; */
+ delete[]sector;
+ delete[]sectorBnd;
+ /*LOG_avail_memo(); */
+
+
+ /*solve recursively each sector */
+ for (int i = 0; i < nsect; i++) {
+
+ /*recover stream */
+ G_debug(3, "opening sector stream %s ", sectorName[i]);
+
+ AMI_STREAM < AEvent > *str =
+ new AMI_STREAM < AEvent > (sectorName[i]);
+ assert(str);
+ G_debug(3, " len=%lu",
+ (unsigned long)str->stream_len());
+ /*recover boundary stream */
+ G_debug(3, "opening boundary sector stream %s ",
+ sectorBndName[i]);
+ AMI_STREAM < AEvent > *bndStr =
+ new AMI_STREAM < AEvent > (sectorBndName[i]);
+ assert(str);
+ G_debug(3, " len=%lu",
+ (unsigned long)bndStr->stream_len());
+
+
+ nvis += distribute_sector(str, bndStr,
+ start_angle +
+ i * ((end_angle - start_angle) / nsect),
+ start_angle + (i +
+ 1) * ((end_angle -
+ start_angle) / nsect),
+ visgrid, vp, hd, viewOptions);
+ }
+
+ /*cleanup */
+ G_free(sectorName);
+ G_free(sectorBndName);
+
+ G_debug(2, "Distribute sector [ %.4f, %.4f] done.",
+ start_angle, end_angle);
+
+ return nvis;
+}
+
+
+
+
+/***********************************************************************
+ enterBndEvents is a stream of events that cross into the sector's
+ (first) boundary; they must be distributed to the boundary streams
+ of the sub-sectors of this sector. Note: the boundary streams of
+ the sub-sectors may not be empty; as a result, events get appended
+ at the end, and they will not be sorted by distance from the
+ vp.
+ */
+void
+distribute_bnd_events(AMI_STREAM < AEvent > *bndEvents,
+ AMI_STREAM < AEvent > *sectorBnd, int nsect,
+ Viewpoint * vp, double start_angle, double end_angle,
+ double *high, long *insert, long *drop)
+{
+
+ G_debug(3, "Distribute boundary of sector [ %.4f, %.4f] ",
+ start_angle, end_angle);
+ assert(bndEvents && sectorBnd && vp && high && insert && drop);
+ AEvent *e;
+ AMI_err ae;
+ double exit_angle;
+ int exit_s;
+ off_t nbEvents = bndEvents->stream_len();
+
+ bndEvents->seek(0);
+ for (off_t i = 0; i < nbEvents; i++) {
+
+ /*get out one event at a time */
+ ae = bndEvents->read_item(&e);
+ assert(ae == AMI_ERROR_NO_ERROR);
+ /*must be outside, but better not check to avoid precision issues
+ //assert(!is_inside(e, start_angle, end_angle));
+
+ //each event must be an ENTER event that falls in a diff sector
+ //than its EXIT */
+ assert(e->eventType == ENTERING_EVENT);
+
+ /*find its corresponding exit event and its sector */
+ exit_angle = calculate_exit_angle(e->row, e->col, vp);
+ exit_s = get_event_sector(exit_angle, start_angle, end_angle, nsect);
+
+ /*exit_s cannot be outside sector; though we have to be careful
+ //with precision */
+ assert(is_inside(exit_s, nsect));
+
+ /*insert this event in the boundary stream of this sub-sector */
+ insert_event_in_sector(e, exit_s, §orBnd[exit_s], high[exit_s],
+ vp, insert, drop);
+
+ } /*for i */
+
+ G_debug(3, "Distribute boundary of sector [ %.4f, %.4f] done.",
+ start_angle, end_angle);
+
+ return;
+}
+
+
+
+
+//***********************************************************************
+/* Solves a segment in memory. it is called by distribute() when
+ sector fits in memory. eventList is the list of events in
+ increasing order of distance from the viewpoint; enterBndEvents is
+ the list of ENTER events that are outside the sector, whose
+ corresponding EXIT events are inside the sector. start_angle and
+ end_angle are the boundaries of the sector, and visgrid is the grid
+ to which the visible/invisible cells must be written. The sector is
+ solved by switching to radial sweep. */
+unsigned long solve_in_memory(AMI_STREAM < AEvent > *eventList,
+ AMI_STREAM < AEvent > *enterBndEvents,
+ double start_angle, double end_angle,
+ IOVisibilityGrid * visgrid, GridHeader *hd,
+ Viewpoint * vp, ViewOptions viewOptions)
+{
+
+ assert(eventList && visgrid && vp);
+ G_debug(2, "solve INTERNAL memory");
+
+ unsigned long nvis = 0; /*number of visible cells */
+
+ G_debug(2, "solve_in_memory: eventlist: %s", eventList->sprint());
+ if (enterBndEvents)
+ G_debug(2, "BndEvents: %s", enterBndEvents->sprint());
+
+ if (eventList->stream_len() == 0) {
+ delete eventList;
+
+ if (enterBndEvents)
+ delete enterBndEvents;
+
+ return nvis;
+ }
+
+ /*sort the events radially */
+ sort_event_list(&eventList);
+
+ /*create the status structure */
+ StatusList *status_struct = create_status_struct();
+
+ /*initialize status structure with all ENTER events whose EXIT
+ //events is inside the sector */
+ AEvent *e;
+ AMI_err ae;
+ StatusNode sn;
+ int inevents = 0;
+
+ /*
+ eventList->seek(0);
+ double enter_angle;
+ ae = eventList->read_item(&e);
+ while (ae == AMI_ERROR_NO_ERROR) {
+ if (e->eventType == EXITING_EVENT) {
+ enter_angle = calculateEnterAngle(e->row, e->col, vp);
+ //to get around precision problems, insert cell in active
+ //structure when close to the boundary --- these may cause a
+ //double insert, but subsequent ENTER events close to the
+ //boundary will be careful not to insert
+ if (!is_inside(enter_angle, start_angle, end_angle) ||
+ is_almost_on_boundary(enter_angle, start_angle)) {
+ DEBUGINIT {printf("inserting "); print_event(*e); printf("\n");}
+ //this must span the first boundary of this sector; insert it
+ //in status structure
+ sn.col = e->col;
+ sn.row = e->row;
+ sn.elev = e->elev;
+ calculateDistNGradient(&sn, vp);
+ insertIntoStatusStruct(sn, status_struct);
+ inevents++;
+ }
+ }
+ ae = eventList->read_item(&e);
+ }
+ assert(ae == AMI_ERROR_END_OF_STREAM);
+ */
+ if (enterBndEvents) {
+ double ax, ay;
+
+ enterBndEvents->seek(0);
+ inevents = enterBndEvents->stream_len();
+ for (off_t i = 0; i < inevents; i++) {
+ ae = enterBndEvents->read_item(&e);
+ assert(ae == AMI_ERROR_NO_ERROR);
+
+ G_debug(3, "INMEM init: initializing boundary ");
+ print_event(*e, 3);
+ G_debug(3, "\n");
+
+ /*this must span the first boundary of this sector; insert it
+ //in status structure */
+ sn.col = e->col;
+ sn.row = e->row;
+
+ e->eventType = ENTERING_EVENT;
+ calculate_event_position(*e, vp->row, vp->col, &ay, &ax);
+ sn.angle[0] = calculate_angle(ax, ay, vp->col, vp->row);
+ calculate_event_gradient(&sn, 0, ay, ax, e->elev[0], vp, *hd);
+
+ e->eventType = CENTER_EVENT;
+ calculate_event_position(*e, vp->row, vp->col, &ay, &ax);
+ sn.angle[1] = calculate_angle(ax, ay, vp->col, vp->row);
+ calculate_dist_n_gradient(&sn, e->elev[1], vp, *hd);
+
+ e->eventType = EXITING_EVENT;
+ calculate_event_position(*e, vp->row, vp->col, &ay, &ax);
+ sn.angle[2] = calculate_angle(ax, ay, vp->col, vp->row);
+ calculate_event_gradient(&sn, 2, ay, ax, e->elev[2], vp, *hd);
+
+ if (sn.angle[0] > sn.angle[1])
+ sn.angle[0] -= 2 * M_PI;
+
+ //calculate_dist_n_gradient(&sn, vp);
+ insert_into_status_struct(sn, status_struct);
+ }
+ }
+
+ G_debug(2, "initialized active structure with %d events", inevents);
+
+
+ /*sweep the event list */
+ VisCell viscell;
+ off_t nbEvents = eventList->stream_len();
+
+ /*printf("nbEvents = %ld\n", (long) nbEvents); */
+ eventList->seek(0);
+ for (off_t i = 0; i < nbEvents; i++) {
+ /*get out one event at a time and process it according to its type */
+ ae = eventList->read_item(&e);
+ assert(ae == AMI_ERROR_NO_ERROR);
+
+ G_debug(3, "INMEM sweep: next event: ");
+ print_event(*e, 3);
+
+ sn.col = e->col;
+ sn.row = e->row;
+ //sn.elev = e->elev;
+ /*calculate Distance to VP and Gradient */
+ calculate_dist_n_gradient(&sn, e->elev[1] + vp->target_offset, vp, *hd);
+
+ switch (e->eventType) {
+ case ENTERING_EVENT:
+ double ax, ay;
+
+ /*insert node into structure */
+ G_debug(3, "..ENTER-EVENT: insert");
+
+ /*don't insert if its close to the boundary---the segment was
+ //already inserted in initialization above
+ //if (!is_almost_on_boundary(e->angle, start_angle))
+ //insertIntoStatusStruct(sn,status_struct); */
+ sn.angle[0] = calculate_enter_angle(sn.row, sn.col, vp);
+ sn.angle[1] = calculate_angle(sn.col, sn.row, vp->col, vp->row);
+ sn.angle[2] = calculate_exit_angle(sn.row, sn.col, vp);
+
+ calculate_event_position(*e, vp->row, vp->col, &ay, &ax);
+ //sn.angle[0] = calculate_angle(ax, ay, vp->col, vp->row);
+ sn.angle[0] = e->angle;
+ calculate_event_gradient(&sn, 0, ay, ax, e->elev[0], vp, *hd);
+
+ e->eventType = CENTER_EVENT;
+ calculate_event_position(*e, vp->row, vp->col, &ay, &ax);
+ sn.angle[1] = calculate_angle(ax, ay, vp->col, vp->row);
+ calculate_dist_n_gradient(&sn, e->elev[1], vp, *hd);
+
+ e->eventType = EXITING_EVENT;
+ calculate_event_position(*e, vp->row, vp->col, &ay, &ax);
+ sn.angle[2] = calculate_angle(ax, ay, vp->col, vp->row);
+ calculate_event_gradient(&sn, 2, ay, ax, e->elev[2], vp, *hd);
+
+ e->eventType = ENTERING_EVENT;
+
+ if (e->angle < M_PI) {
+ if (sn.angle[0] > sn.angle[1])
+ sn.angle[0] -= 2 * M_PI;
+ }
+ else {
+ if (sn.angle[0] > sn.angle[1]) {
+ sn.angle[1] += 2 * M_PI;
+ sn.angle[2] += 2 * M_PI;
+ }
+ }
+
+ insert_into_status_struct(sn, status_struct);
+ break;
+
+ case EXITING_EVENT:
+ /*delete node out of status structure */
+ SOLVEINMEMDEBUG {
+ G_debug(3, "..EXIT-EVENT: delete");
+ /*find its corresponding enter event and its sector */
+ double enter_angle =
+ calculate_enter_angle(e->row, e->col, vp);
+ G_debug(3, " EXIT (a=%f)--->ENTER (a=%f) ", e->angle,
+ enter_angle);
+ }
+ delete_from_status_struct(status_struct, sn.dist2vp);
+ break;
+
+ case CENTER_EVENT:
+ SOLVEINMEMDEBUG {
+ G_debug(3, "..QUERY-EVENT: query");
+ }
+ /*calculate visibility
+
+ //note: if there is nothing in the status structure, it means
+ //there is no prior event to occlude it, so this cell is
+ //VISIBLE. this is taken care of in the status structure --- if
+ //a query event comes when the structure is empty, the query
+ //returns minimum gradient */
+ double max;
+
+ max =
+ find_max_gradient_in_status_struct(status_struct, sn.dist2vp,
+ e->angle, sn.gradient[1]);
+
+ viscell.row = sn.row;
+ viscell.col = sn.col;
+
+ if (max <= sn.gradient[1]) {
+ /*the point is visible */
+ viscell.angle =
+ get_vertical_angle(*vp, sn, e->elev[1] + vp->target_offset, viewOptions.doCurv);
+ assert(viscell.angle > 0);
+ /* viscell.vis = VISIBLE; */
+ add_result_to_io_visibilitygrid(visgrid, &viscell);
+ /*make sure nvis is correct */
+ nvis++;
+ }
+ else {
+ /* else the point is invisible; we do not write it to the
+ //visibility stream, because we only record visible and nodata
+ //values to the stream */
+ /* viscell.vis = INVISIBLE; */
+ /* add_result_to_io_visibilitygrid(visgrid, &viscell); */
+ }
+ break;
+ }
+ } /* for each event */
+
+
+ G_debug(2, "in memory sweeping done.");
+
+ G_debug(2, "Total cells %lu, visible cells %lu (%.1f percent).",
+ (unsigned long)eventList->stream_len(), nvis,
+ (float)((float)nvis * 100 / (float)(eventList->stream_len())));
+
+ /*cleanup */
+ delete_status_structure(status_struct);
+
+
+
+ /*invariant: must delete its eventList */
+ delete eventList;
+
+ if (enterBndEvents)
+ delete enterBndEvents;
+
+ return nvis;
+}
+
+
+
+/***********************************************************************
+ //returns 1 if enter angle is within epsilon from boundary angle*/
+int is_almost_on_boundary(double angle, double boundary_angle)
+{
+ /*printf("is_almost_on_boundary: %f (%f) %f\n", angle, angle-2*M_PI, boundary_angle); */
+ return (fabs(angle - boundary_angle) < EPSILON) ||
+ (fabs(angle - 2 * M_PI - boundary_angle) < EPSILON);
+}
+
+
+/***********************************************************************
+ // returns 1 if angle is within epsilon the boundaries of sector s*/
+int
+is_almost_on_boundary(double angle, int s, double start_angle,
+ double end_angle, int nsect)
+{
+ /*the boundaries of sector s */
+ double ssize = (end_angle - start_angle) / nsect;
+
+ return is_almost_on_boundary(angle, s * ssize) ||
+ is_almost_on_boundary(angle, (s + 1) * ssize);
+}
+
+
+/***********************************************************************
+ returns true if the event is inside the given sector */
+int is_inside(AEvent * e, double start_angle, double end_angle)
+{
+ assert(e);
+ return (e->angle >= (start_angle - EPSILON) &&
+ e->angle <= (end_angle + EPSILON));
+}
+
+/***********************************************************************
+ returns true if this angle is inside the given sector */
+int is_inside(double angle, double start_angle, double end_angle)
+{
+ return (angle >= (start_angle - EPSILON) &&
+ angle <= (end_angle + EPSILON));
+}
+
+
+
+/***********************************************************************
+ return the start angle of the i-th sector. Assuming that
+[start..end] is split into nsectors */
+double
+get_sector_start(int i, double start_angle, double end_angle, int nsect)
+{
+ assert(is_inside(i, nsect));
+ return start_angle + i * ((end_angle - start_angle) / nsect);
+}
+
+
+
+/***********************************************************************
+ return the start angle of the i-th sector. Assuming that
+[start..end] is split into nsectors */
+double get_sector_end(int i, double start_angle, double end_angle, int nsect)
+{
+ assert(is_inside(i, nsect));
+ return start_angle + (i + 1) * ((end_angle - start_angle) / nsect);
+}
+
+
+
+/***********************************************************************
+ return 1 is s is inside sector; that is, if it is not -1 */
+int is_inside(int s, int nsect)
+{
+ return (s >= 0 && s < nsect);
+}
+
+
+/***********************************************************************
+ the event e spans sectors from start_s to end_s; Action: update
+ high[] for each spanned sector. start_s and both_s can be -1, which
+ means outside given sector---in that case long cell spans to the
+ boundary of the sector.
+ */
+void
+process_long_cell(int start_s, int end_s, int nsect,
+ Viewpoint * vp, AEvent * e, double *high)
+{
+
+ G_debug(4, "LONG CELL: spans [%3d, %3d] ", start_s, end_s);
+ double ctrgrad = calculate_center_gradient(e, vp);
+
+ /*ENTER event is outside */
+ if (start_s == -1) {
+ assert(e->eventType == EXITING_EVENT);
+ assert(is_inside(end_s, nsect));
+ /*span from 0 to end_s */
+ for (int j = 0; j < end_s; j++) {
+ if (high[j] < ctrgrad) {
+ /*printf("update high[%d] from %.2f to %.2f ", j, high[j], ctrgrad); */
+ high[j] = ctrgrad;
+ }
+ }
+ return;
+ }
+
+ /*EXIT event is outside */
+ if (end_s == -1) {
+ assert(e->eventType == ENTERING_EVENT);
+ assert(is_inside(start_s, nsect));
+ /*span from start_s to nsect */
+ for (int j = start_s + 1; j < nsect; j++) {
+ if (high[j] < ctrgrad) {
+ /*printf("update high[%d] from %.2f to %.2f ", j, high[j], ctrgrad); */
+ high[j] = ctrgrad;
+ }
+ }
+ return;
+ }
+
+ /*the usual scenario, both inside sector */
+ if (start_s < end_s) {
+ /*we must update high[] in start_s+1..end_s-1 */
+ for (int j = start_s + 1; j < end_s; j++) {
+ if (high[j] < ctrgrad) {
+ /*printf("update high[%d] from %.2f to %.2f ", j, high[j], ctrgrad); */
+ high[j] = ctrgrad;
+ }
+ }
+ return;
+ }
+ else {
+ /*start_s > end_s: we must insert in [start_s..nsect] and [0, end_s] */
+ for (int j = start_s + 1; j < nsect; j++) {
+ if (high[j] < ctrgrad) {
+ /*printf("update high[%d] from %.2f to %.2f ", j, high[j], ctrgrad); */
+ high[j] = ctrgrad;
+ }
+ }
+ for (int j = 0; j < end_s; j++) {
+ if (high[j] < ctrgrad) {
+ /*printf("update high[%d] from %.2f to %.2f ", j, high[j], ctrgrad); */
+ high[j] = ctrgrad;
+ }
+ }
+ }
+ return;
+}
+
+/***********************************************************************
+ prints how many events were inserted and dropped in each sector */
+void
+print_sector_stats(off_t nevents, int nsect, double *high,
+ long *total,
+ long *insert, long *drop, AMI_STREAM < AEvent > *sector,
+ AMI_STREAM < AEvent > *bndSector, long *bndInsert,
+ long longEvents, double start_angle, double end_angle)
+{
+
+
+ unsigned long totalSector = 0, totalDrop = 0, totalInsert = 0;
+
+ for (int i = 0; i < nsect; i++) {
+ assert(total[i] == insert[i] + drop[i]);
+ assert(insert[i] == sector[i].stream_len());
+
+ assert(bndInsert[i] == bndSector[i].stream_len());
+
+ totalSector += total[i];
+ totalDrop += drop[i];
+ totalInsert += insert[i];
+
+ }
+ assert(totalSector == nevents);
+
+ PRINT_DISTRIBUTE {
+ G_debug(3, "-----nsectors=%d", nsect);
+ for (int i = 0; i < nsect; i++) {
+ G_debug(3, "\ts=%3d ", i);
+ G_debug(3, "[%.4f, %.4f] ",
+ get_sector_start(i, start_angle, end_angle, nsect),
+ get_sector_end(i, start_angle, end_angle, nsect));
+ G_debug(3, "high = %9.1f, ", high[i]);
+ G_debug(3, "total = %10ld, ", total[i]);
+ G_debug(3, "inserted = %10ld, ", insert[i]);
+ G_debug(3, "dropped = %10ld, ", drop[i]);
+ G_debug(3, "BOUNDARY = %5ld", bndInsert[i]);
+ G_debug(3, "\n");
+ }
+ }
+ G_debug(3, "Distribute [%.4f, %.4f]: nsect=%d, ",
+ start_angle, end_angle, nsect);
+ G_debug(3,
+ "total events %lu, inserted %lu, dropped %lu, long events=%ld",
+ totalSector, totalInsert, totalDrop, longEvents);
+
+ return;
+}
+
+
+
+/***********************************************************************
+ computes the number of sector for the distribution sweep; technically
+ M/2B because you need 2 streams per sector */
+int compute_n_sectors()
+{
+
+ long memSizeBytes = MM_manager.memory_available();
+ unsigned int blockSizeBytes = UntypedStream::get_block_length();
+
+ /*printf("computeNSect: block=%d, mem=%d\n", blockSizeBytes, (int)memSizeBytes); */
+ int nsect = (int)(memSizeBytes / (2 * blockSizeBytes));
+
+ /*be safe */
+ if (nsect > 4)
+ nsect = nsect / 2;
+
+ /*if it happens that we are at the end of memory, set nsect=2;
+ //technically, if there is not enough memory to hold two
+ //blocks, the function should enter solve_in_memory; so there
+ //is not enough memory to solve in memory nor to
+ //distribute...this shoudl happen only under tests with very
+ //very little memory. just set nsect=2 and hope that it
+ //works */
+
+ if (nsect == 0 || nsect == 1)
+ nsect = 2;
+ else {
+ /*we'll have 2 streams for each sector open; subtract 10 to be safe */
+ if (2 * nsect > MAX_STREAMS_OPEN - 10)
+ nsect = (MAX_STREAMS_OPEN - 10) / 2;
+ }
+ G_debug(1, "nsectors set to %d", nsect);
+
+ return nsect;
+}
+
+
+
+/***********************************************************************
+ compute the sector that contains this angle; there are nsect
+ sectors that span the angle interval [sstartAngle, sendAngle]. if
+ angle falls outside, return -1*/
+int
+get_event_sector(double angle, double sstartAngle, double sendAngle,
+ int nsect)
+{
+
+ int s = -1;
+
+ /*first protect against rounding errors
+ //in the last sector */
+ if (fabs(angle - sendAngle) < EPSILON)
+ return nsect - 1;
+
+ /*in the first sector */
+ if (fabs(angle - sstartAngle) < EPSILON)
+ return 0;
+
+ double ssize = fabs(sstartAngle - sendAngle) / nsect;
+
+ s = (int)((angle - sstartAngle) / ssize);
+ /*printf("getsector: fit %.2f in (%.2f. %.2f)", angle, sstartAngle, sendAngle);
+ //printf("ssize = %.2f, s=%d", ssize, s);
+ //assert (s >= 0 && s < nsect); */
+ if (s < 0 || s >= nsect) {
+ /*falls outside --- this can happen when finding sector of pair
+ //event; e.g. ENTER is inside sector, and its pair EXIT event
+ //falls outside sector. */
+ s = -1;
+ }
+ return s;
+}
+
+
+
+/***********************************************************************
+ insert event in this sector */
+void insert_event_in_sector(AMI_STREAM < AEvent > *str, AEvent * e)
+{
+
+ assert(str && e);
+ AMI_err ae;
+
+ ae = str->write_item(*e);
+ assert(ae == AMI_ERROR_NO_ERROR);
+
+ return;
+}
+
+
+/**********************************************************************
+ insert event e into sector */
+void
+insert_event_in_sector_no_drop(AEvent * e, int s, AMI_STREAM < AEvent > *str,
+ long *insert)
+{
+
+ /*note: if on boundary, PRECISION ISSUES?? should insert both sectors? */
+ DISTRIBDEBUG {
+ print_event(*e, 2);
+ G_debug(2, " insert in sector %3d", s);
+ }
+ AMI_err ae;
+
+ ae = str->write_item(*e);
+ assert(ae == AMI_ERROR_NO_ERROR);
+ insert[s]++;
+
+ return;
+}
+
+/**********************************************************************
+ insert event e into sector if it is not occluded by high_s */
+void
+insert_event_in_sector(AEvent * e, int s, AMI_STREAM < AEvent > *str,
+ double high_s, Viewpoint * vp, long *insert,
+ long *drop)
+{
+
+ /*note: if on boundary, PRECISION ISSUES?? should insert both sectors?
+
+ //if not occluded by high_s insert it in its sector */
+ if (!is_center_gradient_occluded(e, high_s, vp)) {
+ insert[s]++;
+ DISTRIBDEBUG {
+ print_event(*e, 2);
+ G_debug(2, " insert in sector %3d", s);
+ }
+ AMI_err ae;
+
+ ae = str->write_item(*e);
+ assert(ae == AMI_ERROR_NO_ERROR);
+
+ }
+ else {
+ /*assert(calculateCenterGradient(e, vp) <= high[s]);
+ //technically, if its a QUERY we should write it as invisible in
+ //vis stream; but as an optimization, our vis stream only
+ //records visible stuff. */
+ DISTRIBDEBUG print_dropped(e, vp, high_s);
+
+ drop[s]++;
+ }
+
+ return;
+}
+
+
+/***********************************************************************
+ returns 1 if the center of event is occluded by the gradient, which
+ is assumed to be in line with the event */
+int is_center_gradient_occluded(AEvent * e, double gradient, Viewpoint * vp)
+{
+
+ assert(e && vp);
+ double eg = calculate_center_gradient(e, vp);
+
+ return (eg < gradient);
+}
+
+/***********************************************************************
+called when dropping an event e, high is the highest gradiant value
+//in its sector*/
+void print_dropped(AEvent * e, Viewpoint * vp, double high)
+{
+
+ assert(e && vp);
+ double eg = calculate_center_gradient(e, vp);
+
+ G_debug(3, " dropping grad=%.2f, high=%.2f", eg, high);
+
+ return;
+}
Deleted: grass/trunk/raster/r.viewshed/eventlist.cc
===================================================================
--- grass-addons/raster/r.viewshed/eventlist.cc 2011-12-02 09:30:54 UTC (rev 49482)
+++ grass/trunk/raster/r.viewshed/eventlist.cc 2011-12-02 09:56:38 UTC (rev 49483)
@@ -1,718 +0,0 @@
-
-/****************************************************************************
- *
- * MODULE: r.viewshed
- *
- * AUTHOR(S): Laura Toma, Bowdoin College - ltoma at bowdoin.edu
- * Yi Zhuang - yzhuang at bowdoin.edu
-
- * Ported to GRASS by William Richard -
- * wkrichar at bowdoin.edu or willster3021 at 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 <stdlib.h>
-#include <stdio.h>
-#include <assert.h>
-
-extern "C"
-{
-#include <grass/gis.h>
-}
-
-#include "eventlist.h"
-
-
-
-/* forced to use this because DistanceCompare::compare has troubles if
- i put it inside the class */
-Viewpoint globalVP;
-
-
-
-/* ------------------------------------------------------------
- compute the gradient of the CENTER of this event wrt viewpoint. For
- efficiency it does not compute the gradient, but the square of the
- arctan of the gradient. Assuming all gradients are computed the same
- way, this is correct. */
-double calculate_center_gradient(AEvent * e, Viewpoint * vp)
-{
-
- assert(e && vp);
- double gradient, sqdist;
-
- /*square of the distance from the center of this event to vp */
- sqdist = (e->row - vp->row) * (e->row - vp->row) +
- (e->col - vp->col) * (e->col - vp->col);
-
- gradient = (e->elev[1] - vp->elev) * (e->elev[1] - vp->elev) / sqdist;
- /*maintain sign */
- if (e->elev[1] < vp->elev)
- gradient = -gradient;
- return gradient;
-}
-
-
-
-
-
-/* ------------------------------------------------------------
- //calculate the angle at which the event is. Return value is the angle.
-
- angle quadrants:
- 2 1
- 3 4
- ----->x
- |
- |
- |
- V y
-
- */
-
-/*/////////////////////////////////////////////////////////////////////
- //return the angle from this event wrt viewpoint; the type of the
- //event is taken into position to compute a different amngle for each
- //event associated with a cell */
-double calculate_event_angle(AEvent * e, Viewpoint * vp)
-{
-
- assert(e && vp);
- double ex, ey;
-
- calculate_event_position(*e, vp->row, vp->col, &ey, &ex);
- return calculate_angle(ex, ey, vp->col, vp->row);
-}
-
-
-/*/////////////////////////////////////////////////////////////////////
- //calculate the exit angle corresponding to this cell */
-double
-calculate_exit_angle(dimensionType row, dimensionType col, Viewpoint * vp)
-{
- AEvent e;
- double x, y;
-
- e.eventType = EXITING_EVENT;
- e.angle = 0;
- e.elev[0] = e.elev[1] = e.elev[2] = 0;
- e.row = row;
- e.col = col;
- calculate_event_position(e, vp->row, vp->col, &y, &x);
- return calculate_angle(x, y, vp->col, vp->row);
-}
-
-
-/*/////////////////////////////////////////////////////////////////////
- //calculate the enter angle corresponding to this cell */
-double
-calculate_enter_angle(dimensionType row, dimensionType col, Viewpoint * vp)
-{
- AEvent e;
- double x, y;
-
- e.eventType = ENTERING_EVENT;
- e.angle = 0;
- e.elev[0] = e.elev[1] = e.elev[2] = 0;
- e.row = row;
- e.col = col;
- calculate_event_position(e, vp->row, vp->col, &y, &x);
- return calculate_angle(x, y, vp->col, vp->row);
-}
-
-/*///////////////////////////////////////////////////////////////////// */
-double
-calculate_angle(double eventX, double eventY,
- double viewpointX, double viewpointY)
-{
- double angle = atan(fabs(eventY - viewpointY) / fabs(eventX - viewpointX));
-
- /*M_PI is defined in math.h to represent 3.14159... */
- if (viewpointY == eventY && eventX > viewpointX) {
- return 0; /*between 1st and 4th quadrant */
- }
- else if (eventX > viewpointX && eventY < viewpointY) {
- /*first quadrant */
- return angle;
-
- }
- else if (viewpointX == eventX && viewpointY > eventY) {
- /*between 1st and 2nd quadrant */
- return (M_PI) / 2;
-
- }
- else if (eventX < viewpointX && eventY < viewpointY) {
- /*second quadrant */
- return (M_PI - angle);
-
- }
- else if (viewpointY == eventY && eventX < viewpointX) {
- /*between 1st and 3rd quadrant */
- return M_PI;
-
- }
- else if (eventY > viewpointY && eventX < viewpointX) {
- /*3rd quadrant */
- return (M_PI + angle);
-
- }
- else if (viewpointX == eventX && viewpointY < eventY) {
- /*between 3rd and 4th quadrant */
- return (M_PI * 3.0 / 2.0);
- }
- else if (eventX > viewpointX && eventY > viewpointY) {
- /*4th quadrant */
- return (M_PI * 2.0 - angle);
- }
- assert(eventX == viewpointX && eventY == viewpointY);
- return 0;
-}
-
-
-
-/* ------------------------------------------------------------ */
-/* calculate the exact position of the given event, and store them in x
- and y.
- quadrants: 1 2
- 3 4
- ----->x
- |
- |
- |
- V y
- */
-void
-calculate_event_position(AEvent e, dimensionType viewpointRow,
- dimensionType viewpointCol, double *y, double *x)
-{
- assert(x && y);
- *x = 0;
- *y = 0;
-
- if (e.eventType == CENTER_EVENT) {
- /*FOR CENTER_EVENTS */
- *y = e.row;
- *x = e.col;
- return;
- }
-
- if (e.row < viewpointRow && e.col < viewpointCol) {
- /*first quadrant */
- if (e.eventType == ENTERING_EVENT) {
- /*if it is ENTERING_EVENT */
- *y = e.row - 0.5;
- *x = e.col + 0.5;
- }
- else {
- /*otherwise it is EXITING_EVENT */
- *y = e.row + 0.5;
- *x = e.col - 0.5;
- }
-
- }
- else if (e.col == viewpointCol && e.row < viewpointRow) {
- /*between the first and second quadrant */
- if (e.eventType == ENTERING_EVENT) {
- /*if it is ENTERING_EVENT */
- *y = e.row + 0.5;
- *x = e.col + 0.5;
- }
- else {
- /*otherwise it is EXITING_EVENT */
- *y = e.row + 0.5;
- *x = e.col - 0.5;
- }
-
- }
- else if (e.col > viewpointCol && e.row < viewpointRow) {
- /*second quadrant */
- if (e.eventType == ENTERING_EVENT) {
- /*if it is ENTERING_EVENT */
- *y = e.row + 0.5;
- *x = e.col + 0.5;
- }
- else { /*otherwise it is EXITING_EVENT */
- *y = e.row - 0.5;
- *x = e.col - 0.5;
- }
-
- }
- else if (e.row == viewpointRow && e.col > viewpointCol) {
- /*between the second and the fourth quadrant */
- if (e.eventType == ENTERING_EVENT) {
- /*if it is ENTERING_EVENT */
- *y = e.row + 0.5;
- *x = e.col - 0.5;
- }
- else {
- /*otherwise it is EXITING_EVENT */
- *y = e.row - 0.5;
- *x = e.col - 0.5;
- }
-
- }
- else if (e.col > viewpointCol && e.row > viewpointRow) {
- /*fourth quadrant */
- if (e.eventType == ENTERING_EVENT) {
- /*if it is ENTERING_EVENT */
- *y = e.row + 0.5;
- *x = e.col - 0.5;
- }
- else {
- /*otherwise it is EXITING_EVENT */
- *y = e.row - 0.5;
- *x = e.col + 0.5;
- }
-
- }
- else if (e.col == viewpointCol && e.row > viewpointRow) {
- /*between the third and fourth quadrant */
- if (e.eventType == ENTERING_EVENT) {
- /*if it is ENTERING_EVENT */
- *y = e.row - 0.5;
- *x = e.col - 0.5;
- }
- else {
- /*otherwise it is EXITING_EVENT */
- *y = e.row - 0.5;
- *x = e.col + 0.5;
- }
-
- }
- else if (e.col < viewpointCol && e.row > viewpointRow) {
- /*third quadrant */
- if (e.eventType == ENTERING_EVENT) {
- /*if it is ENTERING_EVENT */
- *y = e.row - 0.5;
- *x = e.col - 0.5;
- }
- else {
- /*otherwise it is EXITING_EVENT */
- *y = e.row + 0.5;
- *x = e.col + 0.5;
- }
-
- }
- else if (e.row == viewpointRow && e.col < viewpointCol) {
- /*between first and third quadrant */
- if (e.eventType == ENTERING_EVENT) { /*if it is ENTERING_EVENT */
- *y = e.row - 0.5;
- *x = e.col + 0.5;
- }
- else {
- /*otherwise it is EXITING_EVENT */
- *y = e.row + 0.5;
- *x = e.col + 0.5;
- }
- }
- else {
- /*must be the viewpoint cell itself */
- assert(e.row == viewpointRow && e.col == viewpointCol);
- *x = e.col;
- *y = e.row;
- }
-
- assert(fabs(*x - e.col) < 1 && fabs(*y - e.row) < 1);
- /*
- if ((fabs(*x -e.col) >=1) || (fabs(*y -e.row) >=1)) {
- G_warning("x-e.col=%f, y-e.row=%f ", fabs(*x -e.col), fabs(*y -e.row));
- print_event(e, 0);
- G_warning("vp=(%d, %d), x=%.3f, y=%.3f", viewpointRow, viewpointCol, *x, *y);
- exit(1);
- }
- */
- return;
-}
-
-void
-calculate_event_row_col(AEvent e, dimensionType viewpointRow,
- dimensionType viewpointCol, int *y, int *x)
-{
- assert(x && y);
- *x = 0;
- *y = 0;
-
- if (e.eventType == CENTER_EVENT) {
- G_fatal_error("calculate_event_row_col() must not be called for CENTER events");
- }
-
- if (e.row < viewpointRow && e.col < viewpointCol) {
- /*first quadrant */
- if (e.eventType == ENTERING_EVENT) {
- /*if it is ENTERING_EVENT */
- *y = e.row - 1;
- *x = e.col + 1;
- }
- else {
- /*otherwise it is EXITING_EVENT */
- *y = e.row + 1;
- *x = e.col - 1;
- }
-
- }
- else if (e.col == viewpointCol && e.row < viewpointRow) {
- /*between the first and second quadrant */
- if (e.eventType == ENTERING_EVENT) {
- /*if it is ENTERING_EVENT */
- *y = e.row + 1;
- *x = e.col + 1;
- }
- else {
- /*otherwise it is EXITING_EVENT */
- *y = e.row + 1;
- *x = e.col - 1;
- }
-
- }
- else if (e.col > viewpointCol && e.row < viewpointRow) {
- /*second quadrant */
- if (e.eventType == ENTERING_EVENT) {
- /*if it is ENTERING_EVENT */
- *y = e.row + 1;
- *x = e.col + 1;
- }
- else { /*otherwise it is EXITING_EVENT */
- *y = e.row - 1;
- *x = e.col - 1;
- }
-
- }
- else if (e.row == viewpointRow && e.col > viewpointCol) {
- /*between the second and the fourth quadrant */
- if (e.eventType == ENTERING_EVENT) {
- /*if it is ENTERING_EVENT */
- *y = e.row + 1;
- *x = e.col - 1;
- }
- else {
- /*otherwise it is EXITING_EVENT */
- *y = e.row - 1;
- *x = e.col - 1;
- }
-
- }
- else if (e.col > viewpointCol && e.row > viewpointRow) {
- /*fourth quadrant */
- if (e.eventType == ENTERING_EVENT) {
- /*if it is ENTERING_EVENT */
- *y = e.row + 1;
- *x = e.col - 1;
- }
- else {
- /*otherwise it is EXITING_EVENT */
- *y = e.row - 1;
- *x = e.col + 1;
- }
-
- }
- else if (e.col == viewpointCol && e.row > viewpointRow) {
- /*between the third and fourth quadrant */
- if (e.eventType == ENTERING_EVENT) {
- /*if it is ENTERING_EVENT */
- *y = e.row - 1;
- *x = e.col - 1;
- }
- else {
- /*otherwise it is EXITING_EVENT */
- *y = e.row - 1;
- *x = e.col + 1;
- }
-
- }
- else if (e.col < viewpointCol && e.row > viewpointRow) {
- /*third quadrant */
- if (e.eventType == ENTERING_EVENT) {
- /*if it is ENTERING_EVENT */
- *y = e.row - 1;
- *x = e.col - 1;
- }
- else {
- /*otherwise it is EXITING_EVENT */
- *y = e.row + 1;
- *x = e.col + 1;
- }
-
- }
- else if (e.row == viewpointRow && e.col < viewpointCol) {
- /*between first and third quadrant */
- if (e.eventType == ENTERING_EVENT) { /*if it is ENTERING_EVENT */
- *y = e.row - 1;
- *x = e.col + 1;
- }
- else {
- /*otherwise it is EXITING_EVENT */
- *y = e.row + 1;
- *x = e.col + 1;
- }
- }
- else {
- /*must be the viewpoint cell itself */
- G_debug(1, "calculate_event_row_col() called for viewpoint cell itself");
- assert(e.row == viewpointRow && e.col == viewpointCol);
- *x = e.col;
- *y = e.row;
- }
-
- /* assert(fabs(*x - e.col) <= 1 && fabs(*y - e.row) <= 1); */
-
- if ((abs(*x - e.col) > 1) || (abs(*y - e.row) > 1)) {
- G_warning("calculate_event_row_col() :");
- G_warning("x-e.col=%d, y-e.row=%d", abs(*x - e.col), abs(*y - e.row));
- print_event(e, 0);
- G_warning("vp=(%d, %d), x=%d, y=%d", viewpointRow, viewpointCol, *x, *y);
- exit(1);
- }
-
- return;
-}
-
-/* ------------------------------------------------------------ */
-void print_event(AEvent a, int debug_level)
-{
- char c = '0';
-
- if (a.eventType == ENTERING_EVENT)
- c = 'E';
- if (a.eventType == EXITING_EVENT)
- c = 'X';
- if (a.eventType == CENTER_EVENT)
- c = 'Q';
-
- if (debug_level < 1)
- G_warning("ev=[(%3d, %3d), e=%8.1f a=%4.2f t=%c] ",
- a.row, a.col, a.elev[1], a.angle, c);
- else
- G_debug(debug_level, "ev=[(%3d, %3d), e=%8.1f a=%4.2f t=%c] ",
- a.row, a.col, a.elev[1], a.angle, c);
- return;
-}
-
-
-/* ------------------------------------------------------------ */
-/*computes the distance from the event to the viewpoint. Note: all 3
- //events associate to a cell are considered at the same distance, from
- //the center of the cell to the viewpoint */
-double
-get_square_distance_from_viewpoint(const AEvent & a, const Viewpoint & vp)
-{
-
- double eventy, eventx;
-
- calculate_event_position(a, vp.row, vp.col, &eventy, &eventx);
-
- double dist = (eventx - vp.col) * (eventx - vp.col) +
- (eventy - vp.row) * (eventy - vp.row);
- /*don't take sqrt, it is expensive; suffices for comparison */
- return dist;
-}
-
-/* ------------------------------------------------------------ */
-/* a duplicate of get_square_distance_from_viewpoint() needed for debug */
-double
-get_square_distance_from_viewpoint_with_print(const AEvent & a,
- const Viewpoint & vp)
-{
-
- double eventy, eventx;
-
- calculate_event_position(a, vp.row, vp.col, &eventy, &eventx);
- double dist = (eventx - vp.col) * (eventx - vp.col) +
- (eventy - vp.row) * (eventy - vp.row);
- /*don't take sqrt, it is expensive; suffices for comparison */
-
- print_event(a, 2);
- G_debug(2, " pos= (%.3f. %.3f) sqdist=%.3f", eventx, eventy, dist);
-
- return dist;
-}
-
-
-/* ------------------------------------------------------------ */
-/*determines if the point at row,col is outside the maximum distance
- limit. Return 1 if the point is outside limit, 0 if point is inside
- limit. */
-int is_point_outside_max_dist(Viewpoint vp, GridHeader hd,
- dimensionType row, dimensionType col,
- float maxDist)
-{
- /* it is not too smart to compare floats */
- if ((int)maxDist == INFINITY_DISTANCE)
- return 0;
-
- if (maxDist < G_distance(G_col_to_easting(vp.col + 0.5, &hd.window),
- G_row_to_northing(vp.row + 0.5, &hd.window),
- G_col_to_easting(col + 0.5, &hd.window),
- G_row_to_northing(row + 0.5, &hd.window))) {
- return 1;
- }
-
- return 0;
-}
-
-
-
-/* ------------------------------------------------------------
- //note: this is expensive because distance is not storedin the event
- //and must be computed on the fly */
-int DistanceCompare::compare(const AEvent & a, const AEvent & b)
-{
-
- /*calculate distance from viewpoint
- //don't take sqrt, it is expensive; suffices for comparison */
- double da, db;
-
- /*da = get_square_distance_from_viewpoint(a, globalVP);
- //db = get_square_distance_from_viewpoint(b, globalVP); */
-
- /*in the event these are not inlined */
- double eventy, eventx;
-
- calculate_event_position(a, globalVP.row, globalVP.col, &eventy, &eventx);
- da = (eventx - globalVP.col) * (eventx - globalVP.col) +
- (eventy - globalVP.row) * (eventy - globalVP.row);
- calculate_event_position(b, globalVP.row, globalVP.col, &eventy, &eventx);
- db = (eventx - globalVP.col) * (eventx - globalVP.col) +
- (eventy - globalVP.row) * (eventy - globalVP.row);
-
- if (da > db) {
- return 1;
- }
- else if (da < db) {
- return -1;
- }
- else {
- return 0;
- }
- return 0;
-}
-
-
-/* ------------------------------------------------------------ */
-int RadialCompare::compare(const AEvent & a, const AEvent & b)
-{
-
- if (a.row == b.row && a.col == b.col && a.eventType == b.eventType)
- return 0;
-
- assert(a.angle >= 0 && b.angle >= 0);
-
- if (a.angle > b.angle) {
- return 1;
- }
- else if (a.angle < b.angle) {
- return -1;
- }
- else {
- /*a.angle == b.angle */
- if (a.eventType == EXITING_EVENT)
- return -1;
- else if (a.eventType == ENTERING_EVENT)
- return 1;
- return 0;
- }
-}
-
-/* ------------------------------------------------------------ */
-/* a copy of the function above is needed by qsort, when the
- computation runs in memory */
-
-int radial_compare_events(const void *x, const void *y)
-{
-
- AEvent *a, *b;
-
- a = (AEvent *) x;
- b = (AEvent *) y;
- if (a->row == b->row && a->col == b->col && a->eventType == b->eventType)
- return 0;
-
- assert(a->angle >= 0 && b->angle >= 0);
-
- if (a->angle > b->angle) {
- return 1;
- }
- else if (a->angle < b->angle) {
- return -1;
- }
- else {
- /*a->angle == b->angle */
- if (a->eventType == EXITING_EVENT)
- return -1;
- else if (a->eventType == ENTERING_EVENT)
- return 1;
- return 0;
- }
-}
-
-
-
-/* ------------------------------------------------------------ */
-/*sort the event list in radial order */
-void sort_event_list(AMI_STREAM < AEvent > **eventList)
-{
-
- /*printf("sorting events.."); fflush(stdout); */
- assert(*eventList);
-
- AMI_STREAM < AEvent > *sortedStr;
- RadialCompare cmpObj;
- AMI_err ae;
-
- ae = AMI_sort(*eventList, &sortedStr, &cmpObj, 1);
- assert(ae == AMI_ERROR_NO_ERROR);
- *eventList = sortedStr;
- /*printf("..done.\n"); fflush(stdout); */
- return;
-}
-
-
-/* ------------------------------------------------------------ */
-/*sort the event list in distance order */
-void
-sort_event_list_by_distance(AMI_STREAM < AEvent > **eventList, Viewpoint vp)
-{
-
- /*printf("sorting events by distance from viewpoint.."); fflush(stdout); */
- assert(*eventList);
-
- AMI_STREAM < AEvent > *sortedStr;
- DistanceCompare cmpObj;
-
- globalVP.row = vp.row;
- globalVP.col = vp.col;
- /*printViewpoint(globalVP); */
- AMI_err ae;
-
- ae = AMI_sort(*eventList, &sortedStr, &cmpObj, 1);
- assert(ae == AMI_ERROR_NO_ERROR);
- *eventList = sortedStr;
- /*printf("..sorting done.\n"); fflush(stdout); */
- return;
-}
-
Copied: grass/trunk/raster/r.viewshed/eventlist.cpp (from rev 49482, grass-addons/raster/r.viewshed/eventlist.cc)
===================================================================
--- grass/trunk/raster/r.viewshed/eventlist.cpp (rev 0)
+++ grass/trunk/raster/r.viewshed/eventlist.cpp 2011-12-02 09:56:38 UTC (rev 49483)
@@ -0,0 +1,718 @@
+
+/****************************************************************************
+ *
+ * MODULE: r.viewshed
+ *
+ * AUTHOR(S): Laura Toma, Bowdoin College - ltoma at bowdoin.edu
+ * Yi Zhuang - yzhuang at bowdoin.edu
+
+ * Ported to GRASS by William Richard -
+ * wkrichar at bowdoin.edu or willster3021 at 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 <stdlib.h>
+#include <stdio.h>
+#include <assert.h>
+
+extern "C"
+{
+#include <grass/gis.h>
+}
+
+#include "eventlist.h"
+
+
+
+/* forced to use this because DistanceCompare::compare has troubles if
+ i put it inside the class */
+Viewpoint globalVP;
+
+
+
+/* ------------------------------------------------------------
+ compute the gradient of the CENTER of this event wrt viewpoint. For
+ efficiency it does not compute the gradient, but the square of the
+ arctan of the gradient. Assuming all gradients are computed the same
+ way, this is correct. */
+double calculate_center_gradient(AEvent * e, Viewpoint * vp)
+{
+
+ assert(e && vp);
+ double gradient, sqdist;
+
+ /*square of the distance from the center of this event to vp */
+ sqdist = (e->row - vp->row) * (e->row - vp->row) +
+ (e->col - vp->col) * (e->col - vp->col);
+
+ gradient = (e->elev[1] - vp->elev) * (e->elev[1] - vp->elev) / sqdist;
+ /*maintain sign */
+ if (e->elev[1] < vp->elev)
+ gradient = -gradient;
+ return gradient;
+}
+
+
+
+
+
+/* ------------------------------------------------------------
+ //calculate the angle at which the event is. Return value is the angle.
+
+ angle quadrants:
+ 2 1
+ 3 4
+ ----->x
+ |
+ |
+ |
+ V y
+
+ */
+
+/*/////////////////////////////////////////////////////////////////////
+ //return the angle from this event wrt viewpoint; the type of the
+ //event is taken into position to compute a different amngle for each
+ //event associated with a cell */
+double calculate_event_angle(AEvent * e, Viewpoint * vp)
+{
+
+ assert(e && vp);
+ double ex, ey;
+
+ calculate_event_position(*e, vp->row, vp->col, &ey, &ex);
+ return calculate_angle(ex, ey, vp->col, vp->row);
+}
+
+
+/*/////////////////////////////////////////////////////////////////////
+ //calculate the exit angle corresponding to this cell */
+double
+calculate_exit_angle(dimensionType row, dimensionType col, Viewpoint * vp)
+{
+ AEvent e;
+ double x, y;
+
+ e.eventType = EXITING_EVENT;
+ e.angle = 0;
+ e.elev[0] = e.elev[1] = e.elev[2] = 0;
+ e.row = row;
+ e.col = col;
+ calculate_event_position(e, vp->row, vp->col, &y, &x);
+ return calculate_angle(x, y, vp->col, vp->row);
+}
+
+
+/*/////////////////////////////////////////////////////////////////////
+ //calculate the enter angle corresponding to this cell */
+double
+calculate_enter_angle(dimensionType row, dimensionType col, Viewpoint * vp)
+{
+ AEvent e;
+ double x, y;
+
+ e.eventType = ENTERING_EVENT;
+ e.angle = 0;
+ e.elev[0] = e.elev[1] = e.elev[2] = 0;
+ e.row = row;
+ e.col = col;
+ calculate_event_position(e, vp->row, vp->col, &y, &x);
+ return calculate_angle(x, y, vp->col, vp->row);
+}
+
+/*///////////////////////////////////////////////////////////////////// */
+double
+calculate_angle(double eventX, double eventY,
+ double viewpointX, double viewpointY)
+{
+ double angle = atan(fabs(eventY - viewpointY) / fabs(eventX - viewpointX));
+
+ /*M_PI is defined in math.h to represent 3.14159... */
+ if (viewpointY == eventY && eventX > viewpointX) {
+ return 0; /*between 1st and 4th quadrant */
+ }
+ else if (eventX > viewpointX && eventY < viewpointY) {
+ /*first quadrant */
+ return angle;
+
+ }
+ else if (viewpointX == eventX && viewpointY > eventY) {
+ /*between 1st and 2nd quadrant */
+ return (M_PI) / 2;
+
+ }
+ else if (eventX < viewpointX && eventY < viewpointY) {
+ /*second quadrant */
+ return (M_PI - angle);
+
+ }
+ else if (viewpointY == eventY && eventX < viewpointX) {
+ /*between 1st and 3rd quadrant */
+ return M_PI;
+
+ }
+ else if (eventY > viewpointY && eventX < viewpointX) {
+ /*3rd quadrant */
+ return (M_PI + angle);
+
+ }
+ else if (viewpointX == eventX && viewpointY < eventY) {
+ /*between 3rd and 4th quadrant */
+ return (M_PI * 3.0 / 2.0);
+ }
+ else if (eventX > viewpointX && eventY > viewpointY) {
+ /*4th quadrant */
+ return (M_PI * 2.0 - angle);
+ }
+ assert(eventX == viewpointX && eventY == viewpointY);
+ return 0;
+}
+
+
+
+/* ------------------------------------------------------------ */
+/* calculate the exact position of the given event, and store them in x
+ and y.
+ quadrants: 1 2
+ 3 4
+ ----->x
+ |
+ |
+ |
+ V y
+ */
+void
+calculate_event_position(AEvent e, dimensionType viewpointRow,
+ dimensionType viewpointCol, double *y, double *x)
+{
+ assert(x && y);
+ *x = 0;
+ *y = 0;
+
+ if (e.eventType == CENTER_EVENT) {
+ /*FOR CENTER_EVENTS */
+ *y = e.row;
+ *x = e.col;
+ return;
+ }
+
+ if (e.row < viewpointRow && e.col < viewpointCol) {
+ /*first quadrant */
+ if (e.eventType == ENTERING_EVENT) {
+ /*if it is ENTERING_EVENT */
+ *y = e.row - 0.5;
+ *x = e.col + 0.5;
+ }
+ else {
+ /*otherwise it is EXITING_EVENT */
+ *y = e.row + 0.5;
+ *x = e.col - 0.5;
+ }
+
+ }
+ else if (e.col == viewpointCol && e.row < viewpointRow) {
+ /*between the first and second quadrant */
+ if (e.eventType == ENTERING_EVENT) {
+ /*if it is ENTERING_EVENT */
+ *y = e.row + 0.5;
+ *x = e.col + 0.5;
+ }
+ else {
+ /*otherwise it is EXITING_EVENT */
+ *y = e.row + 0.5;
+ *x = e.col - 0.5;
+ }
+
+ }
+ else if (e.col > viewpointCol && e.row < viewpointRow) {
+ /*second quadrant */
+ if (e.eventType == ENTERING_EVENT) {
+ /*if it is ENTERING_EVENT */
+ *y = e.row + 0.5;
+ *x = e.col + 0.5;
+ }
+ else { /*otherwise it is EXITING_EVENT */
+ *y = e.row - 0.5;
+ *x = e.col - 0.5;
+ }
+
+ }
+ else if (e.row == viewpointRow && e.col > viewpointCol) {
+ /*between the second and the fourth quadrant */
+ if (e.eventType == ENTERING_EVENT) {
+ /*if it is ENTERING_EVENT */
+ *y = e.row + 0.5;
+ *x = e.col - 0.5;
+ }
+ else {
+ /*otherwise it is EXITING_EVENT */
+ *y = e.row - 0.5;
+ *x = e.col - 0.5;
+ }
+
+ }
+ else if (e.col > viewpointCol && e.row > viewpointRow) {
+ /*fourth quadrant */
+ if (e.eventType == ENTERING_EVENT) {
+ /*if it is ENTERING_EVENT */
+ *y = e.row + 0.5;
+ *x = e.col - 0.5;
+ }
+ else {
+ /*otherwise it is EXITING_EVENT */
+ *y = e.row - 0.5;
+ *x = e.col + 0.5;
+ }
+
+ }
+ else if (e.col == viewpointCol && e.row > viewpointRow) {
+ /*between the third and fourth quadrant */
+ if (e.eventType == ENTERING_EVENT) {
+ /*if it is ENTERING_EVENT */
+ *y = e.row - 0.5;
+ *x = e.col - 0.5;
+ }
+ else {
+ /*otherwise it is EXITING_EVENT */
+ *y = e.row - 0.5;
+ *x = e.col + 0.5;
+ }
+
+ }
+ else if (e.col < viewpointCol && e.row > viewpointRow) {
+ /*third quadrant */
+ if (e.eventType == ENTERING_EVENT) {
+ /*if it is ENTERING_EVENT */
+ *y = e.row - 0.5;
+ *x = e.col - 0.5;
+ }
+ else {
+ /*otherwise it is EXITING_EVENT */
+ *y = e.row + 0.5;
+ *x = e.col + 0.5;
+ }
+
+ }
+ else if (e.row == viewpointRow && e.col < viewpointCol) {
+ /*between first and third quadrant */
+ if (e.eventType == ENTERING_EVENT) { /*if it is ENTERING_EVENT */
+ *y = e.row - 0.5;
+ *x = e.col + 0.5;
+ }
+ else {
+ /*otherwise it is EXITING_EVENT */
+ *y = e.row + 0.5;
+ *x = e.col + 0.5;
+ }
+ }
+ else {
+ /*must be the viewpoint cell itself */
+ assert(e.row == viewpointRow && e.col == viewpointCol);
+ *x = e.col;
+ *y = e.row;
+ }
+
+ assert(fabs(*x - e.col) < 1 && fabs(*y - e.row) < 1);
+ /*
+ if ((fabs(*x -e.col) >=1) || (fabs(*y -e.row) >=1)) {
+ G_warning("x-e.col=%f, y-e.row=%f ", fabs(*x -e.col), fabs(*y -e.row));
+ print_event(e, 0);
+ G_warning("vp=(%d, %d), x=%.3f, y=%.3f", viewpointRow, viewpointCol, *x, *y);
+ exit(1);
+ }
+ */
+ return;
+}
+
+void
+calculate_event_row_col(AEvent e, dimensionType viewpointRow,
+ dimensionType viewpointCol, int *y, int *x)
+{
+ assert(x && y);
+ *x = 0;
+ *y = 0;
+
+ if (e.eventType == CENTER_EVENT) {
+ G_fatal_error("calculate_event_row_col() must not be called for CENTER events");
+ }
+
+ if (e.row < viewpointRow && e.col < viewpointCol) {
+ /*first quadrant */
+ if (e.eventType == ENTERING_EVENT) {
+ /*if it is ENTERING_EVENT */
+ *y = e.row - 1;
+ *x = e.col + 1;
+ }
+ else {
+ /*otherwise it is EXITING_EVENT */
+ *y = e.row + 1;
+ *x = e.col - 1;
+ }
+
+ }
+ else if (e.col == viewpointCol && e.row < viewpointRow) {
+ /*between the first and second quadrant */
+ if (e.eventType == ENTERING_EVENT) {
+ /*if it is ENTERING_EVENT */
+ *y = e.row + 1;
+ *x = e.col + 1;
+ }
+ else {
+ /*otherwise it is EXITING_EVENT */
+ *y = e.row + 1;
+ *x = e.col - 1;
+ }
+
+ }
+ else if (e.col > viewpointCol && e.row < viewpointRow) {
+ /*second quadrant */
+ if (e.eventType == ENTERING_EVENT) {
+ /*if it is ENTERING_EVENT */
+ *y = e.row + 1;
+ *x = e.col + 1;
+ }
+ else { /*otherwise it is EXITING_EVENT */
+ *y = e.row - 1;
+ *x = e.col - 1;
+ }
+
+ }
+ else if (e.row == viewpointRow && e.col > viewpointCol) {
+ /*between the second and the fourth quadrant */
+ if (e.eventType == ENTERING_EVENT) {
+ /*if it is ENTERING_EVENT */
+ *y = e.row + 1;
+ *x = e.col - 1;
+ }
+ else {
+ /*otherwise it is EXITING_EVENT */
+ *y = e.row - 1;
+ *x = e.col - 1;
+ }
+
+ }
+ else if (e.col > viewpointCol && e.row > viewpointRow) {
+ /*fourth quadrant */
+ if (e.eventType == ENTERING_EVENT) {
+ /*if it is ENTERING_EVENT */
+ *y = e.row + 1;
+ *x = e.col - 1;
+ }
+ else {
+ /*otherwise it is EXITING_EVENT */
+ *y = e.row - 1;
+ *x = e.col + 1;
+ }
+
+ }
+ else if (e.col == viewpointCol && e.row > viewpointRow) {
+ /*between the third and fourth quadrant */
+ if (e.eventType == ENTERING_EVENT) {
+ /*if it is ENTERING_EVENT */
+ *y = e.row - 1;
+ *x = e.col - 1;
+ }
+ else {
+ /*otherwise it is EXITING_EVENT */
+ *y = e.row - 1;
+ *x = e.col + 1;
+ }
+
+ }
+ else if (e.col < viewpointCol && e.row > viewpointRow) {
+ /*third quadrant */
+ if (e.eventType == ENTERING_EVENT) {
+ /*if it is ENTERING_EVENT */
+ *y = e.row - 1;
+ *x = e.col - 1;
+ }
+ else {
+ /*otherwise it is EXITING_EVENT */
+ *y = e.row + 1;
+ *x = e.col + 1;
+ }
+
+ }
+ else if (e.row == viewpointRow && e.col < viewpointCol) {
+ /*between first and third quadrant */
+ if (e.eventType == ENTERING_EVENT) { /*if it is ENTERING_EVENT */
+ *y = e.row - 1;
+ *x = e.col + 1;
+ }
+ else {
+ /*otherwise it is EXITING_EVENT */
+ *y = e.row + 1;
+ *x = e.col + 1;
+ }
+ }
+ else {
+ /*must be the viewpoint cell itself */
+ G_debug(1, "calculate_event_row_col() called for viewpoint cell itself");
+ assert(e.row == viewpointRow && e.col == viewpointCol);
+ *x = e.col;
+ *y = e.row;
+ }
+
+ /* assert(fabs(*x - e.col) <= 1 && fabs(*y - e.row) <= 1); */
+
+ if ((abs(*x - e.col) > 1) || (abs(*y - e.row) > 1)) {
+ G_warning("calculate_event_row_col() :");
+ G_warning("x-e.col=%d, y-e.row=%d", abs(*x - e.col), abs(*y - e.row));
+ print_event(e, 0);
+ G_warning("vp=(%d, %d), x=%d, y=%d", viewpointRow, viewpointCol, *x, *y);
+ exit(1);
+ }
+
+ return;
+}
+
+/* ------------------------------------------------------------ */
+void print_event(AEvent a, int debug_level)
+{
+ char c = '0';
+
+ if (a.eventType == ENTERING_EVENT)
+ c = 'E';
+ if (a.eventType == EXITING_EVENT)
+ c = 'X';
+ if (a.eventType == CENTER_EVENT)
+ c = 'Q';
+
+ if (debug_level < 1)
+ G_warning("ev=[(%3d, %3d), e=%8.1f a=%4.2f t=%c] ",
+ a.row, a.col, a.elev[1], a.angle, c);
+ else
+ G_debug(debug_level, "ev=[(%3d, %3d), e=%8.1f a=%4.2f t=%c] ",
+ a.row, a.col, a.elev[1], a.angle, c);
+ return;
+}
+
+
+/* ------------------------------------------------------------ */
+/*computes the distance from the event to the viewpoint. Note: all 3
+ //events associate to a cell are considered at the same distance, from
+ //the center of the cell to the viewpoint */
+double
+get_square_distance_from_viewpoint(const AEvent & a, const Viewpoint & vp)
+{
+
+ double eventy, eventx;
+
+ calculate_event_position(a, vp.row, vp.col, &eventy, &eventx);
+
+ double dist = (eventx - vp.col) * (eventx - vp.col) +
+ (eventy - vp.row) * (eventy - vp.row);
+ /*don't take sqrt, it is expensive; suffices for comparison */
+ return dist;
+}
+
+/* ------------------------------------------------------------ */
+/* a duplicate of get_square_distance_from_viewpoint() needed for debug */
+double
+get_square_distance_from_viewpoint_with_print(const AEvent & a,
+ const Viewpoint & vp)
+{
+
+ double eventy, eventx;
+
+ calculate_event_position(a, vp.row, vp.col, &eventy, &eventx);
+ double dist = (eventx - vp.col) * (eventx - vp.col) +
+ (eventy - vp.row) * (eventy - vp.row);
+ /*don't take sqrt, it is expensive; suffices for comparison */
+
+ print_event(a, 2);
+ G_debug(2, " pos= (%.3f. %.3f) sqdist=%.3f", eventx, eventy, dist);
+
+ return dist;
+}
+
+
+/* ------------------------------------------------------------ */
+/*determines if the point at row,col is outside the maximum distance
+ limit. Return 1 if the point is outside limit, 0 if point is inside
+ limit. */
+int is_point_outside_max_dist(Viewpoint vp, GridHeader hd,
+ dimensionType row, dimensionType col,
+ float maxDist)
+{
+ /* it is not too smart to compare floats */
+ if ((int)maxDist == INFINITY_DISTANCE)
+ return 0;
+
+ if (maxDist < G_distance(Rast_col_to_easting(vp.col + 0.5, &hd.window),
+ Rast_row_to_northing(vp.row + 0.5, &hd.window),
+ Rast_col_to_easting(col + 0.5, &hd.window),
+ Rast_row_to_northing(row + 0.5, &hd.window))) {
+ return 1;
+ }
+
+ return 0;
+}
+
+
+
+/* ------------------------------------------------------------
+ //note: this is expensive because distance is not storedin the event
+ //and must be computed on the fly */
+int DistanceCompare::compare(const AEvent & a, const AEvent & b)
+{
+
+ /*calculate distance from viewpoint
+ //don't take sqrt, it is expensive; suffices for comparison */
+ double da, db;
+
+ /*da = get_square_distance_from_viewpoint(a, globalVP);
+ //db = get_square_distance_from_viewpoint(b, globalVP); */
+
+ /*in the event these are not inlined */
+ double eventy, eventx;
+
+ calculate_event_position(a, globalVP.row, globalVP.col, &eventy, &eventx);
+ da = (eventx - globalVP.col) * (eventx - globalVP.col) +
+ (eventy - globalVP.row) * (eventy - globalVP.row);
+ calculate_event_position(b, globalVP.row, globalVP.col, &eventy, &eventx);
+ db = (eventx - globalVP.col) * (eventx - globalVP.col) +
+ (eventy - globalVP.row) * (eventy - globalVP.row);
+
+ if (da > db) {
+ return 1;
+ }
+ else if (da < db) {
+ return -1;
+ }
+ else {
+ return 0;
+ }
+ return 0;
+}
+
+
+/* ------------------------------------------------------------ */
+int RadialCompare::compare(const AEvent & a, const AEvent & b)
+{
+
+ if (a.row == b.row && a.col == b.col && a.eventType == b.eventType)
+ return 0;
+
+ assert(a.angle >= 0 && b.angle >= 0);
+
+ if (a.angle > b.angle) {
+ return 1;
+ }
+ else if (a.angle < b.angle) {
+ return -1;
+ }
+ else {
+ /*a.angle == b.angle */
+ if (a.eventType == EXITING_EVENT)
+ return -1;
+ else if (a.eventType == ENTERING_EVENT)
+ return 1;
+ return 0;
+ }
+}
+
+/* ------------------------------------------------------------ */
+/* a copy of the function above is needed by qsort, when the
+ computation runs in memory */
+
+int radial_compare_events(const void *x, const void *y)
+{
+
+ AEvent *a, *b;
+
+ a = (AEvent *) x;
+ b = (AEvent *) y;
+ if (a->row == b->row && a->col == b->col && a->eventType == b->eventType)
+ return 0;
+
+ assert(a->angle >= 0 && b->angle >= 0);
+
+ if (a->angle > b->angle) {
+ return 1;
+ }
+ else if (a->angle < b->angle) {
+ return -1;
+ }
+ else {
+ /*a->angle == b->angle */
+ if (a->eventType == EXITING_EVENT)
+ return -1;
+ else if (a->eventType == ENTERING_EVENT)
+ return 1;
+ return 0;
+ }
+}
+
+
+
+/* ------------------------------------------------------------ */
+/*sort the event list in radial order */
+void sort_event_list(AMI_STREAM < AEvent > **eventList)
+{
+
+ /*printf("sorting events.."); fflush(stdout); */
+ assert(*eventList);
+
+ AMI_STREAM < AEvent > *sortedStr;
+ RadialCompare cmpObj;
+ AMI_err ae;
+
+ ae = AMI_sort(*eventList, &sortedStr, &cmpObj, 1);
+ assert(ae == AMI_ERROR_NO_ERROR);
+ *eventList = sortedStr;
+ /*printf("..done.\n"); fflush(stdout); */
+ return;
+}
+
+
+/* ------------------------------------------------------------ */
+/*sort the event list in distance order */
+void
+sort_event_list_by_distance(AMI_STREAM < AEvent > **eventList, Viewpoint vp)
+{
+
+ /*printf("sorting events by distance from viewpoint.."); fflush(stdout); */
+ assert(*eventList);
+
+ AMI_STREAM < AEvent > *sortedStr;
+ DistanceCompare cmpObj;
+
+ globalVP.row = vp.row;
+ globalVP.col = vp.col;
+ /*printViewpoint(globalVP); */
+ AMI_err ae;
+
+ ae = AMI_sort(*eventList, &sortedStr, &cmpObj, 1);
+ assert(ae == AMI_ERROR_NO_ERROR);
+ *eventList = sortedStr;
+ /*printf("..sorting done.\n"); fflush(stdout); */
+ return;
+}
+
Deleted: grass/trunk/raster/r.viewshed/grass.cc
===================================================================
--- grass-addons/raster/r.viewshed/grass.cc 2011-12-02 09:30:54 UTC (rev 49482)
+++ grass/trunk/raster/r.viewshed/grass.cc 2011-12-02 09:56:38 UTC (rev 49483)
@@ -1,1030 +0,0 @@
-
-/****************************************************************************
- *
- * MODULE: r.viewshed
- *
- * AUTHOR(S): Laura Toma, Bowdoin College - ltoma at bowdoin.edu
- * Yi Zhuang - yzhuang at bowdoin.edu
- *
- * Ported to GRASS by William Richard -
- * wkrichar at bowdoin.edu or willster3021 at 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 <stdlib.h>
-#include <stdio.h>
-
-extern "C"
-{
-#include <grass/config.h>
-#include <grass/gis.h>
-#include <grass/glocale.h>
-}
-
-#include "grass.h"
-#include "visibility.h"
-
-
-
-
-
-/* ------------------------------------------------------------ */
-/* If viewOptions.doCurv is on then adjust the passed height for
- curvature of the earth; otherwise return the passed height
- unchanged.
- If viewOptions.doRefr is on then adjust the curved height for
- the effect of atmospheric refraction too.
- */
-surface_type adjust_for_curvature(Viewpoint vp, double row,
- double col, surface_type h,
- ViewOptions viewOptions, GridHeader *hd)
-{
-
- if (!viewOptions.doCurv)
- return h;
-
- assert(viewOptions.ellps_a != 0);
-
- /* distance must be in meters because ellps_a is in meters */
- double dist = G_distance(G_col_to_easting(vp.col + 0.5, &(hd->window)),
- G_row_to_northing(vp.row + 0.5, &(hd->window)),
- G_col_to_easting(col + 0.5, &(hd->window)),
- G_row_to_northing(row + 0.5, &(hd->window)));
-
- double adjustment = (dist * dist) / (2.0 * viewOptions.ellps_a);
-
- if (!viewOptions.doRefr)
- return h - adjustment;
-
- return h - (adjustment * (1.0 - viewOptions.refr_coef));
-}
-
-
-
-/* ************************************************************ */
-/*return a GridHeader that has all the relevant data filled in */
-GridHeader *read_header(char *rastName, Cell_head * region)
-{
-
- assert(rastName);
-
- /*allocate the grid header to fill */
- GridHeader *hd = (GridHeader *) G_malloc(sizeof(GridHeader));
-
- assert(hd);
-
- /*get the num rows and cols from GRASS */
- int nrows, ncols;
-
- nrows = G_window_rows();
- ncols = G_window_cols();
- /*check for loss of prescion */
- if (nrows <= maxDimension && ncols <= maxDimension) {
- hd->nrows = (dimensionType) nrows;
- hd->ncols = (dimensionType) ncols;
- }
- else
- G_fatal_error(_("Grid dimension too big for current precision"));
-
-
- /*fill in rest of header */
- hd->xllcorner = G_col_to_easting(0, region);
- hd->yllcorner = G_row_to_northing(0, region);
- /* Cell_head stores 2 resolutions, while GridHeader only stores 1 */
- // make sure the two Cell_head resolutions are equal
- if (fabs(region->ew_res - region->ns_res) > .001) {
- G_warning(_("East-west resolution does not equal north-south resolution. "
- "The viewshed computation assumes the cells are square, so in "
- "this case this may result in innacuracies."));
- // exit(EXIT_FAILURE);
- }
- hd->ew_res = region->ew_res;
- hd->ns_res = region->ns_res;
- //store the null value of the map
- G_set_null_value(&(hd->nodata_value), 1, G_SURFACE_TYPE);
- G_message("Nodata value set to %f", hd->nodata_value);
-
-
-
- return hd;
-}
-
-/* calculate ENTER and EXIT event elevation (bilinear interpolation) */
-surface_type calculate_event_elevation(AEvent e, int nrows, int ncols,
- dimensionType vprow, dimensionType vpcol,
- G_SURFACE_T **inrast, RASTER_MAP_TYPE data_type)
-{
- int row1, col1;
- surface_type event_elev;
- G_SURFACE_T elev1, elev2, elev3, elev4;
-
- calculate_event_row_col(e, vprow, vpcol, &row1, &col1);
- if (row1 >= 0 && row1 < nrows && col1 >= 0 && col1 < ncols) {
- elev1 = inrast[row1 - e.row + 1][col1];
- elev2 = inrast[row1 - e.row + 1][e.col];
- elev3 = inrast[1][col1];
- elev4 = inrast[1][e.col];
- if (G_is_null_value(&elev1, data_type) || G_is_null_value(&elev2, data_type) ||
- G_is_null_value(&elev3, data_type) || G_is_null_value(&elev4, data_type))
- event_elev = inrast[1][e.col];
- else {
- event_elev = (elev1 + elev2 + elev3 + elev4) / 4.;
- }
- }
- else
- event_elev = inrast[1][e.col];
-
- return event_elev;
-}
-
-
-/* ************************************************************ */
-/* input: an array capable to hold the max number of events, a raster
- name, a viewpoint and the viewOptions; action: figure out all events
- in the input file, and write them to the event list. data is
- allocated and initialized with all the cells on the same row as the
- viewpoint. it returns the number of events. initialize and fill
- AEvent* with all the events for the map. Used when solving in
- memory, so the AEvent* should fit in memory. */
-size_t
-init_event_list_in_memory(AEvent * eventList, char *rastName,
- Viewpoint * vp, GridHeader * hd,
- ViewOptions viewOptions, surface_type ***data,
- MemoryVisibilityGrid * visgrid)
-{
-
- G_message(_("Computing events ..."));
- assert(eventList && vp && visgrid);
- //GRASS should be defined
-
- /*alloc data ; data is used to store all the cells on the same row
- as the viewpoint. */
- *data = (surface_type **)G_malloc(3 * sizeof(surface_type *));
- assert(*data);
- (*data)[0] = (surface_type *)G_malloc(3 * G_window_cols() * sizeof(surface_type));
- assert((*data)[0]);
- (*data)[1] = (*data)[0] + G_window_cols();
- (*data)[2] = (*data)[1] + G_window_cols();
-
- /*get the mapset name */
- char *mapset;
-
- mapset = G_find_cell(rastName, "");
- if (mapset == NULL)
- G_fatal_error(_("Raster map [%s] not found"), rastName);
-
- /*open map */
- int infd;
-
- if ((infd = G_open_cell_old(rastName, mapset)) < 0)
- G_fatal_error(_("Cannot open raster file [%s]"), rastName);
-
- /*get the data_type */
- RASTER_MAP_TYPE data_type;
-
- /* data_type = G_raster_map_type(rastName, mapset); */
- data_type = G_SURFACE_TYPE;
-
- /*buffer to hold 3 rows */
- G_SURFACE_T **inrast;
- int nrows = G_window_rows();
- int ncols = G_window_cols();
-
- inrast = (G_SURFACE_T **)G_malloc(3 * sizeof(G_SURFACE_T *));
- assert(inrast);
- inrast[0] = (G_SURFACE_T *)G_allocate_raster_buf(data_type);
- assert(inrast[0]);
- inrast[1] = (G_SURFACE_T *)G_allocate_raster_buf(data_type);
- assert(inrast[1]);
- inrast[2] = (G_SURFACE_T *)G_allocate_raster_buf(data_type);
- assert(inrast[2]);
-
- G_set_null_value(inrast[0], ncols, data_type);
- G_set_null_value(inrast[1], ncols, data_type);
- G_set_null_value(inrast[2], ncols, data_type);
-
- /*DCELL to check for loss of prescion- haven't gotten that to work
- yet though */
- DCELL d;
- int isnull = 0;
-
- /*keep track of the number of events added, to be returned later */
- size_t nevents = 0;
-
- /*scan through the raster data */
- dimensionType i, j, k;
- int row1, col1;
- double ax, ay;
- G_SURFACE_T *elev1, *elev2, *elev3, *elev4;
- AEvent e;
-
- /* read first row */
- G_get_raster_row(infd, inrast[2], 0, data_type);
-
- e.angle = -1;
- for (i = 0; i < nrows; i++) {
- /*read in the raster row */
- int rasterRowResult = 1;
-
- G_SURFACE_T *tmprast = inrast[0];
- inrast[0] = inrast[1];
- inrast[1] = inrast[2];
- inrast[2] = tmprast;
-
- if (i < nrows - 1)
- rasterRowResult = G_get_raster_row(infd, inrast[2], i + 1, data_type);
- else
- G_set_null_value(inrast[2], ncols, data_type);
-
- if (rasterRowResult <= 0)
- G_fatal_error(_("Coord not read from row %d of <%s>"), i,
- rastName);
-
- G_percent(i, nrows, 2);
-
- /*fill event list with events from this row */
- for (j = 0; j < G_window_cols(); j++) {
- e.row = i;
- e.col = j;
-
- /*read the elevation value into the event */
- isnull = G_is_null_value(&(inrast[1][j]), data_type);
- e.elev[1] = inrast[1][j];
-
- /* adjust for curvature */
- e.elev[1] = adjust_for_curvature(*vp, i, j, e.elev[1], viewOptions, hd);
-
- /*write it into the row of data going through the viewpoint */
- if (i == vp->row) {
- (*data)[0][j] = e.elev[1];
- (*data)[1][j] = e.elev[1];
- (*data)[2][j] = e.elev[1];
- }
-
- /* set the viewpoint, and don't insert it into eventlist */
- if (i == vp->row && j == vp->col) {
- set_viewpoint_elev(vp, e.elev[1] + viewOptions.obsElev);
- if (viewOptions.tgtElev > 0)
- vp->target_offset = viewOptions.tgtElev;
- else
- vp->target_offset = 0.;
- if (isnull) {
- /*what to do when viewpoint is NODATA ? */
- G_warning(_("Viewpoint is NODATA."));
- G_message(_("Will assume its elevation is = %f"),
- vp->elev);
- }
-
- add_result_to_inmem_visibilitygrid(visgrid, i, j,
- 180);
- continue;
- }
-
- /*don't insert in eventlist nodata cell events */
- if (isnull) {
- /* record this cell as being NODATA; this is necessary so
- that we can distingush invisible events, from nodata
- events in the output */
- add_result_to_inmem_visibilitygrid(visgrid, i, j,
- hd->nodata_value);
- continue;
- }
-
- /* if point is outside maxDist, do NOT include it as an
- event */
- if (is_point_outside_max_dist
- (*vp, *hd, i, j, viewOptions.maxDist))
- continue;
-
- /* if it got here it is not the viewpoint, not NODATA, and
- within max distance from viewpoint; generate its 3 events
- and insert them */
-
- /* get ENTER elevation */
- e.eventType = ENTERING_EVENT;
- e.elev[0] = calculate_event_elevation(e, nrows, ncols,
- vp->row, vp->col, inrast, data_type);
- /* adjust for curvature */
- if (viewOptions.doCurv) {
- calculate_event_position(e, vp->row, vp->col, &ay, &ax);
- e.elev[0] = adjust_for_curvature(*vp, ay, ax, e.elev[0], viewOptions, hd);
- }
-
- /* get EXIT elevation */
- e.eventType = EXITING_EVENT;
- e.elev[2] = calculate_event_elevation(e, nrows, ncols,
- vp->row, vp->col, inrast, data_type);
- /* adjust for curvature */
- if (viewOptions.doCurv) {
- calculate_event_position(e, vp->row, vp->col, &ay, &ax);
- e.elev[2] = adjust_for_curvature(*vp, ay, ax, e.elev[2], viewOptions, hd);
- }
-
- /*write adjusted elevation into the row of data going through the viewpoint */
- if (i == vp->row) {
- (*data)[0][j] = e.elev[0];
- (*data)[1][j] = e.elev[1];
- (*data)[2][j] = e.elev[2];
- }
-
- /*put event into event list */
- e.eventType = ENTERING_EVENT;
- calculate_event_position(e, vp->row, vp->col, &ay, &ax);
- e.angle = calculate_angle(ax, ay, vp->col, vp->row);
- eventList[nevents] = e;
- nevents++;
-
- e.eventType = CENTER_EVENT;
- calculate_event_position(e, vp->row, vp->col, &ay, &ax);
- e.angle = calculate_angle(ax, ay, vp->col, vp->row);
- eventList[nevents] = e;
- nevents++;
-
- e.eventType = EXITING_EVENT;
- calculate_event_position(e, vp->row, vp->col, &ay, &ax);
- e.angle = calculate_angle(ax, ay, vp->col, vp->row);
- eventList[nevents] = e;
- nevents++;
-
- }
- }
- G_percent(nrows, nrows, 2);
-
- G_close_cell(infd);
-
- G_free(inrast[0]);
- G_free(inrast[1]);
- G_free(inrast[2]);
- G_free(inrast);
-
- return nevents;
-}
-
-
-
-
-
-/* ************************************************************ */
-/* input: an arcascii file, a grid header and a viewpoint; action:
- figure out all events in the input file, and write them to the
- stream. It assumes the file pointer is positioned rigth after the
- grid header so that this function can read all grid elements.
-
- if data is not NULL, it creates an array that stores all events on
- the same row as the viewpoint.
- */
-AMI_STREAM < AEvent > *init_event_list(char *rastName, Viewpoint * vp,
- GridHeader * hd,
- ViewOptions viewOptions,
- surface_type ***data,
- IOVisibilityGrid * visgrid)
-{
-
- G_message(_("Computing events ..."));
- assert(rastName && vp && hd && visgrid);
-
- if (data != NULL) {
- /*data is used to store all the cells on the same row as the
- //viewpoint. */
- *data = (surface_type **)G_malloc(3 * sizeof(surface_type *));
- assert(*data);
- (*data)[0] = (surface_type *)G_malloc(3 * G_window_cols() * sizeof(surface_type));
- assert((*data)[0]);
- (*data)[1] = (*data)[0] + G_window_cols();
- (*data)[2] = (*data)[1] + G_window_cols();
- }
-
- /*create the event stream that will hold the events */
- AMI_STREAM < AEvent > *eventList = new AMI_STREAM < AEvent > ();
- assert(eventList);
-
- /*determine which mapset we are in */
- char *mapset;
-
- mapset = G_find_cell(rastName, "");
- if (mapset == NULL)
- G_fatal_error(_("Raster map [%s] not found"), rastName);
-
- /*open map */
- int infd;
-
- if ((infd = G_open_cell_old(rastName, mapset)) < 0)
- G_fatal_error(_("Cannot open raster file [%s]"), rastName);
-
- RASTER_MAP_TYPE data_type;
-
- /* data_type = G_raster_map_type(rastName, mapset); */
- data_type = G_SURFACE_TYPE;
- G_SURFACE_T **inrast;
- int nrows = G_window_rows();
- int ncols = G_window_cols();
-
- inrast = (G_SURFACE_T **)G_malloc(3 * sizeof(G_SURFACE_T *));
- assert(inrast);
- inrast[0] = (G_SURFACE_T *)G_allocate_raster_buf(data_type);
- assert(inrast[0]);
- inrast[1] = (G_SURFACE_T *)G_allocate_raster_buf(data_type);
- assert(inrast[1]);
- inrast[2] = (G_SURFACE_T *)G_allocate_raster_buf(data_type);
- assert(inrast[2]);
-
- G_set_null_value(inrast[0], ncols, data_type);
- G_set_null_value(inrast[1], ncols, data_type);
- G_set_null_value(inrast[2], ncols, data_type);
-
- /*scan through the raster data */
- DCELL d;
- int isnull = 0;
- dimensionType i, j, k;
- int row1, col1;
- double ax, ay;
- G_SURFACE_T *elev1, *elev2, *elev3, *elev4;
- AEvent e;
-
- /* read first row */
- G_get_raster_row(infd, inrast[2], 0, data_type);
-
- e.angle = -1;
-
- /*start scanning through the grid */
- for (i = 0; i < nrows; i++) {
-
- G_percent(i, nrows, 2);
-
- /*read in the raster row */
- int rasterRowResult = 1;
-
- G_SURFACE_T *tmprast = inrast[0];
- inrast[0] = inrast[1];
- inrast[1] = inrast[2];
- inrast[2] = tmprast;
-
- if (i < nrows - 1)
- rasterRowResult = G_get_raster_row(infd, inrast[2], i + 1, data_type);
- else
- G_set_null_value(inrast[2], ncols, data_type);
-
- if (rasterRowResult <= 0)
- G_fatal_error(_("Coord not read from row %d of <%s>"), i,
- rastName);
-
- /*fill event list with events from this row */
- for (j = 0; j < ncols; j++) {
-
- e.row = i;
- e.col = j;
-
- /*read the elevation value into the event */
- isnull = G_is_null_value(&(inrast[1][j]), data_type);
- e.elev[1] = inrast[1][j];
-
- /* adjust for curvature */
- e.elev[1] = adjust_for_curvature(*vp, i, j, e.elev[1], viewOptions, hd);
-
- if (data != NULL) {
-
- /*write the row of data going through the viewpoint */
- if (i == vp->row) {
- (*data)[0][j] = e.elev[1];
- (*data)[1][j] = e.elev[1];
- (*data)[2][j] = e.elev[1];
- }
- }
-
- /* set the viewpoint */
- if (i == vp->row && j == vp->col) {
- set_viewpoint_elev(vp, e.elev[1] + viewOptions.obsElev);
- /*what to do when viewpoint is NODATA */
- if (is_nodata(hd, e.elev[1])) {
- G_warning("Viewpoint is NODATA.");
- G_message("Will assume its elevation is %.f", e.elev[1]);
- };
- if (viewOptions.tgtElev > 0)
- vp->target_offset = viewOptions.tgtElev;
- else
- vp->target_offset = 0.;
-
- /* add viewpoint to visibility grid */
- VisCell visCell = { i, j, 180 };
- add_result_to_io_visibilitygrid(visgrid, &visCell);
-
- /*don't insert viewpoint into eventlist */
- continue;
- }
-
- /*don't insert the nodata cell events */
- if (is_nodata(hd, e.elev[1])) {
- /* record this cell as being NODATA. ; this is necessary so
- that we can distingush invisible events, from nodata
- events in the output */
- VisCell visCell = { i, j, hd->nodata_value };
- add_result_to_io_visibilitygrid(visgrid, &visCell);
- continue;
- }
-
- /* if point is outside maxDist, do NOT include it as an
- event */
- if (is_point_outside_max_dist
- (*vp, *hd, i, j, viewOptions.maxDist))
- continue;
-
- /* get ENTER elevation */
- e.eventType = ENTERING_EVENT;
- e.elev[0] = calculate_event_elevation(e, nrows, ncols,
- vp->row, vp->col, inrast, data_type);
- /* adjust for curvature */
- if (viewOptions.doCurv) {
- calculate_event_position(e, vp->row, vp->col, &ay, &ax);
- e.elev[0] = adjust_for_curvature(*vp, ay, ax, e.elev[0], viewOptions, hd);
- }
-
- /* get EXIT elevation */
- e.eventType = EXITING_EVENT;
- e.elev[2] = calculate_event_elevation(e, nrows, ncols,
- vp->row, vp->col, inrast, data_type);
- /* adjust for curvature */
- if (viewOptions.doCurv) {
- calculate_event_position(e, vp->row, vp->col, &ay, &ax);
- e.elev[2] = adjust_for_curvature(*vp, ay, ax, e.elev[2], viewOptions, hd);
- }
-
- if (data != NULL) {
-
- /*write the row of data going through the viewpoint */
- if (i == vp->row) {
- (*data)[0][j] = e.elev[0];
- (*data)[1][j] = e.elev[1];
- (*data)[2][j] = e.elev[2];
- }
- }
-
- /*put event into event list */
- e.eventType = ENTERING_EVENT;
- calculate_event_position(e, vp->row, vp->col, &ay, &ax);
- e.angle = calculate_angle(ax, ay, vp->col, vp->row);
- eventList->write_item(e);
-
- e.eventType = CENTER_EVENT;
- calculate_event_position(e, vp->row, vp->col, &ay, &ax);
- e.angle = calculate_angle(ax, ay, vp->col, vp->row);
- eventList->write_item(e);
-
- e.eventType = EXITING_EVENT;
- calculate_event_position(e, vp->row, vp->col, &ay, &ax);
- e.angle = calculate_angle(ax, ay, vp->col, vp->row);
- eventList->write_item(e);
- } /* for j */
-
- } /* for i */
- G_percent(nrows, nrows, 2);
-
- G_close_cell(infd);
-
- G_free(inrast[0]);
- G_free(inrast[1]);
- G_free(inrast[2]);
- G_free(inrast);
-
- G_debug(1, "nbEvents = %lu", (unsigned long)eventList->stream_len());
- G_debug(1, "Event stream length: %lu x %dB (%lu MB)",
- (unsigned long)eventList->stream_len(), (int)sizeof(AEvent),
- (unsigned long)(((long long)(eventList->stream_len() *
- sizeof(AEvent))) >> 20));
-
- return eventList;
-}
-
-
-
-
-
-
-/* ************************************************************ */
-/* saves the grid into a GRASS raster. Loops through all elements x
- in row-column order and writes fun(x) to file. */
-void
-save_grid_to_GRASS(Grid * grid, char *filename, RASTER_MAP_TYPE type,
- float (*fun) (float))
-{
-
- G_message(_("Saving grid to <%s>"), filename);
- assert(grid && filename);
-
- /*open the new raster */
- int outfd;
-
- outfd = G_open_raster_new(filename, type);
-
- /*get the buffer to store values to read and write to each row */
- void *outrast;
-
- outrast = G_allocate_raster_buf(type);
- assert(outrast);
-
- dimensionType i, j;
-
- for (i = 0; i < G_window_rows(); i++) {
- for (j = 0; j < G_window_cols(); j++) {
-
- if (is_visible(grid->grid_data[i][j])) {
- switch (type) {
- case CELL_TYPE:
- ((CELL *) outrast)[j] = (CELL) fun(grid->grid_data[i][j]);
- break;
- case FCELL_TYPE:
- ((FCELL *) outrast)[j] = (FCELL) fun(grid->grid_data[i][j]);
- break;
- case DCELL_TYPE:
- ((DCELL *) outrast)[j] = (DCELL) fun(grid->grid_data[i][j]);
- break;
- }
- }
- else
- writeNodataValue(outrast, j, type);
- } /* for j */
- G_put_raster_row(outfd, outrast, type);
- } /* for i */
-
- G_close_cell(outfd);
- return;
-}
-
-
-
-
-
-/* ************************************************************ */
-/* using the visibility information recorded in visgrid, it creates an
- output viewshed raster with name outfname; for every point p that
- is visible in the grid, the corresponding value in the output
- raster is elevation(p) - viewpoint_elevation(p); the elevation
- values are read from elevfname raster */
-
-void
-save_vis_elev_to_GRASS(Grid * visgrid, char *elevfname, char *visfname,
- float vp_elev)
-{
-
- G_message(_("Saving grid to <%s>"), visfname);
- assert(visgrid && elevfname && visfname);
-
- /*get the mapset name */
- char *mapset;
-
- mapset = G_find_cell(elevfname, "");
- if (mapset == NULL)
- G_fatal_error(_("Raster map [%s] not found"), elevfname);
-
- /*open elevation map */
- int elevfd;
-
- if ((elevfd = G_open_cell_old(elevfname, mapset)) < 0)
- G_fatal_error(_("Cannot open raster file [%s]"), elevfname);
-
- /*get elevation data_type */
- RASTER_MAP_TYPE elev_data_type;
-
- elev_data_type = G_raster_map_type(elevfname, mapset);
-
- /* create the visibility raster of same type */
- int visfd;
-
- visfd = G_open_raster_new(visfname, elev_data_type);
-
- /*get the buffers to store each row */
- void *elevrast;
-
- elevrast = G_allocate_raster_buf(elev_data_type);
- assert(elevrast);
- void *visrast;
-
- visrast = G_allocate_raster_buf(elev_data_type);
- assert(visrast);
-
- dimensionType i, j;
- double elev = 0, viewshed_value;
-
- for (i = 0; i < G_window_rows(); i++) {
- /* get the row from elevation */
- if (G_get_raster_row(elevfd, elevrast, i, elev_data_type) <= 0)
- G_fatal_error(_("save_vis_elev_to_GRASS: could not read row %d"),
- i);
-
- for (j = 0; j < G_window_cols(); j++) {
-
- /* read the current elevation value */
- int isNull = 0;
-
- switch (elev_data_type) {
- case CELL_TYPE:
- isNull = G_is_c_null_value(&((CELL *) elevrast)[j]);
- elev = (double)(((CELL *) elevrast)[j]);
- break;
- case FCELL_TYPE:
- isNull = G_is_f_null_value(&((FCELL *) elevrast)[j]);
- elev = (double)(((FCELL *) elevrast)[j]);
- break;
- case DCELL_TYPE:
- isNull = G_is_d_null_value(&((DCELL *) elevrast)[j]);
- elev = (double)(((DCELL *) elevrast)[j]);
- break;
- }
-
- if (is_visible(visgrid->grid_data[i][j])) {
- /* elevation cannot be null */
- assert(!isNull);
- /* write elev - viewpoint_elevation */
- viewshed_value = elev - vp_elev;
- writeValue(visrast, j, viewshed_value, elev_data_type);
- }
- else if (is_invisible_not_nodata(visgrid->grid_data[i][j])) {
- /* elevation cannot be null */
- assert(!isNull);
- /* write INVISIBLE */
- /*
- viewshed_value = INVISIBLE;
- writeValue(visrast, j, viewshed_value, elev_data_type);
- */
- /* write NODATA */
- writeNodataValue(visrast, j, elev_data_type);
- }
- else {
- /* nodata */
- assert(isNull);
- /* write NODATA */
- writeNodataValue(visrast, j, elev_data_type);
- }
-
-
- } /* for j */
- G_put_raster_row(visfd, visrast, elev_data_type);
- } /* for i */
-
- G_close_cell(elevfd);
- G_close_cell(visfd);
- return;
-}
-
-
-
-
-/* helper function to deal with GRASS writing to a row buffer */
-void writeValue(void *bufrast, int j, double x, RASTER_MAP_TYPE data_type)
-{
-
- switch (data_type) {
- case CELL_TYPE:
- ((CELL *) bufrast)[j] = (CELL) x;
- break;
- case FCELL_TYPE:
- ((FCELL *) bufrast)[j] = (FCELL) x;
- break;
- case DCELL_TYPE:
- ((DCELL *) bufrast)[j] = (DCELL) x;
- break;
- default:
- G_fatal_error(_("Unknown data type"));
- }
-}
-
-void writeNodataValue(void *bufrast, int j, RASTER_MAP_TYPE data_type)
-{
-
- switch (data_type) {
- case CELL_TYPE:
- G_set_c_null_value(&((CELL *) bufrast)[j], 1);
- break;
- case FCELL_TYPE:
- G_set_f_null_value(&((FCELL *) bufrast)[j], 1);
- break;
- case DCELL_TYPE:
- G_set_d_null_value(&((DCELL *) bufrast)[j], 1);
- break;
- default:
- G_fatal_error(_("Unknown data type"));
- }
-}
-
-
-/* ************************************************************ */
-/* write the visibility grid to GRASS. assume all cells that are not
- in stream are NOT visible. assume stream is sorted in (i,j) order.
- for each value x it writes to grass fun(x) */
-void
-save_io_visibilitygrid_to_GRASS(IOVisibilityGrid * visgrid,
- char *fname, RASTER_MAP_TYPE type,
- float (*fun) (float))
-{
-
- G_message(_("Saving grid to <%s>"), fname);
- assert(fname && visgrid);
-
- /* open the output raster and set up its row buffer */
- int visfd;
-
- visfd = G_open_raster_new(fname, type);
- void *visrast;
-
- visrast = G_allocate_raster_buf(type);
- assert(visrast);
-
- /*set up reading data from visibility stream */
- AMI_STREAM < VisCell > *vstr = visgrid->visStr;
- off_t streamLen, counter = 0;
-
- streamLen = vstr->stream_len();
- vstr->seek(0);
-
- /*read the first element */
- AMI_err ae;
- VisCell *curResult = NULL;
-
- if (streamLen > 0) {
- ae = vstr->read_item(&curResult);
- assert(ae == AMI_ERROR_NO_ERROR);
- counter++;
- }
-
- dimensionType i, j;
-
- for (i = 0; i < G_window_rows(); i++) {
- for (j = 0; j < G_window_cols(); j++) {
-
- if (curResult->row == i && curResult->col == j) {
- /*cell is recodred in the visibility stream: it must be
- either visible, or NODATA */
- if (is_visible(curResult->angle))
- writeValue(visrast, j, fun(curResult->angle), type);
- else
- writeNodataValue(visrast, j, type);
-
- /*read next element of stream */
- if (counter < streamLen) {
- ae = vstr->read_item(&curResult);
- assert(ae == AMI_ERROR_NO_ERROR);
- counter++;
- }
- }
- else {
- /* this cell is not in stream, so it is invisible */
- writeNodataValue(visrast, j, type);
- }
- } /* for j */
-
- G_put_raster_row(visfd, visrast, type);
- } /* for i */
-
- G_close_cell(visfd);
-}
-
-
-
-
-
-
-
-/* ************************************************************ */
-/* using the visibility information recorded in visgrid, it creates
- an output viewshed raster with name outfname; for every point p
- that is visible in the grid, the corresponding value in the output
- raster is elevation(p) - viewpoint_elevation(p); the elevation
- values are read from elevfname raster. assume stream is sorted in
- (i,j) order. */
-void
-save_io_vis_and_elev_to_GRASS(IOVisibilityGrid * visgrid, char *elevfname,
- char *visfname, float vp_elev)
-{
-
- G_message(_("Saving grid to <%s>"), visfname);
- assert(visfname && visgrid);
-
- /*get mapset name and data type */
- char *mapset;
-
- mapset = G_find_cell(elevfname, "");
- if (mapset == NULL)
- G_fatal_error(_("Opening <%s>: cannot find raster"), elevfname);
-
- /*open elevation map */
- int elevfd;
-
- if ((elevfd = G_open_cell_old(elevfname, mapset)) < 0)
- G_fatal_error(_("Cannot open raster file [%s]"), elevfname);
-
- /*get elevation data_type */
- RASTER_MAP_TYPE elev_data_type;
-
- elev_data_type = G_raster_map_type(elevfname, mapset);
-
- /* open visibility raster */
- int visfd;
-
- visfd = G_open_raster_new(visfname, elev_data_type);
-
- /*get the buffers to store each row */
- void *elevrast;
-
- elevrast = G_allocate_raster_buf(elev_data_type);
- assert(elevrast);
- void *visrast;
-
- visrast = G_allocate_raster_buf(elev_data_type);
- assert(visrast);
-
- /*set up stream reading stuff */
- off_t streamLen, counter = 0;
- AMI_err ae;
- VisCell *curResult = NULL;
-
- AMI_STREAM < VisCell > *vstr = visgrid->visStr;
- streamLen = vstr->stream_len();
- vstr->seek(0);
-
- /*read the first element */
- if (streamLen > 0) {
- ae = vstr->read_item(&curResult);
- assert(ae == AMI_ERROR_NO_ERROR);
- counter++;
- }
-
- dimensionType i, j;
- double elev = 0, viewshed_value;
-
- for (i = 0; i < G_window_rows(); i++) {
-
- if (G_get_raster_row(elevfd, elevrast, i, elev_data_type) <= 0)
- G_fatal_error(_("Could not read row %d"), i);
-
- for (j = 0; j < G_window_cols(); j++) {
-
- /* read the current elevation value */
- int isNull = 0;
-
- switch (elev_data_type) {
- case CELL_TYPE:
- isNull = G_is_c_null_value(&((CELL *) elevrast)[j]);
- elev = (double)(((CELL *) elevrast)[j]);
- break;
- case FCELL_TYPE:
- isNull = G_is_f_null_value(&((FCELL *) elevrast)[j]);
- elev = (double)(((FCELL *) elevrast)[j]);
- break;
- case DCELL_TYPE:
- isNull = G_is_d_null_value(&((DCELL *) elevrast)[j]);
- elev = (double)(((DCELL *) elevrast)[j]);
- break;
- }
-
-
- if (curResult->row == i && curResult->col == j) {
- /*cell is recodred in the visibility stream: it must be
- either visible, or NODATA */
- if (is_visible(curResult->angle))
- writeValue(visrast, j, elev - vp_elev, elev_data_type);
- else
- writeNodataValue(visrast, j, elev_data_type);
- /*read next element of stream */
- if (counter < streamLen) {
- ae = vstr->read_item(&curResult);
- assert(ae == AMI_ERROR_NO_ERROR);
- counter++;
- }
- }
- else {
- /* this cell is not in stream, so it is invisible */
- writeNodataValue(visrast, j, elev_data_type);
- }
- } /* for j */
-
- G_put_raster_row(visfd, visrast, elev_data_type);
- } /* for i */
-
- G_close_cell(elevfd);
- G_close_cell(visfd);
- return;
-}
Copied: grass/trunk/raster/r.viewshed/grass.cpp (from rev 49482, grass-addons/raster/r.viewshed/grass.cc)
===================================================================
--- grass/trunk/raster/r.viewshed/grass.cpp (rev 0)
+++ grass/trunk/raster/r.viewshed/grass.cpp 2011-12-02 09:56:38 UTC (rev 49483)
@@ -0,0 +1,1011 @@
+
+/****************************************************************************
+ *
+ * MODULE: r.viewshed
+ *
+ * AUTHOR(S): Laura Toma, Bowdoin College - ltoma at bowdoin.edu
+ * Yi Zhuang - yzhuang at bowdoin.edu
+ *
+ * Ported to GRASS by William Richard -
+ * wkrichar at bowdoin.edu or willster3021 at 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 <stdlib.h>
+#include <stdio.h>
+
+extern "C"
+{
+#include <grass/config.h>
+#include <grass/gis.h>
+#include <grass/glocale.h>
+}
+
+#include "grass.h"
+#include "visibility.h"
+
+
+
+
+
+/* ------------------------------------------------------------ */
+/* If viewOptions.doCurv is on then adjust the passed height for
+ curvature of the earth; otherwise return the passed height
+ unchanged.
+ If viewOptions.doRefr is on then adjust the curved height for
+ the effect of atmospheric refraction too.
+ */
+surface_type adjust_for_curvature(Viewpoint vp, double row,
+ double col, surface_type h,
+ ViewOptions viewOptions, GridHeader *hd)
+{
+
+ if (!viewOptions.doCurv)
+ return h;
+
+ assert(viewOptions.ellps_a != 0);
+
+ /* distance must be in meters because ellps_a is in meters */
+ double dist = G_distance(Rast_col_to_easting(vp.col + 0.5, &(hd->window)),
+ Rast_row_to_northing(vp.row + 0.5, &(hd->window)),
+ Rast_col_to_easting(col + 0.5, &(hd->window)),
+ Rast_row_to_northing(row + 0.5, &(hd->window)));
+
+ double adjustment = (dist * dist) / (2.0 * viewOptions.ellps_a);
+
+ if (!viewOptions.doRefr)
+ return h - adjustment;
+
+ return h - (adjustment * (1.0 - viewOptions.refr_coef));
+}
+
+
+
+/* ************************************************************ */
+/*return a GridHeader that has all the relevant data filled in */
+GridHeader *read_header(char *rastName, Cell_head * region)
+{
+
+ assert(rastName);
+
+ /*allocate the grid header to fill */
+ GridHeader *hd = (GridHeader *) G_malloc(sizeof(GridHeader));
+
+ assert(hd);
+
+ /*get the num rows and cols from GRASS */
+ int nrows, ncols;
+
+ nrows = Rast_window_rows();
+ ncols = Rast_window_cols();
+ /*check for loss of prescion */
+ if (nrows <= maxDimension && ncols <= maxDimension) {
+ hd->nrows = (dimensionType) nrows;
+ hd->ncols = (dimensionType) ncols;
+ }
+ else
+ G_fatal_error(_("Grid dimension too big for current precision"));
+
+
+ /*fill in rest of header */
+ hd->xllcorner = Rast_col_to_easting(0, region);
+ hd->yllcorner = Rast_row_to_northing(0, region);
+ /* Cell_head stores 2 resolutions, while GridHeader only stores 1 */
+ // make sure the two Cell_head resolutions are equal
+ if (fabs(region->ew_res - region->ns_res) > .001) {
+ G_warning(_("East-west resolution does not equal north-south resolution. "
+ "The viewshed computation assumes the cells are square, so in "
+ "this case this may result in innacuracies."));
+ // exit(EXIT_FAILURE);
+ }
+ hd->ew_res = region->ew_res;
+ hd->ns_res = region->ns_res;
+ //store the null value of the map
+ Rast_set_null_value(&(hd->nodata_value), 1, G_SURFACE_TYPE);
+ G_message("Nodata value set to %f", hd->nodata_value);
+
+
+
+ return hd;
+}
+
+/* calculate ENTER and EXIT event elevation (bilinear interpolation) */
+surface_type calculate_event_elevation(AEvent e, int nrows, int ncols,
+ dimensionType vprow, dimensionType vpcol,
+ G_SURFACE_T **inrast, RASTER_MAP_TYPE data_type)
+{
+ int row1, col1;
+ surface_type event_elev;
+ G_SURFACE_T elev1, elev2, elev3, elev4;
+
+ calculate_event_row_col(e, vprow, vpcol, &row1, &col1);
+ if (row1 >= 0 && row1 < nrows && col1 >= 0 && col1 < ncols) {
+ elev1 = inrast[row1 - e.row + 1][col1];
+ elev2 = inrast[row1 - e.row + 1][e.col];
+ elev3 = inrast[1][col1];
+ elev4 = inrast[1][e.col];
+ if (Rast_is_null_value(&elev1, data_type) ||
+ Rast_is_null_value(&elev2, data_type) ||
+ Rast_is_null_value(&elev3, data_type) ||
+ Rast_is_null_value(&elev4, data_type))
+ event_elev = inrast[1][e.col];
+ else {
+ event_elev = (elev1 + elev2 + elev3 + elev4) / 4.;
+ }
+ }
+ else
+ event_elev = inrast[1][e.col];
+
+ return event_elev;
+}
+
+
+/* ************************************************************ */
+/* input: an array capable to hold the max number of events, a raster
+ name, a viewpoint and the viewOptions; action: figure out all events
+ in the input file, and write them to the event list. data is
+ allocated and initialized with all the cells on the same row as the
+ viewpoint. it returns the number of events. initialize and fill
+ AEvent* with all the events for the map. Used when solving in
+ memory, so the AEvent* should fit in memory. */
+size_t
+init_event_list_in_memory(AEvent * eventList, char *rastName,
+ Viewpoint * vp, GridHeader * hd,
+ ViewOptions viewOptions, surface_type ***data,
+ MemoryVisibilityGrid * visgrid)
+{
+
+ G_message(_("Computing events ..."));
+ assert(eventList && vp && visgrid);
+ //GRASS should be defined
+
+ /*alloc data ; data is used to store all the cells on the same row
+ as the viewpoint. */
+ *data = (surface_type **)G_malloc(3 * sizeof(surface_type *));
+ assert(*data);
+ (*data)[0] = (surface_type *)G_malloc(3 * Rast_window_cols() * sizeof(surface_type));
+ assert((*data)[0]);
+ (*data)[1] = (*data)[0] + Rast_window_cols();
+ (*data)[2] = (*data)[1] + Rast_window_cols();
+
+ /*get the mapset name */
+ const char *mapset;
+
+ mapset = G_find_raster(rastName, "");
+ if (mapset == NULL)
+ G_fatal_error(_("Raster map [%s] not found"), rastName);
+
+ /*open map */
+ int infd;
+
+ if ((infd = Rast_open_old(rastName, mapset)) < 0)
+ G_fatal_error(_("Cannot open raster file [%s]"), rastName);
+
+ /*get the data_type */
+ RASTER_MAP_TYPE data_type;
+
+ /* data_type = G_raster_map_type(rastName, mapset); */
+ data_type = G_SURFACE_TYPE;
+
+ /*buffer to hold 3 rows */
+ G_SURFACE_T **inrast;
+ int nrows = Rast_window_rows();
+ int ncols = Rast_window_cols();
+
+ inrast = (G_SURFACE_T **)G_malloc(3 * sizeof(G_SURFACE_T *));
+ assert(inrast);
+ inrast[0] = (G_SURFACE_T *)Rast_allocate_buf(data_type);
+ assert(inrast[0]);
+ inrast[1] = (G_SURFACE_T *)Rast_allocate_buf(data_type);
+ assert(inrast[1]);
+ inrast[2] = (G_SURFACE_T *)Rast_allocate_buf(data_type);
+ assert(inrast[2]);
+
+ Rast_set_null_value(inrast[0], ncols, data_type);
+ Rast_set_null_value(inrast[1], ncols, data_type);
+ Rast_set_null_value(inrast[2], ncols, data_type);
+
+ int isnull = 0;
+
+ /*keep track of the number of events added, to be returned later */
+ size_t nevents = 0;
+
+ /*scan through the raster data */
+ dimensionType i, j;
+ double ax, ay;
+ AEvent e;
+
+ /* read first row */
+ Rast_get_row(infd, inrast[2], 0, data_type);
+
+ e.angle = -1;
+ for (i = 0; i < nrows; i++) {
+ /*read in the raster row */
+
+ G_SURFACE_T *tmprast = inrast[0];
+ inrast[0] = inrast[1];
+ inrast[1] = inrast[2];
+ inrast[2] = tmprast;
+
+ if (i < nrows - 1)
+ Rast_get_row(infd, inrast[2], i + 1, data_type);
+ else
+ Rast_set_null_value(inrast[2], ncols, data_type);
+
+ G_percent(i, nrows, 2);
+
+ /*fill event list with events from this row */
+ for (j = 0; j < Rast_window_cols(); j++) {
+ e.row = i;
+ e.col = j;
+
+ /*read the elevation value into the event */
+ isnull = Rast_is_null_value(&(inrast[1][j]), data_type);
+ e.elev[1] = inrast[1][j];
+
+ /* adjust for curvature */
+ e.elev[1] = adjust_for_curvature(*vp, i, j, e.elev[1], viewOptions, hd);
+
+ /*write it into the row of data going through the viewpoint */
+ if (i == vp->row) {
+ (*data)[0][j] = e.elev[1];
+ (*data)[1][j] = e.elev[1];
+ (*data)[2][j] = e.elev[1];
+ }
+
+ /* set the viewpoint, and don't insert it into eventlist */
+ if (i == vp->row && j == vp->col) {
+ set_viewpoint_elev(vp, e.elev[1] + viewOptions.obsElev);
+ if (viewOptions.tgtElev > 0)
+ vp->target_offset = viewOptions.tgtElev;
+ else
+ vp->target_offset = 0.;
+ if (isnull) {
+ /*what to do when viewpoint is NODATA ? */
+ G_warning(_("Viewpoint is NODATA."));
+ G_message(_("Will assume its elevation is = %f"),
+ vp->elev);
+ }
+
+ add_result_to_inmem_visibilitygrid(visgrid, i, j,
+ 180);
+ continue;
+ }
+
+ /*don't insert in eventlist nodata cell events */
+ if (isnull) {
+ /* record this cell as being NODATA; this is necessary so
+ that we can distingush invisible events, from nodata
+ events in the output */
+ add_result_to_inmem_visibilitygrid(visgrid, i, j,
+ hd->nodata_value);
+ continue;
+ }
+
+ /* if point is outside maxDist, do NOT include it as an
+ event */
+ if (is_point_outside_max_dist
+ (*vp, *hd, i, j, viewOptions.maxDist))
+ continue;
+
+ /* if it got here it is not the viewpoint, not NODATA, and
+ within max distance from viewpoint; generate its 3 events
+ and insert them */
+
+ /* get ENTER elevation */
+ e.eventType = ENTERING_EVENT;
+ e.elev[0] = calculate_event_elevation(e, nrows, ncols,
+ vp->row, vp->col, inrast, data_type);
+ /* adjust for curvature */
+ if (viewOptions.doCurv) {
+ calculate_event_position(e, vp->row, vp->col, &ay, &ax);
+ e.elev[0] = adjust_for_curvature(*vp, ay, ax, e.elev[0], viewOptions, hd);
+ }
+
+ /* get EXIT elevation */
+ e.eventType = EXITING_EVENT;
+ e.elev[2] = calculate_event_elevation(e, nrows, ncols,
+ vp->row, vp->col, inrast, data_type);
+ /* adjust for curvature */
+ if (viewOptions.doCurv) {
+ calculate_event_position(e, vp->row, vp->col, &ay, &ax);
+ e.elev[2] = adjust_for_curvature(*vp, ay, ax, e.elev[2], viewOptions, hd);
+ }
+
+ /*write adjusted elevation into the row of data going through the viewpoint */
+ if (i == vp->row) {
+ (*data)[0][j] = e.elev[0];
+ (*data)[1][j] = e.elev[1];
+ (*data)[2][j] = e.elev[2];
+ }
+
+ /*put event into event list */
+ e.eventType = ENTERING_EVENT;
+ calculate_event_position(e, vp->row, vp->col, &ay, &ax);
+ e.angle = calculate_angle(ax, ay, vp->col, vp->row);
+ eventList[nevents] = e;
+ nevents++;
+
+ e.eventType = CENTER_EVENT;
+ calculate_event_position(e, vp->row, vp->col, &ay, &ax);
+ e.angle = calculate_angle(ax, ay, vp->col, vp->row);
+ eventList[nevents] = e;
+ nevents++;
+
+ e.eventType = EXITING_EVENT;
+ calculate_event_position(e, vp->row, vp->col, &ay, &ax);
+ e.angle = calculate_angle(ax, ay, vp->col, vp->row);
+ eventList[nevents] = e;
+ nevents++;
+
+ }
+ }
+ G_percent(nrows, nrows, 2);
+
+ Rast_close(infd);
+
+ G_free(inrast[0]);
+ G_free(inrast[1]);
+ G_free(inrast[2]);
+ G_free(inrast);
+
+ return nevents;
+}
+
+
+
+
+
+/* ************************************************************ */
+/* input: an arcascii file, a grid header and a viewpoint; action:
+ figure out all events in the input file, and write them to the
+ stream. It assumes the file pointer is positioned rigth after the
+ grid header so that this function can read all grid elements.
+
+ if data is not NULL, it creates an array that stores all events on
+ the same row as the viewpoint.
+ */
+AMI_STREAM < AEvent > *init_event_list(char *rastName, Viewpoint * vp,
+ GridHeader * hd,
+ ViewOptions viewOptions,
+ surface_type ***data,
+ IOVisibilityGrid * visgrid)
+{
+
+ G_message(_("Computing events ..."));
+ assert(rastName && vp && hd && visgrid);
+
+ if (data != NULL) {
+ /*data is used to store all the cells on the same row as the
+ //viewpoint. */
+ *data = (surface_type **)G_malloc(3 * sizeof(surface_type *));
+ assert(*data);
+ (*data)[0] = (surface_type *)G_malloc(3 * Rast_window_cols() * sizeof(surface_type));
+ assert((*data)[0]);
+ (*data)[1] = (*data)[0] + Rast_window_cols();
+ (*data)[2] = (*data)[1] + Rast_window_cols();
+ }
+
+ /*create the event stream that will hold the events */
+ AMI_STREAM < AEvent > *eventList = new AMI_STREAM < AEvent > ();
+ assert(eventList);
+
+ /*determine which mapset we are in */
+ const char *mapset;
+
+ mapset = G_find_raster(rastName, "");
+ if (mapset == NULL)
+ G_fatal_error(_("Raster map [%s] not found"), rastName);
+
+ /*open map */
+ int infd;
+
+ if ((infd = Rast_open_old(rastName, mapset)) < 0)
+ G_fatal_error(_("Cannot open raster file [%s]"), rastName);
+
+ RASTER_MAP_TYPE data_type;
+
+ /* data_type = G_raster_map_type(rastName, mapset); */
+ data_type = G_SURFACE_TYPE;
+ G_SURFACE_T **inrast;
+ int nrows = Rast_window_rows();
+ int ncols = Rast_window_cols();
+
+ inrast = (G_SURFACE_T **)G_malloc(3 * sizeof(G_SURFACE_T *));
+ assert(inrast);
+ inrast[0] = (G_SURFACE_T *)Rast_allocate_buf(data_type);
+ assert(inrast[0]);
+ inrast[1] = (G_SURFACE_T *)Rast_allocate_buf(data_type);
+ assert(inrast[1]);
+ inrast[2] = (G_SURFACE_T *)Rast_allocate_buf(data_type);
+ assert(inrast[2]);
+
+ Rast_set_null_value(inrast[0], ncols, data_type);
+ Rast_set_null_value(inrast[1], ncols, data_type);
+ Rast_set_null_value(inrast[2], ncols, data_type);
+
+ /*scan through the raster data */
+ int isnull = 0;
+ dimensionType i, j;
+ double ax, ay;
+ AEvent e;
+
+ /* read first row */
+ Rast_get_row(infd, inrast[2], 0, data_type);
+
+ e.angle = -1;
+
+ /*start scanning through the grid */
+ for (i = 0; i < nrows; i++) {
+
+ G_percent(i, nrows, 2);
+
+ /*read in the raster row */
+
+ G_SURFACE_T *tmprast = inrast[0];
+ inrast[0] = inrast[1];
+ inrast[1] = inrast[2];
+ inrast[2] = tmprast;
+
+ if (i < nrows - 1)
+ Rast_get_row(infd, inrast[2], i + 1, data_type);
+ else
+ Rast_set_null_value(inrast[2], ncols, data_type);
+
+ /*fill event list with events from this row */
+ for (j = 0; j < ncols; j++) {
+
+ e.row = i;
+ e.col = j;
+
+ /*read the elevation value into the event */
+ isnull = Rast_is_null_value(&(inrast[1][j]), data_type);
+ e.elev[1] = inrast[1][j];
+
+ /* adjust for curvature */
+ e.elev[1] = adjust_for_curvature(*vp, i, j, e.elev[1], viewOptions, hd);
+
+ if (data != NULL) {
+
+ /*write the row of data going through the viewpoint */
+ if (i == vp->row) {
+ (*data)[0][j] = e.elev[1];
+ (*data)[1][j] = e.elev[1];
+ (*data)[2][j] = e.elev[1];
+ }
+ }
+
+ /* set the viewpoint */
+ if (i == vp->row && j == vp->col) {
+ set_viewpoint_elev(vp, e.elev[1] + viewOptions.obsElev);
+ /*what to do when viewpoint is NODATA */
+ if (is_nodata(hd, e.elev[1])) {
+ G_warning("Viewpoint is NODATA.");
+ G_message("Will assume its elevation is %.f", e.elev[1]);
+ };
+ if (viewOptions.tgtElev > 0)
+ vp->target_offset = viewOptions.tgtElev;
+ else
+ vp->target_offset = 0.;
+
+ /* add viewpoint to visibility grid */
+ VisCell visCell = { i, j, 180 };
+ add_result_to_io_visibilitygrid(visgrid, &visCell);
+
+ /*don't insert viewpoint into eventlist */
+ continue;
+ }
+
+ /*don't insert the nodata cell events */
+ if (is_nodata(hd, e.elev[1])) {
+ /* record this cell as being NODATA. ; this is necessary so
+ that we can distingush invisible events, from nodata
+ events in the output */
+ VisCell visCell = { i, j, hd->nodata_value };
+ add_result_to_io_visibilitygrid(visgrid, &visCell);
+ continue;
+ }
+
+ /* if point is outside maxDist, do NOT include it as an
+ event */
+ if (is_point_outside_max_dist
+ (*vp, *hd, i, j, viewOptions.maxDist))
+ continue;
+
+ /* get ENTER elevation */
+ e.eventType = ENTERING_EVENT;
+ e.elev[0] = calculate_event_elevation(e, nrows, ncols,
+ vp->row, vp->col, inrast, data_type);
+ /* adjust for curvature */
+ if (viewOptions.doCurv) {
+ calculate_event_position(e, vp->row, vp->col, &ay, &ax);
+ e.elev[0] = adjust_for_curvature(*vp, ay, ax, e.elev[0], viewOptions, hd);
+ }
+
+ /* get EXIT elevation */
+ e.eventType = EXITING_EVENT;
+ e.elev[2] = calculate_event_elevation(e, nrows, ncols,
+ vp->row, vp->col, inrast, data_type);
+ /* adjust for curvature */
+ if (viewOptions.doCurv) {
+ calculate_event_position(e, vp->row, vp->col, &ay, &ax);
+ e.elev[2] = adjust_for_curvature(*vp, ay, ax, e.elev[2], viewOptions, hd);
+ }
+
+ if (data != NULL) {
+
+ /*write the row of data going through the viewpoint */
+ if (i == vp->row) {
+ (*data)[0][j] = e.elev[0];
+ (*data)[1][j] = e.elev[1];
+ (*data)[2][j] = e.elev[2];
+ }
+ }
+
+ /*put event into event list */
+ e.eventType = ENTERING_EVENT;
+ calculate_event_position(e, vp->row, vp->col, &ay, &ax);
+ e.angle = calculate_angle(ax, ay, vp->col, vp->row);
+ eventList->write_item(e);
+
+ e.eventType = CENTER_EVENT;
+ calculate_event_position(e, vp->row, vp->col, &ay, &ax);
+ e.angle = calculate_angle(ax, ay, vp->col, vp->row);
+ eventList->write_item(e);
+
+ e.eventType = EXITING_EVENT;
+ calculate_event_position(e, vp->row, vp->col, &ay, &ax);
+ e.angle = calculate_angle(ax, ay, vp->col, vp->row);
+ eventList->write_item(e);
+ } /* for j */
+
+ } /* for i */
+ G_percent(nrows, nrows, 2);
+
+ Rast_close(infd);
+
+ G_free(inrast[0]);
+ G_free(inrast[1]);
+ G_free(inrast[2]);
+ G_free(inrast);
+
+ G_debug(1, "nbEvents = %lu", (unsigned long)eventList->stream_len());
+ G_debug(1, "Event stream length: %lu x %dB (%lu MB)",
+ (unsigned long)eventList->stream_len(), (int)sizeof(AEvent),
+ (unsigned long)(((long long)(eventList->stream_len() *
+ sizeof(AEvent))) >> 20));
+
+ return eventList;
+}
+
+
+
+
+
+
+/* ************************************************************ */
+/* saves the grid into a GRASS raster. Loops through all elements x
+ in row-column order and writes fun(x) to file. */
+void
+save_grid_to_GRASS(Grid * grid, char *filename, RASTER_MAP_TYPE type,
+ float (*fun) (float))
+{
+
+ G_message(_("Saving grid to <%s>"), filename);
+ assert(grid && filename);
+
+ /*open the new raster */
+ int outfd;
+
+ outfd = Rast_open_new(filename, type);
+
+ /*get the buffer to store values to read and write to each row */
+ void *outrast;
+
+ outrast = Rast_allocate_buf(type);
+ assert(outrast);
+
+ dimensionType i, j;
+
+ for (i = 0; i < Rast_window_rows(); i++) {
+ for (j = 0; j < Rast_window_cols(); j++) {
+
+ if (is_visible(grid->grid_data[i][j])) {
+ switch (type) {
+ case CELL_TYPE:
+ ((CELL *) outrast)[j] = (CELL) fun(grid->grid_data[i][j]);
+ break;
+ case FCELL_TYPE:
+ ((FCELL *) outrast)[j] = (FCELL) fun(grid->grid_data[i][j]);
+ break;
+ case DCELL_TYPE:
+ ((DCELL *) outrast)[j] = (DCELL) fun(grid->grid_data[i][j]);
+ break;
+ }
+ }
+ else
+ writeNodataValue(outrast, j, type);
+ } /* for j */
+ Rast_put_row(outfd, outrast, type);
+ } /* for i */
+
+ Rast_close(outfd);
+ return;
+}
+
+
+
+
+
+/* ************************************************************ */
+/* using the visibility information recorded in visgrid, it creates an
+ output viewshed raster with name outfname; for every point p that
+ is visible in the grid, the corresponding value in the output
+ raster is elevation(p) - viewpoint_elevation(p); the elevation
+ values are read from elevfname raster */
+
+void
+save_vis_elev_to_GRASS(Grid * visgrid, char *elevfname, char *visfname,
+ float vp_elev)
+{
+
+ G_message(_("Saving grid to <%s>"), visfname);
+ assert(visgrid && elevfname && visfname);
+
+ /*get the mapset name */
+ const char *mapset;
+
+ mapset = G_find_raster(elevfname, "");
+ if (mapset == NULL)
+ G_fatal_error(_("Raster map [%s] not found"), elevfname);
+
+ /*open elevation map */
+ int elevfd;
+
+ if ((elevfd = Rast_open_old(elevfname, mapset)) < 0)
+ G_fatal_error(_("Cannot open raster file [%s]"), elevfname);
+
+ /*get elevation data_type */
+ RASTER_MAP_TYPE elev_data_type;
+
+ elev_data_type = Rast_map_type(elevfname, mapset);
+
+ /* create the visibility raster of same type */
+ int visfd;
+
+ visfd = Rast_open_new(visfname, elev_data_type);
+
+ /*get the buffers to store each row */
+ void *elevrast;
+
+ elevrast = Rast_allocate_buf(elev_data_type);
+ assert(elevrast);
+ void *visrast;
+
+ visrast = Rast_allocate_buf(elev_data_type);
+ assert(visrast);
+
+ dimensionType i, j;
+ double elev = 0, viewshed_value;
+
+ for (i = 0; i < Rast_window_rows(); i++) {
+ /* get the row from elevation */
+ Rast_get_row(elevfd, elevrast, i, elev_data_type);
+
+ for (j = 0; j < Rast_window_cols(); j++) {
+
+ /* read the current elevation value */
+ int isNull = 0;
+
+ switch (elev_data_type) {
+ case CELL_TYPE:
+ isNull = Rast_is_c_null_value(&((CELL *) elevrast)[j]);
+ elev = (double)(((CELL *) elevrast)[j]);
+ break;
+ case FCELL_TYPE:
+ isNull = Rast_is_f_null_value(&((FCELL *) elevrast)[j]);
+ elev = (double)(((FCELL *) elevrast)[j]);
+ break;
+ case DCELL_TYPE:
+ isNull = Rast_is_d_null_value(&((DCELL *) elevrast)[j]);
+ elev = (double)(((DCELL *) elevrast)[j]);
+ break;
+ }
+
+ if (is_visible(visgrid->grid_data[i][j])) {
+ /* elevation cannot be null */
+ assert(!isNull);
+ /* write elev - viewpoint_elevation */
+ viewshed_value = elev - vp_elev;
+ writeValue(visrast, j, viewshed_value, elev_data_type);
+ }
+ else if (is_invisible_not_nodata(visgrid->grid_data[i][j])) {
+ /* elevation cannot be null */
+ assert(!isNull);
+ /* write INVISIBLE */
+ /*
+ viewshed_value = INVISIBLE;
+ writeValue(visrast, j, viewshed_value, elev_data_type);
+ */
+ /* write NODATA */
+ writeNodataValue(visrast, j, elev_data_type);
+ }
+ else {
+ /* nodata */
+ assert(isNull);
+ /* write NODATA */
+ writeNodataValue(visrast, j, elev_data_type);
+ }
+
+
+ } /* for j */
+ Rast_put_row(visfd, visrast, elev_data_type);
+ } /* for i */
+
+ Rast_close(elevfd);
+ Rast_close(visfd);
+ return;
+}
+
+
+
+
+/* helper function to deal with GRASS writing to a row buffer */
+void writeValue(void *bufrast, int j, double x, RASTER_MAP_TYPE data_type)
+{
+
+ switch (data_type) {
+ case CELL_TYPE:
+ ((CELL *) bufrast)[j] = (CELL) x;
+ break;
+ case FCELL_TYPE:
+ ((FCELL *) bufrast)[j] = (FCELL) x;
+ break;
+ case DCELL_TYPE:
+ ((DCELL *) bufrast)[j] = (DCELL) x;
+ break;
+ default:
+ G_fatal_error(_("Unknown data type"));
+ }
+}
+
+void writeNodataValue(void *bufrast, int j, RASTER_MAP_TYPE data_type)
+{
+
+ switch (data_type) {
+ case CELL_TYPE:
+ Rast_set_c_null_value(&((CELL *) bufrast)[j], 1);
+ break;
+ case FCELL_TYPE:
+ Rast_set_f_null_value(&((FCELL *) bufrast)[j], 1);
+ break;
+ case DCELL_TYPE:
+ Rast_set_d_null_value(&((DCELL *) bufrast)[j], 1);
+ break;
+ default:
+ G_fatal_error(_("Unknown data type"));
+ }
+}
+
+
+/* ************************************************************ */
+/* write the visibility grid to GRASS. assume all cells that are not
+ in stream are NOT visible. assume stream is sorted in (i,j) order.
+ for each value x it writes to grass fun(x) */
+void
+save_io_visibilitygrid_to_GRASS(IOVisibilityGrid * visgrid,
+ char *fname, RASTER_MAP_TYPE type,
+ float (*fun) (float))
+{
+
+ G_message(_("Saving grid to <%s>"), fname);
+ assert(fname && visgrid);
+
+ /* open the output raster and set up its row buffer */
+ int visfd;
+
+ visfd = Rast_open_new(fname, type);
+ void *visrast;
+
+ visrast = Rast_allocate_buf(type);
+ assert(visrast);
+
+ /*set up reading data from visibility stream */
+ AMI_STREAM < VisCell > *vstr = visgrid->visStr;
+ off_t streamLen, counter = 0;
+
+ streamLen = vstr->stream_len();
+ vstr->seek(0);
+
+ /*read the first element */
+ AMI_err ae;
+ VisCell *curResult = NULL;
+
+ if (streamLen > 0) {
+ ae = vstr->read_item(&curResult);
+ assert(ae == AMI_ERROR_NO_ERROR);
+ counter++;
+ }
+
+ dimensionType i, j;
+
+ for (i = 0; i < Rast_window_rows(); i++) {
+ for (j = 0; j < Rast_window_cols(); j++) {
+
+ if (curResult->row == i && curResult->col == j) {
+ /*cell is recodred in the visibility stream: it must be
+ either visible, or NODATA */
+ if (is_visible(curResult->angle))
+ writeValue(visrast, j, fun(curResult->angle), type);
+ else
+ writeNodataValue(visrast, j, type);
+
+ /*read next element of stream */
+ if (counter < streamLen) {
+ ae = vstr->read_item(&curResult);
+ assert(ae == AMI_ERROR_NO_ERROR);
+ counter++;
+ }
+ }
+ else {
+ /* this cell is not in stream, so it is invisible */
+ writeNodataValue(visrast, j, type);
+ }
+ } /* for j */
+
+ Rast_put_row(visfd, visrast, type);
+ } /* for i */
+
+ Rast_close(visfd);
+}
+
+
+
+
+
+
+
+/* ************************************************************ */
+/* using the visibility information recorded in visgrid, it creates
+ an output viewshed raster with name outfname; for every point p
+ that is visible in the grid, the corresponding value in the output
+ raster is elevation(p) - viewpoint_elevation(p); the elevation
+ values are read from elevfname raster. assume stream is sorted in
+ (i,j) order. */
+void
+save_io_vis_and_elev_to_GRASS(IOVisibilityGrid * visgrid, char *elevfname,
+ char *visfname, float vp_elev)
+{
+
+ G_message(_("Saving grid to <%s>"), visfname);
+ assert(visfname && visgrid);
+
+ /*get mapset name and data type */
+ const char *mapset;
+
+ mapset = G_find_raster(elevfname, "");
+ if (mapset == NULL)
+ G_fatal_error(_("Opening <%s>: cannot find raster"), elevfname);
+
+ /*open elevation map */
+ int elevfd;
+
+ if ((elevfd = Rast_open_old(elevfname, mapset)) < 0)
+ G_fatal_error(_("Cannot open raster file [%s]"), elevfname);
+
+ /*get elevation data_type */
+ RASTER_MAP_TYPE elev_data_type;
+
+ elev_data_type = Rast_map_type(elevfname, mapset);
+
+ /* open visibility raster */
+ int visfd;
+
+ visfd = Rast_open_new(visfname, elev_data_type);
+
+ /*get the buffers to store each row */
+ void *elevrast;
+
+ elevrast = Rast_allocate_buf(elev_data_type);
+ assert(elevrast);
+ void *visrast;
+
+ visrast = Rast_allocate_buf(elev_data_type);
+ assert(visrast);
+
+ /*set up stream reading stuff */
+ off_t streamLen, counter = 0;
+ AMI_err ae;
+ VisCell *curResult = NULL;
+
+ AMI_STREAM < VisCell > *vstr = visgrid->visStr;
+ streamLen = vstr->stream_len();
+ vstr->seek(0);
+
+ /*read the first element */
+ if (streamLen > 0) {
+ ae = vstr->read_item(&curResult);
+ assert(ae == AMI_ERROR_NO_ERROR);
+ counter++;
+ }
+
+ dimensionType i, j;
+ double elev = 0, viewshed_value;
+
+ for (i = 0; i < Rast_window_rows(); i++) {
+
+ Rast_get_row(elevfd, elevrast, i, elev_data_type);
+
+ for (j = 0; j < Rast_window_cols(); j++) {
+
+ /* read the current elevation value */
+ int isNull = 0;
+
+ switch (elev_data_type) {
+ case CELL_TYPE:
+ isNull = Rast_is_c_null_value(&((CELL *) elevrast)[j]);
+ elev = (double)(((CELL *) elevrast)[j]);
+ break;
+ case FCELL_TYPE:
+ isNull = Rast_is_f_null_value(&((FCELL *) elevrast)[j]);
+ elev = (double)(((FCELL *) elevrast)[j]);
+ break;
+ case DCELL_TYPE:
+ isNull = Rast_is_d_null_value(&((DCELL *) elevrast)[j]);
+ elev = (double)(((DCELL *) elevrast)[j]);
+ break;
+ }
+
+
+ if (curResult->row == i && curResult->col == j) {
+ /*cell is recodred in the visibility stream: it must be
+ either visible, or NODATA */
+ if (is_visible(curResult->angle))
+ writeValue(visrast, j, elev - vp_elev, elev_data_type);
+ else
+ writeNodataValue(visrast, j, elev_data_type);
+ /*read next element of stream */
+ if (counter < streamLen) {
+ ae = vstr->read_item(&curResult);
+ assert(ae == AMI_ERROR_NO_ERROR);
+ counter++;
+ }
+ }
+ else {
+ /* this cell is not in stream, so it is invisible */
+ writeNodataValue(visrast, j, elev_data_type);
+ }
+ } /* for j */
+
+ Rast_put_row(visfd, visrast, elev_data_type);
+ } /* for i */
+
+ Rast_close(elevfd);
+ Rast_close(visfd);
+ return;
+}
Modified: grass/trunk/raster/r.viewshed/grass.h
===================================================================
--- grass-addons/raster/r.viewshed/grass.h 2011-12-02 09:30:54 UTC (rev 49482)
+++ grass/trunk/raster/r.viewshed/grass.h 2011-12-02 09:56:38 UTC (rev 49483)
@@ -43,6 +43,7 @@
extern "C"
{
#include <grass/gis.h>
+#include <grass/raster.h>
#include <grass/glocale.h>
}
Deleted: grass/trunk/raster/r.viewshed/grid.cc
===================================================================
--- grass-addons/raster/r.viewshed/grid.cc 2011-12-02 09:30:54 UTC (rev 49482)
+++ grass/trunk/raster/r.viewshed/grid.cc 2011-12-02 09:56:38 UTC (rev 49483)
@@ -1,175 +0,0 @@
-
-/****************************************************************************
- *
- * MODULE: r.viewshed
- *
- * AUTHOR(S): Laura Toma, Bowdoin College - ltoma at bowdoin.edu
- * Yi Zhuang - yzhuang at bowdoin.edu
-
- * Ported to GRASS by William Richard -
- * wkrichar at bowdoin.edu or willster3021 at 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 <stdio.h>
-#include <math.h>
-#include <stdlib.h>
-#include <assert.h>
-
-extern "C"
-{
-#include <grass/config.h>
-#include <grass/gis.h>
-#include <grass/glocale.h>
-}
-
-#include "grid.h"
-
-
-
-
-/* ------------------------------------------------------------ */
-/*copy from b to a */
-void copy_header(GridHeader * a, GridHeader b)
-{
- assert(a);
- a->nrows = b.nrows;
- a->ncols = b.ncols;
- a->xllcorner = b.xllcorner;
- a->yllcorner = b.yllcorner;
- a->ns_res = b.ns_res;
- a->ew_res = b.ew_res;
- a->nodata_value = b.nodata_value;
- return;
-}
-
-
-/* ------------------------------------------------------------ */
-/*returns 1 if value is Nodata, 0 if it is not */
-int is_nodata(GridHeader * hd, float value)
-{
- assert(hd);
-
- return G_is_null_value(&value, G_SURFACE_TYPE);
-
-}
-
-/* ------------------------------------------------------------ */
-/*returns 1 if value is Nodata, 0 if it is not */
-int is_nodata(Grid * grid, float value)
-{
- assert(grid);
- return is_nodata(grid->hd, value);
-}
-
-
-
-/* ------------------------------------------------------------ */
-/* create an empty grid and return it. The header and the data are set
- to NULL. */
-Grid *create_empty_grid()
-{
-
- Grid *ptr_grid = (Grid *) G_malloc(sizeof(Grid));
-
- assert(ptr_grid);
-
- /*initialize structure */
- ptr_grid->hd = NULL;
- ptr_grid->grid_data = NULL;
-
-#ifdef _DEBUG_ON
- printf("**DEBUG: createEmptyGrid \n");
- fflush(stdout);
-#endif
-
- return ptr_grid;
-}
-
-
-
-
-/* ------------------------------------------------------------ */
-/* allocate memroy for grid_data; grid must have a header that gives
- the dimensions */
-void alloc_grid_data(Grid * pgrid)
-{
- assert(pgrid);
- assert(pgrid->hd);
-
- pgrid->grid_data = (float **)G_malloc(pgrid->hd->nrows * sizeof(float *));
-
- assert(pgrid->grid_data);
-
- dimensionType i;
-
- for (i = 0; i < pgrid->hd->nrows; i++) {
- pgrid->grid_data[i] =
- (float *)G_malloc(pgrid->hd->ncols * sizeof(float));
-
- assert(pgrid->grid_data[i]);
- }
-
-#ifdef _DEBUG_ON
- printf("**DEBUG: allocGridData\n");
- fflush(stdout);
-#endif
-
- return;
-}
-
-
-/* ------------------------------------------------------------ */
-/*destroy the structure and reclaim all memory allocated */
-void destroy_grid(Grid * grid)
-{
- assert(grid);
-
- /*free grid data if its allocated */
- if (grid->grid_data) {
- dimensionType i;
-
- for (i = 0; i < grid->hd->nrows; i++) {
- if (!grid->grid_data[i])
- G_free((float *)grid->grid_data[i]);
- }
-
- G_free((float **)grid->grid_data);
- }
-
- G_free(grid->hd);
- G_free(grid);
-
-#ifdef _DEBUG_ON
- printf("**DEBUG: grid destroyed.\n");
- fflush(stdout);
-#endif
-
- return;
-}
Copied: grass/trunk/raster/r.viewshed/grid.cpp (from rev 49482, grass-addons/raster/r.viewshed/grid.cc)
===================================================================
--- grass/trunk/raster/r.viewshed/grid.cpp (rev 0)
+++ grass/trunk/raster/r.viewshed/grid.cpp 2011-12-02 09:56:38 UTC (rev 49483)
@@ -0,0 +1,175 @@
+
+/****************************************************************************
+ *
+ * MODULE: r.viewshed
+ *
+ * AUTHOR(S): Laura Toma, Bowdoin College - ltoma at bowdoin.edu
+ * Yi Zhuang - yzhuang at bowdoin.edu
+
+ * Ported to GRASS by William Richard -
+ * wkrichar at bowdoin.edu or willster3021 at 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 <stdio.h>
+#include <math.h>
+#include <stdlib.h>
+#include <assert.h>
+
+extern "C"
+{
+#include <grass/config.h>
+#include <grass/gis.h>
+#include <grass/glocale.h>
+}
+
+#include "grid.h"
+
+
+
+
+/* ------------------------------------------------------------ */
+/*copy from b to a */
+void copy_header(GridHeader * a, GridHeader b)
+{
+ assert(a);
+ a->nrows = b.nrows;
+ a->ncols = b.ncols;
+ a->xllcorner = b.xllcorner;
+ a->yllcorner = b.yllcorner;
+ a->ns_res = b.ns_res;
+ a->ew_res = b.ew_res;
+ a->nodata_value = b.nodata_value;
+ return;
+}
+
+
+/* ------------------------------------------------------------ */
+/*returns 1 if value is Nodata, 0 if it is not */
+int is_nodata(GridHeader * hd, float value)
+{
+ assert(hd);
+
+ return Rast_is_null_value(&value, G_SURFACE_TYPE);
+
+}
+
+/* ------------------------------------------------------------ */
+/*returns 1 if value is Nodata, 0 if it is not */
+int is_nodata(Grid * grid, float value)
+{
+ assert(grid);
+ return is_nodata(grid->hd, value);
+}
+
+
+
+/* ------------------------------------------------------------ */
+/* create an empty grid and return it. The header and the data are set
+ to NULL. */
+Grid *create_empty_grid()
+{
+
+ Grid *ptr_grid = (Grid *) G_malloc(sizeof(Grid));
+
+ assert(ptr_grid);
+
+ /*initialize structure */
+ ptr_grid->hd = NULL;
+ ptr_grid->grid_data = NULL;
+
+#ifdef _DEBUG_ON
+ printf("**DEBUG: createEmptyGrid \n");
+ fflush(stdout);
+#endif
+
+ return ptr_grid;
+}
+
+
+
+
+/* ------------------------------------------------------------ */
+/* allocate memroy for grid_data; grid must have a header that gives
+ the dimensions */
+void alloc_grid_data(Grid * pgrid)
+{
+ assert(pgrid);
+ assert(pgrid->hd);
+
+ pgrid->grid_data = (float **)G_malloc(pgrid->hd->nrows * sizeof(float *));
+
+ assert(pgrid->grid_data);
+
+ dimensionType i;
+
+ for (i = 0; i < pgrid->hd->nrows; i++) {
+ pgrid->grid_data[i] =
+ (float *)G_malloc(pgrid->hd->ncols * sizeof(float));
+
+ assert(pgrid->grid_data[i]);
+ }
+
+#ifdef _DEBUG_ON
+ printf("**DEBUG: allocGridData\n");
+ fflush(stdout);
+#endif
+
+ return;
+}
+
+
+/* ------------------------------------------------------------ */
+/*destroy the structure and reclaim all memory allocated */
+void destroy_grid(Grid * grid)
+{
+ assert(grid);
+
+ /*free grid data if its allocated */
+ if (grid->grid_data) {
+ dimensionType i;
+
+ for (i = 0; i < grid->hd->nrows; i++) {
+ if (!grid->grid_data[i])
+ G_free((float *)grid->grid_data[i]);
+ }
+
+ G_free((float **)grid->grid_data);
+ }
+
+ G_free(grid->hd);
+ G_free(grid);
+
+#ifdef _DEBUG_ON
+ printf("**DEBUG: grid destroyed.\n");
+ fflush(stdout);
+#endif
+
+ return;
+}
Modified: grass/trunk/raster/r.viewshed/grid.h
===================================================================
--- grass-addons/raster/r.viewshed/grid.h 2011-12-02 09:30:54 UTC (rev 49482)
+++ grass/trunk/raster/r.viewshed/grid.h 2011-12-02 09:56:38 UTC (rev 49483)
@@ -49,6 +49,7 @@
extern "C"
{
#include <grass/gis.h>
+#include <grass/raster.h>
}
#define G_SURFACE_TYPE FCELL_TYPE
Deleted: grass/trunk/raster/r.viewshed/main.cc
===================================================================
--- grass-addons/raster/r.viewshed/main.cc 2011-12-02 09:30:54 UTC (rev 49482)
+++ grass/trunk/raster/r.viewshed/main.cc 2011-12-02 09:56:38 UTC (rev 49483)
@@ -1,698 +0,0 @@
-/****************************************************************************
- *
- * MODULE: r.viewshed
- *
- * AUTHOR(S): Laura Toma, Bowdoin College - ltoma at bowdoin.edu
- * Yi Zhuang - yzhuang at bowdoin.edu
- *
- * Ported to GRASS by William Richard -
- * wkrichar at bowdoin.edu or willster3021 at gmail.com
- * Markus Metz: surface interpolation
- *
- * Date: July 2008; 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-2011 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 <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <ctype.h>
-#include <unistd.h>
-
-extern "C"
-{
-#include <grass/config.h>
-#include <grass/gis.h>
-#include <grass/glocale.h>
-}
-#include "grass.h"
-#include <grass/iostream/ami.h>
-
-#include "viewshed.h"
-#include "visibility.h"
-#include "grid.h"
-#include "rbbst.h"
-#include "statusstructure.h"
-#include "distribute.h"
-
-
-
-
-/* if the user does not specify how much memory is available for the
- program, this is the default value used (in bytes) */
-#define DEFAULT_MEMORY 500<<20
-
-
-/* observer elevation above the terrain */
-#define DEFAULT_OBS_ELEVATION 0
-
-
-/* All these flags are used for debugging */
-
-/* if this flag is set, it always runs in memory */
-//#define FORCE_INTERNAL
-
-/* if this is set, it runs in external memory, even if the problem is
- small enough to fit in memory. In external memory it first tries
- to run the base-case, then recursion. */
-//#define FORCE_EXTERNAL
-
-/* if this flag is set it runs in external memory, and starts
- recursion without checking the base-case. */
-//#define FORCE_DISTRIBUTION
-
-
-
-/* ------------------------------------------------------------ */
-/* forward declarations */
-/* ------------------------------------------------------------ */
-void print_timings_internal(Rtimer sweepTime, Rtimer outputTime,
- Rtimer totalTime);
-void print_timings_external_memory(Rtimer totalTime, Rtimer viewshedTime,
- Rtimer outputTime, Rtimer sortOutputTime);
-
-void parse_args(int argc, char *argv[], int *vpRow, int *vpCol,
- ViewOptions * viewOptions, long long *memSizeBytes,
- Cell_head * window);
-
-
-
-
-/* ------------------------------------------------------------ */
-int main(int argc, char *argv[])
-{
-
- /* GRASS initialization stuff */
- struct GModule *module;
-
- /*initialize GIS environment */
- G_gisinit(argv[0]);
-
- /*initialize module */
- module = G_define_module();
- module->keywords = _("raster, viewshed, line of sight");
- module->description = _("IO-efficient viewshed algorithm");
-
- struct Cell_head region;
- char *optstreamdir;
-
- if (G_get_set_window(®ion) == -1)
- G_fatal_error("Error getting current region");
-
-
- /* ************************************************************ */
- /* parameters set up */
- long long memSizeBytes = DEFAULT_MEMORY;
-
- /* the maximum size of main memory that the program ca use. The
- user can specify it, otherwise the default value of 500MB is
- used. The program uses this value to decied in which mode to
- run --- in internal memory, or external memory. */
-
- int vpRow, vpCol;
-
- /* the coordinates of the viewpoint in the raster; right now the
- algorithm assumes that the viewpoint is inside the grid, though
- this is not necessary; some changes will be needed to make it
- work with a viewpoint outside the terrain */
-
- ViewOptions viewOptions;
-
- //viewOptions.inputfname = (char*)malloc(500);
- //viewOptions.outputfname = (char*)malloc(500);
- //assert(inputfname && outputfname);
- viewOptions.obsElev = DEFAULT_OBS_ELEVATION;
- viewOptions.maxDist = INFINITY_DISTANCE;
- viewOptions.outputMode = OUTPUT_ANGLE;
- viewOptions.doCurv = FALSE;
- viewOptions.doRefr = FALSE;
- viewOptions.refr_coef = 1.0/7.0;
-
- parse_args(argc, argv, &vpRow, &vpCol, &viewOptions, &memSizeBytes,
- ®ion);
-
- /* set viewpoint with the coordinates specified by user. The
- height of the viewpoint is not known at this point---it will be
- set during the execution of the algorithm */
- Viewpoint vp;
-
- set_viewpoint_coord(&vp, vpRow, vpCol);
-
-
- /* ************************************************************ */
- /* set up the header of the raster with all raster info and make
- sure the requested viewpoint is on the map */
- GridHeader *hd;
-
- hd = read_header(viewOptions.inputfname, ®ion);
- assert(hd);
- G_get_set_window(&(hd->window));
-
- /* LT: there is no need to exit if viewpoint is outside grid,
- the algorithm will work correctly in theory. But this
- requires some changes. To do. */
- if (!(vp.row < hd->nrows && vp.col < hd->ncols)) {
- G_warning(_("Viewpoint outside grid"));
- G_warning(_("viewpont: (row=%d, col=%d)"), vp.row, vp.col);
- G_fatal_error(_("grid: (rows=%d, cols=%d)"), hd->nrows, hd->ncols);
- }
-
-
- /* set curvature params */
- viewOptions.cellsize = region.ew_res;
- double e2;
-
- G_get_ellipsoid_parameters(&viewOptions.ellps_a, &e2);
- if (viewOptions.ellps_a == 0) {
- /*according to r.los, this can be
- problematic, so we'll have a backup, hardcoded radius :-( */
- G_warning(_("Problems obtaining current ellipsoid parameters, using sphere (6370997.0)"));
- viewOptions.ellps_a = 6370997.00;
- }
-
- G_begin_distance_calculations();
-
-
-
-
- /* ************************************************************ */
- /* decide whether the computation of the viewshed will take place
- in-memory or in external memory */
- int IN_MEMORY;
- long long inmemSizeBytes = get_viewshed_memory_usage(hd);
-
- G_verbose_message(_("In-memory memory usage is %lld B (%d MB), \
- max mem allowed=%lld B(%dMB)"), inmemSizeBytes,
- (int)(inmemSizeBytes >> 20), memSizeBytes,
- (int)(memSizeBytes >> 20));
- if (inmemSizeBytes < memSizeBytes) {
- IN_MEMORY = 1;
- G_verbose_message("***** IN_MEMORY MODE *****");
- }
- else {
- G_verbose_message("***** EXTERNAL_MEMORY MODE *****");
- IN_MEMORY = 0;
- }
-
- /* the mode can be forced to in memory or external if the user
- wants to test or debug a specific mode */
-#ifdef FORCE_EXTERNAL
- IN_MEMORY = 0;
- G_debug(1, "FORCED EXTERNAL");
-#endif
-
-#ifdef FORCE_INTERNAL
- IN_MEMORY = 1;
- G_debug(1, "FORCED INTERNAL");
-#endif
-
-
- /* ************************************************************ */
- /* compute viewshed in memory */
- /* ************************************************************ */
- if (IN_MEMORY) {
- /*//////////////////////////////////////////////////// */
- /*/viewshed in internal memory */
- /*//////////////////////////////////////////////////// */
- Rtimer totalTime, outputTime, sweepTime;
- MemoryVisibilityGrid *visgrid;
-
- rt_start(totalTime);
-
- /*compute the viewshed and store it in visgrid */
- rt_start(sweepTime);
- visgrid =
- viewshed_in_memory(viewOptions.inputfname, hd, &vp, viewOptions);
- rt_stop(sweepTime);
-
- /* write the output */
- rt_start(outputTime);
- save_inmem_visibilitygrid(visgrid, viewOptions, vp);
- rt_stop(outputTime);
-
- rt_stop(totalTime);
-
- print_timings_internal(sweepTime, outputTime, totalTime);
- }
-
-
-
-
- /* ************************************************************ */
- /* compute viewshed in external memory */
- /* ************************************************************ */
- else {
-
- /* ************************************************************ */
- /* set up external memory mode */
- /* setup STREAM_DIR if not already set */
- char buf[1000];
-
- if (getenv(STREAM_TMPDIR) != NULL) {
- /*if already set */
- G_debug(1, "%s=%s", STREAM_TMPDIR, getenv(STREAM_TMPDIR));
- G_debug(1, "Intermediate stream location: %s",
- getenv(STREAM_TMPDIR));
- }
- else {
- /*set it */
- sprintf(buf, "%s=%s", STREAM_TMPDIR, viewOptions.streamdir);
- G_debug(1, "setting %s ", buf);
- putenv(buf);
- if (getenv(STREAM_TMPDIR) == NULL) {
- G_fatal_error(_("%s not set"), "STREAM_TMPDIR");
- exit(1);
- }
- else {
- G_debug(1, "are ok.");
- }
- G_debug(1, "Intermediate stream location: %s", viewOptions.streamdir);
- }
- G_important_message(_("Intermediate files will not be deleted \
- in case of abnormal termination."));
- G_important_message(_("To save space delete these files manually!"));
-
-
- /* initialize IOSTREAM memory manager */
- MM_manager.set_memory_limit(memSizeBytes);
- MM_manager.warn_memory_limit();
- MM_manager.print_limit_mode();
-
-
-
- /* ************************************************************ */
- /* BASE CASE OR DISTRIBUTION */
- /* determine whether base-case of external algorithm is enough,
- or recursion is necessary */
- int BASE_CASE = 0;
-
- if (get_active_str_size_bytes(hd) < memSizeBytes)
- BASE_CASE = 1;
-
- /*if the user set the FORCE_DISTRIBUTION flag, then the
- algorithm runs in the fuly recursive mode (even if this is
- not necessary). This is used solely for debugging purpses */
-#ifdef FORCE_DISTRIBUTION
- BASE_CASE = 0;
-#endif
-
-
-
-
- /* ************************************************************ */
- /* external memory, base case */
- /* ************************************************************ */
- if (BASE_CASE) {
- G_debug
- (1, "---Active structure small, starting base case---");
-
- Rtimer totalTime, viewshedTime, outputTime, sortOutputTime;
-
- rt_start(totalTime);
-
- /*run viewshed's algorithm */
- IOVisibilityGrid *visgrid;
-
- rt_start(viewshedTime);
- visgrid =
- viewshed_external(viewOptions.inputfname, hd, &vp,
- viewOptions);
- rt_stop(viewshedTime);
-
- /*sort output */
- rt_start(sortOutputTime);
- sort_io_visibilitygrid(visgrid);
- rt_stop(sortOutputTime);
-
- /*save output stream to file. */
- rt_start(outputTime);
- save_io_visibilitygrid(visgrid, viewOptions, vp);
- rt_stop(outputTime);
-
- rt_stop(totalTime);
-
- print_timings_external_memory(totalTime, viewshedTime,
- outputTime, sortOutputTime);
- }
-
-
-
- /************************************************************/
- /* external memory, recursive distribution sweeping recursion */
- /************************************************************ */
- else { /* if not BASE_CASE */
-#ifndef FORCE_DISTRIBUTION
- G_debug(1, "---Active structure does not fit in memory,");
-#else
- G_debug(1, "FORCED DISTRIBUTION");
-#endif
-
- Rtimer totalTime, sweepTime, outputTime, sortOutputTime;
-
- rt_start(totalTime);
-
- /*get the viewshed solution by distribution */
- IOVisibilityGrid *visgrid;
-
- rt_start(sweepTime);
- visgrid =
- distribute_and_sweep(viewOptions.inputfname, hd, &vp,
- viewOptions);
-
- rt_stop(sweepTime);
-
- /*sort the visibility grid so that it is in order when it is
- outputted */
- rt_start(sortOutputTime);
- sort_io_visibilitygrid(visgrid);
- rt_stop(sortOutputTime);
-
- rt_start(outputTime);
- save_io_visibilitygrid(visgrid, viewOptions, vp);
- rt_stop(outputTime);
-
-
- rt_stop(totalTime);
-
- print_timings_external_memory(totalTime, sweepTime,
- outputTime, sortOutputTime);
-
- }
- }
- /*end external memory, distribution sweep */
-
-
- /**************************************/
- /* FINISH UP, ALL CASES */
- /**************************************/
-
- /*close input file and free grid header */
- G_free(hd);
- /*following GRASS's coding standards for history and exiting */
- struct History history;
-
- G_short_history(viewOptions.outputfname, "raster", &history);
- G_command_history(&history);
- G_write_history(viewOptions.outputfname, &history);
- exit(EXIT_SUCCESS);
-}
-
-
-
-
-/* ------------------------------------------------------------ */
-/* parse arguments */
-void
-parse_args(int argc, char *argv[], int *vpRow, int *vpCol,
- ViewOptions * viewOptions, long long *memSizeBytes,
- Cell_head * window)
-{
-
- assert(vpRow && vpCol && memSizeBytes && window);
-
- /* the input */
- struct Option *inputOpt;
-
- inputOpt = G_define_standard_option(G_OPT_R_ELEV);
- inputOpt->key = "input";
- inputOpt->guisection = _("Input_options");
-
- /* the output */
- struct Option *outputOpt;
-
- outputOpt = G_define_standard_option(G_OPT_R_OUTPUT);
- outputOpt->label = _("Name of output viewshed raster map");
- outputOpt->description =
- _("default format: {NULL (invisible), vertical angle wrt viewpoint (visible)}");
- outputOpt->guisection = _("Output_options");
-
- /* curvature flag */
- struct Flag *curvature;
-
- curvature = G_define_flag();
- curvature->key = 'c';
- curvature->description =
- _("Consider the curvature of the earth (current ellipsoid)");
-
- /* atmospheric refraction flag */
- struct Flag *refractionFlag;
-
- refractionFlag = G_define_flag();
- refractionFlag->key = 'r';
- refractionFlag->description =
- _("Consider the effect of atmospheric refraction");
-
- /* boolean output flag */
- struct Flag *booleanOutput;
-
- booleanOutput = G_define_flag();
- booleanOutput->key = 'b';
- booleanOutput->description =
- _("Output format is {0 (invisible) 1 (visible)}");
-
- /* output mode = elevation flag */
- struct Flag *elevationFlag;
-
- elevationFlag = G_define_flag();
- elevationFlag->key = 'e';
- elevationFlag->description =
- _("Output format is invisible = NULL, else current elev - viewpoint_elev");
-
-
- /* viewpoint coordinates */
- struct Option *viewLocOpt;
-
- viewLocOpt = G_define_option();
- viewLocOpt->key = "coordinate";
- viewLocOpt->type = TYPE_STRING;
- viewLocOpt->required = YES;
- viewLocOpt->key_desc = "east,north";
- viewLocOpt->description = _("Coordinates of viewing position");
- viewLocOpt->guisection = _("Input_options");
-
- /* observer elevation */
- struct Option *obsElevOpt;
-
- obsElevOpt = G_define_option();
- obsElevOpt->key = "obs_elev";
- obsElevOpt->type = TYPE_DOUBLE;
- obsElevOpt->required = NO;
- obsElevOpt->key_desc = "value";
- obsElevOpt->description = _("Viewing elevation above the ground");
- obsElevOpt->answer = "1.75";
- obsElevOpt->guisection = _("Input_options");
-
- /* target elevation offset */
- struct Option *tgtElevOpt;
-
- tgtElevOpt = G_define_option();
- tgtElevOpt->key = "tgt_elev";
- tgtElevOpt->type = TYPE_DOUBLE;
- tgtElevOpt->required = NO;
- tgtElevOpt->key_desc = "value";
- tgtElevOpt->description = _("Offset for target elevation above the ground");
- tgtElevOpt->answer = "0.0";
- tgtElevOpt->guisection = _("Input_options");
-
- /* max distance */
- struct Option *maxDistOpt;
-
- maxDistOpt = G_define_option();
- maxDistOpt->key = "max_dist";
- maxDistOpt->type = TYPE_DOUBLE;
- maxDistOpt->required = NO;
- maxDistOpt->key_desc = "value";
- maxDistOpt->description =
- _("Maximum visibility radius. By default infinity (-1).");
- char infdist[10];
-
- sprintf(infdist, "%d", INFINITY_DISTANCE);
- maxDistOpt->answer = infdist;
- maxDistOpt->guisection = _("Input_options");
-
- /* atmospheric refraction coeff. 1/7 for visual, 0.325 for radio waves, ... */
- /* in future we might calculate this based on the physics, for now we
- just fudge by the 1/7th approximation.
-
- ?? See ??
-
- @article{yoeli1985making,
- title={The making of intervisibility maps with computer and plotter},
- author={Yoeli, Pinhas},
- journal={Cartographica: The International Journal for Geographic Information and Geovisualization},
- volume={22},
- number={3},
- pages={88--103},
- year={1985},
- publisher={UT Press}
- }
- */
- struct Option *refrCoeffOpt;
-
- refrCoeffOpt = G_define_option();
- refrCoeffOpt->key = "refraction_coeff";
- refrCoeffOpt->description = _("Refraction coefficient");
- refrCoeffOpt->type = TYPE_DOUBLE;
- refrCoeffOpt->required = NO;
- refrCoeffOpt->answer = "0.14286";
- refrCoeffOpt->options = "0.0-1.0";
-
- /* memory size */
- struct Option *memAmountOpt;
-
- memAmountOpt = G_define_option();
- memAmountOpt->key = "memory";
- memAmountOpt->type = TYPE_INTEGER;
- memAmountOpt->required = NO;
- memAmountOpt->key_desc = "value";
- memAmountOpt->description =
- _("Amount of memory to be used in MB");
- memAmountOpt->answer = "500";
-
- /* temporary STREAM path */
- struct Option *streamdirOpt;
-
- streamdirOpt = G_define_option() ;
- streamdirOpt->key = "stream_dir";
- streamdirOpt->type = TYPE_STRING;
- streamdirOpt->required = NO;
-#ifdef __MINGW32__
- streamdirOpt->answer = G_convert_dirseps_from_host(G_store(getenv("TEMP")));
-#else
- streamdirOpt->answer = "/var/tmp/";
-#endif
- streamdirOpt->description=
- _("Directory to hold temporary files (they can be large)");
-
- /*fill the options and flags with G_parser */
- if (G_parser(argc, argv))
- exit(EXIT_FAILURE);
-
-
- /* store the parameters into a structure to be used along the way */
- strcpy(viewOptions->inputfname, inputOpt->answer);
- strcpy(viewOptions->outputfname, outputOpt->answer);
- strcpy(viewOptions->streamdir,streamdirOpt->answer);
-
- viewOptions->obsElev = atof(obsElevOpt->answer);
- if(tgtElevOpt->answer)
- viewOptions->tgtElev = atof(tgtElevOpt->answer);
-
- viewOptions->maxDist = atof(maxDistOpt->answer);
- if (viewOptions->maxDist < 0 && viewOptions->maxDist != INFINITY_DISTANCE) {
- G_fatal_error(_("A negative max distance value is not allowed"));
- }
-
- viewOptions->doCurv = curvature->answer;
- viewOptions->doRefr = refractionFlag->answer;
- if (refractionFlag->answer && !curvature->answer)
- G_fatal_error(_("Atmospheric refraction is only calculated with "
- "respect to the curvature of the Earth. "
- "Enable the -c flag as well."));
- viewOptions->refr_coef = atof(refrCoeffOpt->answer);
-
- if (booleanOutput->answer)
- viewOptions->outputMode = OUTPUT_BOOL;
- else if (elevationFlag->answer)
- viewOptions->outputMode = OUTPUT_ELEV;
- else
- viewOptions->outputMode = OUTPUT_ANGLE;
-
- int memSizeMB = atoi(memAmountOpt->answer);
-
- if (memSizeMB < 0) {
- G_warning(_("Amount of memory cannot be negative."));
- G_warning(_(" Converting %d to %d MB"), memSizeMB, -memSizeMB);
- memSizeMB = -memSizeMB;
- }
- *memSizeBytes = (long long)memSizeMB;
- *memSizeBytes = (*memSizeBytes) << 20;
-
- G_get_set_window(window);
-
- /*The algorithm runs with the viewpoint row and col, so we need to
- convert the lat-lon coordinates to row and column format */
- *vpRow = (int)G_northing_to_row(atof(viewLocOpt->answers[1]), window);
- *vpCol = (int)G_easting_to_col(atof(viewLocOpt->answers[0]), window);
- G_debug(3, "viewpoint converted from current projection: (%.3f, %.3f) to col, row (%d, %d)",
- atof(viewLocOpt->answers[0]), atof(viewLocOpt->answers[1]), *vpCol, *vpRow);
-
- return;
-}
-
-
-
-
-/* ------------------------------------------------------------ */
-/*print the timings for the internal memory method of computing the
- viewshed */
-void
-print_timings_internal(Rtimer sweepTime, Rtimer outputTime, Rtimer totalTime)
-{
-
- char timeused[100];
-
- G_verbose_message("TOTAL TIMING:");
-
- rt_sprint_safe(timeused, sweepTime);
- G_verbose_message("Sweep: %s", timeused);
- G_verbose_message("\n");
-
- rt_sprint_safe(timeused, outputTime);
- G_verbose_message("Output: %s", timeused);
- G_verbose_message("\n");
-
- rt_sprint_safe(timeused, totalTime);
- G_verbose_message("Total: %s", timeused);
- G_verbose_message("\n");
-}
-
-
-/* ------------------------------------------------------------ */
-/*print the timings for the external memory method of solving the viewshed */
-void
-print_timings_external_memory(Rtimer totalTime, Rtimer viewshedTime,
- Rtimer outputTime, Rtimer sortOutputTime)
-{
-
- /*print timings */
- char timeused[100];
-
- G_verbose_message("\n\nTOTAL TIMING:");
-
- rt_sprint_safe(timeused, viewshedTime);
- G_verbose_message("Total sweep: %s", timeused);
-
- rt_sprint_safe(timeused, sortOutputTime);
- G_verbose_message("Sort output: %s", timeused);
-
- rt_sprint_safe(timeused, outputTime);
- G_verbose_message("Write result grid: %s", timeused);
-
- rt_sprint_safe(timeused, totalTime);
- G_verbose_message("Total Time: %s", timeused);
- G_verbose_message("\n\n");
- return;
-}
Copied: grass/trunk/raster/r.viewshed/main.cpp (from rev 49482, grass-addons/raster/r.viewshed/main.cc)
===================================================================
--- grass/trunk/raster/r.viewshed/main.cpp (rev 0)
+++ grass/trunk/raster/r.viewshed/main.cpp 2011-12-02 09:56:38 UTC (rev 49483)
@@ -0,0 +1,698 @@
+/****************************************************************************
+ *
+ * MODULE: r.viewshed
+ *
+ * AUTHOR(S): Laura Toma, Bowdoin College - ltoma at bowdoin.edu
+ * Yi Zhuang - yzhuang at bowdoin.edu
+ *
+ * Ported to GRASS by William Richard -
+ * wkrichar at bowdoin.edu or willster3021 at gmail.com
+ * Markus Metz: surface interpolation
+ *
+ * Date: July 2008; 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-2011 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 <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <unistd.h>
+
+extern "C"
+{
+#include <grass/config.h>
+#include <grass/gis.h>
+#include <grass/glocale.h>
+}
+#include "grass.h"
+#include <grass/iostream/ami.h>
+
+#include "viewshed.h"
+#include "visibility.h"
+#include "grid.h"
+#include "rbbst.h"
+#include "statusstructure.h"
+#include "distribute.h"
+
+
+
+
+/* if the user does not specify how much memory is available for the
+ program, this is the default value used (in bytes) */
+#define DEFAULT_MEMORY 500<<20
+
+
+/* observer elevation above the terrain */
+#define DEFAULT_OBS_ELEVATION 0
+
+
+/* All these flags are used for debugging */
+
+/* if this flag is set, it always runs in memory */
+//#define FORCE_INTERNAL
+
+/* if this is set, it runs in external memory, even if the problem is
+ small enough to fit in memory. In external memory it first tries
+ to run the base-case, then recursion. */
+//#define FORCE_EXTERNAL
+
+/* if this flag is set it runs in external memory, and starts
+ recursion without checking the base-case. */
+//#define FORCE_DISTRIBUTION
+
+
+
+/* ------------------------------------------------------------ */
+/* forward declarations */
+/* ------------------------------------------------------------ */
+void print_timings_internal(Rtimer sweepTime, Rtimer outputTime,
+ Rtimer totalTime);
+void print_timings_external_memory(Rtimer totalTime, Rtimer viewshedTime,
+ Rtimer outputTime, Rtimer sortOutputTime);
+
+void parse_args(int argc, char *argv[], int *vpRow, int *vpCol,
+ ViewOptions * viewOptions, long long *memSizeBytes,
+ Cell_head * window);
+
+
+
+
+/* ------------------------------------------------------------ */
+int main(int argc, char *argv[])
+{
+
+ /* GRASS initialization stuff */
+ struct GModule *module;
+
+ /*initialize GIS environment */
+ G_gisinit(argv[0]);
+
+ /*initialize module */
+ module = G_define_module();
+ G_add_keyword(_("raster"));
+ G_add_keyword(_("viewshed"));
+ G_add_keyword(_("line of sight"));
+ module->description = _("IO-efficient viewshed algorithm");
+
+ struct Cell_head region;
+
+ Rast_get_window(®ion);
+
+
+ /* ************************************************************ */
+ /* parameters set up */
+ long long memSizeBytes = DEFAULT_MEMORY;
+
+ /* the maximum size of main memory that the program ca use. The
+ user can specify it, otherwise the default value of 500MB is
+ used. The program uses this value to decied in which mode to
+ run --- in internal memory, or external memory. */
+
+ int vpRow, vpCol;
+
+ /* the coordinates of the viewpoint in the raster; right now the
+ algorithm assumes that the viewpoint is inside the grid, though
+ this is not necessary; some changes will be needed to make it
+ work with a viewpoint outside the terrain */
+
+ ViewOptions viewOptions;
+
+ //viewOptions.inputfname = (char*)malloc(500);
+ //viewOptions.outputfname = (char*)malloc(500);
+ //assert(inputfname && outputfname);
+ viewOptions.obsElev = DEFAULT_OBS_ELEVATION;
+ viewOptions.maxDist = INFINITY_DISTANCE;
+ viewOptions.outputMode = OUTPUT_ANGLE;
+ viewOptions.doCurv = FALSE;
+ viewOptions.doRefr = FALSE;
+ viewOptions.refr_coef = 1.0/7.0;
+
+ parse_args(argc, argv, &vpRow, &vpCol, &viewOptions, &memSizeBytes,
+ ®ion);
+
+ /* set viewpoint with the coordinates specified by user. The
+ height of the viewpoint is not known at this point---it will be
+ set during the execution of the algorithm */
+ Viewpoint vp;
+
+ set_viewpoint_coord(&vp, vpRow, vpCol);
+
+
+ /* ************************************************************ */
+ /* set up the header of the raster with all raster info and make
+ sure the requested viewpoint is on the map */
+ GridHeader *hd;
+
+ hd = read_header(viewOptions.inputfname, ®ion);
+ assert(hd);
+ G_get_set_window(&(hd->window));
+
+ /* LT: there is no need to exit if viewpoint is outside grid,
+ the algorithm will work correctly in theory. But this
+ requires some changes. To do. */
+ if (!(vp.row < hd->nrows && vp.col < hd->ncols)) {
+ G_warning(_("Viewpoint outside grid"));
+ G_warning(_("viewpont: (row=%d, col=%d)"), vp.row, vp.col);
+ G_fatal_error(_("grid: (rows=%d, cols=%d)"), hd->nrows, hd->ncols);
+ }
+
+
+ /* set curvature params */
+ viewOptions.cellsize = region.ew_res;
+ double e2;
+
+ G_get_ellipsoid_parameters(&viewOptions.ellps_a, &e2);
+ if (viewOptions.ellps_a == 0) {
+ /*according to r.los, this can be
+ problematic, so we'll have a backup, hardcoded radius :-( */
+ G_warning(_("Problems obtaining current ellipsoid parameters, using sphere (6370997.0)"));
+ viewOptions.ellps_a = 6370997.00;
+ }
+
+ G_begin_distance_calculations();
+
+
+
+
+ /* ************************************************************ */
+ /* decide whether the computation of the viewshed will take place
+ in-memory or in external memory */
+ int IN_MEMORY;
+ long long inmemSizeBytes = get_viewshed_memory_usage(hd);
+
+ G_verbose_message(_("In-memory memory usage is %lld B (%d MB), \
+ max mem allowed=%lld B(%dMB)"), inmemSizeBytes,
+ (int)(inmemSizeBytes >> 20), memSizeBytes,
+ (int)(memSizeBytes >> 20));
+ if (inmemSizeBytes < memSizeBytes) {
+ IN_MEMORY = 1;
+ G_verbose_message("***** IN_MEMORY MODE *****");
+ }
+ else {
+ G_verbose_message("***** EXTERNAL_MEMORY MODE *****");
+ IN_MEMORY = 0;
+ }
+
+ /* the mode can be forced to in memory or external if the user
+ wants to test or debug a specific mode */
+#ifdef FORCE_EXTERNAL
+ IN_MEMORY = 0;
+ G_debug(1, "FORCED EXTERNAL");
+#endif
+
+#ifdef FORCE_INTERNAL
+ IN_MEMORY = 1;
+ G_debug(1, "FORCED INTERNAL");
+#endif
+
+
+ /* ************************************************************ */
+ /* compute viewshed in memory */
+ /* ************************************************************ */
+ if (IN_MEMORY) {
+ /*//////////////////////////////////////////////////// */
+ /*/viewshed in internal memory */
+ /*//////////////////////////////////////////////////// */
+ Rtimer totalTime, outputTime, sweepTime;
+ MemoryVisibilityGrid *visgrid;
+
+ rt_start(totalTime);
+
+ /*compute the viewshed and store it in visgrid */
+ rt_start(sweepTime);
+ visgrid =
+ viewshed_in_memory(viewOptions.inputfname, hd, &vp, viewOptions);
+ rt_stop(sweepTime);
+
+ /* write the output */
+ rt_start(outputTime);
+ save_inmem_visibilitygrid(visgrid, viewOptions, vp);
+ rt_stop(outputTime);
+
+ rt_stop(totalTime);
+
+ print_timings_internal(sweepTime, outputTime, totalTime);
+ }
+
+
+
+
+ /* ************************************************************ */
+ /* compute viewshed in external memory */
+ /* ************************************************************ */
+ else {
+
+ /* ************************************************************ */
+ /* set up external memory mode */
+ /* setup STREAM_DIR if not already set */
+ char buf[1000];
+
+ if (getenv(STREAM_TMPDIR) != NULL) {
+ /*if already set */
+ G_debug(1, "%s=%s", STREAM_TMPDIR, getenv(STREAM_TMPDIR));
+ G_debug(1, "Intermediate stream location: %s",
+ getenv(STREAM_TMPDIR));
+ }
+ else {
+ /*set it */
+ sprintf(buf, "%s=%s", STREAM_TMPDIR, viewOptions.streamdir);
+ G_debug(1, "setting %s ", buf);
+ putenv(buf);
+ if (getenv(STREAM_TMPDIR) == NULL) {
+ G_fatal_error(_("%s not set"), "STREAM_TMPDIR");
+ exit(1);
+ }
+ else {
+ G_debug(1, "are ok.");
+ }
+ G_debug(1, "Intermediate stream location: %s", viewOptions.streamdir);
+ }
+ G_important_message(_("Intermediate files will not be deleted \
+ in case of abnormal termination."));
+ G_important_message(_("To save space delete these files manually!"));
+
+
+ /* initialize IOSTREAM memory manager */
+ MM_manager.set_memory_limit(memSizeBytes);
+ MM_manager.warn_memory_limit();
+ MM_manager.print_limit_mode();
+
+
+
+ /* ************************************************************ */
+ /* BASE CASE OR DISTRIBUTION */
+ /* determine whether base-case of external algorithm is enough,
+ or recursion is necessary */
+ int BASE_CASE = 0;
+
+ if (get_active_str_size_bytes(hd) < memSizeBytes)
+ BASE_CASE = 1;
+
+ /*if the user set the FORCE_DISTRIBUTION flag, then the
+ algorithm runs in the fuly recursive mode (even if this is
+ not necessary). This is used solely for debugging purpses */
+#ifdef FORCE_DISTRIBUTION
+ BASE_CASE = 0;
+#endif
+
+
+
+
+ /* ************************************************************ */
+ /* external memory, base case */
+ /* ************************************************************ */
+ if (BASE_CASE) {
+ G_debug
+ (1, "---Active structure small, starting base case---");
+
+ Rtimer totalTime, viewshedTime, outputTime, sortOutputTime;
+
+ rt_start(totalTime);
+
+ /*run viewshed's algorithm */
+ IOVisibilityGrid *visgrid;
+
+ rt_start(viewshedTime);
+ visgrid =
+ viewshed_external(viewOptions.inputfname, hd, &vp,
+ viewOptions);
+ rt_stop(viewshedTime);
+
+ /*sort output */
+ rt_start(sortOutputTime);
+ sort_io_visibilitygrid(visgrid);
+ rt_stop(sortOutputTime);
+
+ /*save output stream to file. */
+ rt_start(outputTime);
+ save_io_visibilitygrid(visgrid, viewOptions, vp);
+ rt_stop(outputTime);
+
+ rt_stop(totalTime);
+
+ print_timings_external_memory(totalTime, viewshedTime,
+ outputTime, sortOutputTime);
+ }
+
+
+
+ /************************************************************/
+ /* external memory, recursive distribution sweeping recursion */
+ /************************************************************ */
+ else { /* if not BASE_CASE */
+#ifndef FORCE_DISTRIBUTION
+ G_debug(1, "---Active structure does not fit in memory,");
+#else
+ G_debug(1, "FORCED DISTRIBUTION");
+#endif
+
+ Rtimer totalTime, sweepTime, outputTime, sortOutputTime;
+
+ rt_start(totalTime);
+
+ /*get the viewshed solution by distribution */
+ IOVisibilityGrid *visgrid;
+
+ rt_start(sweepTime);
+ visgrid =
+ distribute_and_sweep(viewOptions.inputfname, hd, &vp,
+ viewOptions);
+
+ rt_stop(sweepTime);
+
+ /*sort the visibility grid so that it is in order when it is
+ outputted */
+ rt_start(sortOutputTime);
+ sort_io_visibilitygrid(visgrid);
+ rt_stop(sortOutputTime);
+
+ rt_start(outputTime);
+ save_io_visibilitygrid(visgrid, viewOptions, vp);
+ rt_stop(outputTime);
+
+
+ rt_stop(totalTime);
+
+ print_timings_external_memory(totalTime, sweepTime,
+ outputTime, sortOutputTime);
+
+ }
+ }
+ /*end external memory, distribution sweep */
+
+
+ /**************************************/
+ /* FINISH UP, ALL CASES */
+ /**************************************/
+
+ /*close input file and free grid header */
+ G_free(hd);
+ /*following GRASS's coding standards for history and exiting */
+ struct History history;
+
+ Rast_short_history(viewOptions.outputfname, "raster", &history);
+ Rast_command_history(&history);
+ Rast_write_history(viewOptions.outputfname, &history);
+ exit(EXIT_SUCCESS);
+}
+
+
+
+
+/* ------------------------------------------------------------ */
+/* parse arguments */
+void
+parse_args(int argc, char *argv[], int *vpRow, int *vpCol,
+ ViewOptions * viewOptions, long long *memSizeBytes,
+ Cell_head * window)
+{
+
+ assert(vpRow && vpCol && memSizeBytes && window);
+
+ /* the input */
+ struct Option *inputOpt;
+
+ inputOpt = G_define_standard_option(G_OPT_R_ELEV);
+ inputOpt->key = "input";
+ inputOpt->guisection = _("Input_options");
+
+ /* the output */
+ struct Option *outputOpt;
+
+ outputOpt = G_define_standard_option(G_OPT_R_OUTPUT);
+ outputOpt->label = _("Name of output viewshed raster map");
+ outputOpt->description =
+ _("default format: {NULL (invisible), vertical angle wrt viewpoint (visible)}");
+ outputOpt->guisection = _("Output_options");
+
+ /* curvature flag */
+ struct Flag *curvature;
+
+ curvature = G_define_flag();
+ curvature->key = 'c';
+ curvature->description =
+ _("Consider the curvature of the earth (current ellipsoid)");
+
+ /* atmospheric refraction flag */
+ struct Flag *refractionFlag;
+
+ refractionFlag = G_define_flag();
+ refractionFlag->key = 'r';
+ refractionFlag->description =
+ _("Consider the effect of atmospheric refraction");
+
+ /* boolean output flag */
+ struct Flag *booleanOutput;
+
+ booleanOutput = G_define_flag();
+ booleanOutput->key = 'b';
+ booleanOutput->description =
+ _("Output format is {0 (invisible) 1 (visible)}");
+
+ /* output mode = elevation flag */
+ struct Flag *elevationFlag;
+
+ elevationFlag = G_define_flag();
+ elevationFlag->key = 'e';
+ elevationFlag->description =
+ _("Output format is invisible = NULL, else current elev - viewpoint_elev");
+
+
+ /* viewpoint coordinates */
+ struct Option *viewLocOpt;
+
+ viewLocOpt = G_define_option();
+ viewLocOpt->key = "coordinate";
+ viewLocOpt->type = TYPE_STRING;
+ viewLocOpt->required = YES;
+ viewLocOpt->key_desc = "east,north";
+ viewLocOpt->description = _("Coordinates of viewing position");
+ viewLocOpt->guisection = _("Input_options");
+
+ /* observer elevation */
+ struct Option *obsElevOpt;
+
+ obsElevOpt = G_define_option();
+ obsElevOpt->key = "obs_elev";
+ obsElevOpt->type = TYPE_DOUBLE;
+ obsElevOpt->required = NO;
+ obsElevOpt->key_desc = "value";
+ obsElevOpt->description = _("Viewing elevation above the ground");
+ obsElevOpt->answer = "1.75";
+ obsElevOpt->guisection = _("Input_options");
+
+ /* target elevation offset */
+ struct Option *tgtElevOpt;
+
+ tgtElevOpt = G_define_option();
+ tgtElevOpt->key = "tgt_elev";
+ tgtElevOpt->type = TYPE_DOUBLE;
+ tgtElevOpt->required = NO;
+ tgtElevOpt->key_desc = "value";
+ tgtElevOpt->description = _("Offset for target elevation above the ground");
+ tgtElevOpt->answer = "0.0";
+ tgtElevOpt->guisection = _("Input_options");
+
+ /* max distance */
+ struct Option *maxDistOpt;
+
+ maxDistOpt = G_define_option();
+ maxDistOpt->key = "max_dist";
+ maxDistOpt->type = TYPE_DOUBLE;
+ maxDistOpt->required = NO;
+ maxDistOpt->key_desc = "value";
+ maxDistOpt->description =
+ _("Maximum visibility radius. By default infinity (-1).");
+ char infdist[10];
+
+ sprintf(infdist, "%d", INFINITY_DISTANCE);
+ maxDistOpt->answer = infdist;
+ maxDistOpt->guisection = _("Input_options");
+
+ /* atmospheric refraction coeff. 1/7 for visual, 0.325 for radio waves, ... */
+ /* in future we might calculate this based on the physics, for now we
+ just fudge by the 1/7th approximation.
+
+ ?? See ??
+
+ @article{yoeli1985making,
+ title={The making of intervisibility maps with computer and plotter},
+ author={Yoeli, Pinhas},
+ journal={Cartographica: The International Journal for Geographic Information and Geovisualization},
+ volume={22},
+ number={3},
+ pages={88--103},
+ year={1985},
+ publisher={UT Press}
+ }
+ */
+ struct Option *refrCoeffOpt;
+
+ refrCoeffOpt = G_define_option();
+ refrCoeffOpt->key = "refraction_coeff";
+ refrCoeffOpt->description = _("Refraction coefficient");
+ refrCoeffOpt->type = TYPE_DOUBLE;
+ refrCoeffOpt->required = NO;
+ refrCoeffOpt->answer = "0.14286";
+ refrCoeffOpt->options = "0.0-1.0";
+
+ /* memory size */
+ struct Option *memAmountOpt;
+
+ memAmountOpt = G_define_option();
+ memAmountOpt->key = "memory";
+ memAmountOpt->type = TYPE_INTEGER;
+ memAmountOpt->required = NO;
+ memAmountOpt->key_desc = "value";
+ memAmountOpt->description =
+ _("Amount of memory to be used in MB");
+ memAmountOpt->answer = "500";
+
+ /* temporary STREAM path */
+ struct Option *streamdirOpt;
+
+ streamdirOpt = G_define_option() ;
+ streamdirOpt->key = "stream_dir";
+ streamdirOpt->type = TYPE_STRING;
+ streamdirOpt->required = NO;
+#ifdef __MINGW32__
+ streamdirOpt->answer = G_convert_dirseps_from_host(G_store(getenv("TEMP")));
+#else
+ streamdirOpt->answer = "/var/tmp/";
+#endif
+ streamdirOpt->description=
+ _("Directory to hold temporary files (they can be large)");
+
+ /*fill the options and flags with G_parser */
+ if (G_parser(argc, argv))
+ exit(EXIT_FAILURE);
+
+
+ /* store the parameters into a structure to be used along the way */
+ strcpy(viewOptions->inputfname, inputOpt->answer);
+ strcpy(viewOptions->outputfname, outputOpt->answer);
+ strcpy(viewOptions->streamdir,streamdirOpt->answer);
+
+ viewOptions->obsElev = atof(obsElevOpt->answer);
+ if(tgtElevOpt->answer)
+ viewOptions->tgtElev = atof(tgtElevOpt->answer);
+
+ viewOptions->maxDist = atof(maxDistOpt->answer);
+ if (viewOptions->maxDist < 0 && viewOptions->maxDist != INFINITY_DISTANCE) {
+ G_fatal_error(_("A negative max distance value is not allowed"));
+ }
+
+ viewOptions->doCurv = curvature->answer;
+ viewOptions->doRefr = refractionFlag->answer;
+ if (refractionFlag->answer && !curvature->answer)
+ G_fatal_error(_("Atmospheric refraction is only calculated with "
+ "respect to the curvature of the Earth. "
+ "Enable the -c flag as well."));
+ viewOptions->refr_coef = atof(refrCoeffOpt->answer);
+
+ if (booleanOutput->answer)
+ viewOptions->outputMode = OUTPUT_BOOL;
+ else if (elevationFlag->answer)
+ viewOptions->outputMode = OUTPUT_ELEV;
+ else
+ viewOptions->outputMode = OUTPUT_ANGLE;
+
+ int memSizeMB = atoi(memAmountOpt->answer);
+
+ if (memSizeMB < 0) {
+ G_warning(_("Amount of memory cannot be negative."));
+ G_warning(_(" Converting %d to %d MB"), memSizeMB, -memSizeMB);
+ memSizeMB = -memSizeMB;
+ }
+ *memSizeBytes = (long long)memSizeMB;
+ *memSizeBytes = (*memSizeBytes) << 20;
+
+ G_get_set_window(window);
+
+ /*The algorithm runs with the viewpoint row and col, so we need to
+ convert the lat-lon coordinates to row and column format */
+ *vpRow = (int)Rast_northing_to_row(atof(viewLocOpt->answers[1]), window);
+ *vpCol = (int)Rast_easting_to_col(atof(viewLocOpt->answers[0]), window);
+ G_debug(3, "viewpoint converted from current projection: (%.3f, %.3f) to col, row (%d, %d)",
+ atof(viewLocOpt->answers[0]), atof(viewLocOpt->answers[1]), *vpCol, *vpRow);
+
+ return;
+}
+
+
+
+
+/* ------------------------------------------------------------ */
+/*print the timings for the internal memory method of computing the
+ viewshed */
+void
+print_timings_internal(Rtimer sweepTime, Rtimer outputTime, Rtimer totalTime)
+{
+
+ char timeused[100];
+
+ G_verbose_message("TOTAL TIMING:");
+
+ rt_sprint_safe(timeused, sweepTime);
+ G_verbose_message("Sweep: %s", timeused);
+ G_verbose_message("\n");
+
+ rt_sprint_safe(timeused, outputTime);
+ G_verbose_message("Output: %s", timeused);
+ G_verbose_message("\n");
+
+ rt_sprint_safe(timeused, totalTime);
+ G_verbose_message("Total: %s", timeused);
+ G_verbose_message("\n");
+}
+
+
+/* ------------------------------------------------------------ */
+/*print the timings for the external memory method of solving the viewshed */
+void
+print_timings_external_memory(Rtimer totalTime, Rtimer viewshedTime,
+ Rtimer outputTime, Rtimer sortOutputTime)
+{
+
+ /*print timings */
+ char timeused[100];
+
+ G_verbose_message("\n\nTOTAL TIMING:");
+
+ rt_sprint_safe(timeused, viewshedTime);
+ G_verbose_message("Total sweep: %s", timeused);
+
+ rt_sprint_safe(timeused, sortOutputTime);
+ G_verbose_message("Sort output: %s", timeused);
+
+ rt_sprint_safe(timeused, outputTime);
+ G_verbose_message("Write result grid: %s", timeused);
+
+ rt_sprint_safe(timeused, totalTime);
+ G_verbose_message("Total Time: %s", timeused);
+ G_verbose_message("\n\n");
+ return;
+}
Deleted: grass/trunk/raster/r.viewshed/rbbst.cc
===================================================================
--- grass-addons/raster/r.viewshed/rbbst.cc 2011-12-02 09:30:54 UTC (rev 49482)
+++ grass/trunk/raster/r.viewshed/rbbst.cc 2011-12-02 09:56:38 UTC (rev 49483)
@@ -1,818 +0,0 @@
-
-/****************************************************************************
- *
- * MODULE: r.viewshed
- *
- * AUTHOR(S): Laura Toma, Bowdoin College - ltoma at bowdoin.edu
- * Yi Zhuang - yzhuang at bowdoin.edu
-
- * Ported to GRASS by William Richard -
- * wkrichar at bowdoin.edu or willster3021 at 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.
- *
- *****************************************************************************/
-
-/*
-
- A R/B BST. Always call initNILnode() before using the tree.
- Version 0.0.0
-
- Version 0.0.1
- Rewrote BST Deletion to improve efficiency
-
- Version 0.0.2
- Bug fixed in deletion.
- CLRS pseudocode forgot to make sure that x is not NIL before
- calling rbDeleteFixup(root,x).
-
- Version 0.0.3
- Some Cleanup. Separated the public portion and the
- private porthion of the interface in the header
-
-
- =================================
- This is based on BST 1.0.4
- BST change log
- <---------------->
- find max is implemented in this version.
- Version 1.0.2
-
- Version 1.0.4
- Major bug fix in deletion (when the node has two children,
- one of them has a wrong parent pointer after the rotation in the deletion.)
- <----------------->
- */
-
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <assert.h>
-#include <math.h>
-#include "rbbst.h"
-
-extern "C"
-{
-#include <grass/gis.h>
-#include <grass/glocale.h>
-}
-
-
-
-TreeNode *NIL;
-
-#define EPSILON 0.0000001
-
-
-/*public:--------------------------------- */
-RBTree *create_tree(TreeValue tv)
-{
- init_nil_node();
- RBTree *rbt = (RBTree *) G_malloc(sizeof(RBTree));
- TreeNode *root = (TreeNode *) G_malloc(sizeof(TreeNode));
-
- rbt->root = root;
- rbt->root->value = tv;
- rbt->root->left = NIL;
- rbt->root->right = NIL;
- rbt->root->parent = NIL;
- rbt->root->color = RB_BLACK;
-
- return rbt;
-}
-
-/*LT: not sure if this is correct */
-int is_empty(RBTree * t)
-{
- assert(t);
- return (t->root == NIL);
-}
-
-void delete_tree(RBTree * t)
-{
- destroy_sub_tree(t->root);
- return;
-}
-
-void destroy_sub_tree(TreeNode * node)
-{
- if (node == NIL)
- return;
-
- destroy_sub_tree(node->left);
- destroy_sub_tree(node->right);
- G_free(node);
- return;
-}
-
-void insert_into(RBTree * rbt, TreeValue value)
-{
- insert_into_tree(&(rbt->root), value);
- return;
-}
-
-void delete_from(RBTree * rbt, double key)
-{
- delete_from_tree(&(rbt->root), key);
- return;
-}
-
-TreeNode *search_for_node_with_key(RBTree * rbt, double key)
-{
- return search_for_node(rbt->root, key);
-}
-
-/*------------The following is designed for viewshed's algorithm-------*/
-double find_max_gradient_within_key(RBTree * rbt, double key, double angle, double gradient)
-{
- return find_max_value_within_key(rbt->root, key, angle, gradient);
-}
-
-/*<--------------------------------->
- //Private below this line */
-void init_nil_node()
-{
- NIL = (TreeNode *) G_malloc(sizeof(TreeNode));
- NIL->color = RB_BLACK;
- NIL->value.angle[0] = 0;
- NIL->value.angle[1] = 0;
- NIL->value.angle[2] = 0;
- NIL->value.gradient[0] = SMALLEST_GRADIENT;
- NIL->value.gradient[1] = SMALLEST_GRADIENT;
- NIL->value.gradient[2] = SMALLEST_GRADIENT;
- NIL->value.maxGradient = SMALLEST_GRADIENT;
- NIL->value.key = 0;
-
- NIL->parent = NULL;
- NIL->left = NULL;
- NIL->right = NULL;
- return;
-}
-
-/*you can write change this compare function, depending on your TreeValue struct
- //compare function used by findMaxValue
- //-1: v1 < v2
- //0: v1 = v2
- //2: v1 > v2 */
-char compare_values(TreeValue * v1, TreeValue * v2)
-{
- if (v1->gradient[1] > v2->gradient[1])
- return 1;
- if (v1->gradient[1] < v2->gradient[1])
- return -1;
-
- return 0;
-}
-
-
-/*a function used to compare two doubles */
-char compare_double(double a, double b)
-{
- if (fabs(a - b) < EPSILON)
- return 0;
- if (a - b < 0)
- return -1;
-
- return 1;
-}
-
-
-
-/*create a tree node */
-TreeNode *create_tree_node(TreeValue value)
-{
- TreeNode *ret;
-
- ret = (TreeNode *) G_malloc(sizeof(TreeNode));
-
- ret->color = RB_RED;
-
- ret->left = NIL;
- ret->right = NIL;
- ret->parent = NIL;
-
- ret->value = value;
- ret->value.maxGradient = SMALLEST_GRADIENT;
- return ret;
-}
-
-/*create node with its value set to the value given
- //and insert the node into the tree
- //rbInsertFixup may change the root pointer, so TreeNode** is passed in */
-void insert_into_tree(TreeNode ** root, TreeValue value)
-{
- TreeNode *curNode;
- TreeNode *nextNode;
-
- curNode = *root;
-
- if (compare_double(value.key, curNode->value.key) == -1) {
- nextNode = curNode->left;
- }
- else {
- nextNode = curNode->right;
- }
-
-
- while (nextNode != NIL) {
- curNode = nextNode;
-
- if (compare_double(value.key, curNode->value.key) == -1) {
- nextNode = curNode->left;
- }
- else {
- nextNode = curNode->right;
- }
- }
-
- /*create a new node
- //and place it at the right place
- //created node is RED by default */
- nextNode = create_tree_node(value);
-
- nextNode->parent = curNode;
-
- if (compare_double(value.key, curNode->value.key) == -1) {
- curNode->left = nextNode;
- }
- else {
- curNode->right = nextNode;
- }
-
- TreeNode *inserted = nextNode;
-
- /*update augmented maxGradient */
- nextNode->value.maxGradient = nextNode->value.gradient[1];
- while (nextNode->parent != NIL) {
- if (nextNode->parent->value.maxGradient < nextNode->value.maxGradient)
- nextNode->parent->value.maxGradient = nextNode->value.maxGradient;
-
- if (nextNode->parent->value.maxGradient > nextNode->value.maxGradient)
- break;
- nextNode = nextNode->parent;
- }
-
- /*fix rb tree after insertion */
- rb_insert_fixup(root, inserted);
-
- return;
-}
-
-void rb_insert_fixup(TreeNode ** root, TreeNode * z)
-{
- /*see pseudocode on page 281 in CLRS */
- TreeNode *y;
-
- while (z->parent->color == RB_RED) {
- if (z->parent == z->parent->parent->left) {
- y = z->parent->parent->right;
- if (y->color == RB_RED) { /*case 1 */
- z->parent->color = RB_BLACK;
- y->color = RB_BLACK;
- z->parent->parent->color = RB_RED;
- z = z->parent->parent;
- }
- else {
- if (z == z->parent->right) { /*case 2 */
- z = z->parent;
- left_rotate(root, z); /*convert case 2 to case 3 */
- }
- z->parent->color = RB_BLACK; /*case 3 */
- z->parent->parent->color = RB_RED;
- right_rotate(root, z->parent->parent);
- }
-
- }
- else { /*(z->parent == z->parent->parent->right) */
- y = z->parent->parent->left;
- if (y->color == RB_RED) { /*case 1 */
- z->parent->color = RB_BLACK;
- y->color = RB_BLACK;
- z->parent->parent->color = RB_RED;
- z = z->parent->parent;
- }
- else {
- if (z == z->parent->left) { /*case 2 */
- z = z->parent;
- right_rotate(root, z); /*convert case 2 to case 3 */
- }
- z->parent->color = RB_BLACK; /*case 3 */
- z->parent->parent->color = RB_RED;
- left_rotate(root, z->parent->parent);
- }
- }
- }
- (*root)->color = RB_BLACK;
-
- return;
-}
-
-
-
-
-/*search for a node with the given key */
-TreeNode *search_for_node(TreeNode * root, double key)
-{
- TreeNode *curNode = root;
-
- while (curNode != NIL && compare_double(key, curNode->value.key) != 0) {
-
- if (compare_double(key, curNode->value.key) == -1) {
- curNode = curNode->left;
- }
- else {
- curNode = curNode->right;
- }
-
- }
-
- return curNode;
-}
-
-/*function used by treeSuccessor */
-TreeNode *tree_minimum(TreeNode * x)
-{
- while (x->left != NIL)
- x = x->left;
-
- return x;
-}
-
-/*function used by deletion */
-TreeNode *tree_successor(TreeNode * x)
-{
- if (x->right != NIL)
- return tree_minimum(x->right);
- TreeNode *y = x->parent;
-
- while (y != NIL && x == y->right) {
- x = y;
- if (y->parent == NIL)
- return y;
- y = y->parent;
- }
- return y;
-}
-
-
-/*delete the node out of the tree */
-void delete_from_tree(TreeNode ** root, double key)
-{
- double tmpMax;
- TreeNode *z;
- TreeNode *x;
- TreeNode *y;
- TreeNode *toFix;
-
- z = search_for_node(*root, key);
-
- if (z == NIL) {
- /*node to delete is not found */
- G_fatal_error(_("Attempt to delete node with key=%f failed"), key);
- }
-
- /*1-3 */
- if (z->left == NIL || z->right == NIL)
- y = z;
- else
- y = tree_successor(z);
-
- if (y == NIL) {
- G_fatal_error(_("Successor node not found. Deletion fails."));
- }
-
- /*4-6 */
- if (y->left != NIL)
- x = y->left;
- else
- x = y->right;
-
- /*7 */
- x->parent = y->parent;
-
- /*8-12 */
- if (y->parent == NIL) {
- *root = x;
-
- toFix = *root; /*augmentation to be fixed */
- }
- else {
- if (y == y->parent->left)
- y->parent->left = x;
- else
- y->parent->right = x;
-
- toFix = y->parent; /*augmentation to be fixed */
- }
-
- /*fix augmentation for removing y */
- TreeNode *curNode = y;
- double left, right;
-
- while (curNode->parent != NIL) {
- if (curNode->parent->value.maxGradient == y->value.gradient[1]) {
- left = find_max_value(curNode->parent->left);
- right = find_max_value(curNode->parent->right);
-
- if (left > right)
- curNode->parent->value.maxGradient = left;
- else
- curNode->parent->value.maxGradient = right;
-
- if (curNode->parent->value.gradient[1] >
- curNode->parent->value.maxGradient)
- curNode->parent->value.maxGradient =
- curNode->parent->value.gradient[1];
- }
- else {
- break;
- }
- curNode = curNode->parent;
- }
-
-
- /*fix augmentation for x */
- tmpMax =
- toFix->left->value.maxGradient >
- toFix->right->value.maxGradient ? toFix->left->value.
- maxGradient : toFix->right->value.maxGradient;
- if (tmpMax > toFix->value.gradient[1])
- toFix->value.maxGradient = tmpMax;
- else
- toFix->value.maxGradient = toFix->value.gradient[1];
-
- /*13-15 */
- if (y != NIL && y != z) {
- double zGradient = z->value.gradient[1];
-
- z->value.key = y->value.key;
- z->value.gradient[0] = y->value.gradient[0];
- z->value.gradient[1] = y->value.gradient[1];
- z->value.gradient[2] = y->value.gradient[2];
- z->value.angle[0] = y->value.angle[0];
- z->value.angle[1] = y->value.angle[1];
- z->value.angle[2] = y->value.angle[2];
-
-
- toFix = z;
- /*fix augmentation */
- tmpMax =
- toFix->left->value.maxGradient >
- toFix->right->value.maxGradient ? toFix->left->value.
- maxGradient : toFix->right->value.maxGradient;
- if (tmpMax > toFix->value.gradient[1])
- toFix->value.maxGradient = tmpMax;
- else
- toFix->value.maxGradient = toFix->value.gradient[1];
-
- while (z->parent != NIL) {
- if (z->parent->value.maxGradient == zGradient) {
- if (z->parent->value.gradient[1] != zGradient &&
- (!(z->parent->left->value.maxGradient == zGradient &&
- z->parent->right->value.maxGradient == zGradient))) {
-
- left = find_max_value(z->parent->left);
- right = find_max_value(z->parent->right);
-
- if (left > right)
- z->parent->value.maxGradient = left;
- else
- z->parent->value.maxGradient = right;
-
- if (z->parent->value.gradient[1] >
- z->parent->value.maxGradient)
- z->parent->value.maxGradient =
- z->parent->value.gradient[1];
-
- }
-
- }
- else {
- if (z->value.maxGradient > z->parent->value.maxGradient)
- z->parent->value.maxGradient = z->value.maxGradient;
- }
- z = z->parent;
- }
-
- }
-
- /*16-17 */
- if (y->color == RB_BLACK && x != NIL)
- rb_delete_fixup(root, x);
-
- /*18 */
- G_free(y);
-
- return;
-}
-
-/*fix the rb tree after deletion */
-void rb_delete_fixup(TreeNode ** root, TreeNode * x)
-{
- TreeNode *w;
-
- while (x != *root && x->color == RB_BLACK) {
- if (x == x->parent->left) {
- w = x->parent->right;
- if (w->color == RB_RED) {
- w->color = RB_BLACK;
- x->parent->color = RB_RED;
- left_rotate(root, x->parent);
- w = x->parent->right;
- }
-
- if (w == NIL) {
- x = x->parent;
- continue;
- }
-
- if (w->left->color == RB_BLACK && w->right->color == RB_BLACK) {
- w->color = RB_RED;
- x = x->parent;
- }
- else {
- if (w->right->color == RB_BLACK) {
- w->left->color = RB_BLACK;
- w->color = RB_RED;
- right_rotate(root, w);
- w = x->parent->right;
- }
-
- w->color = x->parent->color;
- x->parent->color = RB_BLACK;
- w->right->color = RB_BLACK;
- left_rotate(root, x->parent);
- x = *root;
- }
-
- }
- else { /*(x==x->parent->right) */
- w = x->parent->left;
- if (w->color == RB_RED) {
- w->color = RB_BLACK;
- x->parent->color = RB_RED;
- right_rotate(root, x->parent);
- w = x->parent->left;
- }
-
- if (w == NIL) {
- x = x->parent;
- continue;
- }
-
- if (w->right->color == RB_BLACK && w->left->color == RB_BLACK) {
- w->color = RB_RED;
- x = x->parent;
- }
- else {
- if (w->left->color == RB_BLACK) {
- w->right->color = RB_BLACK;
- w->color = RB_RED;
- left_rotate(root, w);
- w = x->parent->left;
- }
-
- w->color = x->parent->color;
- x->parent->color = RB_BLACK;
- w->left->color = RB_BLACK;
- right_rotate(root, x->parent);
- x = *root;
- }
-
- }
- }
- x->color = RB_BLACK;
-
- return;
-}
-
-/*find the max value in the given tree
- //you need to provide a compare function to compare the nodes */
-double find_max_value(TreeNode * root)
-{
- if (!root)
- return SMALLEST_GRADIENT;
- assert(root);
- /*assert(root->value.maxGradient != SMALLEST_GRADIENT);
- //LT: this shoudl be fixed
- //if (root->value.maxGradient != SMALLEST_GRADIENT) */
- return root->value.maxGradient;
-}
-
-
-
-/* find max within the max key */
-double find_max_value_within_key(TreeNode * root, double maxKey, double angle, double gradient)
-{
- TreeNode *keyNode = search_for_node(root, maxKey);
-
- if (keyNode == NIL) {
- /*fprintf(stderr, "key node not found. error occured!\n");
- //there is no point in the structure with key < maxKey */
- return SMALLEST_GRADIENT;
- exit(1);
- }
-
- TreeNode *currNode = keyNode;
- double max = SMALLEST_GRADIENT;
- double tmpMax;
- double curr_gradient;
-
- /* traverse all nodes with smaller distance */
- while (currNode != NIL) {
- int checkme = (currNode->value.angle[0] <= angle &&
- currNode->value.angle[2] >= angle);
-
- if (!checkme && currNode->value.key > 0) {
- G_warning(_("\nangles outside angle %.4f"), angle);
- G_warning(_("ENTER angle %.4f"), currNode->value.angle[0]);
- G_warning(_("CENTER angle %.4f"), currNode->value.angle[1]);
- G_warning(_("EXIT angle %.4f"), currNode->value.angle[2]);
- G_warning(_("\nENTER gradient %.4f"), currNode->value.gradient[0]);
- G_warning(_("CENTER gradient %.4f"), currNode->value.gradient[1]);
- G_warning(_("EXIT gradient %.4f"), currNode->value.gradient[2]);
- }
-
- if (currNode->value.key > maxKey) {
- G_fatal_error(_("current dist too large %.4f > %.4f"), currNode->value.key, maxKey);
- }
-
-
- if (checkme && currNode != keyNode) {
- if (angle < currNode->value.angle[1]) {
- curr_gradient = currNode->value.gradient[1] +
- (currNode->value.gradient[0] - currNode->value.gradient[1]) *
- (currNode->value.angle[1] - angle) /
- (currNode->value.angle[1] - currNode->value.angle[0]);
- }
- else if (angle > currNode->value.angle[1]) {
- curr_gradient = currNode->value.gradient[1] +
- (currNode->value.gradient[2] - currNode->value.gradient[1]) *
- (angle - currNode->value.angle[1]) /
- (currNode->value.angle[2] - currNode->value.angle[1]);
- }
- else /* angle == currNode->value.angle[1] */
- curr_gradient = currNode->value.gradient[1];
-
- if (curr_gradient > max)
- max = curr_gradient;
-
- if (max > gradient)
- return max;
- }
- /* get next smaller key */
- if (currNode->left != NIL) {
- currNode = currNode->left;
- while (currNode->right != NIL)
- currNode = currNode->right;
- }
- else {
- /* at smallest item in this branch, go back up */
- TreeNode *lastNode;
-
- do {
- lastNode = currNode;
- currNode = currNode->parent;
- } while (currNode != NIL && lastNode == currNode->left);
- }
- }
- return max;
-
- /* old code assuming flat cells */
- while (keyNode->parent != NIL) {
- if (keyNode == keyNode->parent->right) { /*its the right node of its parent; */
- tmpMax = find_max_value(keyNode->parent->left);
- if (tmpMax > max)
- max = tmpMax;
- if (keyNode->parent->value.gradient[1] > max)
- max = keyNode->parent->value.gradient[1];
- }
- keyNode = keyNode->parent;
- }
-
- return max;
-}
-
-
-void left_rotate(TreeNode ** root, TreeNode * x)
-{
- TreeNode *y;
-
- y = x->right;
-
- /*maintain augmentation */
- double tmpMax;
-
- /*fix x */
- tmpMax = x->left->value.maxGradient > y->left->value.maxGradient ?
- x->left->value.maxGradient : y->left->value.maxGradient;
-
- if (tmpMax > x->value.gradient[1])
- x->value.maxGradient = tmpMax;
- else
- x->value.maxGradient = x->value.gradient[1];
-
-
- /*fix y */
- tmpMax = x->value.maxGradient > y->right->value.maxGradient ?
- x->value.maxGradient : y->right->value.maxGradient;
-
- if (tmpMax > y->value.gradient[1])
- y->value.maxGradient = tmpMax;
- else
- y->value.maxGradient = y->value.gradient[1];
-
- /*left rotation
- //see pseudocode on page 278 in CLRS */
-
- x->right = y->left; /*turn y's left subtree into x's right subtree */
- y->left->parent = x;
-
- y->parent = x->parent; /*link x's parent to y */
-
- if (x->parent == NIL) {
- *root = y;
- }
- else {
- if (x == x->parent->left)
- x->parent->left = y;
- else
- x->parent->right = y;
- }
-
- y->left = x;
- x->parent = y;
-
- return;
-}
-
-void right_rotate(TreeNode ** root, TreeNode * y)
-{
- TreeNode *x;
-
- x = y->left;
-
- /*maintain augmentation
- //fix y */
- double tmpMax;
-
- tmpMax = x->right->value.maxGradient > y->right->value.maxGradient ?
- x->right->value.maxGradient : y->right->value.maxGradient;
-
- if (tmpMax > y->value.gradient[1])
- y->value.maxGradient = tmpMax;
- else
- y->value.maxGradient = y->value.gradient[1];
-
- /*fix x */
- tmpMax = x->left->value.maxGradient > y->value.maxGradient ?
- x->left->value.maxGradient : y->value.maxGradient;
-
- if (tmpMax > x->value.gradient[1])
- x->value.maxGradient = tmpMax;
- else
- x->value.maxGradient = x->value.gradient[1];
-
- /*ratation */
- y->left = x->right;
- x->right->parent = y;
-
- x->parent = y->parent;
-
- if (y->parent == NIL) {
- *root = x;
- }
- else {
- if (y->parent->left == y)
- y->parent->left = x;
- else
- y->parent->right = x;
- }
-
- x->right = y;
- y->parent = x;
-
- return;
-}
Copied: grass/trunk/raster/r.viewshed/rbbst.cpp (from rev 49482, grass-addons/raster/r.viewshed/rbbst.cc)
===================================================================
--- grass/trunk/raster/r.viewshed/rbbst.cpp (rev 0)
+++ grass/trunk/raster/r.viewshed/rbbst.cpp 2011-12-02 09:56:38 UTC (rev 49483)
@@ -0,0 +1,818 @@
+
+/****************************************************************************
+ *
+ * MODULE: r.viewshed
+ *
+ * AUTHOR(S): Laura Toma, Bowdoin College - ltoma at bowdoin.edu
+ * Yi Zhuang - yzhuang at bowdoin.edu
+
+ * Ported to GRASS by William Richard -
+ * wkrichar at bowdoin.edu or willster3021 at 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.
+ *
+ *****************************************************************************/
+
+/*
+
+ A R/B BST. Always call initNILnode() before using the tree.
+ Version 0.0.0
+
+ Version 0.0.1
+ Rewrote BST Deletion to improve efficiency
+
+ Version 0.0.2
+ Bug fixed in deletion.
+ CLRS pseudocode forgot to make sure that x is not NIL before
+ calling rbDeleteFixup(root,x).
+
+ Version 0.0.3
+ Some Cleanup. Separated the public portion and the
+ private porthion of the interface in the header
+
+
+ =================================
+ This is based on BST 1.0.4
+ BST change log
+ <---------------->
+ find max is implemented in this version.
+ Version 1.0.2
+
+ Version 1.0.4
+ Major bug fix in deletion (when the node has two children,
+ one of them has a wrong parent pointer after the rotation in the deletion.)
+ <----------------->
+ */
+
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <assert.h>
+#include <math.h>
+#include "rbbst.h"
+
+extern "C"
+{
+#include <grass/gis.h>
+#include <grass/glocale.h>
+}
+
+
+
+TreeNode *NIL;
+
+#define EPSILON 0.0000001
+
+
+/*public:--------------------------------- */
+RBTree *create_tree(TreeValue tv)
+{
+ init_nil_node();
+ RBTree *rbt = (RBTree *) G_malloc(sizeof(RBTree));
+ TreeNode *root = (TreeNode *) G_malloc(sizeof(TreeNode));
+
+ rbt->root = root;
+ rbt->root->value = tv;
+ rbt->root->left = NIL;
+ rbt->root->right = NIL;
+ rbt->root->parent = NIL;
+ rbt->root->color = RB_BLACK;
+
+ return rbt;
+}
+
+/*LT: not sure if this is correct */
+int is_empty(RBTree * t)
+{
+ assert(t);
+ return (t->root == NIL);
+}
+
+void delete_tree(RBTree * t)
+{
+ destroy_sub_tree(t->root);
+ return;
+}
+
+void destroy_sub_tree(TreeNode * node)
+{
+ if (node == NIL)
+ return;
+
+ destroy_sub_tree(node->left);
+ destroy_sub_tree(node->right);
+ G_free(node);
+ return;
+}
+
+void insert_into(RBTree * rbt, TreeValue value)
+{
+ insert_into_tree(&(rbt->root), value);
+ return;
+}
+
+void delete_from(RBTree * rbt, double key)
+{
+ delete_from_tree(&(rbt->root), key);
+ return;
+}
+
+TreeNode *search_for_node_with_key(RBTree * rbt, double key)
+{
+ return search_for_node(rbt->root, key);
+}
+
+/*------------The following is designed for viewshed's algorithm-------*/
+double find_max_gradient_within_key(RBTree * rbt, double key, double angle, double gradient)
+{
+ return find_max_value_within_key(rbt->root, key, angle, gradient);
+}
+
+/*<--------------------------------->
+ //Private below this line */
+void init_nil_node()
+{
+ NIL = (TreeNode *) G_malloc(sizeof(TreeNode));
+ NIL->color = RB_BLACK;
+ NIL->value.angle[0] = 0;
+ NIL->value.angle[1] = 0;
+ NIL->value.angle[2] = 0;
+ NIL->value.gradient[0] = SMALLEST_GRADIENT;
+ NIL->value.gradient[1] = SMALLEST_GRADIENT;
+ NIL->value.gradient[2] = SMALLEST_GRADIENT;
+ NIL->value.maxGradient = SMALLEST_GRADIENT;
+ NIL->value.key = 0;
+
+ NIL->parent = NULL;
+ NIL->left = NULL;
+ NIL->right = NULL;
+ return;
+}
+
+/*you can write change this compare function, depending on your TreeValue struct
+ //compare function used by findMaxValue
+ //-1: v1 < v2
+ //0: v1 = v2
+ //2: v1 > v2 */
+char compare_values(TreeValue * v1, TreeValue * v2)
+{
+ if (v1->gradient[1] > v2->gradient[1])
+ return 1;
+ if (v1->gradient[1] < v2->gradient[1])
+ return -1;
+
+ return 0;
+}
+
+
+/*a function used to compare two doubles */
+char compare_double(double a, double b)
+{
+ if (fabs(a - b) < EPSILON)
+ return 0;
+ if (a - b < 0)
+ return -1;
+
+ return 1;
+}
+
+
+
+/*create a tree node */
+TreeNode *create_tree_node(TreeValue value)
+{
+ TreeNode *ret;
+
+ ret = (TreeNode *) G_malloc(sizeof(TreeNode));
+
+ ret->color = RB_RED;
+
+ ret->left = NIL;
+ ret->right = NIL;
+ ret->parent = NIL;
+
+ ret->value = value;
+ ret->value.maxGradient = SMALLEST_GRADIENT;
+ return ret;
+}
+
+/*create node with its value set to the value given
+ //and insert the node into the tree
+ //rbInsertFixup may change the root pointer, so TreeNode** is passed in */
+void insert_into_tree(TreeNode ** root, TreeValue value)
+{
+ TreeNode *curNode;
+ TreeNode *nextNode;
+
+ curNode = *root;
+
+ if (compare_double(value.key, curNode->value.key) == -1) {
+ nextNode = curNode->left;
+ }
+ else {
+ nextNode = curNode->right;
+ }
+
+
+ while (nextNode != NIL) {
+ curNode = nextNode;
+
+ if (compare_double(value.key, curNode->value.key) == -1) {
+ nextNode = curNode->left;
+ }
+ else {
+ nextNode = curNode->right;
+ }
+ }
+
+ /*create a new node
+ //and place it at the right place
+ //created node is RED by default */
+ nextNode = create_tree_node(value);
+
+ nextNode->parent = curNode;
+
+ if (compare_double(value.key, curNode->value.key) == -1) {
+ curNode->left = nextNode;
+ }
+ else {
+ curNode->right = nextNode;
+ }
+
+ TreeNode *inserted = nextNode;
+
+ /*update augmented maxGradient */
+ nextNode->value.maxGradient = nextNode->value.gradient[1];
+ while (nextNode->parent != NIL) {
+ if (nextNode->parent->value.maxGradient < nextNode->value.maxGradient)
+ nextNode->parent->value.maxGradient = nextNode->value.maxGradient;
+
+ if (nextNode->parent->value.maxGradient > nextNode->value.maxGradient)
+ break;
+ nextNode = nextNode->parent;
+ }
+
+ /*fix rb tree after insertion */
+ rb_insert_fixup(root, inserted);
+
+ return;
+}
+
+void rb_insert_fixup(TreeNode ** root, TreeNode * z)
+{
+ /*see pseudocode on page 281 in CLRS */
+ TreeNode *y;
+
+ while (z->parent->color == RB_RED) {
+ if (z->parent == z->parent->parent->left) {
+ y = z->parent->parent->right;
+ if (y->color == RB_RED) { /*case 1 */
+ z->parent->color = RB_BLACK;
+ y->color = RB_BLACK;
+ z->parent->parent->color = RB_RED;
+ z = z->parent->parent;
+ }
+ else {
+ if (z == z->parent->right) { /*case 2 */
+ z = z->parent;
+ left_rotate(root, z); /*convert case 2 to case 3 */
+ }
+ z->parent->color = RB_BLACK; /*case 3 */
+ z->parent->parent->color = RB_RED;
+ right_rotate(root, z->parent->parent);
+ }
+
+ }
+ else { /*(z->parent == z->parent->parent->right) */
+ y = z->parent->parent->left;
+ if (y->color == RB_RED) { /*case 1 */
+ z->parent->color = RB_BLACK;
+ y->color = RB_BLACK;
+ z->parent->parent->color = RB_RED;
+ z = z->parent->parent;
+ }
+ else {
+ if (z == z->parent->left) { /*case 2 */
+ z = z->parent;
+ right_rotate(root, z); /*convert case 2 to case 3 */
+ }
+ z->parent->color = RB_BLACK; /*case 3 */
+ z->parent->parent->color = RB_RED;
+ left_rotate(root, z->parent->parent);
+ }
+ }
+ }
+ (*root)->color = RB_BLACK;
+
+ return;
+}
+
+
+
+
+/*search for a node with the given key */
+TreeNode *search_for_node(TreeNode * root, double key)
+{
+ TreeNode *curNode = root;
+
+ while (curNode != NIL && compare_double(key, curNode->value.key) != 0) {
+
+ if (compare_double(key, curNode->value.key) == -1) {
+ curNode = curNode->left;
+ }
+ else {
+ curNode = curNode->right;
+ }
+
+ }
+
+ return curNode;
+}
+
+/*function used by treeSuccessor */
+TreeNode *tree_minimum(TreeNode * x)
+{
+ while (x->left != NIL)
+ x = x->left;
+
+ return x;
+}
+
+/*function used by deletion */
+TreeNode *tree_successor(TreeNode * x)
+{
+ if (x->right != NIL)
+ return tree_minimum(x->right);
+ TreeNode *y = x->parent;
+
+ while (y != NIL && x == y->right) {
+ x = y;
+ if (y->parent == NIL)
+ return y;
+ y = y->parent;
+ }
+ return y;
+}
+
+
+/*delete the node out of the tree */
+void delete_from_tree(TreeNode ** root, double key)
+{
+ double tmpMax;
+ TreeNode *z;
+ TreeNode *x;
+ TreeNode *y;
+ TreeNode *toFix;
+
+ z = search_for_node(*root, key);
+
+ if (z == NIL) {
+ /*node to delete is not found */
+ G_fatal_error(_("Attempt to delete node with key=%f failed"), key);
+ }
+
+ /*1-3 */
+ if (z->left == NIL || z->right == NIL)
+ y = z;
+ else
+ y = tree_successor(z);
+
+ if (y == NIL) {
+ G_fatal_error(_("Successor node not found. Deletion fails."));
+ }
+
+ /*4-6 */
+ if (y->left != NIL)
+ x = y->left;
+ else
+ x = y->right;
+
+ /*7 */
+ x->parent = y->parent;
+
+ /*8-12 */
+ if (y->parent == NIL) {
+ *root = x;
+
+ toFix = *root; /*augmentation to be fixed */
+ }
+ else {
+ if (y == y->parent->left)
+ y->parent->left = x;
+ else
+ y->parent->right = x;
+
+ toFix = y->parent; /*augmentation to be fixed */
+ }
+
+ /*fix augmentation for removing y */
+ TreeNode *curNode = y;
+ double left, right;
+
+ while (curNode->parent != NIL) {
+ if (curNode->parent->value.maxGradient == y->value.gradient[1]) {
+ left = find_max_value(curNode->parent->left);
+ right = find_max_value(curNode->parent->right);
+
+ if (left > right)
+ curNode->parent->value.maxGradient = left;
+ else
+ curNode->parent->value.maxGradient = right;
+
+ if (curNode->parent->value.gradient[1] >
+ curNode->parent->value.maxGradient)
+ curNode->parent->value.maxGradient =
+ curNode->parent->value.gradient[1];
+ }
+ else {
+ break;
+ }
+ curNode = curNode->parent;
+ }
+
+
+ /*fix augmentation for x */
+ tmpMax =
+ toFix->left->value.maxGradient >
+ toFix->right->value.maxGradient ? toFix->left->value.
+ maxGradient : toFix->right->value.maxGradient;
+ if (tmpMax > toFix->value.gradient[1])
+ toFix->value.maxGradient = tmpMax;
+ else
+ toFix->value.maxGradient = toFix->value.gradient[1];
+
+ /*13-15 */
+ if (y != NIL && y != z) {
+ double zGradient = z->value.gradient[1];
+
+ z->value.key = y->value.key;
+ z->value.gradient[0] = y->value.gradient[0];
+ z->value.gradient[1] = y->value.gradient[1];
+ z->value.gradient[2] = y->value.gradient[2];
+ z->value.angle[0] = y->value.angle[0];
+ z->value.angle[1] = y->value.angle[1];
+ z->value.angle[2] = y->value.angle[2];
+
+
+ toFix = z;
+ /*fix augmentation */
+ tmpMax =
+ toFix->left->value.maxGradient >
+ toFix->right->value.maxGradient ? toFix->left->value.
+ maxGradient : toFix->right->value.maxGradient;
+ if (tmpMax > toFix->value.gradient[1])
+ toFix->value.maxGradient = tmpMax;
+ else
+ toFix->value.maxGradient = toFix->value.gradient[1];
+
+ while (z->parent != NIL) {
+ if (z->parent->value.maxGradient == zGradient) {
+ if (z->parent->value.gradient[1] != zGradient &&
+ (!(z->parent->left->value.maxGradient == zGradient &&
+ z->parent->right->value.maxGradient == zGradient))) {
+
+ left = find_max_value(z->parent->left);
+ right = find_max_value(z->parent->right);
+
+ if (left > right)
+ z->parent->value.maxGradient = left;
+ else
+ z->parent->value.maxGradient = right;
+
+ if (z->parent->value.gradient[1] >
+ z->parent->value.maxGradient)
+ z->parent->value.maxGradient =
+ z->parent->value.gradient[1];
+
+ }
+
+ }
+ else {
+ if (z->value.maxGradient > z->parent->value.maxGradient)
+ z->parent->value.maxGradient = z->value.maxGradient;
+ }
+ z = z->parent;
+ }
+
+ }
+
+ /*16-17 */
+ if (y->color == RB_BLACK && x != NIL)
+ rb_delete_fixup(root, x);
+
+ /*18 */
+ G_free(y);
+
+ return;
+}
+
+/*fix the rb tree after deletion */
+void rb_delete_fixup(TreeNode ** root, TreeNode * x)
+{
+ TreeNode *w;
+
+ while (x != *root && x->color == RB_BLACK) {
+ if (x == x->parent->left) {
+ w = x->parent->right;
+ if (w->color == RB_RED) {
+ w->color = RB_BLACK;
+ x->parent->color = RB_RED;
+ left_rotate(root, x->parent);
+ w = x->parent->right;
+ }
+
+ if (w == NIL) {
+ x = x->parent;
+ continue;
+ }
+
+ if (w->left->color == RB_BLACK && w->right->color == RB_BLACK) {
+ w->color = RB_RED;
+ x = x->parent;
+ }
+ else {
+ if (w->right->color == RB_BLACK) {
+ w->left->color = RB_BLACK;
+ w->color = RB_RED;
+ right_rotate(root, w);
+ w = x->parent->right;
+ }
+
+ w->color = x->parent->color;
+ x->parent->color = RB_BLACK;
+ w->right->color = RB_BLACK;
+ left_rotate(root, x->parent);
+ x = *root;
+ }
+
+ }
+ else { /*(x==x->parent->right) */
+ w = x->parent->left;
+ if (w->color == RB_RED) {
+ w->color = RB_BLACK;
+ x->parent->color = RB_RED;
+ right_rotate(root, x->parent);
+ w = x->parent->left;
+ }
+
+ if (w == NIL) {
+ x = x->parent;
+ continue;
+ }
+
+ if (w->right->color == RB_BLACK && w->left->color == RB_BLACK) {
+ w->color = RB_RED;
+ x = x->parent;
+ }
+ else {
+ if (w->left->color == RB_BLACK) {
+ w->right->color = RB_BLACK;
+ w->color = RB_RED;
+ left_rotate(root, w);
+ w = x->parent->left;
+ }
+
+ w->color = x->parent->color;
+ x->parent->color = RB_BLACK;
+ w->left->color = RB_BLACK;
+ right_rotate(root, x->parent);
+ x = *root;
+ }
+
+ }
+ }
+ x->color = RB_BLACK;
+
+ return;
+}
+
+/*find the max value in the given tree
+ //you need to provide a compare function to compare the nodes */
+double find_max_value(TreeNode * root)
+{
+ if (!root)
+ return SMALLEST_GRADIENT;
+ assert(root);
+ /*assert(root->value.maxGradient != SMALLEST_GRADIENT);
+ //LT: this shoudl be fixed
+ //if (root->value.maxGradient != SMALLEST_GRADIENT) */
+ return root->value.maxGradient;
+}
+
+
+
+/* find max within the max key */
+double find_max_value_within_key(TreeNode * root, double maxKey, double angle, double gradient)
+{
+ TreeNode *keyNode = search_for_node(root, maxKey);
+
+ if (keyNode == NIL) {
+ /*fprintf(stderr, "key node not found. error occured!\n");
+ //there is no point in the structure with key < maxKey */
+ return SMALLEST_GRADIENT;
+ exit(1);
+ }
+
+ TreeNode *currNode = keyNode;
+ double max = SMALLEST_GRADIENT;
+ double tmpMax;
+ double curr_gradient;
+
+ /* traverse all nodes with smaller distance */
+ while (currNode != NIL) {
+ int checkme = (currNode->value.angle[0] <= angle &&
+ currNode->value.angle[2] >= angle);
+
+ if (!checkme && currNode->value.key > 0) {
+ G_warning(_("\nangles outside angle %.4f"), angle);
+ G_warning(_("ENTER angle %.4f"), currNode->value.angle[0]);
+ G_warning(_("CENTER angle %.4f"), currNode->value.angle[1]);
+ G_warning(_("EXIT angle %.4f"), currNode->value.angle[2]);
+ G_warning(_("\nENTER gradient %.4f"), currNode->value.gradient[0]);
+ G_warning(_("CENTER gradient %.4f"), currNode->value.gradient[1]);
+ G_warning(_("EXIT gradient %.4f"), currNode->value.gradient[2]);
+ }
+
+ if (currNode->value.key > maxKey) {
+ G_fatal_error(_("current dist too large %.4f > %.4f"), currNode->value.key, maxKey);
+ }
+
+
+ if (checkme && currNode != keyNode) {
+ if (angle < currNode->value.angle[1]) {
+ curr_gradient = currNode->value.gradient[1] +
+ (currNode->value.gradient[0] - currNode->value.gradient[1]) *
+ (currNode->value.angle[1] - angle) /
+ (currNode->value.angle[1] - currNode->value.angle[0]);
+ }
+ else if (angle > currNode->value.angle[1]) {
+ curr_gradient = currNode->value.gradient[1] +
+ (currNode->value.gradient[2] - currNode->value.gradient[1]) *
+ (angle - currNode->value.angle[1]) /
+ (currNode->value.angle[2] - currNode->value.angle[1]);
+ }
+ else /* angle == currNode->value.angle[1] */
+ curr_gradient = currNode->value.gradient[1];
+
+ if (curr_gradient > max)
+ max = curr_gradient;
+
+ if (max > gradient)
+ return max;
+ }
+ /* get next smaller key */
+ if (currNode->left != NIL) {
+ currNode = currNode->left;
+ while (currNode->right != NIL)
+ currNode = currNode->right;
+ }
+ else {
+ /* at smallest item in this branch, go back up */
+ TreeNode *lastNode;
+
+ do {
+ lastNode = currNode;
+ currNode = currNode->parent;
+ } while (currNode != NIL && lastNode == currNode->left);
+ }
+ }
+ return max;
+
+ /* old code assuming flat cells */
+ while (keyNode->parent != NIL) {
+ if (keyNode == keyNode->parent->right) { /*its the right node of its parent; */
+ tmpMax = find_max_value(keyNode->parent->left);
+ if (tmpMax > max)
+ max = tmpMax;
+ if (keyNode->parent->value.gradient[1] > max)
+ max = keyNode->parent->value.gradient[1];
+ }
+ keyNode = keyNode->parent;
+ }
+
+ return max;
+}
+
+
+void left_rotate(TreeNode ** root, TreeNode * x)
+{
+ TreeNode *y;
+
+ y = x->right;
+
+ /*maintain augmentation */
+ double tmpMax;
+
+ /*fix x */
+ tmpMax = x->left->value.maxGradient > y->left->value.maxGradient ?
+ x->left->value.maxGradient : y->left->value.maxGradient;
+
+ if (tmpMax > x->value.gradient[1])
+ x->value.maxGradient = tmpMax;
+ else
+ x->value.maxGradient = x->value.gradient[1];
+
+
+ /*fix y */
+ tmpMax = x->value.maxGradient > y->right->value.maxGradient ?
+ x->value.maxGradient : y->right->value.maxGradient;
+
+ if (tmpMax > y->value.gradient[1])
+ y->value.maxGradient = tmpMax;
+ else
+ y->value.maxGradient = y->value.gradient[1];
+
+ /*left rotation
+ //see pseudocode on page 278 in CLRS */
+
+ x->right = y->left; /*turn y's left subtree into x's right subtree */
+ y->left->parent = x;
+
+ y->parent = x->parent; /*link x's parent to y */
+
+ if (x->parent == NIL) {
+ *root = y;
+ }
+ else {
+ if (x == x->parent->left)
+ x->parent->left = y;
+ else
+ x->parent->right = y;
+ }
+
+ y->left = x;
+ x->parent = y;
+
+ return;
+}
+
+void right_rotate(TreeNode ** root, TreeNode * y)
+{
+ TreeNode *x;
+
+ x = y->left;
+
+ /*maintain augmentation
+ //fix y */
+ double tmpMax;
+
+ tmpMax = x->right->value.maxGradient > y->right->value.maxGradient ?
+ x->right->value.maxGradient : y->right->value.maxGradient;
+
+ if (tmpMax > y->value.gradient[1])
+ y->value.maxGradient = tmpMax;
+ else
+ y->value.maxGradient = y->value.gradient[1];
+
+ /*fix x */
+ tmpMax = x->left->value.maxGradient > y->value.maxGradient ?
+ x->left->value.maxGradient : y->value.maxGradient;
+
+ if (tmpMax > x->value.gradient[1])
+ x->value.maxGradient = tmpMax;
+ else
+ x->value.maxGradient = x->value.gradient[1];
+
+ /*ratation */
+ y->left = x->right;
+ x->right->parent = y;
+
+ x->parent = y->parent;
+
+ if (y->parent == NIL) {
+ *root = x;
+ }
+ else {
+ if (y->parent->left == y)
+ y->parent->left = x;
+ else
+ y->parent->right = x;
+ }
+
+ x->right = y;
+ y->parent = x;
+
+ return;
+}
Deleted: grass/trunk/raster/r.viewshed/statusstructure.cc
===================================================================
--- grass-addons/raster/r.viewshed/statusstructure.cc 2011-12-02 09:30:54 UTC (rev 49482)
+++ grass/trunk/raster/r.viewshed/statusstructure.cc 2011-12-02 09:56:38 UTC (rev 49483)
@@ -1,286 +0,0 @@
-
-/****************************************************************************
- *
- * MODULE: r.viewshed
- *
- * AUTHOR(S): Laura Toma, Bowdoin College - ltoma at bowdoin.edu
- * Yi Zhuang - yzhuang at bowdoin.edu
-
- * Ported to GRASS by William Richard -
- * wkrichar at bowdoin.edu or willster3021 at 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) * 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;
- 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 dx = (col - vp->col) * hd.ew_res;
- double dy = (row - vp->row) * hd.ns_res;
- double 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);
-}
Copied: grass/trunk/raster/r.viewshed/statusstructure.cpp (from rev 49482, grass-addons/raster/r.viewshed/statusstructure.cc)
===================================================================
--- grass/trunk/raster/r.viewshed/statusstructure.cpp (rev 0)
+++ grass/trunk/raster/r.viewshed/statusstructure.cpp 2011-12-02 09:56:38 UTC (rev 49483)
@@ -0,0 +1,286 @@
+
+/****************************************************************************
+ *
+ * MODULE: r.viewshed
+ *
+ * AUTHOR(S): Laura Toma, Bowdoin College - ltoma at bowdoin.edu
+ * Yi Zhuang - yzhuang at bowdoin.edu
+
+ * Ported to GRASS by William Richard -
+ * wkrichar at bowdoin.edu or willster3021 at 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) * 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;
+ 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 dx = (col - vp->col) * hd.ew_res;
+ double dy = (row - vp->row) * hd.ns_res;
+ double 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);
+}
Deleted: grass/trunk/raster/r.viewshed/viewshed.cc
===================================================================
--- grass-addons/raster/r.viewshed/viewshed.cc 2011-12-02 09:30:54 UTC (rev 49482)
+++ grass/trunk/raster/r.viewshed/viewshed.cc 2011-12-02 09:56:38 UTC (rev 49483)
@@ -1,692 +0,0 @@
-/****************************************************************************
- *
- * MODULE: r.viewshed
- *
- * AUTHOR(S): Laura Toma, Bowdoin College - ltoma at bowdoin.edu
- * Yi Zhuang - yzhuang at bowdoin.edu
- *
- * Ported to GRASS by William Richard -
- * wkrichar at bowdoin.edu or willster3021 at 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 <assert.h>
-#include <stdlib.h>
-#include <stdio.h>
-
-extern "C"
-{
-#include "grass/gis.h"
-#include "grass/glocale.h"
-}
-
-#include "viewshed.h"
-#include "visibility.h"
-#include "eventlist.h"
-#include "statusstructure.h"
-#include "grass.h"
-
-
-#define VIEWSHEDDEBUG if(0)
-#define INMEMORY_DEBUG if(0)
-
-
-
-/* ------------------------------------------------------------ */
-/* return the memory usage (in bytes) of viewshed */
-long long get_viewshed_memory_usage(GridHeader * hd)
-{
-
-
- assert(hd);
- /* the output visibility grid */
- long long totalcells = (long long)hd->nrows * (long long)hd->ncols;
-
- G_verbose_message(_("rows=%d, cols=%d, total = %lld"), hd->nrows, hd->ncols,
- totalcells);
- long long gridMemUsage = totalcells * sizeof(float);
-
- G_debug(1, "grid usage=%lld", gridMemUsage);
-
- /* the event array */
- long long eventListMemUsage = totalcells * 3 * sizeof(AEvent);
-
- G_debug(1, "memory_usage: eventList=%lld", eventListMemUsage);
-
- /* the double array <data> that stores all the cells in the same row
- as the viewpoint */
- long long dataMemUsage = (long long)(hd->ncols * sizeof(double));
-
- G_debug(1, "viewshed memory usage: size AEvent=%dB, nevents=%lld, \
- total=%lld B (%d MB)", (int)sizeof(AEvent), totalcells * 3,
- gridMemUsage + eventListMemUsage + dataMemUsage,
- (int)((gridMemUsage + eventListMemUsage + dataMemUsage) >> 20));
-
- return (gridMemUsage + eventListMemUsage + dataMemUsage);
-
-}
-
-
-/* ------------------------------------------------------------ */
-void
-print_viewshed_timings(Rtimer initEventTime,
- Rtimer sortEventTime, Rtimer sweepTime)
-{
-
- char timeused[1000];
-
- G_verbose_message(_("Sweep timings:"));
- rt_sprint_safe(timeused, initEventTime);
- G_verbose_message("Init events: %s", timeused);
-
- rt_sprint_safe(timeused, sortEventTime);
- G_verbose_message("Sort events: %s", timeused);
-
- rt_sprint_safe(timeused, sweepTime);
- G_verbose_message("Process events: %s", timeused);
-
- return;
-}
-
-
-/* ------------------------------------------------------------ */
-static void print_statusnode(StatusNode sn)
-{
- G_debug(3, "processing (row=%d, col=%d, dist=%f, grad=%f)",
- sn.row, sn.col, sn.dist2vp, sn.gradient[1]);
- return;
-}
-
-
-
-/* ------------------------------------------------------------ */
-/* allocates the eventlist array used by kreveled_in_memory; it is
- possible that the amount of memory required is more than that
- supported by the platform; for e.g. on a 32-bt platform cannot
- allocate more than 4GB. Try to detect this situation. */
-AEvent *allocate_eventlist(GridHeader * hd)
-{
-
- AEvent *eventList;
-
- long long totalsize = hd->ncols * hd->nrows * 3;
-
- totalsize *= sizeof(AEvent);
- G_debug(1, "total size of eventlist is %lld B (%d MB); ",
- totalsize, (int)(totalsize >> 20));
-
- /* what's the size of size_t on this machine? */
- int sizet_size;
-
- sizet_size = (int)sizeof(size_t);
- G_debug(1, "size_t is %d B", sizet_size);
-
- if (sizet_size >= 8) {
- G_debug(1, "64-bit platform, great.");
- }
- else {
- /* this is the max value of size_t */
- long long maxsizet = ((long long)1 << (sizeof(size_t) * 8)) - 1;
-
- G_debug(1, "max size_t is %lld", maxsizet);
-
- /* checking whether allocating totalsize causes an overflow */
- if (totalsize > maxsizet) {
- G_fatal_error(_("Running the program in-memory mode requires " \
- "memory beyond the capability of the platform. " \
- "Use external mode, or a 64-bit platform."));
- }
- }
-
- G_debug(1, "allocating eventList...");
- eventList = (AEvent *) G_malloc(totalsize);
-
- assert(eventList);
- G_debug(1, "...ok");
-
- return eventList;
-}
-
-
-
-
-/*///////////////////////////////////////////////////////////
- ------------------------------------------------------------ run
- Viewshed's sweep algorithm on the grid stored in the given file, and
- with the given viewpoint. Create a visibility grid and return
- it. The computation runs in memory, which means the input grid, the
- status structure and the output grid are stored in arrays in
- memory.
-
-
- The output: A cell x in the visibility grid is recorded as follows:
-
- if it is NODATA, then x is set to NODATA
- if it is invisible, then x is set to INVISIBLE
- if it is visible, then x is set to the vertical angle wrt to viewpoint
-
- */
-MemoryVisibilityGrid *viewshed_in_memory(char *inputfname, GridHeader * hd,
- Viewpoint * vp,
- ViewOptions viewOptions)
-{
-
- assert(inputfname && hd && vp);
- G_verbose_message(_("Start sweeping."));
-
- /* ------------------------------ */
- /* create the visibility grid */
- MemoryVisibilityGrid *visgrid;
-
- visgrid = create_inmem_visibilitygrid(*hd, *vp);
- /* set everything initially invisible */
- set_inmem_visibilitygrid(visgrid, INVISIBLE);
- assert(visgrid);
- G_debug(1, "visibility grid size: %d x %d x %d B (%d MB)",
- hd->nrows, hd->ncols, (int)sizeof(float),
- (int)(((long long)(hd->nrows * hd->ncols *
- sizeof(float))) >> 20));
-
-
- /* ------------------------------ */
- /* construct the event list corresponding to the given input file
- and viewpoint; this creates an array of all the cells on the
- same row as the viewpoint */
- surface_type **data;
- size_t nevents;
-
- Rtimer initEventTime;
-
- rt_start(initEventTime);
-
- AEvent *eventList = allocate_eventlist(hd);
-
- nevents = init_event_list_in_memory(eventList, inputfname, vp, hd,
- viewOptions, &data, visgrid);
-
- assert(data);
- rt_stop(initEventTime);
- G_debug(1, "actual nb events is %lu", (long unsigned int)nevents);
-
- /* ------------------------------ */
- /*sort the events radially by angle */
- Rtimer sortEventTime;
-
- rt_start(sortEventTime);
- G_verbose_message(_("Sorting events..."));
- fflush(stdout);
-
- /*this is recursive and seg faults for large arrays
- //qsort(eventList, nevents, sizeof(AEvent), radial_compare_events);
-
- //this is too slow...
- //heapsort(eventList, nevents, sizeof(AEvent), radial_compare_events);
-
- //iostream quicksort */
- RadialCompare cmpObj;
-
- quicksort(eventList, nevents, cmpObj);
- G_verbose_message(_("Done."));
- fflush(stdout);
- rt_stop(sortEventTime);
-
-
- /* ------------------------------ */
- /*create the status structure */
- StatusList *status_struct = create_status_struct();
-
- /*Put cells that are initially on the sweepline into status structure */
- Rtimer sweepTime;
- StatusNode sn;
-
- rt_start(sweepTime);
- for (dimensionType i = vp->col + 1; i < hd->ncols; i++) {
- AEvent e;
- double ax, ay;
-
- sn.col = i;
- sn.row = vp->row;
- e.col = i;
- e.row = vp->row;
- e.elev[0] = data[0][i];
- e.elev[1] = data[1][i];
- e.elev[2] = data[2][i];
-
- if (!is_nodata(visgrid->grid->hd, data[1][i]) &&
- !is_point_outside_max_dist(*vp, *hd, sn.row, sn.col,
- viewOptions.maxDist)) {
- /*calculate Distance to VP and Gradient, store them into sn */
- /* need either 3 elevation values or
- * 3 gradients calculated from 3 elevation values */
- /* need also 3 angles */
- e.eventType = ENTERING_EVENT;
- calculate_event_position(e, vp->row, vp->col, &ay, &ax);
- sn.angle[0] = calculate_angle(ax, ay, vp->col, vp->row);
- calculate_event_gradient(&sn, 0, ay, ax, e.elev[0], vp, *hd);
-
- e.eventType = CENTER_EVENT;
- calculate_event_position(e, vp->row, vp->col, &ay, &ax);
- sn.angle[1] = calculate_angle(ax, ay, vp->col, vp->row);
- calculate_dist_n_gradient(&sn, e.elev[1], vp, *hd);
-
- e.eventType = EXITING_EVENT;
- calculate_event_position(e, vp->row, vp->col, &ay, &ax);
- sn.angle[2] = calculate_angle(ax, ay, vp->col, vp->row);
- calculate_event_gradient(&sn, 2, ay, ax, e.elev[2], vp, *hd);
-
- assert(sn.angle[1] == 0);
-
- if (sn.angle[0] > sn.angle[1])
- sn.angle[0] -= 2 * M_PI;
-
- G_debug(2, "inserting: ");
- print_statusnode(sn);
- /*insert sn into the status structure */
- insert_into_status_struct(sn, status_struct);
- }
- }
- G_free(data[0]);
- G_free(data);
-
-
-
- /* ------------------------------ */
- /*sweep the event list */
- long nvis = 0; /*number of visible cells */
- AEvent *e;
-
- G_message(_("Determine visibility..."));
- G_percent(0, 100, 2);
-
- for (size_t i = 0; i < nevents; i++) {
-
- int perc = (int)((double)i / nevents * 1000000.);
- if (perc > 0 && perc < 1000000)
- G_percent(perc, 1000000, 2);
-
- /*get out one event at a time and process it according to its type */
- e = &(eventList[i]);
-
- sn.col = e->col;
- sn.row = e->row;
- //sn.elev = e->elev;
-
- /*calculate Distance to VP and Gradient */
- calculate_dist_n_gradient(&sn, e->elev[1] + vp->target_offset, vp, *hd);
- G_debug(3, "event: ");
- print_event(*e, 3);
- G_debug(3, "sn.dist=%f, sn.gradient=%f", sn.dist2vp, sn.gradient[1]);
-
- switch (e->eventType) {
- case ENTERING_EVENT:
- double ax, ay;
- /*insert node into structure */
- G_debug(3, "..ENTER-EVENT: insert");
-
- /* need either 3 elevation values or
- * 3 gradients calculated from 3 elevation values */
- /* need also 3 angles */
- calculate_event_position(*e, vp->row, vp->col, &ay, &ax);
- //sn.angle[0] = calculate_angle(ax, ay, vp->col, vp->row);
- sn.angle[0] = e->angle;
- calculate_event_gradient(&sn, 0, ay, ax, e->elev[0], vp, *hd);
-
- e->eventType = CENTER_EVENT;
- calculate_event_position(*e, vp->row, vp->col, &ay, &ax);
- sn.angle[1] = calculate_angle(ax, ay, vp->col, vp->row);
- calculate_dist_n_gradient(&sn, e->elev[1], vp, *hd);
-
- e->eventType = EXITING_EVENT;
- calculate_event_position(*e, vp->row, vp->col, &ay, &ax);
- sn.angle[2] = calculate_angle(ax, ay, vp->col, vp->row);
- calculate_event_gradient(&sn, 2, ay, ax, e->elev[2], vp, *hd);
-
- e->eventType = ENTERING_EVENT;
-
- if (e->angle < M_PI) {
- if (sn.angle[0] > sn.angle[1])
- sn.angle[0] -= 2 * M_PI;
- }
- else {
- if (sn.angle[0] > sn.angle[1]) {
- sn.angle[1] += 2 * M_PI;
- sn.angle[2] += 2 * M_PI;
- }
- }
-
- insert_into_status_struct(sn, status_struct);
- break;
-
- case EXITING_EVENT:
- /*delete node out of status structure */
- G_debug(3, "..EXIT-EVENT: delete");
- /* need only distance */
- delete_from_status_struct(status_struct, sn.dist2vp);
- break;
-
- case CENTER_EVENT:
- G_debug(3, "..QUERY-EVENT: query");
- /*calculate visibility */
- double max;
-
- /* consider current angle and gradient */
- max =
- find_max_gradient_in_status_struct(status_struct, sn.dist2vp,
- e->angle, sn.gradient[1]);
-
- /*the point is visible: store its vertical angle */
- if (max <= sn.gradient[1]) {
- float vert_angle = get_vertical_angle(*vp, sn, e->elev[1] + vp->target_offset,
- viewOptions.doCurv);
-
- add_result_to_inmem_visibilitygrid(visgrid, sn.row, sn.col,
- vert_angle);
- assert(vert_angle >= 0);
- /* when you write the visibility grid you assume that
- visible values are positive */
- nvis++;
- }
- //else {
- /* cell is invisible */
- /* the visibility grid is initialized all invisible */
- //visgrid->grid->grid_data[sn.row][sn.col] = INVISIBLE;
- //}
- break;
- }
- }
- rt_stop(sweepTime);
- G_percent(1, 1, 1);
-
- G_verbose_message(_("Sweeping done."));
- G_verbose_message(_("Total cells %ld, visible cells %ld (%.1f percent)."),
- (long)visgrid->grid->hd->nrows * visgrid->grid->hd->ncols,
- nvis,
- (float)((float)nvis * 100 /
- (float)(visgrid->grid->hd->nrows *
- visgrid->grid->hd->ncols)));
-
- print_viewshed_timings(initEventTime, sortEventTime, sweepTime);
-
- /*cleanup */
- G_free(eventList);
-
- return visgrid;
-}
-
-
-
-
-
-
-
-
-/*///////////////////////////////////////////////////////////
- ------------------------------------------------------------
- run Viewshed's algorithm on the grid stored in the given file, and
- with the given viewpoint. Create a visibility grid and return it. It
- runs in external memory, i.e. the input grid and the outpt grid are
- stored as streams
- */
-
-IOVisibilityGrid *viewshed_external(char *inputfname, GridHeader * hd,
- Viewpoint * vp, ViewOptions viewOptions)
-{
-
- assert(inputfname && hd && vp);
- G_message(_("Start sweeping."));
-
-
- /* ------------------------------ */
- /*initialize the visibility grid */
- IOVisibilityGrid *visgrid;
-
- visgrid = init_io_visibilitygrid(*hd, *vp);
-
-
- /* ------------------------------ */
- /* construct the event list corresponding to the give input file and
- viewpoint; this creates an array of all the cells on
- the same row as the viewpoint */
- Rtimer initEventTime, sortEventTime, sweepTime;
-
- AMI_STREAM < AEvent > *eventList;
- surface_type **data;
-
- rt_start(initEventTime);
-
- eventList = init_event_list(inputfname, vp, hd, viewOptions,
- &data, visgrid);
-
- assert(eventList && data);
- eventList->seek(0);
- rt_stop(initEventTime);
- /*printf("Event stream length: %lu\n", (unsigned long)eventList->stream_len()); */
-
-
- /* ------------------------------ */
- /*sort the events radially by angle */
- G_verbose_message(_("Sorting events..."));
-
- rt_start(sortEventTime);
- sort_event_list(&eventList);
- eventList->seek(0); /*this does not seem to be ensured by sort?? */
- rt_stop(sortEventTime);
-
-
- /* ------------------------------ */
- /*create the status structure */
- StatusList *status_struct = create_status_struct();
-
- /* Put cells that are initially on the sweepline into status
- structure */
- StatusNode sn;
-
- G_message(_("Calculating distances..."));
-
- rt_start(sweepTime);
- for (dimensionType i = vp->col + 1; i < hd->ncols; i++) {
- AEvent e;
- double ax, ay;
-
- G_percent(i, hd->ncols, 2);
-
- sn.col = i;
- sn.row = vp->row;
- e.col = i;
- e.row = vp->row;
- e.elev[0] = data[0][i];
- e.elev[1] = data[1][i];
- e.elev[2] = data[2][i];
- if (!is_nodata(visgrid->hd, data[1][i]) &&
- !is_point_outside_max_dist(*vp, *hd, sn.row, sn.col,
- viewOptions.maxDist)) {
- /*calculate Distance to VP and Gradient, store them into sn */
- /* need either 3 elevation values or
- * 3 gradients calculated from 3 elevation values */
- /* need also 3 angles */
- e.eventType = ENTERING_EVENT;
- calculate_event_position(e, vp->row, vp->col, &ay, &ax);
- sn.angle[0] = calculate_angle(ax, ay, vp->col, vp->row);
- calculate_event_gradient(&sn, 0, ay, ax, e.elev[0], vp, *hd);
-
- e.eventType = CENTER_EVENT;
- calculate_event_position(e, vp->row, vp->col, &ay, &ax);
- sn.angle[1] = calculate_angle(ax, ay, vp->col, vp->row);
- calculate_dist_n_gradient(&sn, e.elev[1], vp, *hd);
-
- e.eventType = EXITING_EVENT;
- calculate_event_position(e, vp->row, vp->col, &ay, &ax);
- sn.angle[2] = calculate_angle(ax, ay, vp->col, vp->row);
- calculate_event_gradient(&sn, 2, ay, ax, e.elev[2], vp, *hd);
-
- assert(sn.angle[1] == 0);
-
- if (sn.angle[0] > sn.angle[1])
- sn.angle[0] -= 2 * M_PI;
-
- G_debug(3, "inserting: ");
- print_statusnode(sn);
-
- /*insert sn into the status structure */
- insert_into_status_struct(sn, status_struct);
- }
- }
- G_percent(hd->ncols, hd->ncols, 2);
- G_free(data[0]);
- G_free(data);
-
-
- /* ------------------------------ */
- /*sweep the event list */
- long nvis = 0; /*number of visible cells */
- VisCell viscell;
- AEvent *e;
- AMI_err ae;
- off_t nbEvents = eventList->stream_len();
-
- /*printf("nbEvents = %ld\n", (long) nbEvents); */
-
- G_message(_("Determine visibility..."));
- G_percent(0, 100, 2);
-
- for (off_t i = 0; i < nbEvents; i++) {
-
- int perc = (int)((double)i / nbEvents * 1000000.);
- if (perc > 0)
- G_percent(perc, 1000000, 2);
-
- /*get out one event at a time and process it according to its type */
- ae = eventList->read_item(&e);
- assert(ae == AMI_ERROR_NO_ERROR);
-
- sn.col = e->col;
- sn.row = e->row;
- //sn.elev = e->elev;
- /*calculate Distance to VP and Gradient */
- calculate_dist_n_gradient(&sn, e->elev[1] + vp->target_offset, vp, *hd);
-
- G_debug(3, "next event: ");
- print_statusnode(sn);
-
- switch (e->eventType) {
- case ENTERING_EVENT:
- double ax, ay;
-
- /*insert node into structure */
- /* need either 3 elevation values or
- * 3 gradients calculated from 3 elevation values */
- /* need also 3 angles */
- calculate_event_position(*e, vp->row, vp->col, &ay, &ax);
- //sn.angle[0] = calculate_angle(ax, ay, vp->col, vp->row);
- sn.angle[0] = e->angle;
- calculate_event_gradient(&sn, 0, ay, ax, e->elev[0], vp, *hd);
-
- e->eventType = CENTER_EVENT;
- calculate_event_position(*e, vp->row, vp->col, &ay, &ax);
- sn.angle[1] = calculate_angle(ax, ay, vp->col, vp->row);
- calculate_dist_n_gradient(&sn, e->elev[1], vp, *hd);
-
- e->eventType = EXITING_EVENT;
- calculate_event_position(*e, vp->row, vp->col, &ay, &ax);
- sn.angle[2] = calculate_angle(ax, ay, vp->col, vp->row);
- calculate_event_gradient(&sn, 2, ay, ax, e->elev[2], vp, *hd);
-
- e->eventType = ENTERING_EVENT;
-
- if (e->angle < M_PI) {
- if (sn.angle[0] > sn.angle[1])
- sn.angle[0] -= 2 * M_PI;
- }
- else {
- if (sn.angle[0] > sn.angle[1]) {
- sn.angle[1] += 2 * M_PI;
- sn.angle[2] += 2 * M_PI;
- }
- }
-
- G_debug(3, "..ENTER-EVENT: insert");
-
- insert_into_status_struct(sn, status_struct);
- break;
-
- case EXITING_EVENT:
- /*delete node out of status structure */
-
- G_debug(3, "..EXIT-EVENT: delete");
-
- delete_from_status_struct(status_struct, sn.dist2vp);
- break;
-
- case CENTER_EVENT:
- G_debug(3, "..QUERY-EVENT: query");
-
- /*calculate visibility */
- viscell.row = sn.row;
- viscell.col = sn.col;
- double max;
-
- max =
- find_max_gradient_in_status_struct(status_struct, sn.dist2vp,
- e->angle, sn.gradient[1]);
-
- /*the point is visible */
- if (max <= sn.gradient[1]) {
- viscell.angle =
- get_vertical_angle(*vp, sn, e->elev[1] + vp->target_offset, viewOptions.doCurv);
- assert(viscell.angle >= 0);
- /* viscell.vis = VISIBLE; */
- add_result_to_io_visibilitygrid(visgrid, &viscell);
- nvis++;
- }
- else {
- /* else the cell is invisible; we do not write it to the
- visibility stream because we only record visible cells, and
- nodata cells; */
- /* viscell.vis = INVISIBLE; */
- /* add_result_to_io_visibilitygrid(visgrid, &viscell); */
- }
- break;
- }
- } /* for each event */
- rt_stop(sweepTime);
- G_percent(1, 1, 1);
-
- G_message(_("Sweeping done."));
- G_verbose_message(_("Total cells %ld, visible cells %ld (%.1f percent)."),
- (long)visgrid->hd->nrows * visgrid->hd->ncols,
- nvis,
- (float)((float)nvis * 100 /
- (float)(visgrid->hd->nrows * visgrid->hd->ncols)));
-
- print_viewshed_timings(initEventTime, sortEventTime, sweepTime);
-
- /*cleanup */
- delete eventList;
-
- return visgrid;
-}
Copied: grass/trunk/raster/r.viewshed/viewshed.cpp (from rev 49482, grass-addons/raster/r.viewshed/viewshed.cc)
===================================================================
--- grass/trunk/raster/r.viewshed/viewshed.cpp (rev 0)
+++ grass/trunk/raster/r.viewshed/viewshed.cpp 2011-12-02 09:56:38 UTC (rev 49483)
@@ -0,0 +1,692 @@
+/****************************************************************************
+ *
+ * MODULE: r.viewshed
+ *
+ * AUTHOR(S): Laura Toma, Bowdoin College - ltoma at bowdoin.edu
+ * Yi Zhuang - yzhuang at bowdoin.edu
+ *
+ * Ported to GRASS by William Richard -
+ * wkrichar at bowdoin.edu or willster3021 at 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 <assert.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+extern "C"
+{
+#include "grass/gis.h"
+#include "grass/glocale.h"
+}
+
+#include "viewshed.h"
+#include "visibility.h"
+#include "eventlist.h"
+#include "statusstructure.h"
+#include "grass.h"
+
+
+#define VIEWSHEDDEBUG if(0)
+#define INMEMORY_DEBUG if(0)
+
+
+
+/* ------------------------------------------------------------ */
+/* return the memory usage (in bytes) of viewshed */
+long long get_viewshed_memory_usage(GridHeader * hd)
+{
+
+
+ assert(hd);
+ /* the output visibility grid */
+ long long totalcells = (long long)hd->nrows * (long long)hd->ncols;
+
+ G_verbose_message(_("rows=%d, cols=%d, total = %lld"), hd->nrows, hd->ncols,
+ totalcells);
+ long long gridMemUsage = totalcells * sizeof(float);
+
+ G_debug(1, "grid usage=%lld", gridMemUsage);
+
+ /* the event array */
+ long long eventListMemUsage = totalcells * 3 * sizeof(AEvent);
+
+ G_debug(1, "memory_usage: eventList=%lld", eventListMemUsage);
+
+ /* the double array <data> that stores all the cells in the same row
+ as the viewpoint */
+ long long dataMemUsage = (long long)(hd->ncols * sizeof(double));
+
+ G_debug(1, "viewshed memory usage: size AEvent=%dB, nevents=%lld, \
+ total=%lld B (%d MB)", (int)sizeof(AEvent), totalcells * 3,
+ gridMemUsage + eventListMemUsage + dataMemUsage,
+ (int)((gridMemUsage + eventListMemUsage + dataMemUsage) >> 20));
+
+ return (gridMemUsage + eventListMemUsage + dataMemUsage);
+
+}
+
+
+/* ------------------------------------------------------------ */
+void
+print_viewshed_timings(Rtimer initEventTime,
+ Rtimer sortEventTime, Rtimer sweepTime)
+{
+
+ char timeused[1000];
+
+ G_verbose_message(_("Sweep timings:"));
+ rt_sprint_safe(timeused, initEventTime);
+ G_verbose_message("Init events: %s", timeused);
+
+ rt_sprint_safe(timeused, sortEventTime);
+ G_verbose_message("Sort events: %s", timeused);
+
+ rt_sprint_safe(timeused, sweepTime);
+ G_verbose_message("Process events: %s", timeused);
+
+ return;
+}
+
+
+/* ------------------------------------------------------------ */
+static void print_statusnode(StatusNode sn)
+{
+ G_debug(3, "processing (row=%d, col=%d, dist=%f, grad=%f)",
+ sn.row, sn.col, sn.dist2vp, sn.gradient[1]);
+ return;
+}
+
+
+
+/* ------------------------------------------------------------ */
+/* allocates the eventlist array used by kreveled_in_memory; it is
+ possible that the amount of memory required is more than that
+ supported by the platform; for e.g. on a 32-bt platform cannot
+ allocate more than 4GB. Try to detect this situation. */
+AEvent *allocate_eventlist(GridHeader * hd)
+{
+
+ AEvent *eventList;
+
+ long long totalsize = hd->ncols * hd->nrows * 3;
+
+ totalsize *= sizeof(AEvent);
+ G_debug(1, "total size of eventlist is %lld B (%d MB); ",
+ totalsize, (int)(totalsize >> 20));
+
+ /* what's the size of size_t on this machine? */
+ int sizet_size;
+
+ sizet_size = (int)sizeof(size_t);
+ G_debug(1, "size_t is %d B", sizet_size);
+
+ if (sizet_size >= 8) {
+ G_debug(1, "64-bit platform, great.");
+ }
+ else {
+ /* this is the max value of size_t */
+ long long maxsizet = ((long long)1 << (sizeof(size_t) * 8)) - 1;
+
+ G_debug(1, "max size_t is %lld", maxsizet);
+
+ /* checking whether allocating totalsize causes an overflow */
+ if (totalsize > maxsizet) {
+ G_fatal_error(_("Running the program in-memory mode requires " \
+ "memory beyond the capability of the platform. " \
+ "Use external mode, or a 64-bit platform."));
+ }
+ }
+
+ G_debug(1, "allocating eventList...");
+ eventList = (AEvent *) G_malloc(totalsize);
+
+ assert(eventList);
+ G_debug(1, "...ok");
+
+ return eventList;
+}
+
+
+
+
+/*///////////////////////////////////////////////////////////
+ ------------------------------------------------------------ run
+ Viewshed's sweep algorithm on the grid stored in the given file, and
+ with the given viewpoint. Create a visibility grid and return
+ it. The computation runs in memory, which means the input grid, the
+ status structure and the output grid are stored in arrays in
+ memory.
+
+
+ The output: A cell x in the visibility grid is recorded as follows:
+
+ if it is NODATA, then x is set to NODATA
+ if it is invisible, then x is set to INVISIBLE
+ if it is visible, then x is set to the vertical angle wrt to viewpoint
+
+ */
+MemoryVisibilityGrid *viewshed_in_memory(char *inputfname, GridHeader * hd,
+ Viewpoint * vp,
+ ViewOptions viewOptions)
+{
+
+ assert(inputfname && hd && vp);
+ G_verbose_message(_("Start sweeping."));
+
+ /* ------------------------------ */
+ /* create the visibility grid */
+ MemoryVisibilityGrid *visgrid;
+
+ visgrid = create_inmem_visibilitygrid(*hd, *vp);
+ /* set everything initially invisible */
+ set_inmem_visibilitygrid(visgrid, INVISIBLE);
+ assert(visgrid);
+ G_debug(1, "visibility grid size: %d x %d x %d B (%d MB)",
+ hd->nrows, hd->ncols, (int)sizeof(float),
+ (int)(((long long)(hd->nrows * hd->ncols *
+ sizeof(float))) >> 20));
+
+
+ /* ------------------------------ */
+ /* construct the event list corresponding to the given input file
+ and viewpoint; this creates an array of all the cells on the
+ same row as the viewpoint */
+ surface_type **data;
+ size_t nevents;
+
+ Rtimer initEventTime;
+
+ rt_start(initEventTime);
+
+ AEvent *eventList = allocate_eventlist(hd);
+
+ nevents = init_event_list_in_memory(eventList, inputfname, vp, hd,
+ viewOptions, &data, visgrid);
+
+ assert(data);
+ rt_stop(initEventTime);
+ G_debug(1, "actual nb events is %lu", (long unsigned int)nevents);
+
+ /* ------------------------------ */
+ /*sort the events radially by angle */
+ Rtimer sortEventTime;
+
+ rt_start(sortEventTime);
+ G_verbose_message(_("Sorting events..."));
+ fflush(stdout);
+
+ /*this is recursive and seg faults for large arrays
+ //qsort(eventList, nevents, sizeof(AEvent), radial_compare_events);
+
+ //this is too slow...
+ //heapsort(eventList, nevents, sizeof(AEvent), radial_compare_events);
+
+ //iostream quicksort */
+ RadialCompare cmpObj;
+
+ quicksort(eventList, nevents, cmpObj);
+ G_verbose_message(_("Done."));
+ fflush(stdout);
+ rt_stop(sortEventTime);
+
+
+ /* ------------------------------ */
+ /*create the status structure */
+ StatusList *status_struct = create_status_struct();
+
+ /*Put cells that are initially on the sweepline into status structure */
+ Rtimer sweepTime;
+ StatusNode sn;
+
+ rt_start(sweepTime);
+ for (dimensionType i = vp->col + 1; i < hd->ncols; i++) {
+ AEvent e;
+ double ax, ay;
+
+ sn.col = i;
+ sn.row = vp->row;
+ e.col = i;
+ e.row = vp->row;
+ e.elev[0] = data[0][i];
+ e.elev[1] = data[1][i];
+ e.elev[2] = data[2][i];
+
+ if (!is_nodata(visgrid->grid->hd, data[1][i]) &&
+ !is_point_outside_max_dist(*vp, *hd, sn.row, sn.col,
+ viewOptions.maxDist)) {
+ /*calculate Distance to VP and Gradient, store them into sn */
+ /* need either 3 elevation values or
+ * 3 gradients calculated from 3 elevation values */
+ /* need also 3 angles */
+ e.eventType = ENTERING_EVENT;
+ calculate_event_position(e, vp->row, vp->col, &ay, &ax);
+ sn.angle[0] = calculate_angle(ax, ay, vp->col, vp->row);
+ calculate_event_gradient(&sn, 0, ay, ax, e.elev[0], vp, *hd);
+
+ e.eventType = CENTER_EVENT;
+ calculate_event_position(e, vp->row, vp->col, &ay, &ax);
+ sn.angle[1] = calculate_angle(ax, ay, vp->col, vp->row);
+ calculate_dist_n_gradient(&sn, e.elev[1], vp, *hd);
+
+ e.eventType = EXITING_EVENT;
+ calculate_event_position(e, vp->row, vp->col, &ay, &ax);
+ sn.angle[2] = calculate_angle(ax, ay, vp->col, vp->row);
+ calculate_event_gradient(&sn, 2, ay, ax, e.elev[2], vp, *hd);
+
+ assert(sn.angle[1] == 0);
+
+ if (sn.angle[0] > sn.angle[1])
+ sn.angle[0] -= 2 * M_PI;
+
+ G_debug(2, "inserting: ");
+ print_statusnode(sn);
+ /*insert sn into the status structure */
+ insert_into_status_struct(sn, status_struct);
+ }
+ }
+ G_free(data[0]);
+ G_free(data);
+
+
+
+ /* ------------------------------ */
+ /*sweep the event list */
+ long nvis = 0; /*number of visible cells */
+ AEvent *e;
+
+ G_message(_("Determine visibility..."));
+ G_percent(0, 100, 2);
+
+ for (size_t i = 0; i < nevents; i++) {
+
+ int perc = (int)((double)i / nevents * 1000000.);
+ if (perc > 0 && perc < 1000000)
+ G_percent(perc, 1000000, 2);
+
+ /*get out one event at a time and process it according to its type */
+ e = &(eventList[i]);
+
+ sn.col = e->col;
+ sn.row = e->row;
+ //sn.elev = e->elev;
+
+ /*calculate Distance to VP and Gradient */
+ calculate_dist_n_gradient(&sn, e->elev[1] + vp->target_offset, vp, *hd);
+ G_debug(3, "event: ");
+ print_event(*e, 3);
+ G_debug(3, "sn.dist=%f, sn.gradient=%f", sn.dist2vp, sn.gradient[1]);
+
+ switch (e->eventType) {
+ case ENTERING_EVENT:
+ double ax, ay;
+ /*insert node into structure */
+ G_debug(3, "..ENTER-EVENT: insert");
+
+ /* need either 3 elevation values or
+ * 3 gradients calculated from 3 elevation values */
+ /* need also 3 angles */
+ calculate_event_position(*e, vp->row, vp->col, &ay, &ax);
+ //sn.angle[0] = calculate_angle(ax, ay, vp->col, vp->row);
+ sn.angle[0] = e->angle;
+ calculate_event_gradient(&sn, 0, ay, ax, e->elev[0], vp, *hd);
+
+ e->eventType = CENTER_EVENT;
+ calculate_event_position(*e, vp->row, vp->col, &ay, &ax);
+ sn.angle[1] = calculate_angle(ax, ay, vp->col, vp->row);
+ calculate_dist_n_gradient(&sn, e->elev[1], vp, *hd);
+
+ e->eventType = EXITING_EVENT;
+ calculate_event_position(*e, vp->row, vp->col, &ay, &ax);
+ sn.angle[2] = calculate_angle(ax, ay, vp->col, vp->row);
+ calculate_event_gradient(&sn, 2, ay, ax, e->elev[2], vp, *hd);
+
+ e->eventType = ENTERING_EVENT;
+
+ if (e->angle < M_PI) {
+ if (sn.angle[0] > sn.angle[1])
+ sn.angle[0] -= 2 * M_PI;
+ }
+ else {
+ if (sn.angle[0] > sn.angle[1]) {
+ sn.angle[1] += 2 * M_PI;
+ sn.angle[2] += 2 * M_PI;
+ }
+ }
+
+ insert_into_status_struct(sn, status_struct);
+ break;
+
+ case EXITING_EVENT:
+ /*delete node out of status structure */
+ G_debug(3, "..EXIT-EVENT: delete");
+ /* need only distance */
+ delete_from_status_struct(status_struct, sn.dist2vp);
+ break;
+
+ case CENTER_EVENT:
+ G_debug(3, "..QUERY-EVENT: query");
+ /*calculate visibility */
+ double max;
+
+ /* consider current angle and gradient */
+ max =
+ find_max_gradient_in_status_struct(status_struct, sn.dist2vp,
+ e->angle, sn.gradient[1]);
+
+ /*the point is visible: store its vertical angle */
+ if (max <= sn.gradient[1]) {
+ float vert_angle = get_vertical_angle(*vp, sn, e->elev[1] + vp->target_offset,
+ viewOptions.doCurv);
+
+ add_result_to_inmem_visibilitygrid(visgrid, sn.row, sn.col,
+ vert_angle);
+ assert(vert_angle >= 0);
+ /* when you write the visibility grid you assume that
+ visible values are positive */
+ nvis++;
+ }
+ //else {
+ /* cell is invisible */
+ /* the visibility grid is initialized all invisible */
+ //visgrid->grid->grid_data[sn.row][sn.col] = INVISIBLE;
+ //}
+ break;
+ }
+ }
+ rt_stop(sweepTime);
+ G_percent(1, 1, 1);
+
+ G_verbose_message(_("Sweeping done."));
+ G_verbose_message(_("Total cells %ld, visible cells %ld (%.1f percent)."),
+ (long)visgrid->grid->hd->nrows * visgrid->grid->hd->ncols,
+ nvis,
+ (float)((float)nvis * 100 /
+ (float)(visgrid->grid->hd->nrows *
+ visgrid->grid->hd->ncols)));
+
+ print_viewshed_timings(initEventTime, sortEventTime, sweepTime);
+
+ /*cleanup */
+ G_free(eventList);
+
+ return visgrid;
+}
+
+
+
+
+
+
+
+
+/*///////////////////////////////////////////////////////////
+ ------------------------------------------------------------
+ run Viewshed's algorithm on the grid stored in the given file, and
+ with the given viewpoint. Create a visibility grid and return it. It
+ runs in external memory, i.e. the input grid and the outpt grid are
+ stored as streams
+ */
+
+IOVisibilityGrid *viewshed_external(char *inputfname, GridHeader * hd,
+ Viewpoint * vp, ViewOptions viewOptions)
+{
+
+ assert(inputfname && hd && vp);
+ G_message(_("Start sweeping."));
+
+
+ /* ------------------------------ */
+ /*initialize the visibility grid */
+ IOVisibilityGrid *visgrid;
+
+ visgrid = init_io_visibilitygrid(*hd, *vp);
+
+
+ /* ------------------------------ */
+ /* construct the event list corresponding to the give input file and
+ viewpoint; this creates an array of all the cells on
+ the same row as the viewpoint */
+ Rtimer initEventTime, sortEventTime, sweepTime;
+
+ AMI_STREAM < AEvent > *eventList;
+ surface_type **data;
+
+ rt_start(initEventTime);
+
+ eventList = init_event_list(inputfname, vp, hd, viewOptions,
+ &data, visgrid);
+
+ assert(eventList && data);
+ eventList->seek(0);
+ rt_stop(initEventTime);
+ /*printf("Event stream length: %lu\n", (unsigned long)eventList->stream_len()); */
+
+
+ /* ------------------------------ */
+ /*sort the events radially by angle */
+ G_verbose_message(_("Sorting events..."));
+
+ rt_start(sortEventTime);
+ sort_event_list(&eventList);
+ eventList->seek(0); /*this does not seem to be ensured by sort?? */
+ rt_stop(sortEventTime);
+
+
+ /* ------------------------------ */
+ /*create the status structure */
+ StatusList *status_struct = create_status_struct();
+
+ /* Put cells that are initially on the sweepline into status
+ structure */
+ StatusNode sn;
+
+ G_message(_("Calculating distances..."));
+
+ rt_start(sweepTime);
+ for (dimensionType i = vp->col + 1; i < hd->ncols; i++) {
+ AEvent e;
+ double ax, ay;
+
+ G_percent(i, hd->ncols, 2);
+
+ sn.col = i;
+ sn.row = vp->row;
+ e.col = i;
+ e.row = vp->row;
+ e.elev[0] = data[0][i];
+ e.elev[1] = data[1][i];
+ e.elev[2] = data[2][i];
+ if (!is_nodata(visgrid->hd, data[1][i]) &&
+ !is_point_outside_max_dist(*vp, *hd, sn.row, sn.col,
+ viewOptions.maxDist)) {
+ /*calculate Distance to VP and Gradient, store them into sn */
+ /* need either 3 elevation values or
+ * 3 gradients calculated from 3 elevation values */
+ /* need also 3 angles */
+ e.eventType = ENTERING_EVENT;
+ calculate_event_position(e, vp->row, vp->col, &ay, &ax);
+ sn.angle[0] = calculate_angle(ax, ay, vp->col, vp->row);
+ calculate_event_gradient(&sn, 0, ay, ax, e.elev[0], vp, *hd);
+
+ e.eventType = CENTER_EVENT;
+ calculate_event_position(e, vp->row, vp->col, &ay, &ax);
+ sn.angle[1] = calculate_angle(ax, ay, vp->col, vp->row);
+ calculate_dist_n_gradient(&sn, e.elev[1], vp, *hd);
+
+ e.eventType = EXITING_EVENT;
+ calculate_event_position(e, vp->row, vp->col, &ay, &ax);
+ sn.angle[2] = calculate_angle(ax, ay, vp->col, vp->row);
+ calculate_event_gradient(&sn, 2, ay, ax, e.elev[2], vp, *hd);
+
+ assert(sn.angle[1] == 0);
+
+ if (sn.angle[0] > sn.angle[1])
+ sn.angle[0] -= 2 * M_PI;
+
+ G_debug(3, "inserting: ");
+ print_statusnode(sn);
+
+ /*insert sn into the status structure */
+ insert_into_status_struct(sn, status_struct);
+ }
+ }
+ G_percent(hd->ncols, hd->ncols, 2);
+ G_free(data[0]);
+ G_free(data);
+
+
+ /* ------------------------------ */
+ /*sweep the event list */
+ long nvis = 0; /*number of visible cells */
+ VisCell viscell;
+ AEvent *e;
+ AMI_err ae;
+ off_t nbEvents = eventList->stream_len();
+
+ /*printf("nbEvents = %ld\n", (long) nbEvents); */
+
+ G_message(_("Determine visibility..."));
+ G_percent(0, 100, 2);
+
+ for (off_t i = 0; i < nbEvents; i++) {
+
+ int perc = (int)((double)i / nbEvents * 1000000.);
+ if (perc > 0)
+ G_percent(perc, 1000000, 2);
+
+ /*get out one event at a time and process it according to its type */
+ ae = eventList->read_item(&e);
+ assert(ae == AMI_ERROR_NO_ERROR);
+
+ sn.col = e->col;
+ sn.row = e->row;
+ //sn.elev = e->elev;
+ /*calculate Distance to VP and Gradient */
+ calculate_dist_n_gradient(&sn, e->elev[1] + vp->target_offset, vp, *hd);
+
+ G_debug(3, "next event: ");
+ print_statusnode(sn);
+
+ switch (e->eventType) {
+ case ENTERING_EVENT:
+ double ax, ay;
+
+ /*insert node into structure */
+ /* need either 3 elevation values or
+ * 3 gradients calculated from 3 elevation values */
+ /* need also 3 angles */
+ calculate_event_position(*e, vp->row, vp->col, &ay, &ax);
+ //sn.angle[0] = calculate_angle(ax, ay, vp->col, vp->row);
+ sn.angle[0] = e->angle;
+ calculate_event_gradient(&sn, 0, ay, ax, e->elev[0], vp, *hd);
+
+ e->eventType = CENTER_EVENT;
+ calculate_event_position(*e, vp->row, vp->col, &ay, &ax);
+ sn.angle[1] = calculate_angle(ax, ay, vp->col, vp->row);
+ calculate_dist_n_gradient(&sn, e->elev[1], vp, *hd);
+
+ e->eventType = EXITING_EVENT;
+ calculate_event_position(*e, vp->row, vp->col, &ay, &ax);
+ sn.angle[2] = calculate_angle(ax, ay, vp->col, vp->row);
+ calculate_event_gradient(&sn, 2, ay, ax, e->elev[2], vp, *hd);
+
+ e->eventType = ENTERING_EVENT;
+
+ if (e->angle < M_PI) {
+ if (sn.angle[0] > sn.angle[1])
+ sn.angle[0] -= 2 * M_PI;
+ }
+ else {
+ if (sn.angle[0] > sn.angle[1]) {
+ sn.angle[1] += 2 * M_PI;
+ sn.angle[2] += 2 * M_PI;
+ }
+ }
+
+ G_debug(3, "..ENTER-EVENT: insert");
+
+ insert_into_status_struct(sn, status_struct);
+ break;
+
+ case EXITING_EVENT:
+ /*delete node out of status structure */
+
+ G_debug(3, "..EXIT-EVENT: delete");
+
+ delete_from_status_struct(status_struct, sn.dist2vp);
+ break;
+
+ case CENTER_EVENT:
+ G_debug(3, "..QUERY-EVENT: query");
+
+ /*calculate visibility */
+ viscell.row = sn.row;
+ viscell.col = sn.col;
+ double max;
+
+ max =
+ find_max_gradient_in_status_struct(status_struct, sn.dist2vp,
+ e->angle, sn.gradient[1]);
+
+ /*the point is visible */
+ if (max <= sn.gradient[1]) {
+ viscell.angle =
+ get_vertical_angle(*vp, sn, e->elev[1] + vp->target_offset, viewOptions.doCurv);
+ assert(viscell.angle >= 0);
+ /* viscell.vis = VISIBLE; */
+ add_result_to_io_visibilitygrid(visgrid, &viscell);
+ nvis++;
+ }
+ else {
+ /* else the cell is invisible; we do not write it to the
+ visibility stream because we only record visible cells, and
+ nodata cells; */
+ /* viscell.vis = INVISIBLE; */
+ /* add_result_to_io_visibilitygrid(visgrid, &viscell); */
+ }
+ break;
+ }
+ } /* for each event */
+ rt_stop(sweepTime);
+ G_percent(1, 1, 1);
+
+ G_message(_("Sweeping done."));
+ G_verbose_message(_("Total cells %ld, visible cells %ld (%.1f percent)."),
+ (long)visgrid->hd->nrows * visgrid->hd->ncols,
+ nvis,
+ (float)((float)nvis * 100 /
+ (float)(visgrid->hd->nrows * visgrid->hd->ncols)));
+
+ print_viewshed_timings(initEventTime, sortEventTime, sweepTime);
+
+ /*cleanup */
+ delete eventList;
+
+ return visgrid;
+}
Deleted: grass/trunk/raster/r.viewshed/visibility.cc
===================================================================
--- grass-addons/raster/r.viewshed/visibility.cc 2011-12-02 09:30:54 UTC (rev 49482)
+++ grass/trunk/raster/r.viewshed/visibility.cc 2011-12-02 09:56:38 UTC (rev 49483)
@@ -1,419 +0,0 @@
-
-/****************************************************************************
- *
- * MODULE: r.viewshed
- *
- * AUTHOR(S): Laura Toma, Bowdoin College - ltoma at bowdoin.edu
- * Yi Zhuang - yzhuang at bowdoin.edu
-
- * Ported to GRASS by William Richard -
- * wkrichar at bowdoin.edu or willster3021 at 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 <stdio.h>
-
-extern "C"
-{
-#include <grass/gis.h>
-#include <grass/glocale.h>
-}
-
-#include "grid.h"
-#include "visibility.h"
-#include "grass.h"
-
-
-
-/* ------------------------------------------------------------ */
-/* viewpoint functions */
-void print_viewpoint(Viewpoint vp)
-{
- G_debug(3, "vp=(%d, %d, %.1f) ", vp.row, vp.col, vp.elev);
- return;
-}
-
-/* ------------------------------------------------------------ */
-void set_viewpoint_coord(Viewpoint * vp, dimensionType row, dimensionType col)
-{
- assert(vp);
- vp->row = row;
- vp->col = col;
- return;
-}
-
-/* ------------------------------------------------------------ */
-void set_viewpoint_elev(Viewpoint * vp, float elev)
-{
- assert(vp);
- vp->elev = elev;
- return;
-}
-
-/* ------------------------------------------------------------ */
-/*copy from b to a */
-void copy_viewpoint(Viewpoint * a, Viewpoint b)
-{
- assert(a);
- a->row = b.row;
- a->col = b.col;
- a->elev = b.elev;
- return;
-}
-
-
-/* ------------------------------------------------------------ */
-/* MemoryVisibilityGrid functions */
-
-/* create and return a grid of the sizes specified in the header */
-MemoryVisibilityGrid *create_inmem_visibilitygrid(GridHeader hd, Viewpoint vp)
-{
-
- MemoryVisibilityGrid *visgrid;
-
- visgrid = (MemoryVisibilityGrid *) G_malloc(sizeof(MemoryVisibilityGrid));
-
- assert(visgrid);
-
-
- /* create the grid */
- visgrid->grid = create_empty_grid();
- assert(visgrid->grid);
-
- /* create the header */
- visgrid->grid->hd = (GridHeader *) G_malloc(sizeof(GridHeader));
-
- assert(visgrid->grid->hd);
-
- /* set the header */
- copy_header(visgrid->grid->hd, hd);
-
- /* allocate the Grid data */
- alloc_grid_data(visgrid->grid);
-
- /*allocate viewpoint */
- visgrid->vp = (Viewpoint *) G_malloc(sizeof(Viewpoint));
-
- assert(visgrid->vp);
- copy_viewpoint(visgrid->vp, vp);
-
- return visgrid;
-}
-
-
-
-
-/* ------------------------------------------------------------ */
-void free_inmem_visibilitygrid(MemoryVisibilityGrid * visgrid)
-{
-
- assert(visgrid);
-
- if (visgrid->grid) {
- destroy_grid(visgrid->grid);
- }
- if (visgrid->vp) {
- G_free(visgrid->vp);
- }
- G_free(visgrid);
-
- return;
-}
-
-
-
-/* ------------------------------------------------------------ */
-/*set all values of visgrid's Grid to the given value */
-void set_inmem_visibilitygrid(MemoryVisibilityGrid * visgrid, float val)
-{
-
- assert(visgrid && visgrid->grid && visgrid->grid->hd &&
- visgrid->grid->grid_data);
-
- dimensionType i, j;
-
- for (i = 0; i < visgrid->grid->hd->nrows; i++) {
- assert(visgrid->grid->grid_data[i]);
- for (j = 0; j < visgrid->grid->hd->ncols; j++) {
- visgrid->grid->grid_data[i][j] = val;
- }
- }
- return;
-}
-
-
-
-/* ------------------------------------------------------------ */
-/*set the (i,j) value of visgrid's Grid to the given value */
-void add_result_to_inmem_visibilitygrid(MemoryVisibilityGrid * visgrid,
- dimensionType i, dimensionType j,
- float val)
-{
-
- assert(visgrid && visgrid->grid && visgrid->grid->hd &&
- visgrid->grid->grid_data);
- assert(i < visgrid->grid->hd->nrows);
- assert(j < visgrid->grid->hd->ncols);
- assert(visgrid->grid->grid_data[i]);
-
- visgrid->grid->grid_data[i][j] = val;
-
- return;
-}
-
-
-
-/* ------------------------------------------------------------ */
-/* The following functions are used to convert the visibility results
- recorded during the viewshed computation into the output grid into
- tehe output required by the user.
-
- x is assumed to be the visibility value computed for a cell during the
- viewshed computation.
-
- The value computed during the viewshed is the following:
-
- x is NODATA if the cell is NODATA;
-
-
- x is INVISIBLE if the cell is invisible;
-
- x is the vertical angle of the cell wrt the viewpoint if the cell is
- visible---the angle is a value in (0,180).
- */
-int is_visible(float x)
-{
- /* if GRASS is on, we cannot guarantee that NODATA is negative; so
- we need to check */
- int isnull = G_is_null_value(&x, G_SURFACE_TYPE);
-
- if (isnull)
- return 0;
- else
- return (x >= 0);
-}
-int is_invisible_not_nodata(float x)
-{
-
- return ((int)x == (int)INVISIBLE);
-}
-
-int is_invisible_nodata(float x)
-{
-
- return (!is_visible(x)) && (!is_invisible_not_nodata(x));
-}
-
-/* ------------------------------------------------------------ */
-/* This function is called when the program runs in
- viewOptions.outputMode == OUTPUT_BOOL. */
-float booleanVisibilityOutput(float x)
-{
- /* NODATA and INVISIBLE are both negative values */
- if (is_visible(x))
- return BOOL_VISIBLE;
- else
- return BOOL_INVISIBLE;
-}
-
-/* ------------------------------------------------------------ */
-/* This function is called when the program runs in
- viewOptions.outputMode == OUTPUT_ANGLE. In this case x represents
- the right value. */
-float angleVisibilityOutput(float x)
-{
-
- return x;
-}
-
-
-/* ------------------------------------------------------------ */
-/* visgrid is the structure that records the visibility information
- after the sweep is done. Use it to write the visibility output
- grid and then distroy it.
- */
-void save_inmem_visibilitygrid(MemoryVisibilityGrid * visgrid,
- ViewOptions viewOptions, Viewpoint vp)
-{
-
- if (viewOptions.outputMode == OUTPUT_BOOL)
- save_grid_to_GRASS(visgrid->grid, viewOptions.outputfname, CELL_TYPE,
- booleanVisibilityOutput);
- else if (viewOptions.outputMode == OUTPUT_ANGLE)
- save_grid_to_GRASS(visgrid->grid, viewOptions.outputfname, FCELL_TYPE,
- angleVisibilityOutput);
- else
- /* elevation output */
- save_vis_elev_to_GRASS(visgrid->grid, viewOptions.inputfname,
- viewOptions.outputfname,
- vp.elev + viewOptions.obsElev);
-
- free_inmem_visibilitygrid(visgrid);
-
- return;
-}
-
-
-
-/* ------------------------------------------------------------ */
-/* IOVisibilityGrid functions */
-/* ------------------------------------------------------------ */
-
-/* ------------------------------------------------------------ */
-/*create grid from given header and viewpoint */
-IOVisibilityGrid *init_io_visibilitygrid(GridHeader hd, Viewpoint vp)
-{
- IOVisibilityGrid *visgrid;
-
- visgrid = (IOVisibilityGrid *) G_malloc(sizeof(IOVisibilityGrid));
-
- assert(visgrid);
-
- /*header */
- visgrid->hd = (GridHeader *) G_malloc(sizeof(GridHeader));
-
- assert(visgrid->hd);
- copy_header(visgrid->hd, hd);
-
- /*viewpoint */
- visgrid->vp = (Viewpoint *) G_malloc(sizeof(Viewpoint));
-
- assert(visgrid->vp);
- copy_viewpoint(visgrid->vp, vp);
-
- /*stream */
- visgrid->visStr = new AMI_STREAM < VisCell > ();
- assert(visgrid->visStr);
-
- return visgrid;
-}
-
-
-
-/* ------------------------------------------------------------ */
-/*free the grid */
-void free_io_visibilitygrid(IOVisibilityGrid * grid)
-{
- assert(grid);
-
- if (grid->hd)
- G_free(grid->hd);
- if (grid->vp)
- G_free(grid->vp);
- if (grid->visStr)
- delete grid->visStr;
-
- G_free(grid);
-
- return;
-}
-
-
-
-/* ------------------------------------------------------------ */
-/*write cell to stream */
-void add_result_to_io_visibilitygrid(IOVisibilityGrid * visgrid,
- VisCell * cell)
-{
-
- assert(visgrid && cell);
-
- AMI_err ae;
-
- assert(visgrid->visStr);
- ae = visgrid->visStr->write_item(*cell);
- assert(ae == AMI_ERROR_NO_ERROR);
- return;
-}
-
-
-/* ------------------------------------------------------------ */
-/*compare function, (i,j) grid order */
-int IJCompare::compare(const VisCell & a, const VisCell & b)
-{
- if (a.row > b.row)
- return 1;
- if (a.row < b.row)
- return -1;
-
- /*a.row==b.row */
- if (a.col > b.col)
- return 1;
- if (a.col < b.col)
- return -1;
- /*all equal */
- return 0;
-}
-
-
-/* ------------------------------------------------------------ */
-/*sort stream in grid order */
-void sort_io_visibilitygrid(IOVisibilityGrid * visGrid)
-{
-
- assert(visGrid);
- assert(visGrid->visStr);
- if (visGrid->visStr->stream_len() == 0)
- return;
-
- AMI_STREAM < VisCell > *sortedStr;
- AMI_err ae;
- IJCompare cmpObj;
-
- ae = AMI_sort(visGrid->visStr, &sortedStr, &cmpObj, 1);
- assert(ae == AMI_ERROR_NO_ERROR);
- assert(sortedStr);
- sortedStr->seek(0);
-
- visGrid->visStr = sortedStr;
- return;
-}
-
-
-/* ------------------------------------------------------------ */
-void
-save_io_visibilitygrid(IOVisibilityGrid * visgrid,
- ViewOptions viewOptions, Viewpoint vp)
-{
-
- if (viewOptions.outputMode == OUTPUT_BOOL)
- save_io_visibilitygrid_to_GRASS(visgrid, viewOptions.outputfname,
- CELL_TYPE, booleanVisibilityOutput);
-
- else if (viewOptions.outputMode == OUTPUT_ANGLE)
- save_io_visibilitygrid_to_GRASS(visgrid, viewOptions.outputfname,
- FCELL_TYPE, angleVisibilityOutput);
- else
- /* elevation output */
- save_io_vis_and_elev_to_GRASS(visgrid, viewOptions.inputfname,
- viewOptions.outputfname,
- vp.elev + viewOptions.obsElev);
-
- /*free visibiliyty grid */
- free_io_visibilitygrid(visgrid);
-
- return;
-}
Copied: grass/trunk/raster/r.viewshed/visibility.cpp (from rev 49482, grass-addons/raster/r.viewshed/visibility.cc)
===================================================================
--- grass/trunk/raster/r.viewshed/visibility.cpp (rev 0)
+++ grass/trunk/raster/r.viewshed/visibility.cpp 2011-12-02 09:56:38 UTC (rev 49483)
@@ -0,0 +1,419 @@
+
+/****************************************************************************
+ *
+ * MODULE: r.viewshed
+ *
+ * AUTHOR(S): Laura Toma, Bowdoin College - ltoma at bowdoin.edu
+ * Yi Zhuang - yzhuang at bowdoin.edu
+
+ * Ported to GRASS by William Richard -
+ * wkrichar at bowdoin.edu or willster3021 at 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 <stdio.h>
+
+extern "C"
+{
+#include <grass/gis.h>
+#include <grass/glocale.h>
+}
+
+#include "grid.h"
+#include "visibility.h"
+#include "grass.h"
+
+
+
+/* ------------------------------------------------------------ */
+/* viewpoint functions */
+void print_viewpoint(Viewpoint vp)
+{
+ G_debug(3, "vp=(%d, %d, %.1f) ", vp.row, vp.col, vp.elev);
+ return;
+}
+
+/* ------------------------------------------------------------ */
+void set_viewpoint_coord(Viewpoint * vp, dimensionType row, dimensionType col)
+{
+ assert(vp);
+ vp->row = row;
+ vp->col = col;
+ return;
+}
+
+/* ------------------------------------------------------------ */
+void set_viewpoint_elev(Viewpoint * vp, float elev)
+{
+ assert(vp);
+ vp->elev = elev;
+ return;
+}
+
+/* ------------------------------------------------------------ */
+/*copy from b to a */
+void copy_viewpoint(Viewpoint * a, Viewpoint b)
+{
+ assert(a);
+ a->row = b.row;
+ a->col = b.col;
+ a->elev = b.elev;
+ return;
+}
+
+
+/* ------------------------------------------------------------ */
+/* MemoryVisibilityGrid functions */
+
+/* create and return a grid of the sizes specified in the header */
+MemoryVisibilityGrid *create_inmem_visibilitygrid(GridHeader hd, Viewpoint vp)
+{
+
+ MemoryVisibilityGrid *visgrid;
+
+ visgrid = (MemoryVisibilityGrid *) G_malloc(sizeof(MemoryVisibilityGrid));
+
+ assert(visgrid);
+
+
+ /* create the grid */
+ visgrid->grid = create_empty_grid();
+ assert(visgrid->grid);
+
+ /* create the header */
+ visgrid->grid->hd = (GridHeader *) G_malloc(sizeof(GridHeader));
+
+ assert(visgrid->grid->hd);
+
+ /* set the header */
+ copy_header(visgrid->grid->hd, hd);
+
+ /* allocate the Grid data */
+ alloc_grid_data(visgrid->grid);
+
+ /*allocate viewpoint */
+ visgrid->vp = (Viewpoint *) G_malloc(sizeof(Viewpoint));
+
+ assert(visgrid->vp);
+ copy_viewpoint(visgrid->vp, vp);
+
+ return visgrid;
+}
+
+
+
+
+/* ------------------------------------------------------------ */
+void free_inmem_visibilitygrid(MemoryVisibilityGrid * visgrid)
+{
+
+ assert(visgrid);
+
+ if (visgrid->grid) {
+ destroy_grid(visgrid->grid);
+ }
+ if (visgrid->vp) {
+ G_free(visgrid->vp);
+ }
+ G_free(visgrid);
+
+ return;
+}
+
+
+
+/* ------------------------------------------------------------ */
+/*set all values of visgrid's Grid to the given value */
+void set_inmem_visibilitygrid(MemoryVisibilityGrid * visgrid, float val)
+{
+
+ assert(visgrid && visgrid->grid && visgrid->grid->hd &&
+ visgrid->grid->grid_data);
+
+ dimensionType i, j;
+
+ for (i = 0; i < visgrid->grid->hd->nrows; i++) {
+ assert(visgrid->grid->grid_data[i]);
+ for (j = 0; j < visgrid->grid->hd->ncols; j++) {
+ visgrid->grid->grid_data[i][j] = val;
+ }
+ }
+ return;
+}
+
+
+
+/* ------------------------------------------------------------ */
+/*set the (i,j) value of visgrid's Grid to the given value */
+void add_result_to_inmem_visibilitygrid(MemoryVisibilityGrid * visgrid,
+ dimensionType i, dimensionType j,
+ float val)
+{
+
+ assert(visgrid && visgrid->grid && visgrid->grid->hd &&
+ visgrid->grid->grid_data);
+ assert(i < visgrid->grid->hd->nrows);
+ assert(j < visgrid->grid->hd->ncols);
+ assert(visgrid->grid->grid_data[i]);
+
+ visgrid->grid->grid_data[i][j] = val;
+
+ return;
+}
+
+
+
+/* ------------------------------------------------------------ */
+/* The following functions are used to convert the visibility results
+ recorded during the viewshed computation into the output grid into
+ tehe output required by the user.
+
+ x is assumed to be the visibility value computed for a cell during the
+ viewshed computation.
+
+ The value computed during the viewshed is the following:
+
+ x is NODATA if the cell is NODATA;
+
+
+ x is INVISIBLE if the cell is invisible;
+
+ x is the vertical angle of the cell wrt the viewpoint if the cell is
+ visible---the angle is a value in (0,180).
+ */
+int is_visible(float x)
+{
+ /* if GRASS is on, we cannot guarantee that NODATA is negative; so
+ we need to check */
+ int isnull = Rast_is_null_value(&x, G_SURFACE_TYPE);
+
+ if (isnull)
+ return 0;
+ else
+ return (x >= 0);
+}
+int is_invisible_not_nodata(float x)
+{
+
+ return ((int)x == (int)INVISIBLE);
+}
+
+int is_invisible_nodata(float x)
+{
+
+ return (!is_visible(x)) && (!is_invisible_not_nodata(x));
+}
+
+/* ------------------------------------------------------------ */
+/* This function is called when the program runs in
+ viewOptions.outputMode == OUTPUT_BOOL. */
+float booleanVisibilityOutput(float x)
+{
+ /* NODATA and INVISIBLE are both negative values */
+ if (is_visible(x))
+ return BOOL_VISIBLE;
+ else
+ return BOOL_INVISIBLE;
+}
+
+/* ------------------------------------------------------------ */
+/* This function is called when the program runs in
+ viewOptions.outputMode == OUTPUT_ANGLE. In this case x represents
+ the right value. */
+float angleVisibilityOutput(float x)
+{
+
+ return x;
+}
+
+
+/* ------------------------------------------------------------ */
+/* visgrid is the structure that records the visibility information
+ after the sweep is done. Use it to write the visibility output
+ grid and then distroy it.
+ */
+void save_inmem_visibilitygrid(MemoryVisibilityGrid * visgrid,
+ ViewOptions viewOptions, Viewpoint vp)
+{
+
+ if (viewOptions.outputMode == OUTPUT_BOOL)
+ save_grid_to_GRASS(visgrid->grid, viewOptions.outputfname, CELL_TYPE,
+ booleanVisibilityOutput);
+ else if (viewOptions.outputMode == OUTPUT_ANGLE)
+ save_grid_to_GRASS(visgrid->grid, viewOptions.outputfname, FCELL_TYPE,
+ angleVisibilityOutput);
+ else
+ /* elevation output */
+ save_vis_elev_to_GRASS(visgrid->grid, viewOptions.inputfname,
+ viewOptions.outputfname,
+ vp.elev + viewOptions.obsElev);
+
+ free_inmem_visibilitygrid(visgrid);
+
+ return;
+}
+
+
+
+/* ------------------------------------------------------------ */
+/* IOVisibilityGrid functions */
+/* ------------------------------------------------------------ */
+
+/* ------------------------------------------------------------ */
+/*create grid from given header and viewpoint */
+IOVisibilityGrid *init_io_visibilitygrid(GridHeader hd, Viewpoint vp)
+{
+ IOVisibilityGrid *visgrid;
+
+ visgrid = (IOVisibilityGrid *) G_malloc(sizeof(IOVisibilityGrid));
+
+ assert(visgrid);
+
+ /*header */
+ visgrid->hd = (GridHeader *) G_malloc(sizeof(GridHeader));
+
+ assert(visgrid->hd);
+ copy_header(visgrid->hd, hd);
+
+ /*viewpoint */
+ visgrid->vp = (Viewpoint *) G_malloc(sizeof(Viewpoint));
+
+ assert(visgrid->vp);
+ copy_viewpoint(visgrid->vp, vp);
+
+ /*stream */
+ visgrid->visStr = new AMI_STREAM < VisCell > ();
+ assert(visgrid->visStr);
+
+ return visgrid;
+}
+
+
+
+/* ------------------------------------------------------------ */
+/*free the grid */
+void free_io_visibilitygrid(IOVisibilityGrid * grid)
+{
+ assert(grid);
+
+ if (grid->hd)
+ G_free(grid->hd);
+ if (grid->vp)
+ G_free(grid->vp);
+ if (grid->visStr)
+ delete grid->visStr;
+
+ G_free(grid);
+
+ return;
+}
+
+
+
+/* ------------------------------------------------------------ */
+/*write cell to stream */
+void add_result_to_io_visibilitygrid(IOVisibilityGrid * visgrid,
+ VisCell * cell)
+{
+
+ assert(visgrid && cell);
+
+ AMI_err ae;
+
+ assert(visgrid->visStr);
+ ae = visgrid->visStr->write_item(*cell);
+ assert(ae == AMI_ERROR_NO_ERROR);
+ return;
+}
+
+
+/* ------------------------------------------------------------ */
+/*compare function, (i,j) grid order */
+int IJCompare::compare(const VisCell & a, const VisCell & b)
+{
+ if (a.row > b.row)
+ return 1;
+ if (a.row < b.row)
+ return -1;
+
+ /*a.row==b.row */
+ if (a.col > b.col)
+ return 1;
+ if (a.col < b.col)
+ return -1;
+ /*all equal */
+ return 0;
+}
+
+
+/* ------------------------------------------------------------ */
+/*sort stream in grid order */
+void sort_io_visibilitygrid(IOVisibilityGrid * visGrid)
+{
+
+ assert(visGrid);
+ assert(visGrid->visStr);
+ if (visGrid->visStr->stream_len() == 0)
+ return;
+
+ AMI_STREAM < VisCell > *sortedStr;
+ AMI_err ae;
+ IJCompare cmpObj;
+
+ ae = AMI_sort(visGrid->visStr, &sortedStr, &cmpObj, 1);
+ assert(ae == AMI_ERROR_NO_ERROR);
+ assert(sortedStr);
+ sortedStr->seek(0);
+
+ visGrid->visStr = sortedStr;
+ return;
+}
+
+
+/* ------------------------------------------------------------ */
+void
+save_io_visibilitygrid(IOVisibilityGrid * visgrid,
+ ViewOptions viewOptions, Viewpoint vp)
+{
+
+ if (viewOptions.outputMode == OUTPUT_BOOL)
+ save_io_visibilitygrid_to_GRASS(visgrid, viewOptions.outputfname,
+ CELL_TYPE, booleanVisibilityOutput);
+
+ else if (viewOptions.outputMode == OUTPUT_ANGLE)
+ save_io_visibilitygrid_to_GRASS(visgrid, viewOptions.outputfname,
+ FCELL_TYPE, angleVisibilityOutput);
+ else
+ /* elevation output */
+ save_io_vis_and_elev_to_GRASS(visgrid, viewOptions.inputfname,
+ viewOptions.outputfname,
+ vp.elev + viewOptions.obsElev);
+
+ /*free visibiliyty grid */
+ free_io_visibilitygrid(visgrid);
+
+ return;
+}
More information about the grass-commit
mailing list