[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, &sector[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, &sectorBnd[(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, &sectorBnd[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, &sectorBnd[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, &sectorBnd[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(&sectorName[i]);
-	G_debug(2, "saving stream %d: %s\t", i, sectorName[i]);
-
-	sector[i].persist(PERSIST_PERSISTENT);
-	sectorBnd[i].name(&sectorBndName[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, &sectorBnd[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, &sector[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, &sectorBnd[(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, &sectorBnd[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, &sectorBnd[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, &sectorBnd[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(&sectorName[i]);
+	G_debug(2, "saving stream %d: %s\t", i, sectorName[i]);
+
+	sector[i].persist(PERSIST_PERSISTENT);
+	sectorBnd[i].name(&sectorBndName[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, &sectorBnd[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(&region) == -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,
-	       &region);
-
-    /* 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, &region);
-    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(&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,
+	       &region);
+
+    /* 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, &region);
+    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