[GRASS-SVN] r48562 - in grass/trunk: lib/iostream raster/r.terraflow visualization/wximgview visualization/xganim

svn_grass at osgeo.org svn_grass at osgeo.org
Thu Sep 29 19:36:57 EDT 2011


Author: glynn
Date: 2011-09-29 16:36:57 -0700 (Thu, 29 Sep 2011)
New Revision: 48562

Added:
   grass/trunk/lib/iostream/ami_stream.cpp
   grass/trunk/lib/iostream/mm.cpp
   grass/trunk/lib/iostream/mm_utils.cpp
   grass/trunk/lib/iostream/rtimer.cpp
   grass/trunk/raster/r.terraflow/ccforest.cpp
   grass/trunk/raster/r.terraflow/common.cpp
   grass/trunk/raster/r.terraflow/direction.cpp
   grass/trunk/raster/r.terraflow/fill.cpp
   grass/trunk/raster/r.terraflow/filldepr.cpp
   grass/trunk/raster/r.terraflow/flow.cpp
   grass/trunk/raster/r.terraflow/genericWindow.cpp
   grass/trunk/raster/r.terraflow/grid.cpp
   grass/trunk/raster/r.terraflow/main.cpp
   grass/trunk/raster/r.terraflow/nodata.cpp
   grass/trunk/raster/r.terraflow/plateau.cpp
   grass/trunk/raster/r.terraflow/stats.cpp
   grass/trunk/raster/r.terraflow/sweep.cpp
   grass/trunk/raster/r.terraflow/types.cpp
   grass/trunk/raster/r.terraflow/water.cpp
   grass/trunk/raster/r.terraflow/weightWindow.cpp
   grass/trunk/visualization/wximgview/main.cpp
   grass/trunk/visualization/xganim/gui.cpp
   grass/trunk/visualization/xganim/main.cpp
Removed:
   grass/trunk/lib/iostream/ami_stream.cc
   grass/trunk/lib/iostream/mm.cc
   grass/trunk/lib/iostream/mm_utils.cc
   grass/trunk/lib/iostream/rtimer.cc
   grass/trunk/raster/r.terraflow/ccforest.cc
   grass/trunk/raster/r.terraflow/common.cc
   grass/trunk/raster/r.terraflow/direction.cc
   grass/trunk/raster/r.terraflow/fill.cc
   grass/trunk/raster/r.terraflow/filldepr.cc
   grass/trunk/raster/r.terraflow/flow.cc
   grass/trunk/raster/r.terraflow/genericWindow.cc
   grass/trunk/raster/r.terraflow/grid.cc
   grass/trunk/raster/r.terraflow/main.cc
   grass/trunk/raster/r.terraflow/nodata.cc
   grass/trunk/raster/r.terraflow/plateau.cc
   grass/trunk/raster/r.terraflow/stats.cc
   grass/trunk/raster/r.terraflow/sweep.cc
   grass/trunk/raster/r.terraflow/types.cc
   grass/trunk/raster/r.terraflow/water.cc
   grass/trunk/raster/r.terraflow/weightWindow.cc
   grass/trunk/visualization/wximgview/main.cc
   grass/trunk/visualization/xganim/gui.cc
   grass/trunk/visualization/xganim/main.cc
Log:
Use .cpp extension for C++ files


Deleted: grass/trunk/lib/iostream/ami_stream.cc
===================================================================
--- grass/trunk/lib/iostream/ami_stream.cc	2011-09-29 23:35:42 UTC (rev 48561)
+++ grass/trunk/lib/iostream/ami_stream.cc	2011-09-29 23:36:57 UTC (rev 48562)
@@ -1,181 +0,0 @@
-/****************************************************************************
- * 
- *  MODULE:     iostream
- *
-
- *  COPYRIGHT (C) 2007 Laura Toma
- *   
- * 
-
- *  Iostream is a library that implements streams, external memory
- *  sorting on streams, and an external memory priority queue on
- *  streams. These are the fundamental components used in external
- *  memory algorithms.  
-
- * Credits: The library was developed by Laura Toma.  The kernel of
- * class STREAM is based on the similar class existent in the GPL TPIE
- * project developed at Duke University. The sorting and priority
- * queue have been developed by Laura Toma based on communications
- * with Rajiv Wickremesinghe. The library was developed as part of
- * porting Terraflow to GRASS in 2001.  PEARL upgrades in 2003 by
- * Rajiv Wickremesinghe as part of the Terracost project.
-
- * 
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
-
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- *  General Public License for more details.  *
- *  **************************************************************************/
-
-
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <assert.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <unistd.h>
-
-//#include <ami_stream.h>
-#include <grass/iostream/ami_stream.h>
-
-
-char *ami_str_error[] = {
-  "AMI_ERROR_NO_ERROR",
-  "AMI_ERROR_IO_ERROR",
-  "AMI_ERROR_END_OF_STREAM",
-  "AMI_ERROR_OUT_OF_RANGE",
-  "AMI_ERROR_READ_ONLY",
-  "AMI_ERROR_OS_ERROR",
-  "AMI_ERROR_MM_ERROR",
-  "AMI_ERROR_OBJECT_INITIALIZATION",
-  "AMI_ERROR_PERMISSION_DENIED",
-  "AMI_ERROR_INSUFFICIENT_MAIN_MEMORY",
-  "AMI_ERROR_INSUFFICIENT_AVAILABLE_STREAMS",
-  "AMI_ERROR_ENV_UNDEFINED",
-  "AMI_ERROR_NO_MAIN_MEMORY_OPERATION",
-};
-
-/**********************************************************************/
-/* creates a random file name, opens the file for reading and writing
-   and and returns a file descriptor */
-int
-ami_single_temp_name(const std::string& base, char* tmp_path) {
- 
-  char *base_dir;
-  int fd;
-
-  // get the dir
-  base_dir = getenv(STREAM_TMPDIR);
-  if(!base_dir) {
-	fprintf(stderr, "ami_stream: %s not set\n", STREAM_TMPDIR);
-	assert(base_dir);
-	exit(1);
-  }
-  sprintf(tmp_path, "%s/%s_XXXXXX", base_dir, base.c_str());
-
-#ifdef __MINGW32__
-  fd = mktemp(tmp_path) ? open(tmp_path, O_CREAT|O_EXCL|O_RDWR, 0600) : -1;
-#else
-  fd = mkstemp(tmp_path);
-#endif
-
-  if (fd == -1) {
-    cerr <<  "ami_single_temp_name: ";
-#ifdef __MINGW32__
-    perror("mktemp failed: ");
-#else
-    perror("mkstemp failed: ");
-#endif
-    assert(0);
-    exit(1);
-  }
-  return fd;
-}
-
-
-/**********************************************************************/
-/* given fd=fide descriptor, associates with it a stream aopened in
-   access_mode and returns it */
-FILE* 
-open_stream(int fd, AMI_stream_type st) {
-  FILE* fp = NULL;
-  
-  assert(fd > -1);   
-  switch (st) {
-  case   AMI_READ_STREAM:
-    fp = fdopen(fd, "rb");
-    break;
-  case   AMI_WRITE_STREAM:
-    fp = fdopen(fd, "wb");
-    break;
-  case AMI_APPEND_WRITE_STREAM:
-    fp = fdopen(fd, "ab");
-    break;
-  case AMI_APPEND_STREAM:
-    fp = fdopen(fd, "ab+");
-    break;
-  case AMI_READ_WRITE_STREAM: 
-	fp = fdopen(fd, "rb+");
-	if (!fp) {
-	  //if file does not exist, create it
-	  fp = fdopen(fd, "wb+");
-	}
-	break;
-  }
-  if(!fp) {
-    perror("fdopen");
-  }
-  assert(fp);
-
-  return fp;
-}
-
-
-/**********************************************************************/
-/* open the file whose name is pathname in access mode */
-FILE* 
-open_stream(char* pathname, AMI_stream_type st) {
-
-  FILE* fp = NULL;
-  assert(pathname);
-
-  switch (st) {
-  case   AMI_READ_STREAM:
-    fp = fopen(pathname, "rb");
-    break;
-  case   AMI_WRITE_STREAM:
-    fp = fopen(pathname, "wb");
-    break;
-  case AMI_APPEND_WRITE_STREAM:
-    fp = fopen(pathname, "ab");
-    break;
-  case AMI_APPEND_STREAM:
-    fp = fopen(pathname, "ab+");
-    assert(fp);
-    G_fseek (fp, 0, SEEK_END);
-    break;
-  case AMI_READ_WRITE_STREAM: 
-      fp = fopen(pathname, "rb+");
-      if (!fp) {
-	//if file does not exist, create it
-      fp = fopen(pathname, "wb+");
-      }
-      break;
-  }
-  if (!fp) {
-    perror(pathname);
-    assert(0);
-    exit(1);
-  }
-  assert(fp);
-  return fp;
-}
-

Copied: grass/trunk/lib/iostream/ami_stream.cpp (from rev 48560, grass/trunk/lib/iostream/ami_stream.cc)
===================================================================
--- grass/trunk/lib/iostream/ami_stream.cpp	                        (rev 0)
+++ grass/trunk/lib/iostream/ami_stream.cpp	2011-09-29 23:36:57 UTC (rev 48562)
@@ -0,0 +1,181 @@
+/****************************************************************************
+ * 
+ *  MODULE:     iostream
+ *
+
+ *  COPYRIGHT (C) 2007 Laura Toma
+ *   
+ * 
+
+ *  Iostream is a library that implements streams, external memory
+ *  sorting on streams, and an external memory priority queue on
+ *  streams. These are the fundamental components used in external
+ *  memory algorithms.  
+
+ * Credits: The library was developed by Laura Toma.  The kernel of
+ * class STREAM is based on the similar class existent in the GPL TPIE
+ * project developed at Duke University. The sorting and priority
+ * queue have been developed by Laura Toma based on communications
+ * with Rajiv Wickremesinghe. The library was developed as part of
+ * porting Terraflow to GRASS in 2001.  PEARL upgrades in 2003 by
+ * Rajiv Wickremesinghe as part of the Terracost project.
+
+ * 
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  General Public License for more details.  *
+ *  **************************************************************************/
+
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <unistd.h>
+
+//#include <ami_stream.h>
+#include <grass/iostream/ami_stream.h>
+
+
+char *ami_str_error[] = {
+  "AMI_ERROR_NO_ERROR",
+  "AMI_ERROR_IO_ERROR",
+  "AMI_ERROR_END_OF_STREAM",
+  "AMI_ERROR_OUT_OF_RANGE",
+  "AMI_ERROR_READ_ONLY",
+  "AMI_ERROR_OS_ERROR",
+  "AMI_ERROR_MM_ERROR",
+  "AMI_ERROR_OBJECT_INITIALIZATION",
+  "AMI_ERROR_PERMISSION_DENIED",
+  "AMI_ERROR_INSUFFICIENT_MAIN_MEMORY",
+  "AMI_ERROR_INSUFFICIENT_AVAILABLE_STREAMS",
+  "AMI_ERROR_ENV_UNDEFINED",
+  "AMI_ERROR_NO_MAIN_MEMORY_OPERATION",
+};
+
+/**********************************************************************/
+/* creates a random file name, opens the file for reading and writing
+   and and returns a file descriptor */
+int
+ami_single_temp_name(const std::string& base, char* tmp_path) {
+ 
+  char *base_dir;
+  int fd;
+
+  // get the dir
+  base_dir = getenv(STREAM_TMPDIR);
+  if(!base_dir) {
+	fprintf(stderr, "ami_stream: %s not set\n", STREAM_TMPDIR);
+	assert(base_dir);
+	exit(1);
+  }
+  sprintf(tmp_path, "%s/%s_XXXXXX", base_dir, base.c_str());
+
+#ifdef __MINGW32__
+  fd = mktemp(tmp_path) ? open(tmp_path, O_CREAT|O_EXCL|O_RDWR, 0600) : -1;
+#else
+  fd = mkstemp(tmp_path);
+#endif
+
+  if (fd == -1) {
+    cerr <<  "ami_single_temp_name: ";
+#ifdef __MINGW32__
+    perror("mktemp failed: ");
+#else
+    perror("mkstemp failed: ");
+#endif
+    assert(0);
+    exit(1);
+  }
+  return fd;
+}
+
+
+/**********************************************************************/
+/* given fd=fide descriptor, associates with it a stream aopened in
+   access_mode and returns it */
+FILE* 
+open_stream(int fd, AMI_stream_type st) {
+  FILE* fp = NULL;
+  
+  assert(fd > -1);   
+  switch (st) {
+  case   AMI_READ_STREAM:
+    fp = fdopen(fd, "rb");
+    break;
+  case   AMI_WRITE_STREAM:
+    fp = fdopen(fd, "wb");
+    break;
+  case AMI_APPEND_WRITE_STREAM:
+    fp = fdopen(fd, "ab");
+    break;
+  case AMI_APPEND_STREAM:
+    fp = fdopen(fd, "ab+");
+    break;
+  case AMI_READ_WRITE_STREAM: 
+	fp = fdopen(fd, "rb+");
+	if (!fp) {
+	  //if file does not exist, create it
+	  fp = fdopen(fd, "wb+");
+	}
+	break;
+  }
+  if(!fp) {
+    perror("fdopen");
+  }
+  assert(fp);
+
+  return fp;
+}
+
+
+/**********************************************************************/
+/* open the file whose name is pathname in access mode */
+FILE* 
+open_stream(char* pathname, AMI_stream_type st) {
+
+  FILE* fp = NULL;
+  assert(pathname);
+
+  switch (st) {
+  case   AMI_READ_STREAM:
+    fp = fopen(pathname, "rb");
+    break;
+  case   AMI_WRITE_STREAM:
+    fp = fopen(pathname, "wb");
+    break;
+  case AMI_APPEND_WRITE_STREAM:
+    fp = fopen(pathname, "ab");
+    break;
+  case AMI_APPEND_STREAM:
+    fp = fopen(pathname, "ab+");
+    assert(fp);
+    G_fseek (fp, 0, SEEK_END);
+    break;
+  case AMI_READ_WRITE_STREAM: 
+      fp = fopen(pathname, "rb+");
+      if (!fp) {
+	//if file does not exist, create it
+      fp = fopen(pathname, "wb+");
+      }
+      break;
+  }
+  if (!fp) {
+    perror(pathname);
+    assert(0);
+    exit(1);
+  }
+  assert(fp);
+  return fp;
+}
+

Deleted: grass/trunk/lib/iostream/mm.cc
===================================================================
--- grass/trunk/lib/iostream/mm.cc	2011-09-29 23:35:42 UTC (rev 48561)
+++ grass/trunk/lib/iostream/mm.cc	2011-09-29 23:36:57 UTC (rev 48562)
@@ -1,484 +0,0 @@
-/****************************************************************************
- * 
- *  MODULE:     iostream
- *
-
- *  COPYRIGHT (C) 2007 Laura Toma
- *   
- * 
-
- *  Iostream is a library that implements streams, external memory
- *  sorting on streams, and an external memory priority queue on
- *  streams. These are the fundamental components used in external
- *  memory algorithms.  
-
- * Credits: The library was developed by Laura Toma.  The kernel of
- * class STREAM is based on the similar class existent in the GPL TPIE
- * project developed at Duke University. The sorting and priority
- * queue have been developed by Laura Toma based on communications
- * with Rajiv Wickremesinghe. The library was developed as part of
- * porting Terraflow to GRASS in 2001.  PEARL upgrades in 2003 by
- * Rajiv Wickremesinghe as part of the Terracost project.
-
- * 
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
-
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- *  General Public License for more details.  *
- *  **************************************************************************/
-
-
-
-// A simple registration based memory manager.
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <assert.h>
-#include <iostream>
-using namespace std;
-
-//#include <mm.h>
-#include <grass/iostream/mm.h>
-
-#define MM_DEBUG if(0)
-
-
-
-/* ************************************************************ */
-MM_register::MM_register() {
- 
-   instances++;
-    if (instances > 1) {
-      cerr << "MM_register(): Only 1 instance of MM_register should exist.\n";
-      assert(0); //core dump if debugging
-      exit(1);
-    }
-    assert(instances == 1);
- 
-    // by default, we ignore if memory limit is exceeded   
-    register_new = MM_IGNORE_MEMORY_EXCEEDED;
-}
-
-
-
-/* ************************************************************ */
-MM_register::~MM_register(void) {
- 
-  if (instances > 1) {
-    cerr << "MM_register(): Only 1 instance of MM_register should exist.\n";
-    assert(0); //core dump if debugging    
-    exit(1);
-  }
-  assert(instances == 1);
-  instances--;
-}
-
-
-/* ************************************************************ */
-void MM_register::print() {
-  
-  size_t availMB = (remaining >> 20);
-  if (remaining) {
-    cout << "available memory: " << availMB << "MB "
-	 << "(" << remaining << "B)"
-	 << endl; 
-  } else {
-    cout << "available memory: " << remaining << "B, exceeding: " 
-	 << used - user_limit << "B"
-	 << endl; 
-  }
-}
-
-
-/* ************************************************************ */
-// User-callable method to set allowable memory size
-MM_err MM_register::set_memory_limit (size_t new_limit) {
-
-  assert( new_limit > 0); 
-  if (used > new_limit) {
-    //    return MM_ERROR_EXCESSIVE_ALLOCATION;    
-    switch (register_new) {
-    case MM_ABORT_ON_MEMORY_EXCEEDED:
-      cerr << " MM_register::set_memory_limit to " << new_limit 
-      	   << ", used " << used << ". allocation exceeds new limit.\n";
-      cerr.flush();
-      assert(0); //core dump if debugging
-      exit(1);
-      break;
-      
-    case MM_WARN_ON_MEMORY_EXCEEDED:
-      cerr << " MM_register::set_memory_limit to " << new_limit 
-	   << ", used " << used << ". allocation exceeds new limit.\n";
-      break;
-      
-    case MM_IGNORE_MEMORY_EXCEEDED:
-      break;
-    }   
-    user_limit = new_limit;
-    remaining = 0;
-    return MM_ERROR_NO_ERROR;
-  }
-  
-  assert(used <= new_limit);
-  // These are unsigned, so be careful.
-  if (new_limit < user_limit) {
-    remaining -= user_limit - new_limit;
-  } else {
-    remaining += new_limit - user_limit;
-  }
-  user_limit = new_limit;
-  return MM_ERROR_NO_ERROR;
-}  
-
-
-
-/* ************************************************************ */
-//only warn if memory limit exceeded
-void MM_register::warn_memory_limit() {
-  register_new = MM_WARN_ON_MEMORY_EXCEEDED;
-}
-
-
-/* ************************************************************ */
-//abort if memory limit exceeded
-void MM_register::enforce_memory_limit() {
-  register_new = MM_ABORT_ON_MEMORY_EXCEEDED;
-
-  if (used > user_limit) {
-    cerr << " MM_register::enforce_memory_limit: limit=" << user_limit 
-	 << ", used=" << used << ". allocation exceeds limit.\n";
-    assert(0); //core dump if debugging
-    exit(1);
-  }
-}
-
-
-/* ************************************************************ */
-//ignore memory limit accounting
-void MM_register::ignore_memory_limit() {
-  register_new = MM_IGNORE_MEMORY_EXCEEDED;
-}
-
-
-/* ************************************************************ */
-// provide accounting state
-MM_mode MM_register::get_limit_mode() {
-  return register_new;
-}
-
-/* ************************************************************ */
-// provide print ccounting state
-void MM_register::print_limit_mode() {
-  cout << "Memory manager registering memory in ";  
-  switch (register_new)  {
-  case MM_ABORT_ON_MEMORY_EXCEEDED:
-    cout << "MM_ABORT_ON_MEMORY_EXCEEDED";
-    break;
-  case MM_WARN_ON_MEMORY_EXCEEDED:
-    cout << "MM_WARN_ON_MEMORY_EXCEEDED";
-    break;
-  case  MM_IGNORE_MEMORY_EXCEEDED:
-    cout << "MM_IGNORE_MEMORY_EXCEEDED";
-    break;
-  }
-  cout << " mode." << endl;
-}
-
-
-
-/* ************************************************************ */
-//return the amount of memory available before user-specified memory
-//limit will be exceeded
-size_t MM_register::memory_available() {
-  return remaining;    
-}
-
-/* ************************************************************ */
-size_t MM_register::memory_used() {
-  return used;    
-}
-
-
-/* ************************************************************ */
-size_t MM_register::memory_limit() {
-  return user_limit;    
-}
-
-
-/* ---------------------------------------------------------------------- */
-// return the overhead on each memory allocation request 
-
-
-// SIZE_SPACE is to ensure alignment on quad word boundaries.  It may be
-// possible to check whether a machine needs this at configuration
-// time or if dword alignment is ok.  On the HP 9000, bus errors occur
-// when loading doubles that are not qword aligned.
-static const size_t SIZE_SPACE=(sizeof(size_t) > 8 ? sizeof(size_t) : 8);
-
-
-
-int   MM_register::space_overhead ()  {
-  return SIZE_SPACE;
-}
-  
-
-
-
-/* ************************************************************ */
-// check that new allocation request is below user-defined limit.
-// This should be a private method, only called by operator new.
-MM_err MM_register::register_allocation(size_t request) {
-
-  if (request > remaining) {
-    remaining = 0;
-    used += request;
-    return MM_ERROR_INSUFFICIENT_SPACE;
-    
-  } else {
-    used      += request;     
-    remaining -= request;
-    return MM_ERROR_NO_ERROR;
-  }
-}
-
-
-
-/* ************************************************************ */
-// do the accounting for a memory deallocation request.
-// This should be a private method, only called by operators 
-// delete and delete [].
-MM_err MM_register::register_deallocation(size_t sz) {
-  
-  if (sz > used) {
-    used = 0;
-    remaining = user_limit;
-    return MM_ERROR_UNDERFLOW;
-  } else {
-
-    used      -= sz;        
-    if (used < user_limit) {
-      remaining = user_limit - used;
-    } else {
-      assert(remaining == 0);
-    }
-    return MM_ERROR_NO_ERROR;
-  }
-}
-
-
- 
-/* ************************************************************ */
-void* operator new[] (size_t sz) {
-  void *p;
-  
-  MM_DEBUG cout << "new: sz=" << sz << ", register " 
-		<< sz+SIZE_SPACE << "B ,"; 
-
-  if (MM_manager.register_allocation (sz + SIZE_SPACE) != MM_ERROR_NO_ERROR){
-    //must be MM_ERROR_INSUF_SPACE
-    switch(MM_manager.register_new) {
-      
-    case MM_ABORT_ON_MEMORY_EXCEEDED:
-      cerr << "MM error: limit ="<< MM_manager.memory_limit() <<"B. " 
-	   << "allocating " << sz << "B. " 
-	   << "limit exceeded by " 
-	   <<  MM_manager.memory_used() -  MM_manager.memory_limit()<<"B."
-	   << endl;
-      assert (0);		// core dump if debugging
-      exit (1);
-      break;
-      
-    case MM_WARN_ON_MEMORY_EXCEEDED:
-      cerr << "MM warning: limit="<<MM_manager.memory_limit() <<"B. " 
-	   << "allocating " << sz << "B. " 
-	   << " limit exceeded by " 
-	   <<  MM_manager.memory_used() -  MM_manager.memory_limit()<<"B."
-	   << endl;
-      break;
-      
-    case MM_IGNORE_MEMORY_EXCEEDED:
-      break;
-    }
-  }
-  
-  p = malloc(sz + SIZE_SPACE);
-  
-  if (!p) {
-    cerr << "new: out of memory while allocating " << sz << "B" << endl;
-    assert(0);
-    exit (1);
-  }
-  
-  *((size_t *) p) = sz;
-  
-  MM_DEBUG cout << "ptr=" << (void*) (((char *) p) + SIZE_SPACE) << endl;
-  
-  return ((char *) p) + SIZE_SPACE;
-}
-
-
- 
-/* ************************************************************ */
-void* operator new (size_t sz) {
-  void *p;
-  
-  MM_DEBUG cout << "new: sz=" << sz << ", register " 
-		<< sz+SIZE_SPACE << "B ,"; 
-
-  if (MM_manager.register_allocation (sz + SIZE_SPACE) != MM_ERROR_NO_ERROR){
-    //must be MM_ERROR_INSUF_SPACE
-    switch(MM_manager.register_new) {
-      
-    case MM_ABORT_ON_MEMORY_EXCEEDED:
-      cerr << "MM error: limit ="<< MM_manager.memory_limit() <<"B. " 
-	   << "allocating " << sz << "B. " 
-	   << "limit exceeded by " 
-	   <<  MM_manager.memory_used() -  MM_manager.memory_limit()<<"B."
-	   << endl;
-      assert (0);		// core dump if debugging
-      exit (1);
-      break;
-      
-    case MM_WARN_ON_MEMORY_EXCEEDED:
-      cerr << "MM warning: limit="<<MM_manager.memory_limit() <<"B. " 
-	   << "allocating " << sz << "B. " 
-	   << " limit exceeded by " 
-	   <<  MM_manager.memory_used() -  MM_manager.memory_limit()<<"B."
-	   << endl;
-      break;
-      
-    case MM_IGNORE_MEMORY_EXCEEDED:
-      break;
-    }
-  }
-  
-  p = malloc(sz + SIZE_SPACE);
-  
-  if (!p) {
-    cerr << "new: out of memory while allocating " << sz << "B" << endl;
-    assert(0);
-    exit (1);
-  }
-  
-  *((size_t *) p) = sz;
-  
-  MM_DEBUG cout << "ptr=" << (void*) (((char *) p) + SIZE_SPACE) << endl;
-  
-  return ((char *) p) + SIZE_SPACE;
-}
-
-
-
-
-/* ---------------------------------------------------------------------- */
-void operator delete (void *ptr)  {
-  size_t sz;
-  void *p;
-  
-  MM_DEBUG cout << "delete: ptr=" << ptr << ","; 
-
-  if (!ptr) {
-    cerr << "MM warning: operator delete was given a NULL pointer\n";
-    cerr.flush();
-    //this may actually happen: for instance when calling a default
-    //destructor for something that was not allocated with new
-    //e.g. ofstream str(name) ---- ~ofstream() called ==> ptr=NULL
-    
-	//who wrote the above comment? -RW
-    assert(0); 
-    //exit(1);
-    return;
-  }
-  
-  assert(ptr);
-  p = ((char *)ptr) - SIZE_SPACE; // the base of memory
-  sz = *((size_t *)p);
-  
-  MM_DEBUG cout << "size=" << sz <<", free " << p << "B and deallocate " 
-		<< sz + SIZE_SPACE << endl;
-  
-  if(MM_manager.register_deallocation (sz + SIZE_SPACE) != MM_ERROR_NO_ERROR){
-    //must be MM_ERROR_UNDERFLOW
-    cerr << "delete: MM_manager.register_deallocation failed\n";
-    assert(0);
-    exit(1);
-  }
-
-  free(p);
-}
-
-
-
-
-/* ---------------------------------------------------------------------- */
-void operator delete[] (void *ptr) {
-  size_t sz;
-  void *p;
-  
-  MM_DEBUG cout << "delete[]: ptr=" << ptr << ","; 
-
-  if (!ptr) {
-    //can this hapen? -- it does: see delete above
-    cerr << "MM warning: operator delete [] was given a NULL pointer\n";
-    cerr.flush();
-    //assert(0);
-    //exit(1);
-    return;
-  }
-   assert(ptr);
-   p = ((char *)ptr) - SIZE_SPACE; // the base of memory
-   sz = *((size_t *)p);
-
-   MM_DEBUG cout << "size=" << sz <<", free " << p << "B and deallocate " 
-		 << sz + SIZE_SPACE << endl;
-   
-   if(MM_manager.register_deallocation (sz + SIZE_SPACE)!= MM_ERROR_NO_ERROR){
-     //must be MM_ERROR_UNDERFLOW
-     cerr << "delete[]: MM_manager.register_deallocation failed\n";
-     assert(0);
-     exit(1);
-   }
-   
-   free(p);
-}
-
-
-
-
-
-/* ************************************************************ */
-// Instantiate the actual memory manager, and allocate the 
-// its static data members
-MM_register MM_manager;
-int MM_register::instances = 0; // Number of instances. (init)
-// TPIE's "register memory requests" flag
-MM_mode MM_register::register_new = MM_IGNORE_MEMORY_EXCEEDED;
-//This causes constructors for static variables to fail
-//MM_mode MM_register::register_new = MM_ABORT_ON_MEMORY_EXCEEDED; 
-
-
-
-
-
-
-/* ************************************************************ */
-// The counter of mm_register_init instances.  It is implicity set to 0.
-unsigned int mm_register_init::count;
-
-// The constructor and destructor that ensure that the memory manager is
-// created exactly once, and destroyed when appropriate.
-mm_register_init::mm_register_init(void) {
-  if (count++ == 0) {
-    MM_manager.set_memory_limit(MM_DEFAULT_MM_SIZE);
-  }
-}
-
-mm_register_init::~mm_register_init(void) {
-  --count;
-}

Copied: grass/trunk/lib/iostream/mm.cpp (from rev 48560, grass/trunk/lib/iostream/mm.cc)
===================================================================
--- grass/trunk/lib/iostream/mm.cpp	                        (rev 0)
+++ grass/trunk/lib/iostream/mm.cpp	2011-09-29 23:36:57 UTC (rev 48562)
@@ -0,0 +1,484 @@
+/****************************************************************************
+ * 
+ *  MODULE:     iostream
+ *
+
+ *  COPYRIGHT (C) 2007 Laura Toma
+ *   
+ * 
+
+ *  Iostream is a library that implements streams, external memory
+ *  sorting on streams, and an external memory priority queue on
+ *  streams. These are the fundamental components used in external
+ *  memory algorithms.  
+
+ * Credits: The library was developed by Laura Toma.  The kernel of
+ * class STREAM is based on the similar class existent in the GPL TPIE
+ * project developed at Duke University. The sorting and priority
+ * queue have been developed by Laura Toma based on communications
+ * with Rajiv Wickremesinghe. The library was developed as part of
+ * porting Terraflow to GRASS in 2001.  PEARL upgrades in 2003 by
+ * Rajiv Wickremesinghe as part of the Terracost project.
+
+ * 
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  General Public License for more details.  *
+ *  **************************************************************************/
+
+
+
+// A simple registration based memory manager.
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <iostream>
+using namespace std;
+
+//#include <mm.h>
+#include <grass/iostream/mm.h>
+
+#define MM_DEBUG if(0)
+
+
+
+/* ************************************************************ */
+MM_register::MM_register() {
+ 
+   instances++;
+    if (instances > 1) {
+      cerr << "MM_register(): Only 1 instance of MM_register should exist.\n";
+      assert(0); //core dump if debugging
+      exit(1);
+    }
+    assert(instances == 1);
+ 
+    // by default, we ignore if memory limit is exceeded   
+    register_new = MM_IGNORE_MEMORY_EXCEEDED;
+}
+
+
+
+/* ************************************************************ */
+MM_register::~MM_register(void) {
+ 
+  if (instances > 1) {
+    cerr << "MM_register(): Only 1 instance of MM_register should exist.\n";
+    assert(0); //core dump if debugging    
+    exit(1);
+  }
+  assert(instances == 1);
+  instances--;
+}
+
+
+/* ************************************************************ */
+void MM_register::print() {
+  
+  size_t availMB = (remaining >> 20);
+  if (remaining) {
+    cout << "available memory: " << availMB << "MB "
+	 << "(" << remaining << "B)"
+	 << endl; 
+  } else {
+    cout << "available memory: " << remaining << "B, exceeding: " 
+	 << used - user_limit << "B"
+	 << endl; 
+  }
+}
+
+
+/* ************************************************************ */
+// User-callable method to set allowable memory size
+MM_err MM_register::set_memory_limit (size_t new_limit) {
+
+  assert( new_limit > 0); 
+  if (used > new_limit) {
+    //    return MM_ERROR_EXCESSIVE_ALLOCATION;    
+    switch (register_new) {
+    case MM_ABORT_ON_MEMORY_EXCEEDED:
+      cerr << " MM_register::set_memory_limit to " << new_limit 
+      	   << ", used " << used << ". allocation exceeds new limit.\n";
+      cerr.flush();
+      assert(0); //core dump if debugging
+      exit(1);
+      break;
+      
+    case MM_WARN_ON_MEMORY_EXCEEDED:
+      cerr << " MM_register::set_memory_limit to " << new_limit 
+	   << ", used " << used << ". allocation exceeds new limit.\n";
+      break;
+      
+    case MM_IGNORE_MEMORY_EXCEEDED:
+      break;
+    }   
+    user_limit = new_limit;
+    remaining = 0;
+    return MM_ERROR_NO_ERROR;
+  }
+  
+  assert(used <= new_limit);
+  // These are unsigned, so be careful.
+  if (new_limit < user_limit) {
+    remaining -= user_limit - new_limit;
+  } else {
+    remaining += new_limit - user_limit;
+  }
+  user_limit = new_limit;
+  return MM_ERROR_NO_ERROR;
+}  
+
+
+
+/* ************************************************************ */
+//only warn if memory limit exceeded
+void MM_register::warn_memory_limit() {
+  register_new = MM_WARN_ON_MEMORY_EXCEEDED;
+}
+
+
+/* ************************************************************ */
+//abort if memory limit exceeded
+void MM_register::enforce_memory_limit() {
+  register_new = MM_ABORT_ON_MEMORY_EXCEEDED;
+
+  if (used > user_limit) {
+    cerr << " MM_register::enforce_memory_limit: limit=" << user_limit 
+	 << ", used=" << used << ". allocation exceeds limit.\n";
+    assert(0); //core dump if debugging
+    exit(1);
+  }
+}
+
+
+/* ************************************************************ */
+//ignore memory limit accounting
+void MM_register::ignore_memory_limit() {
+  register_new = MM_IGNORE_MEMORY_EXCEEDED;
+}
+
+
+/* ************************************************************ */
+// provide accounting state
+MM_mode MM_register::get_limit_mode() {
+  return register_new;
+}
+
+/* ************************************************************ */
+// provide print ccounting state
+void MM_register::print_limit_mode() {
+  cout << "Memory manager registering memory in ";  
+  switch (register_new)  {
+  case MM_ABORT_ON_MEMORY_EXCEEDED:
+    cout << "MM_ABORT_ON_MEMORY_EXCEEDED";
+    break;
+  case MM_WARN_ON_MEMORY_EXCEEDED:
+    cout << "MM_WARN_ON_MEMORY_EXCEEDED";
+    break;
+  case  MM_IGNORE_MEMORY_EXCEEDED:
+    cout << "MM_IGNORE_MEMORY_EXCEEDED";
+    break;
+  }
+  cout << " mode." << endl;
+}
+
+
+
+/* ************************************************************ */
+//return the amount of memory available before user-specified memory
+//limit will be exceeded
+size_t MM_register::memory_available() {
+  return remaining;    
+}
+
+/* ************************************************************ */
+size_t MM_register::memory_used() {
+  return used;    
+}
+
+
+/* ************************************************************ */
+size_t MM_register::memory_limit() {
+  return user_limit;    
+}
+
+
+/* ---------------------------------------------------------------------- */
+// return the overhead on each memory allocation request 
+
+
+// SIZE_SPACE is to ensure alignment on quad word boundaries.  It may be
+// possible to check whether a machine needs this at configuration
+// time or if dword alignment is ok.  On the HP 9000, bus errors occur
+// when loading doubles that are not qword aligned.
+static const size_t SIZE_SPACE=(sizeof(size_t) > 8 ? sizeof(size_t) : 8);
+
+
+
+int   MM_register::space_overhead ()  {
+  return SIZE_SPACE;
+}
+  
+
+
+
+/* ************************************************************ */
+// check that new allocation request is below user-defined limit.
+// This should be a private method, only called by operator new.
+MM_err MM_register::register_allocation(size_t request) {
+
+  if (request > remaining) {
+    remaining = 0;
+    used += request;
+    return MM_ERROR_INSUFFICIENT_SPACE;
+    
+  } else {
+    used      += request;     
+    remaining -= request;
+    return MM_ERROR_NO_ERROR;
+  }
+}
+
+
+
+/* ************************************************************ */
+// do the accounting for a memory deallocation request.
+// This should be a private method, only called by operators 
+// delete and delete [].
+MM_err MM_register::register_deallocation(size_t sz) {
+  
+  if (sz > used) {
+    used = 0;
+    remaining = user_limit;
+    return MM_ERROR_UNDERFLOW;
+  } else {
+
+    used      -= sz;        
+    if (used < user_limit) {
+      remaining = user_limit - used;
+    } else {
+      assert(remaining == 0);
+    }
+    return MM_ERROR_NO_ERROR;
+  }
+}
+
+
+ 
+/* ************************************************************ */
+void* operator new[] (size_t sz) {
+  void *p;
+  
+  MM_DEBUG cout << "new: sz=" << sz << ", register " 
+		<< sz+SIZE_SPACE << "B ,"; 
+
+  if (MM_manager.register_allocation (sz + SIZE_SPACE) != MM_ERROR_NO_ERROR){
+    //must be MM_ERROR_INSUF_SPACE
+    switch(MM_manager.register_new) {
+      
+    case MM_ABORT_ON_MEMORY_EXCEEDED:
+      cerr << "MM error: limit ="<< MM_manager.memory_limit() <<"B. " 
+	   << "allocating " << sz << "B. " 
+	   << "limit exceeded by " 
+	   <<  MM_manager.memory_used() -  MM_manager.memory_limit()<<"B."
+	   << endl;
+      assert (0);		// core dump if debugging
+      exit (1);
+      break;
+      
+    case MM_WARN_ON_MEMORY_EXCEEDED:
+      cerr << "MM warning: limit="<<MM_manager.memory_limit() <<"B. " 
+	   << "allocating " << sz << "B. " 
+	   << " limit exceeded by " 
+	   <<  MM_manager.memory_used() -  MM_manager.memory_limit()<<"B."
+	   << endl;
+      break;
+      
+    case MM_IGNORE_MEMORY_EXCEEDED:
+      break;
+    }
+  }
+  
+  p = malloc(sz + SIZE_SPACE);
+  
+  if (!p) {
+    cerr << "new: out of memory while allocating " << sz << "B" << endl;
+    assert(0);
+    exit (1);
+  }
+  
+  *((size_t *) p) = sz;
+  
+  MM_DEBUG cout << "ptr=" << (void*) (((char *) p) + SIZE_SPACE) << endl;
+  
+  return ((char *) p) + SIZE_SPACE;
+}
+
+
+ 
+/* ************************************************************ */
+void* operator new (size_t sz) {
+  void *p;
+  
+  MM_DEBUG cout << "new: sz=" << sz << ", register " 
+		<< sz+SIZE_SPACE << "B ,"; 
+
+  if (MM_manager.register_allocation (sz + SIZE_SPACE) != MM_ERROR_NO_ERROR){
+    //must be MM_ERROR_INSUF_SPACE
+    switch(MM_manager.register_new) {
+      
+    case MM_ABORT_ON_MEMORY_EXCEEDED:
+      cerr << "MM error: limit ="<< MM_manager.memory_limit() <<"B. " 
+	   << "allocating " << sz << "B. " 
+	   << "limit exceeded by " 
+	   <<  MM_manager.memory_used() -  MM_manager.memory_limit()<<"B."
+	   << endl;
+      assert (0);		// core dump if debugging
+      exit (1);
+      break;
+      
+    case MM_WARN_ON_MEMORY_EXCEEDED:
+      cerr << "MM warning: limit="<<MM_manager.memory_limit() <<"B. " 
+	   << "allocating " << sz << "B. " 
+	   << " limit exceeded by " 
+	   <<  MM_manager.memory_used() -  MM_manager.memory_limit()<<"B."
+	   << endl;
+      break;
+      
+    case MM_IGNORE_MEMORY_EXCEEDED:
+      break;
+    }
+  }
+  
+  p = malloc(sz + SIZE_SPACE);
+  
+  if (!p) {
+    cerr << "new: out of memory while allocating " << sz << "B" << endl;
+    assert(0);
+    exit (1);
+  }
+  
+  *((size_t *) p) = sz;
+  
+  MM_DEBUG cout << "ptr=" << (void*) (((char *) p) + SIZE_SPACE) << endl;
+  
+  return ((char *) p) + SIZE_SPACE;
+}
+
+
+
+
+/* ---------------------------------------------------------------------- */
+void operator delete (void *ptr)  {
+  size_t sz;
+  void *p;
+  
+  MM_DEBUG cout << "delete: ptr=" << ptr << ","; 
+
+  if (!ptr) {
+    cerr << "MM warning: operator delete was given a NULL pointer\n";
+    cerr.flush();
+    //this may actually happen: for instance when calling a default
+    //destructor for something that was not allocated with new
+    //e.g. ofstream str(name) ---- ~ofstream() called ==> ptr=NULL
+    
+	//who wrote the above comment? -RW
+    assert(0); 
+    //exit(1);
+    return;
+  }
+  
+  assert(ptr);
+  p = ((char *)ptr) - SIZE_SPACE; // the base of memory
+  sz = *((size_t *)p);
+  
+  MM_DEBUG cout << "size=" << sz <<", free " << p << "B and deallocate " 
+		<< sz + SIZE_SPACE << endl;
+  
+  if(MM_manager.register_deallocation (sz + SIZE_SPACE) != MM_ERROR_NO_ERROR){
+    //must be MM_ERROR_UNDERFLOW
+    cerr << "delete: MM_manager.register_deallocation failed\n";
+    assert(0);
+    exit(1);
+  }
+
+  free(p);
+}
+
+
+
+
+/* ---------------------------------------------------------------------- */
+void operator delete[] (void *ptr) {
+  size_t sz;
+  void *p;
+  
+  MM_DEBUG cout << "delete[]: ptr=" << ptr << ","; 
+
+  if (!ptr) {
+    //can this hapen? -- it does: see delete above
+    cerr << "MM warning: operator delete [] was given a NULL pointer\n";
+    cerr.flush();
+    //assert(0);
+    //exit(1);
+    return;
+  }
+   assert(ptr);
+   p = ((char *)ptr) - SIZE_SPACE; // the base of memory
+   sz = *((size_t *)p);
+
+   MM_DEBUG cout << "size=" << sz <<", free " << p << "B and deallocate " 
+		 << sz + SIZE_SPACE << endl;
+   
+   if(MM_manager.register_deallocation (sz + SIZE_SPACE)!= MM_ERROR_NO_ERROR){
+     //must be MM_ERROR_UNDERFLOW
+     cerr << "delete[]: MM_manager.register_deallocation failed\n";
+     assert(0);
+     exit(1);
+   }
+   
+   free(p);
+}
+
+
+
+
+
+/* ************************************************************ */
+// Instantiate the actual memory manager, and allocate the 
+// its static data members
+MM_register MM_manager;
+int MM_register::instances = 0; // Number of instances. (init)
+// TPIE's "register memory requests" flag
+MM_mode MM_register::register_new = MM_IGNORE_MEMORY_EXCEEDED;
+//This causes constructors for static variables to fail
+//MM_mode MM_register::register_new = MM_ABORT_ON_MEMORY_EXCEEDED; 
+
+
+
+
+
+
+/* ************************************************************ */
+// The counter of mm_register_init instances.  It is implicity set to 0.
+unsigned int mm_register_init::count;
+
+// The constructor and destructor that ensure that the memory manager is
+// created exactly once, and destroyed when appropriate.
+mm_register_init::mm_register_init(void) {
+  if (count++ == 0) {
+    MM_manager.set_memory_limit(MM_DEFAULT_MM_SIZE);
+  }
+}
+
+mm_register_init::~mm_register_init(void) {
+  --count;
+}

Deleted: grass/trunk/lib/iostream/mm_utils.cc
===================================================================
--- grass/trunk/lib/iostream/mm_utils.cc	2011-09-29 23:35:42 UTC (rev 48561)
+++ grass/trunk/lib/iostream/mm_utils.cc	2011-09-29 23:36:57 UTC (rev 48562)
@@ -1,65 +0,0 @@
-/****************************************************************************
- * 
- *  MODULE:     iostream
- *
-
- *  COPYRIGHT (C) 2007 Laura Toma
- *   
- * 
-
- *  Iostream is a library that implements streams, external memory
- *  sorting on streams, and an external memory priority queue on
- *  streams. These are the fundamental components used in external
- *  memory algorithms.  
-
- * Credits: The library was developed by Laura Toma.  The kernel of
- * class STREAM is based on the similar class existent in the GPL TPIE
- * project developed at Duke University. The sorting and priority
- * queue have been developed by Laura Toma based on communications
- * with Rajiv Wickremesinghe. The library was developed as part of
- * porting Terraflow to GRASS in 2001.  PEARL upgrades in 2003 by
- * Rajiv Wickremesinghe as part of the Terracost project.
-
- * 
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
-
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- *  General Public License for more details.  *
- *  **************************************************************************/
-
-
-#include <sys/types.h>
-#include <ctype.h>
-#include <ostream>
-#include <iostream>
-using namespace std;
-#include <stdio.h>
-
-//#include <mm.h>
-#include <grass/iostream/mm.h>
-
-void 
-LOG_avail_memo() {
-  size_t sz_avail=0;
-  sz_avail = MM_manager.memory_available();
-  printf("available memory: %.2fMB\n", sz_avail/(float)(1<<20));
-}
-
-size_t
-getAvailableMemory() {
-  size_t fmem;
-  fmem = MM_manager.memory_available();
-  return fmem;
-}
-
-void 
-MEMORY_LOG(std::string str) {
-  printf("%s", str.c_str());
-  fflush(stdout);
-}

Copied: grass/trunk/lib/iostream/mm_utils.cpp (from rev 48560, grass/trunk/lib/iostream/mm_utils.cc)
===================================================================
--- grass/trunk/lib/iostream/mm_utils.cpp	                        (rev 0)
+++ grass/trunk/lib/iostream/mm_utils.cpp	2011-09-29 23:36:57 UTC (rev 48562)
@@ -0,0 +1,65 @@
+/****************************************************************************
+ * 
+ *  MODULE:     iostream
+ *
+
+ *  COPYRIGHT (C) 2007 Laura Toma
+ *   
+ * 
+
+ *  Iostream is a library that implements streams, external memory
+ *  sorting on streams, and an external memory priority queue on
+ *  streams. These are the fundamental components used in external
+ *  memory algorithms.  
+
+ * Credits: The library was developed by Laura Toma.  The kernel of
+ * class STREAM is based on the similar class existent in the GPL TPIE
+ * project developed at Duke University. The sorting and priority
+ * queue have been developed by Laura Toma based on communications
+ * with Rajiv Wickremesinghe. The library was developed as part of
+ * porting Terraflow to GRASS in 2001.  PEARL upgrades in 2003 by
+ * Rajiv Wickremesinghe as part of the Terracost project.
+
+ * 
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  General Public License for more details.  *
+ *  **************************************************************************/
+
+
+#include <sys/types.h>
+#include <ctype.h>
+#include <ostream>
+#include <iostream>
+using namespace std;
+#include <stdio.h>
+
+//#include <mm.h>
+#include <grass/iostream/mm.h>
+
+void 
+LOG_avail_memo() {
+  size_t sz_avail=0;
+  sz_avail = MM_manager.memory_available();
+  printf("available memory: %.2fMB\n", sz_avail/(float)(1<<20));
+}
+
+size_t
+getAvailableMemory() {
+  size_t fmem;
+  fmem = MM_manager.memory_available();
+  return fmem;
+}
+
+void 
+MEMORY_LOG(std::string str) {
+  printf("%s", str.c_str());
+  fflush(stdout);
+}

Deleted: grass/trunk/lib/iostream/rtimer.cc
===================================================================
--- grass/trunk/lib/iostream/rtimer.cc	2011-09-29 23:35:42 UTC (rev 48561)
+++ grass/trunk/lib/iostream/rtimer.cc	2011-09-29 23:36:57 UTC (rev 48562)
@@ -1,64 +0,0 @@
-/****************************************************************************
- * 
- *  MODULE:     iostream
- *
-
- *  COPYRIGHT (C) 2007 Laura Toma
- *   
- * 
-
- *  Iostream is a library that implements streams, external memory
- *  sorting on streams, and an external memory priority queue on
- *  streams. These are the fundamental components used in external
- *  memory algorithms.  
-
- * Credits: The library was developed by Laura Toma.  The kernel of
- * class STREAM is based on the similar class existent in the GPL TPIE
- * project developed at Duke University. The sorting and priority
- * queue have been developed by Laura Toma based on communications
- * with Rajiv Wickremesinghe. The library was developed as part of
- * porting Terraflow to GRASS in 2001.  PEARL upgrades in 2003 by
- * Rajiv Wickremesinghe as part of the Terracost project.
-
- * 
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
-
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- *  General Public License for more details.  *
- *  **************************************************************************/
-
-
-#include <sys/time.h>
-#include <stdio.h>
-#include <string.h>
-#include <strings.h>
-
-//#include <rtimer.h>
-#include <grass/iostream/rtimer.h>
-
-char *
-rt_sprint_safe(char *buf, Rtimer rt) {
-  if(rt_w_useconds(rt) == 0) {
-	sprintf(buf, "[%4.2fu (%.0f%%) %4.2fs (%.0f%%) %4.2f %.1f%%]",
-			0.0, 0.0, 0.0, 0.0, 0.0, 0.0);
-  } else {
-	sprintf(buf, "[%4.2fu (%.0f%%) %4.2fs (%.0f%%) %4.2f %.1f%%]",
-			rt_u_useconds(rt)/1000000,
-			100.0*rt_u_useconds(rt)/rt_w_useconds(rt),
-			rt_s_useconds(rt)/1000000,
-			100.0*rt_s_useconds(rt)/rt_w_useconds(rt),
-			rt_w_useconds(rt)/1000000,
-			100.0*(rt_u_useconds(rt)+rt_s_useconds(rt)) / rt_w_useconds(rt));
-  }
-  return buf;
-}
-
-
-
-

Copied: grass/trunk/lib/iostream/rtimer.cpp (from rev 48560, grass/trunk/lib/iostream/rtimer.cc)
===================================================================
--- grass/trunk/lib/iostream/rtimer.cpp	                        (rev 0)
+++ grass/trunk/lib/iostream/rtimer.cpp	2011-09-29 23:36:57 UTC (rev 48562)
@@ -0,0 +1,64 @@
+/****************************************************************************
+ * 
+ *  MODULE:     iostream
+ *
+
+ *  COPYRIGHT (C) 2007 Laura Toma
+ *   
+ * 
+
+ *  Iostream is a library that implements streams, external memory
+ *  sorting on streams, and an external memory priority queue on
+ *  streams. These are the fundamental components used in external
+ *  memory algorithms.  
+
+ * Credits: The library was developed by Laura Toma.  The kernel of
+ * class STREAM is based on the similar class existent in the GPL TPIE
+ * project developed at Duke University. The sorting and priority
+ * queue have been developed by Laura Toma based on communications
+ * with Rajiv Wickremesinghe. The library was developed as part of
+ * porting Terraflow to GRASS in 2001.  PEARL upgrades in 2003 by
+ * Rajiv Wickremesinghe as part of the Terracost project.
+
+ * 
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  General Public License for more details.  *
+ *  **************************************************************************/
+
+
+#include <sys/time.h>
+#include <stdio.h>
+#include <string.h>
+#include <strings.h>
+
+//#include <rtimer.h>
+#include <grass/iostream/rtimer.h>
+
+char *
+rt_sprint_safe(char *buf, Rtimer rt) {
+  if(rt_w_useconds(rt) == 0) {
+	sprintf(buf, "[%4.2fu (%.0f%%) %4.2fs (%.0f%%) %4.2f %.1f%%]",
+			0.0, 0.0, 0.0, 0.0, 0.0, 0.0);
+  } else {
+	sprintf(buf, "[%4.2fu (%.0f%%) %4.2fs (%.0f%%) %4.2f %.1f%%]",
+			rt_u_useconds(rt)/1000000,
+			100.0*rt_u_useconds(rt)/rt_w_useconds(rt),
+			rt_s_useconds(rt)/1000000,
+			100.0*rt_s_useconds(rt)/rt_w_useconds(rt),
+			rt_w_useconds(rt)/1000000,
+			100.0*(rt_u_useconds(rt)+rt_s_useconds(rt)) / rt_w_useconds(rt));
+  }
+  return buf;
+}
+
+
+
+

Deleted: grass/trunk/raster/r.terraflow/ccforest.cc
===================================================================
--- grass/trunk/raster/r.terraflow/ccforest.cc	2011-09-29 23:35:42 UTC (rev 48561)
+++ grass/trunk/raster/r.terraflow/ccforest.cc	2011-09-29 23:36:57 UTC (rev 48562)
@@ -1,342 +0,0 @@
-/****************************************************************************
- * 
- *  MODULE:	r.terraflow
- *
- *  COPYRIGHT (C) 2007 Laura Toma
- *   
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *****************************************************************************/
-
-#include "ccforest.h"
-#include "sortutils.h"
-#include "streamutils.h"
-
-
-
-
-
-#if(0)
-/* ---------------------------------------------------------------------- */
-static int valueCmp(const keyvalue<long> &a, const keyvalue<long> &b) {
-  if(a.dst() < b.dst()) return -1;
-  if(a.dst() > b.dst()) return 1;
-
-  if(a.src() < b.src()) return -1;
-  if(a.src() > b.src()) return 1;
-
-  return 0;
-}
-
-
-
-/* ---------------------------------------------------------------------- */
-
-static int valueCmp(const keyvalue<int> &a, const keyvalue<int> &b) {
-  if(a.dst() < b.dst()) return -1;
-  if(a.dst() > b.dst()) return 1;
-
-  if(a.src() < b.src()) return -1;
-  if(a.src() > b.src()) return 1;
-
-  return 0;
-}
-#endif
-
-
-
-
-
-/* ---------------------------------------------------------------------- */
-
-template<class T>
-ccforest<T>::ccforest() {
-  edgeStream = new AMI_STREAM<ccedge>();
-  rootStream = new AMI_STREAM<cckeyvalue>();
-  superTree = NULL;
-  rootCycles = 0;
-  foundAllRoots = 0;
-  savedRootValid = 0;
-}
-
-/* ---------------------------------------------------------------------- */
-
-template<class T>
-ccforest<T>::~ccforest() {
-  delete edgeStream;
-  delete rootStream;
-  if(superTree) delete superTree;
-}
-
-/* ---------------------------------------------------------------------- */
-
-template<class T>
-int ccforest<T>::size() {
-  size_t streamLength = edgeStream->stream_len();
-  return streamLength;
-}
-
-/* ---------------------------------------------------------------------- */
-
-
-template<class T> 
-void ccforest<T>::removeDuplicates(T src, T parent,
-				   EMPQueueAdaptive<cckeyvalue,T> &pq) {
-  cckeyvalue kv;
-  
-  while(pq.min(kv) && (src == kv.getPriority())) {
-	pq.extract_min(kv);
-	if(kv.getValue() != parent) { /* cycles... */
-	  rootCycles++;
-	  if(parent < kv.getValue()) {
-		superTree->insert(parent, kv.getValue());
-	  } else {
-		superTree->insert(kv.getValue(), parent);
-	  }
-	  DEBUG_CCFOREST cerr << "ROOT CYCLE DETECTED! " << src << " (" << 
-		parent << "," << kv.getValue() << ")" << endl;
-	}
-  }
-}
-
-/* ---------------------------------------------------------------------- */
-
-/* needs to be re-entrant */
-template<class T> 
-void ccforest<T>::findAllRoots(int depth) {
-  if(foundAllRoots) return;
-  foundAllRoots = 1;
-  Rtimer rt;
-  rt_start(rt);
-
-  if(depth > 5) {
-	cerr << "WARNING: excessive recursion in ccforest (ignored)" << endl;
-  }
-
-  int explicitRootCount = 0;
-  assert(!superTree);
-  superTree = new ccforest<T>();
-
-  DEBUG_CCFOREST *stats << "sort edgeStream (by cclabel)): ";
-  keyCmpKeyvalueType<T> fo;
-  sort(&edgeStream, fo); /* XXX -changed this to use a cmp obj  */
-
-  /* time forward processing */
-  EMPQueueAdaptive<cckeyvalue,T> *pq =
-	new EMPQueueAdaptive<cckeyvalue,T>();	/* parent queue */
-
-  size_t streamLength = edgeStream->stream_len();
-  T prevSrc = T(-1);
-  T parent = T(-1);
-  ccedge prevEdge;
-  for(unsigned int i=0; i<streamLength; i++) {
-	ccedge *e;
-	AMI_err ae = edgeStream->read_item(&e);
-	assert(ae == AMI_ERROR_NO_ERROR);
-
-#if(0)
-	DEBUG_CCFOREST *stats << "------------------------------" << endl;
-	DEBUG_CCFOREST *stats << "processing edge " << *e << endl;
-	DEBUG_CCFOREST pq->print();
-#endif
-
-	if(*e == prevEdge) {
-	  DEBUG_CCFOREST *stats << "\tduplicate " << *e << " removed\n";
-	  continue; /* already have this done */
-	}
-	prevEdge = *e;
-
-	DEBUG_CCFOREST *stats << "processing edge " << *e << endl;
-
-	/* find root (assign parent) */
-	if(e->src() != prevSrc) {
-	  prevSrc = e->src();
-	  cckeyvalue kv;
-	  /* check if we have a key we don't use. */
-	  while(pq->min(kv) && (kv.getPriority() < e->src())) {
-		pq->extract_min(kv);
-		assert(kv.src() >= kv.dst());
-		removeDuplicates(kv.src(), kv.dst(), *pq);
-		ae = rootStream->write_item(kv); /* save root */
-		assert(ae == AMI_ERROR_NO_ERROR);	
-	  }
-	  /* try to find our root */
-	  if(pq->min(kv) && ((e->src() == kv.getPriority()))) {
-		pq->extract_min(kv);
-		parent = kv.getValue();
-		removeDuplicates(e->src(), parent, *pq);
-	  } else {
-		parent = e->src();		/* we are root */
-		explicitRootCount++;
-		/* technically, we could skip this part. the lookup function
-           automatically assumes that values without parents are roots */
-	  }
-
-	  /* save result */
-	  cckeyvalue kroot(e->src(), parent);
-	  assert(kroot.src() >= kroot.dst());
-	  ae = rootStream->write_item(kroot);
-	  assert(ae == AMI_ERROR_NO_ERROR);
-	}
-#ifndef NDEBUG
-	cckeyvalue kv2;
-	assert(pq->is_empty() || (pq->min(kv2) && kv2.getPriority() > e->src()));
-#endif
-
-	/* insert */
-	cckeyvalue kv(e->dst(), parent);
-	assert(kv.src() >= kv.dst());
-	pq->insert(kv);
-
-	/* cout << "identified: " << kroot << endl; */
-  }
-
-  /* drain the priority queue */
-  DEBUG_CCFOREST *stats << "draining priority queue" << endl;
-  while (!pq->is_empty()) {
-	cckeyvalue kv;
-	pq->extract_min(kv);
-	assert(kv.src() >= kv.dst());
-	DEBUG_CCFOREST *stats << "processing edge " << kv << endl;
-
-	removeDuplicates(kv.src(), kv.dst(), *pq);
-	AMI_err ae = rootStream->write_item(kv);
-	assert(ae == AMI_ERROR_NO_ERROR);
-  }
-  delete pq;
-
-  /* note that rootStream is naturally ordered by src */
-
-  if(superTree->size()) {
-	DEBUG_CCFOREST *stats << "resolving cycles..." << endl;
-	/* printStream(rootStream); */
-	DEBUG_CCFOREST *stats << "sort rootStream: ";
-
-	AMI_STREAM<cckeyvalue> *sortedRootStream; 
-	dstCmpKeyvalueType<T> dstfo;
-	sortedRootStream = sort(rootStream, dstfo); 
-	/* XXX replaced this to use a cmp object -- laura
-	   AMI_STREAM<cckeyvalue>*sortedRootStream=new AMI_STREAM<cckeyvalue>();
-	   AMI_err ae = AMI_sort(rootStream, sortedRootStream, valueCmp); 
-	   assert(ae == AMI_ERROR_NO_ERROR);
-	*/
-	delete rootStream;
-
-	cckeyvalue *kv;
-	T parent;
-	AMI_err ae;
-	
-	AMI_STREAM<cckeyvalue>* relabeledRootStream
-	  = new AMI_STREAM<cckeyvalue>();
-	ae = sortedRootStream->seek(0);
-	superTree->findAllRoots(depth+1);
-	while((ae = sortedRootStream->read_item(&kv)) == AMI_ERROR_NO_ERROR) {
-	  parent = superTree->findNextRoot(kv->dst());
-	  ae = relabeledRootStream->write_item(cckeyvalue(kv->src(), parent));
-	  assert(ae == AMI_ERROR_NO_ERROR);
-	}
-	delete sortedRootStream;
-
-	DEBUG_CCFOREST *stats << "sort relabeledRootStream: ";
-	rootStream = sort(relabeledRootStream, fo);
-	/* laura: changed  this
-	   rootStream = new AMI_STREAM<cckeyvalue>();
-	   ae = AMI_sort(relabeledRootStream, rootStream);
-	   assert(ae == AMI_ERROR_NO_ERROR);
-	*/
-	delete relabeledRootStream;
-
-	DEBUG_CCFOREST *stats << "resolving cycles... done." << endl;
-  }
-  rootStream->seek(0);
-
-  DEBUG_CCFOREST *stats << "Rootstream length="
-					  << rootStream->stream_len() << endl;
-  DEBUG_CCFOREST printStream(*stats, rootStream);
-  DEBUG_CCFOREST *stats << "Explicit root count=" << explicitRootCount << endl;
-
-  rt_stop(rt);
-  stats->recordTime("ccforest::findAllRoots",  (long int)rt_seconds(rt));
-}
-
-
-/* ---------------------------------------------------------------------- */
-
-template<class T>
-void 
-ccforest<T>::insert(const T& i, const T& j) {
-  ccedge e(i,j);
-  /* assert(i<j);  not required, as long as it's consistent. */
-  assert(i!=j);					/* meaningless */
-  AMI_err ae = edgeStream->write_item(e);
-  assert(ae == AMI_ERROR_NO_ERROR);
-  /* cout << "INST " << i << ", " << j << endl; */
-}
-
-/* ---------------------------------------------------------------------- */
-
-template<class T>
-T 
-ccforest<T>::findNextRoot(const T& i) {
-  AMI_err ae;
-  cckeyvalue *kroot;
-  T retRoot;
-  
-  findAllRoots();   /* find all the roots if not done */
-  
-  DEBUG_CCFOREST *stats << "looking for " << i << endl;
-  if(!savedRootValid || savedRoot.src() < i) { /* need to read more */
-    ae = rootStream->read_item(&kroot);
-	while(ae == AMI_ERROR_NO_ERROR && kroot->src() < i) {
-	  ae = rootStream->read_item(&kroot);
-	}
-	if(ae == AMI_ERROR_NO_ERROR) {
-	  savedRoot = *kroot;
-	  savedRootValid = 1;
-	} else {
-	  savedRootValid = -1;		/* to avoid reading uselessly */
-	}
-  }
-  
-  if(savedRootValid==1 && savedRoot.src() == i) { /* check savedRoot */
-    retRoot = savedRoot.dst();
-    DEBUG_CCFOREST *stats << "using saved/found value" << endl;
-  } else {
-    DEBUG_CCFOREST *stats << "not found" << endl;
-    retRoot = i;
-  }
-  DEBUG_CCFOREST *stats << "lookup for " << i << " gives " << retRoot
-		      << "; saved = " << savedRoot << endl;
-  return retRoot;
-}
-
-/* ---------------------------------------------------------------------- */
-
-template<class T>
-void
-ccforest<T>::printRootStream() {
-  findAllRoots();  /* find all the roots if not done */
-  printStream(cout, rootStream);
-}
-
-
-template<class T> void
-ccforest<T>::printEdgeStream() {
-  printStream(cout, edgeStream);
-}
-
-/* ---------------------------------------------------------------------- */
-
-template class keyvalue<cclabel_type>;
-template class  keyCmpKeyvalueType<cclabel_type>;
-template class ccforest<cclabel_type>;
-
-

Copied: grass/trunk/raster/r.terraflow/ccforest.cpp (from rev 48560, grass/trunk/raster/r.terraflow/ccforest.cc)
===================================================================
--- grass/trunk/raster/r.terraflow/ccforest.cpp	                        (rev 0)
+++ grass/trunk/raster/r.terraflow/ccforest.cpp	2011-09-29 23:36:57 UTC (rev 48562)
@@ -0,0 +1,342 @@
+/****************************************************************************
+ * 
+ *  MODULE:	r.terraflow
+ *
+ *  COPYRIGHT (C) 2007 Laura Toma
+ *   
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *****************************************************************************/
+
+#include "ccforest.h"
+#include "sortutils.h"
+#include "streamutils.h"
+
+
+
+
+
+#if(0)
+/* ---------------------------------------------------------------------- */
+static int valueCmp(const keyvalue<long> &a, const keyvalue<long> &b) {
+  if(a.dst() < b.dst()) return -1;
+  if(a.dst() > b.dst()) return 1;
+
+  if(a.src() < b.src()) return -1;
+  if(a.src() > b.src()) return 1;
+
+  return 0;
+}
+
+
+
+/* ---------------------------------------------------------------------- */
+
+static int valueCmp(const keyvalue<int> &a, const keyvalue<int> &b) {
+  if(a.dst() < b.dst()) return -1;
+  if(a.dst() > b.dst()) return 1;
+
+  if(a.src() < b.src()) return -1;
+  if(a.src() > b.src()) return 1;
+
+  return 0;
+}
+#endif
+
+
+
+
+
+/* ---------------------------------------------------------------------- */
+
+template<class T>
+ccforest<T>::ccforest() {
+  edgeStream = new AMI_STREAM<ccedge>();
+  rootStream = new AMI_STREAM<cckeyvalue>();
+  superTree = NULL;
+  rootCycles = 0;
+  foundAllRoots = 0;
+  savedRootValid = 0;
+}
+
+/* ---------------------------------------------------------------------- */
+
+template<class T>
+ccforest<T>::~ccforest() {
+  delete edgeStream;
+  delete rootStream;
+  if(superTree) delete superTree;
+}
+
+/* ---------------------------------------------------------------------- */
+
+template<class T>
+int ccforest<T>::size() {
+  size_t streamLength = edgeStream->stream_len();
+  return streamLength;
+}
+
+/* ---------------------------------------------------------------------- */
+
+
+template<class T> 
+void ccforest<T>::removeDuplicates(T src, T parent,
+				   EMPQueueAdaptive<cckeyvalue,T> &pq) {
+  cckeyvalue kv;
+  
+  while(pq.min(kv) && (src == kv.getPriority())) {
+	pq.extract_min(kv);
+	if(kv.getValue() != parent) { /* cycles... */
+	  rootCycles++;
+	  if(parent < kv.getValue()) {
+		superTree->insert(parent, kv.getValue());
+	  } else {
+		superTree->insert(kv.getValue(), parent);
+	  }
+	  DEBUG_CCFOREST cerr << "ROOT CYCLE DETECTED! " << src << " (" << 
+		parent << "," << kv.getValue() << ")" << endl;
+	}
+  }
+}
+
+/* ---------------------------------------------------------------------- */
+
+/* needs to be re-entrant */
+template<class T> 
+void ccforest<T>::findAllRoots(int depth) {
+  if(foundAllRoots) return;
+  foundAllRoots = 1;
+  Rtimer rt;
+  rt_start(rt);
+
+  if(depth > 5) {
+	cerr << "WARNING: excessive recursion in ccforest (ignored)" << endl;
+  }
+
+  int explicitRootCount = 0;
+  assert(!superTree);
+  superTree = new ccforest<T>();
+
+  DEBUG_CCFOREST *stats << "sort edgeStream (by cclabel)): ";
+  keyCmpKeyvalueType<T> fo;
+  sort(&edgeStream, fo); /* XXX -changed this to use a cmp obj  */
+
+  /* time forward processing */
+  EMPQueueAdaptive<cckeyvalue,T> *pq =
+	new EMPQueueAdaptive<cckeyvalue,T>();	/* parent queue */
+
+  size_t streamLength = edgeStream->stream_len();
+  T prevSrc = T(-1);
+  T parent = T(-1);
+  ccedge prevEdge;
+  for(unsigned int i=0; i<streamLength; i++) {
+	ccedge *e;
+	AMI_err ae = edgeStream->read_item(&e);
+	assert(ae == AMI_ERROR_NO_ERROR);
+
+#if(0)
+	DEBUG_CCFOREST *stats << "------------------------------" << endl;
+	DEBUG_CCFOREST *stats << "processing edge " << *e << endl;
+	DEBUG_CCFOREST pq->print();
+#endif
+
+	if(*e == prevEdge) {
+	  DEBUG_CCFOREST *stats << "\tduplicate " << *e << " removed\n";
+	  continue; /* already have this done */
+	}
+	prevEdge = *e;
+
+	DEBUG_CCFOREST *stats << "processing edge " << *e << endl;
+
+	/* find root (assign parent) */
+	if(e->src() != prevSrc) {
+	  prevSrc = e->src();
+	  cckeyvalue kv;
+	  /* check if we have a key we don't use. */
+	  while(pq->min(kv) && (kv.getPriority() < e->src())) {
+		pq->extract_min(kv);
+		assert(kv.src() >= kv.dst());
+		removeDuplicates(kv.src(), kv.dst(), *pq);
+		ae = rootStream->write_item(kv); /* save root */
+		assert(ae == AMI_ERROR_NO_ERROR);	
+	  }
+	  /* try to find our root */
+	  if(pq->min(kv) && ((e->src() == kv.getPriority()))) {
+		pq->extract_min(kv);
+		parent = kv.getValue();
+		removeDuplicates(e->src(), parent, *pq);
+	  } else {
+		parent = e->src();		/* we are root */
+		explicitRootCount++;
+		/* technically, we could skip this part. the lookup function
+           automatically assumes that values without parents are roots */
+	  }
+
+	  /* save result */
+	  cckeyvalue kroot(e->src(), parent);
+	  assert(kroot.src() >= kroot.dst());
+	  ae = rootStream->write_item(kroot);
+	  assert(ae == AMI_ERROR_NO_ERROR);
+	}
+#ifndef NDEBUG
+	cckeyvalue kv2;
+	assert(pq->is_empty() || (pq->min(kv2) && kv2.getPriority() > e->src()));
+#endif
+
+	/* insert */
+	cckeyvalue kv(e->dst(), parent);
+	assert(kv.src() >= kv.dst());
+	pq->insert(kv);
+
+	/* cout << "identified: " << kroot << endl; */
+  }
+
+  /* drain the priority queue */
+  DEBUG_CCFOREST *stats << "draining priority queue" << endl;
+  while (!pq->is_empty()) {
+	cckeyvalue kv;
+	pq->extract_min(kv);
+	assert(kv.src() >= kv.dst());
+	DEBUG_CCFOREST *stats << "processing edge " << kv << endl;
+
+	removeDuplicates(kv.src(), kv.dst(), *pq);
+	AMI_err ae = rootStream->write_item(kv);
+	assert(ae == AMI_ERROR_NO_ERROR);
+  }
+  delete pq;
+
+  /* note that rootStream is naturally ordered by src */
+
+  if(superTree->size()) {
+	DEBUG_CCFOREST *stats << "resolving cycles..." << endl;
+	/* printStream(rootStream); */
+	DEBUG_CCFOREST *stats << "sort rootStream: ";
+
+	AMI_STREAM<cckeyvalue> *sortedRootStream; 
+	dstCmpKeyvalueType<T> dstfo;
+	sortedRootStream = sort(rootStream, dstfo); 
+	/* XXX replaced this to use a cmp object -- laura
+	   AMI_STREAM<cckeyvalue>*sortedRootStream=new AMI_STREAM<cckeyvalue>();
+	   AMI_err ae = AMI_sort(rootStream, sortedRootStream, valueCmp); 
+	   assert(ae == AMI_ERROR_NO_ERROR);
+	*/
+	delete rootStream;
+
+	cckeyvalue *kv;
+	T parent;
+	AMI_err ae;
+	
+	AMI_STREAM<cckeyvalue>* relabeledRootStream
+	  = new AMI_STREAM<cckeyvalue>();
+	ae = sortedRootStream->seek(0);
+	superTree->findAllRoots(depth+1);
+	while((ae = sortedRootStream->read_item(&kv)) == AMI_ERROR_NO_ERROR) {
+	  parent = superTree->findNextRoot(kv->dst());
+	  ae = relabeledRootStream->write_item(cckeyvalue(kv->src(), parent));
+	  assert(ae == AMI_ERROR_NO_ERROR);
+	}
+	delete sortedRootStream;
+
+	DEBUG_CCFOREST *stats << "sort relabeledRootStream: ";
+	rootStream = sort(relabeledRootStream, fo);
+	/* laura: changed  this
+	   rootStream = new AMI_STREAM<cckeyvalue>();
+	   ae = AMI_sort(relabeledRootStream, rootStream);
+	   assert(ae == AMI_ERROR_NO_ERROR);
+	*/
+	delete relabeledRootStream;
+
+	DEBUG_CCFOREST *stats << "resolving cycles... done." << endl;
+  }
+  rootStream->seek(0);
+
+  DEBUG_CCFOREST *stats << "Rootstream length="
+					  << rootStream->stream_len() << endl;
+  DEBUG_CCFOREST printStream(*stats, rootStream);
+  DEBUG_CCFOREST *stats << "Explicit root count=" << explicitRootCount << endl;
+
+  rt_stop(rt);
+  stats->recordTime("ccforest::findAllRoots",  (long int)rt_seconds(rt));
+}
+
+
+/* ---------------------------------------------------------------------- */
+
+template<class T>
+void 
+ccforest<T>::insert(const T& i, const T& j) {
+  ccedge e(i,j);
+  /* assert(i<j);  not required, as long as it's consistent. */
+  assert(i!=j);					/* meaningless */
+  AMI_err ae = edgeStream->write_item(e);
+  assert(ae == AMI_ERROR_NO_ERROR);
+  /* cout << "INST " << i << ", " << j << endl; */
+}
+
+/* ---------------------------------------------------------------------- */
+
+template<class T>
+T 
+ccforest<T>::findNextRoot(const T& i) {
+  AMI_err ae;
+  cckeyvalue *kroot;
+  T retRoot;
+  
+  findAllRoots();   /* find all the roots if not done */
+  
+  DEBUG_CCFOREST *stats << "looking for " << i << endl;
+  if(!savedRootValid || savedRoot.src() < i) { /* need to read more */
+    ae = rootStream->read_item(&kroot);
+	while(ae == AMI_ERROR_NO_ERROR && kroot->src() < i) {
+	  ae = rootStream->read_item(&kroot);
+	}
+	if(ae == AMI_ERROR_NO_ERROR) {
+	  savedRoot = *kroot;
+	  savedRootValid = 1;
+	} else {
+	  savedRootValid = -1;		/* to avoid reading uselessly */
+	}
+  }
+  
+  if(savedRootValid==1 && savedRoot.src() == i) { /* check savedRoot */
+    retRoot = savedRoot.dst();
+    DEBUG_CCFOREST *stats << "using saved/found value" << endl;
+  } else {
+    DEBUG_CCFOREST *stats << "not found" << endl;
+    retRoot = i;
+  }
+  DEBUG_CCFOREST *stats << "lookup for " << i << " gives " << retRoot
+		      << "; saved = " << savedRoot << endl;
+  return retRoot;
+}
+
+/* ---------------------------------------------------------------------- */
+
+template<class T>
+void
+ccforest<T>::printRootStream() {
+  findAllRoots();  /* find all the roots if not done */
+  printStream(cout, rootStream);
+}
+
+
+template<class T> void
+ccforest<T>::printEdgeStream() {
+  printStream(cout, edgeStream);
+}
+
+/* ---------------------------------------------------------------------- */
+
+template class keyvalue<cclabel_type>;
+template class  keyCmpKeyvalueType<cclabel_type>;
+template class ccforest<cclabel_type>;
+
+

Deleted: grass/trunk/raster/r.terraflow/common.cc
===================================================================
--- grass/trunk/raster/r.terraflow/common.cc	2011-09-29 23:35:42 UTC (rev 48561)
+++ grass/trunk/raster/r.terraflow/common.cc	2011-09-29 23:36:57 UTC (rev 48562)
@@ -1,145 +0,0 @@
-/****************************************************************************
- * 
- *  MODULE:	r.terraflow
- *
- *  COPYRIGHT (C) 2007 Laura Toma
- *   
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *****************************************************************************/
-
-
-#include <sys/types.h>
-#ifdef USE_LARGEMEM
-#include <sys/mman.h>
-#endif
-#include <ctype.h>
-
-#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1)
-#include <ostream>
-#else
-#include <ostream.h>
-#endif
-
-#include <iostream>
-using namespace std;
-
-#include "common.h"
-
-
-/* globals */
-
-statsRecorder *stats = NULL;
-userOptions *opt = NULL;
-struct  Cell_head *region = NULL; 
-dimension_type nrows = 0, ncols = 0;
-
-
-size_t
-parse_number(const char *s) {
-  size_t n, mult=1;
-  int len = strlen(s);
-  if(isalpha(s[len-1])) {
-    switch(s[len-1]) {
-    case 'M':
-      mult = 1 << 20;
-      break;
-    case 'K':
-      mult = 1 << 10;
-      break;
-    default:
-      cerr << "bad number format: " << s << endl;
-      exit(-1);
-      break;
-    }
-    /* s[len-1] = '\0'; not needed, as it will stop at first invalid char */
-  }
-  n = atol(s);
-  return n * mult;
-}
-
-
-
-
-/* ---------------------------------------------------------------------- */
-/* is anybody using this?? DELETE ! */
-
-#ifdef USE_LARGEMEM
-
-void *LargeMemory::ptr[LM_HIST];
-size_t LargeMemory::len[LM_HIST];
-int LargeMemory::next = 0;
-
-#ifndef MAP_ANON
-#define MAP_ANON 0
-#endif
-
-#ifdef __alpha
-#undef MAP_FAILED
-#define MAP_FAILED (caddr_t)-1L
-#endif
-
-
-void *
-LargeMemory::alloc(size_t leng) {
-  assert(next < LM_HIST);
-  void *p = mmap(0, leng, PROT_READ|PROT_WRITE, MAP_ANON, -1, 0);
-  if(p == MAP_FAILED) {
-	perror("mmap");
-	exit(1);
-  }
-  len[next] = leng;
-  ptr[next] = p;
-  next++;
-  if(stats) {
-	char buf[BUFSIZ], buf2[32];
-	sprintf(buf, "allocated large memory: %s 0x%lX", 
-			formatNumber(buf2, leng), (unsigned long)p);
-	stats->comment(buf);
-  }
-  return p;
-}
-
-void
-LargeMemory::free(void *p) {
-  int z;
-  int i;
-  for(i=next-1; i>=0; i--) {
-	if(ptr[i] == p) break;
-  }
-  assert(i<next && i>=0); /* must have been allocated before */
-  
-#if (defined sun && defined sparc)
-  z = munmap((caddr_t)p, len[i]);
-#else
-  z = munmap(p, len[i]);
-#endif
-  if(z < 0) {
-	perror("munmap");
-  }
-
-  if(stats) {
-	char buf[BUFSIZ], buf2[32];
-	sprintf(buf, "freed large memory: %s 0x%lX", 
-			formatNumber(buf2, len[i]), (unsigned long)p);
-	stats->comment(buf);
-  }
-
-  next--;
-  if(next) {
-	ptr[i] = ptr[next];
-	len[i] = len[next];
-  }
-}
-
-#endif /*  USE_LARGEMEM */
-
-

Copied: grass/trunk/raster/r.terraflow/common.cpp (from rev 48560, grass/trunk/raster/r.terraflow/common.cc)
===================================================================
--- grass/trunk/raster/r.terraflow/common.cpp	                        (rev 0)
+++ grass/trunk/raster/r.terraflow/common.cpp	2011-09-29 23:36:57 UTC (rev 48562)
@@ -0,0 +1,145 @@
+/****************************************************************************
+ * 
+ *  MODULE:	r.terraflow
+ *
+ *  COPYRIGHT (C) 2007 Laura Toma
+ *   
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *****************************************************************************/
+
+
+#include <sys/types.h>
+#ifdef USE_LARGEMEM
+#include <sys/mman.h>
+#endif
+#include <ctype.h>
+
+#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1)
+#include <ostream>
+#else
+#include <ostream.h>
+#endif
+
+#include <iostream>
+using namespace std;
+
+#include "common.h"
+
+
+/* globals */
+
+statsRecorder *stats = NULL;
+userOptions *opt = NULL;
+struct  Cell_head *region = NULL; 
+dimension_type nrows = 0, ncols = 0;
+
+
+size_t
+parse_number(const char *s) {
+  size_t n, mult=1;
+  int len = strlen(s);
+  if(isalpha(s[len-1])) {
+    switch(s[len-1]) {
+    case 'M':
+      mult = 1 << 20;
+      break;
+    case 'K':
+      mult = 1 << 10;
+      break;
+    default:
+      cerr << "bad number format: " << s << endl;
+      exit(-1);
+      break;
+    }
+    /* s[len-1] = '\0'; not needed, as it will stop at first invalid char */
+  }
+  n = atol(s);
+  return n * mult;
+}
+
+
+
+
+/* ---------------------------------------------------------------------- */
+/* is anybody using this?? DELETE ! */
+
+#ifdef USE_LARGEMEM
+
+void *LargeMemory::ptr[LM_HIST];
+size_t LargeMemory::len[LM_HIST];
+int LargeMemory::next = 0;
+
+#ifndef MAP_ANON
+#define MAP_ANON 0
+#endif
+
+#ifdef __alpha
+#undef MAP_FAILED
+#define MAP_FAILED (caddr_t)-1L
+#endif
+
+
+void *
+LargeMemory::alloc(size_t leng) {
+  assert(next < LM_HIST);
+  void *p = mmap(0, leng, PROT_READ|PROT_WRITE, MAP_ANON, -1, 0);
+  if(p == MAP_FAILED) {
+	perror("mmap");
+	exit(1);
+  }
+  len[next] = leng;
+  ptr[next] = p;
+  next++;
+  if(stats) {
+	char buf[BUFSIZ], buf2[32];
+	sprintf(buf, "allocated large memory: %s 0x%lX", 
+			formatNumber(buf2, leng), (unsigned long)p);
+	stats->comment(buf);
+  }
+  return p;
+}
+
+void
+LargeMemory::free(void *p) {
+  int z;
+  int i;
+  for(i=next-1; i>=0; i--) {
+	if(ptr[i] == p) break;
+  }
+  assert(i<next && i>=0); /* must have been allocated before */
+  
+#if (defined sun && defined sparc)
+  z = munmap((caddr_t)p, len[i]);
+#else
+  z = munmap(p, len[i]);
+#endif
+  if(z < 0) {
+	perror("munmap");
+  }
+
+  if(stats) {
+	char buf[BUFSIZ], buf2[32];
+	sprintf(buf, "freed large memory: %s 0x%lX", 
+			formatNumber(buf2, len[i]), (unsigned long)p);
+	stats->comment(buf);
+  }
+
+  next--;
+  if(next) {
+	ptr[i] = ptr[next];
+	len[i] = len[next];
+  }
+}
+
+#endif /*  USE_LARGEMEM */
+
+

Deleted: grass/trunk/raster/r.terraflow/direction.cc
===================================================================
--- grass/trunk/raster/r.terraflow/direction.cc	2011-09-29 23:35:42 UTC (rev 48561)
+++ grass/trunk/raster/r.terraflow/direction.cc	2011-09-29 23:36:57 UTC (rev 48562)
@@ -1,301 +0,0 @@
-/****************************************************************************
- * 
- *  MODULE:	r.terraflow
- *
- *  COPYRIGHT (C) 2007 Laura Toma
- *   
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *****************************************************************************/
-
-
-#include "direction.h"
-#include "nodata.h"
-#include "common.h" /*for global opt->d8 flag*/
-
-#define TF_ROOTTWO 1.4142135623
-
-/* directions:
-   32 64 128
-   16 *   1
-   8  4   2
-*/
-direction_type 
-encodeDirection(const genericWindow<elevation_type>& elevwin,
-				const dimension_type nrows, const dimension_type ncols,
-				dimension_type row, 
-				dimension_type col) {
-  
-  /*check global opt flag and call appropriate model*/
-	if(opt->d8){
-    return encodeDirectionSFD(elevwin, nrows, ncols, row, col);
-	}
-  return encodeDirectionMFD(elevwin, nrows, ncols, row, col);
-}
-
-/***************************************************************/
-/* returns the direction corresponding to the window using MFD */
-direction_type 
-encodeDirectionMFD(const genericWindow<elevation_type>& elevwin,
-				const dimension_type nrows, const dimension_type ncols,
-				dimension_type row, 
-				dimension_type col) {
-  
-  direction_type dir = DIRECTION_UNDEF;
-  
-  if(!is_nodata(elevwin.get())) {
-    dir = 0;
-    if (elevwin.get(5) < elevwin.get() && !is_void(elevwin.get(5))) dir |= 1;
-    if (elevwin.get(3) < elevwin.get() && !is_void(elevwin.get(3))) dir |= 16;
-    for(int i=0; i<3; i++) {
-      if(elevwin.get(i) < elevwin.get() && !is_void(elevwin.get(i))) dir |= 32<<i;
-      if(elevwin.get(i+6) < elevwin.get() && !is_void(elevwin.get(6+i))) dir |= 8>>i;
-    }
-  }
-  
-  /* if no direction, check for boundary */
-  if(dir==0 || dir==DIRECTION_UNDEF) {
-    if(row==0) {
-      dir = 32 | 64 | 128;
-    }
-    if(row==nrows-1) {
-      dir = 2 | 4 | 8;
-    }
-    if(col==0) {
-      if(row==0) dir = 32;
-      else if(row==nrows-1) dir = 8;
-      else dir = 8 | 16 | 32;
-    }
-    if(col==ncols-1) {
-      if(row==0) dir = 128;
-      else if(row==nrows-1) dir = 2;
-      else dir = 128 | 1 | 2;
-    }
-  }
-  return dir;
-}
-
-/***************************************************************/
-/* returns the direction corresponding to the window using SFD */
-direction_type 
-encodeDirectionSFD(const genericWindow<elevation_type>& elevwin,
-				const dimension_type nrows, const dimension_type ncols,
-				dimension_type row, 
-				dimension_type col) {
-
-  direction_type dir = DIRECTION_UNDEF;
-	float tdrop, max_drop;
-	int max_indx;
-  
-  if(!is_nodata(elevwin.get())) {
-    dir = 0;
-		max_drop = 0;
-		max_indx = -1;
-		for(int i=0; i<9; i++){
-			if(i%2==1){ /*cardinal direction*/
-				tdrop=elevwin.get()-elevwin.get(i);
-				if(tdrop>max_drop){ max_drop=tdrop; max_indx=i; }
-			}
-			else if(i!=4){ /*diagonal*/
-				tdrop=(elevwin.get()-elevwin.get(i))/TF_ROOTTWO;
-				if(tdrop>max_drop){ max_drop=tdrop; max_indx=i; }
-			}
-		}
-		switch(max_indx){
-			case 0:
-			case 1:
-			case 2:
-				dir=32<<max_indx; break;
-		  case 3:
-				dir=16; break;
-			case 5:
-				dir=1; break;
-			case 6:
-			case 7:
-			case 8:
-				dir=8>>(max_indx-6); break;
-			default:
-				dir=0; break;
-		}
-  }
-  
-  /* if no direction, check for boundary */
-  if(dir==0 || dir==DIRECTION_UNDEF) {
-    if(row==0) {
-      dir = 64;
-    }
-    if(row==nrows-1) {
-      dir = 48;
-    }
-    if(col==0) {
-      if(row==0) dir = 32;
-      else if(row==nrows-1) dir = 8;
-      else dir = 16;
-    }
-    if(col==ncols-1) {
-      if(row==0) dir = 128;
-      else if(row==nrows-1) dir = 2;
-      else dir = 1;
-    }
-  }
-  return dir;
-}
-
-direction_type
-findDominant(direction_type dir) {
-  switch(dir) {
-  case 1:
-  case 2:
-  case 4:
-  case 8:
-  case 16:
-  case 32:
-  case 64:
-  case 128:
-	return dir;
-
-  case 1+2:
-  case 128+1:
-	return 1;
-  case 2+4:
-  case 4+8:
-	return 4;
-  case 8+16:
-  case 16+32:
-	return 16;
-  case 32+64:
-  case 64+128:
-	return 64;
-
-  case 1+2+4:
-	return 2;
-  case 2+4+8:
-	return 4;
-  case 4+8+16:
-	return 8;
-  case 8+16+32:
-	return 16;
-  case 16+32+64:
-	return 32;
-  case 32+64+128:
-	return 64;
-  case 64+128+1:
-	return 128;
-  case 128+1+2:
-	return 1;
-
-  case 128+1+2+4:
-  case 64+128+1+2:
-	return 1;
-  case 1+2+4+8:
-  case 2+4+8+16:
-	return 4;
-  case 8+16+32+64:
-  case 4+8+16+32:
-	return 16;
-  case 32+64+128+1:
-  case 16+32+64+128:
-	return 64;
-	
-  case 64+128+1+2+4:
-	return 1;
-  case 128+1+2+4+8:
-	return 2;
-  case 1+2+4+8+16:
-	return 4;
-  case 2+4+8+16+32:
-	return 8;
-  case 4+8+16+32+64:
-	return 16;
-  case 8+16+32+64+128:
-	return 32;
-  case 16+32+64+128+1:
-	return 64;
-  case 32+64+128+1+2:
-	return 128;
-  }
-
-  /* Otherwise, there is no dominant direction.
-	 * SFD must output a single direction 1,2,4,8,16,32,64, or 128
-	 * pick the first matching one, with preference to cardinal direction
-	 */
-	if(dir & 85 ){ 
-		/* at least one cardinal direction (1+4+16+64=E+S+W+N) matches */
-		if(dir & 1){ return 1;}
-		if(dir & 4){ return 4;}
-		if(dir & 16){ return 16;}
-		if(dir & 64){ return 64;}
-	}
-	else{ 
-		/* 2 8 32 128 = SE SW NW NE*/
-		if(dir & 2){ return 2;}
-		if(dir & 8){ return 8;}
-		if(dir & 32){ return 32;}
-		if(dir & 128){ return 128;}
-  }
-  return dir; /* shouldn't get here unless dir <= 0 */
-}
-
-
-char
-directionSymbol(direction_type dir) {
-  char c='?';
-  int cnt=0;
-  char symbols[] = ">\\v/<\\^/";
-
-  if(dir == 0) return '.';
-  
-  dir = findDominant(dir);
-
-  for(int i=0; i<8; i++) {
-	if(dir & (1<<i)) {
-	  cnt++;
-	  c = symbols[i];
-	}
-  }  
-  if(cnt>1) c = 'X';
-
-  switch(dir) {
-  case 1+16:
-  case 128+1+2+8+16+32:
-	c = '-';
-	break;
-  case 1+2+8+16+32:
-  case 128+1+8+16+32:
-	c = '<';
-	break;
-  case 128+1+2+16+32:
-  case 128+1+2+8+16:
-	c = '>';
-	break;
-  case 4+64:
-  case 2+4+8+32+64+128:
-	c = '|';
-	break;
-  case 4+8+32+64+128:
-  case 2+4+32+64+128:
-	c = '^';
-	break;
-  case 2+4+8+64+128:
-  case 2+4+8+32+64:
-	c = 'v';
-	break;
-  case 255:
-	c = '*';
-	break;
-  default:
-	break;
-  }
-  return c;
-} 
-
-
-#undef TF_ROOTTWO

Copied: grass/trunk/raster/r.terraflow/direction.cpp (from rev 48560, grass/trunk/raster/r.terraflow/direction.cc)
===================================================================
--- grass/trunk/raster/r.terraflow/direction.cpp	                        (rev 0)
+++ grass/trunk/raster/r.terraflow/direction.cpp	2011-09-29 23:36:57 UTC (rev 48562)
@@ -0,0 +1,301 @@
+/****************************************************************************
+ * 
+ *  MODULE:	r.terraflow
+ *
+ *  COPYRIGHT (C) 2007 Laura Toma
+ *   
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *****************************************************************************/
+
+
+#include "direction.h"
+#include "nodata.h"
+#include "common.h" /*for global opt->d8 flag*/
+
+#define TF_ROOTTWO 1.4142135623
+
+/* directions:
+   32 64 128
+   16 *   1
+   8  4   2
+*/
+direction_type 
+encodeDirection(const genericWindow<elevation_type>& elevwin,
+				const dimension_type nrows, const dimension_type ncols,
+				dimension_type row, 
+				dimension_type col) {
+  
+  /*check global opt flag and call appropriate model*/
+	if(opt->d8){
+    return encodeDirectionSFD(elevwin, nrows, ncols, row, col);
+	}
+  return encodeDirectionMFD(elevwin, nrows, ncols, row, col);
+}
+
+/***************************************************************/
+/* returns the direction corresponding to the window using MFD */
+direction_type 
+encodeDirectionMFD(const genericWindow<elevation_type>& elevwin,
+				const dimension_type nrows, const dimension_type ncols,
+				dimension_type row, 
+				dimension_type col) {
+  
+  direction_type dir = DIRECTION_UNDEF;
+  
+  if(!is_nodata(elevwin.get())) {
+    dir = 0;
+    if (elevwin.get(5) < elevwin.get() && !is_void(elevwin.get(5))) dir |= 1;
+    if (elevwin.get(3) < elevwin.get() && !is_void(elevwin.get(3))) dir |= 16;
+    for(int i=0; i<3; i++) {
+      if(elevwin.get(i) < elevwin.get() && !is_void(elevwin.get(i))) dir |= 32<<i;
+      if(elevwin.get(i+6) < elevwin.get() && !is_void(elevwin.get(6+i))) dir |= 8>>i;
+    }
+  }
+  
+  /* if no direction, check for boundary */
+  if(dir==0 || dir==DIRECTION_UNDEF) {
+    if(row==0) {
+      dir = 32 | 64 | 128;
+    }
+    if(row==nrows-1) {
+      dir = 2 | 4 | 8;
+    }
+    if(col==0) {
+      if(row==0) dir = 32;
+      else if(row==nrows-1) dir = 8;
+      else dir = 8 | 16 | 32;
+    }
+    if(col==ncols-1) {
+      if(row==0) dir = 128;
+      else if(row==nrows-1) dir = 2;
+      else dir = 128 | 1 | 2;
+    }
+  }
+  return dir;
+}
+
+/***************************************************************/
+/* returns the direction corresponding to the window using SFD */
+direction_type 
+encodeDirectionSFD(const genericWindow<elevation_type>& elevwin,
+				const dimension_type nrows, const dimension_type ncols,
+				dimension_type row, 
+				dimension_type col) {
+
+  direction_type dir = DIRECTION_UNDEF;
+	float tdrop, max_drop;
+	int max_indx;
+  
+  if(!is_nodata(elevwin.get())) {
+    dir = 0;
+		max_drop = 0;
+		max_indx = -1;
+		for(int i=0; i<9; i++){
+			if(i%2==1){ /*cardinal direction*/
+				tdrop=elevwin.get()-elevwin.get(i);
+				if(tdrop>max_drop){ max_drop=tdrop; max_indx=i; }
+			}
+			else if(i!=4){ /*diagonal*/
+				tdrop=(elevwin.get()-elevwin.get(i))/TF_ROOTTWO;
+				if(tdrop>max_drop){ max_drop=tdrop; max_indx=i; }
+			}
+		}
+		switch(max_indx){
+			case 0:
+			case 1:
+			case 2:
+				dir=32<<max_indx; break;
+		  case 3:
+				dir=16; break;
+			case 5:
+				dir=1; break;
+			case 6:
+			case 7:
+			case 8:
+				dir=8>>(max_indx-6); break;
+			default:
+				dir=0; break;
+		}
+  }
+  
+  /* if no direction, check for boundary */
+  if(dir==0 || dir==DIRECTION_UNDEF) {
+    if(row==0) {
+      dir = 64;
+    }
+    if(row==nrows-1) {
+      dir = 48;
+    }
+    if(col==0) {
+      if(row==0) dir = 32;
+      else if(row==nrows-1) dir = 8;
+      else dir = 16;
+    }
+    if(col==ncols-1) {
+      if(row==0) dir = 128;
+      else if(row==nrows-1) dir = 2;
+      else dir = 1;
+    }
+  }
+  return dir;
+}
+
+direction_type
+findDominant(direction_type dir) {
+  switch(dir) {
+  case 1:
+  case 2:
+  case 4:
+  case 8:
+  case 16:
+  case 32:
+  case 64:
+  case 128:
+	return dir;
+
+  case 1+2:
+  case 128+1:
+	return 1;
+  case 2+4:
+  case 4+8:
+	return 4;
+  case 8+16:
+  case 16+32:
+	return 16;
+  case 32+64:
+  case 64+128:
+	return 64;
+
+  case 1+2+4:
+	return 2;
+  case 2+4+8:
+	return 4;
+  case 4+8+16:
+	return 8;
+  case 8+16+32:
+	return 16;
+  case 16+32+64:
+	return 32;
+  case 32+64+128:
+	return 64;
+  case 64+128+1:
+	return 128;
+  case 128+1+2:
+	return 1;
+
+  case 128+1+2+4:
+  case 64+128+1+2:
+	return 1;
+  case 1+2+4+8:
+  case 2+4+8+16:
+	return 4;
+  case 8+16+32+64:
+  case 4+8+16+32:
+	return 16;
+  case 32+64+128+1:
+  case 16+32+64+128:
+	return 64;
+	
+  case 64+128+1+2+4:
+	return 1;
+  case 128+1+2+4+8:
+	return 2;
+  case 1+2+4+8+16:
+	return 4;
+  case 2+4+8+16+32:
+	return 8;
+  case 4+8+16+32+64:
+	return 16;
+  case 8+16+32+64+128:
+	return 32;
+  case 16+32+64+128+1:
+	return 64;
+  case 32+64+128+1+2:
+	return 128;
+  }
+
+  /* Otherwise, there is no dominant direction.
+	 * SFD must output a single direction 1,2,4,8,16,32,64, or 128
+	 * pick the first matching one, with preference to cardinal direction
+	 */
+	if(dir & 85 ){ 
+		/* at least one cardinal direction (1+4+16+64=E+S+W+N) matches */
+		if(dir & 1){ return 1;}
+		if(dir & 4){ return 4;}
+		if(dir & 16){ return 16;}
+		if(dir & 64){ return 64;}
+	}
+	else{ 
+		/* 2 8 32 128 = SE SW NW NE*/
+		if(dir & 2){ return 2;}
+		if(dir & 8){ return 8;}
+		if(dir & 32){ return 32;}
+		if(dir & 128){ return 128;}
+  }
+  return dir; /* shouldn't get here unless dir <= 0 */
+}
+
+
+char
+directionSymbol(direction_type dir) {
+  char c='?';
+  int cnt=0;
+  char symbols[] = ">\\v/<\\^/";
+
+  if(dir == 0) return '.';
+  
+  dir = findDominant(dir);
+
+  for(int i=0; i<8; i++) {
+	if(dir & (1<<i)) {
+	  cnt++;
+	  c = symbols[i];
+	}
+  }  
+  if(cnt>1) c = 'X';
+
+  switch(dir) {
+  case 1+16:
+  case 128+1+2+8+16+32:
+	c = '-';
+	break;
+  case 1+2+8+16+32:
+  case 128+1+8+16+32:
+	c = '<';
+	break;
+  case 128+1+2+16+32:
+  case 128+1+2+8+16:
+	c = '>';
+	break;
+  case 4+64:
+  case 2+4+8+32+64+128:
+	c = '|';
+	break;
+  case 4+8+32+64+128:
+  case 2+4+32+64+128:
+	c = '^';
+	break;
+  case 2+4+8+64+128:
+  case 2+4+8+32+64:
+	c = 'v';
+	break;
+  case 255:
+	c = '*';
+	break;
+  default:
+	break;
+  }
+  return c;
+} 
+
+
+#undef TF_ROOTTWO

Deleted: grass/trunk/raster/r.terraflow/fill.cc
===================================================================
--- grass/trunk/raster/r.terraflow/fill.cc	2011-09-29 23:35:42 UTC (rev 48561)
+++ grass/trunk/raster/r.terraflow/fill.cc	2011-09-29 23:36:57 UTC (rev 48562)
@@ -1,670 +0,0 @@
-/****************************************************************************
- * 
- *  MODULE:	r.terraflow
- *
- *  COPYRIGHT (C) 2007 Laura Toma
- *   
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *****************************************************************************/
-
-#include <stdlib.h>
-#include <ctype.h>
-#include <time.h>
-
-#include <string> 
-#include "fill.h"
-#include "common.h"
-#include "water.h"
-#include "sortutils.h"
-#include "streamutils.h"
-#include "filldepr.h"
-#include "grid.h"
-
-/* globals in common.H
-
-extern statsRecorder *stats;       stats file 
-extern userOptions *opt;           command-line options 
-extern struct  Cell_head *region;  header of the region 
-extern dimension_type nrows, ncols;
-*/
-
-
-#define FILL_DEBUG if(0)
-#define FILL_SAVEALL if(0)
-
-
-/* defined in this module */
-void recordWatersheds(AMI_STREAM<labelElevType> *labeledWater);
-long assignDirections(AMI_STREAM<plateauStats> *statstr, 
-					  AMI_STREAM<plateauType> *platstr,
-					  AMI_STREAM<waterType> *waterstr);
-void assignFinalDirections(AMI_STREAM<plateauStats> *statstr, 
-			   AMI_STREAM<plateauType> *platstr,
-			   AMI_STREAM<waterType> *waterstr);
-template<class T1, class T2, class T3, class T4, class FUN>
-void mergeStreamGridGrid(AMI_STREAM<T1> *grid1,
-			 AMI_STREAM<T2> *grid2,
-			 dimension_type rows, dimension_type cols, 
-			 AMI_STREAM<T3> *str,
-			 FUN fo,
-			 AMI_STREAM<T4> *outStream);
-void merge2waterBase(AMI_STREAM<waterType> *unsortedWaterStr, 
-		     AMI_STREAM<direction_type> *dirStr,
-		     AMI_STREAM<elevation_type> *elStr, 
-		     AMI_STREAM<waterWindowBaseType> *merge);
-AMI_STREAM<waterGridType>*
-merge2waterGrid(AMI_STREAM<waterType> *unsortedWaterStr, 
-		AMI_STREAM<direction_type> *dirStr, 
-		AMI_STREAM<elevation_type> *elStr);
-AMI_STREAM<boundaryType> *
-findBoundariesMain(AMI_STREAM<labelElevType> *labeledWater);
-
-
- 
-
-/* ********************************************************************** */
-/* some helper classes */
-/* ********************************************************************** */
-
-class printElevation {
-public:
-  char *operator()(const elevation_type &p) {
-	static char buf[20];
-	sprintf(buf, "%.1f", (float)p);
-	return buf;
-  }
-};
-
-class printDirection {
-public:
-  char *operator()(const direction_type &p) {
-	static char buf[20];
-	sprintf(buf, "%3d", p);
-	return buf;
-  }
-  char *operator()(const waterWindowBaseType &p) {
-	static char buf[20];
-	sprintf(buf, "%3d", p.dir);
-	return buf;
-  }
-#if(0)
-  char *operator()(const waterWindowBaseType &p) {
-	static char buf[3];
-	buf[0] = directionSymbol(p.dir);
-	buf[1] = '\0';
-	return buf;
-  }
-#endif
-};
-
-class printLabel {
-public: 
-  char *operator()(const labelElevType&p) {
-	static char buf[8];
-	sprintf(buf, CCLABEL_FMT, p.getLabel());
-	return buf;
-  }
-  char *operator()(const waterGridType &p) {
-	static char buf[8];
-	sprintf(buf, CCLABEL_FMT, p.getLabel());
-	return buf;
-  }
-  char *operator()(const waterType &p) {
-	static char buf[8];
-	sprintf(buf, CCLABEL_FMT, p.getLabel());
-	return buf;
-  }
-};
-
-class printDepth {
-public:
-  char *operator()(const waterGridType &p) {
-	static char buf[3];
-	sprintf(buf, "%1u", p.depth);
-	return buf;
-  }
-};
-
-
-
-
-char *
-verbosedir(std::string s) {
-  static char buf[BUFSIZ];
-  sprintf(buf, "dump/%s", s.c_str());
-  return buf;
-}
-
-
-
-/* ---------------------------------------------------------------------- */
-/* fill the terrain (if necessary) and compute flow direction stream;
-   elstr must exist and contain grid data before call, filledstr and
-   dirstr are created; elstr is deleted and replaced with the
-   classified elstr, which has boundary nodata distinguished from
-   inner nodata */
-AMI_STREAM<waterWindowBaseType>*
-computeFlowDirections(AMI_STREAM<elevation_type>*& elstr,
-		      AMI_STREAM<elevation_type>*& filledstr,
-		      AMI_STREAM<direction_type>*& dirstr,
-		      AMI_STREAM<labelElevType> *& labeledWater) {
-
-  Rtimer rt, rtTotal;
-  AMI_STREAM<elevation_type> *elstr_reclass=NULL;
-  AMI_STREAM<ElevationWindow > *winstr=NULL;
-  AMI_STREAM<plateauStats> *statstr=NULL;
-  AMI_STREAM<plateauType> *platstr=NULL;
-  AMI_STREAM<waterType> *waterstr=NULL;
-  AMI_STREAM<waterGridType> *mergedWaterStr=NULL;
-  AMI_STREAM<boundaryType> *boundaryStr=NULL;
-  AMI_STREAM<waterWindowType> *waterWindows=NULL;
-  
-  rt_start(rtTotal);
-  assert(elstr && filledstr == NULL && dirstr == NULL && labeledWater == NULL);
-  stats->comment("------------------------------");
-  stats->comment("COMPUTING FLOW DIRECTIONS");
-  
-  /* adjust nodata -- boundary nodata distinguished from inner
-     nodata */ 
-  stats->comment("classifying nodata (inner & boundary)");
-  
-  elstr_reclass = classifyNodata(elstr);
-  delete elstr;
-  elstr = elstr_reclass;
-  
-
-  /* ---------------------------------------------------------------------- */
-  /* find the plateaus. */
-  /* ---------------------------------------------------------------------- */
-  stats->comment("----------",  opt->verbose);
-  stats->comment("assigning preliminary directions");
-  
-  rt_start(rt);
-  dirstr = new AMI_STREAM<direction_type>;
-  winstr = new AMI_STREAM<ElevationWindow>();
-  statstr = new AMI_STREAM<plateauStats>;
-  
-  platstr = findPlateaus(elstr, nrows, ncols, nodataType::ELEVATION_NODATA,
-						 winstr, dirstr, statstr);
- 
-  delete winstr; /* not used; not made */
-  rt_stop(rt);
-  
-  stats->recordTime("findingPlateaus", rt);
-  stats->recordLength("plateaus", platstr);
-  stats->recordLength("plateau stats", statstr);
-  FILL_SAVEALL {
-    /* printStream(*stats, statstr); */
-    FILL_DEBUG cout << "sort plateauStr (by ij): ";
-    AMI_STREAM<plateauType> *tmp = sort(platstr, ijCmpPlateauType());
-    printStream2Grid(tmp, nrows, ncols, 
-		     verbosedir("label1.asc"), plateauType::printLabel);
-    delete tmp;
-  }
-  
-
-  /* ---------------------------------------------------------------------- */
-  /* assign labels and directions & BFS ordering. depressions have
-     labels, but no direction information.
-  */
-  /* ---------------------------------------------------------------------- */
-  rt_start(rt);
-  waterstr = new AMI_STREAM<waterType>();
-  assignDirections(statstr, platstr, waterstr);
-  delete platstr;
-  delete statstr;
-  rt_stop(rt);
-  stats->recordTime("assigning directions", rt);
-  *stats << "maxWatershedCount=" << labelFactory::getLabelCount() << endl;
-
-  
-  rt_start(rt);
-  mergedWaterStr = merge2waterGrid(waterstr, dirstr, elstr);
-  delete dirstr;
-  delete waterstr;
-  rt_stop(rt);
-  stats->recordTime("merging", rt);
-  stats->recordLength("mergedWaterStr", mergedWaterStr);
-
-
- /* ---------------------------------------------------------------------- */
-  /* watershed analysis */
-  /* IN: mergedWaterStr, labelFactory::... */
-  /* ---------------------------------------------------------------------- */
-  stats->comment("--------------", opt->verbose);
-  stats->comment("generating watersheds and watershed graph");
-
-  rt_start(rt);
-  waterWindows = new AMI_STREAM<waterWindowType>();
-  createWaterWindows(mergedWaterStr, nrows, ncols, waterWindows);
-  delete mergedWaterStr;
-  rt_stop(rt);
-  stats->recordTime("creating windows", rt);
-  stats->recordLength("waterWindows", waterWindows);
-
-
-  /* ---------------------------------------------------------------------- */
-  rt_start(rt);
-  labeledWater = new AMI_STREAM<labelElevType>();
-  boundaryStr = new AMI_STREAM<boundaryType>();
-  generateWatersheds(&waterWindows, nrows, ncols, labeledWater, boundaryStr);
-
-  /* do we need to make boundaries here?? */
-  delete waterWindows;
-  /* cout << "bogus boundary length = " << boundaryStr->stream_len() << endl;*/
-  assert(boundaryStr->stream_len() == 0);
-  delete boundaryStr;
-  
-  assert(labeledWater->stream_len() == nrows * ncols);
-  rt_stop(rt);
-  stats->recordTime("generating watersheds", rt);
-  
-  /* ---------------------------------------------------------------------- */
-  /* find boundaries */
-  /* ---------------------------------------------------------------------- */
-  FILL_DEBUG cerr << "sort labeledWater (by ij):";
-  sort(&labeledWater, ijCmpLabelElevType());
-
-#ifdef SAVE_ASCII  
-  cerr << "saving WATERSHED grid as watershed_grid\n";
-  printStream2Grid(labeledWater, nrows, ncols, 
-		   "watershed.asc", labelElevType::printLabel);
-#endif
-  boundaryStr = findBoundariesMain(labeledWater);
-  
-  
-  /* ---------------------------------------------------------------------- */
-  /* filling */
-  /* valid streams are: boundaryStr, labeledWater */
-  /* ---------------------------------------------------------------------- */
-  rt_start(rt);
-  elevation_type *raise;
-  /*find the raise elevations */
-  
-  FILL_DEBUG cerr << "sort boundaryStr (by elev): ";
-  sort(&boundaryStr, elevCmpBoundaryType());
-
-  raise = fill_depression(boundaryStr, labelFactory::getLabelCount());
-  delete boundaryStr;
-  rt_stop(rt);
-  stats->recordTime("filling depressions", rt);
-  
-  /*fill the terrain*/
-  rt_start(rt);
-  filledstr = new AMI_STREAM<elevation_type>();
-  commit_fill(labeledWater, raise, labelFactory::getLabelCount(), filledstr);
-  assert(filledstr->stream_len() == nrows * ncols);
-  delete [] raise;
-  rt_stop(rt);
-  stats->recordTime("updating filled grid", rt);
-  stats->recordLength("filledstr", filledstr);
-  
-
-  /* ---------------------------------------------------------------------- */
-  /* find plateaus again and reassign directions */
-  /* ---------------------------------------------------------------------- */
-
-  stats->comment("------------------------------");
-  stats->comment("REASSIGNING DIRECTIONS");
-
-  rt_start(rt);
-  winstr = NULL;
-  dirstr = new AMI_STREAM<direction_type>();
-  statstr = new AMI_STREAM<plateauStats>();
-  platstr = findPlateaus(filledstr, nrows, ncols, nodataType::ELEVATION_NODATA,
-			 winstr, dirstr, statstr);
-  rt_stop(rt);
-  stats->recordTime("findingPlateaus2", rt);
-  stats->recordLength("final plateaus", platstr);
-  stats->recordLength("final plateau stats", statstr);
-  FILL_SAVEALL {
-    FILL_DEBUG cout << "sort plateauStr (by ij): "; 
-    AMI_STREAM<plateauType> *tmp = sort(platstr, ijCmpPlateauType());
-    printStream2Grid(tmp, nrows, ncols, 
-		     verbosedir("plateaus.asc"), plateauType::printLabel);
-    delete tmp;
-  }
-
-  /* assign final directions */
-  rt_start(rt);
-  waterstr = new AMI_STREAM<waterType>();
-  long dc = assignDirections(statstr, platstr, waterstr);
-  if(dc) {
-    *stats << "WARNING: " << dc << " depressions (islands) detected\n";
-  }
-  delete platstr;
-  delete statstr;
-  rt_stop(rt);
-  stats->recordTime("final directions", rt);
-  
-  /* merge */
-  rt_start(rt);
-  AMI_STREAM<waterWindowBaseType> *flowStream;
-  /*STREAM_TO_OPTION(flowStream, "flowStream");*/
-   char path[BUFSIZ];
-  char* base_dir = getenv(STREAM_TMPDIR);
-  assert(base_dir);
-  sprintf(path, "%s/flowStream", base_dir);
-  flowStream = new AMI_STREAM<waterWindowBaseType>(path);
-  /*flowStream->persist(PERSIST_PERSISTENT); */
-  stats->comment("creating flowStream: ", flowStream->sprint());
-
-  merge2waterBase(waterstr, dirstr, filledstr, flowStream);
-  delete waterstr;
-  rt_stop(rt);
-  stats->recordTime("merge water,dir,elev to flow", rt);
-  rt_stop(rtTotal);
-  
-#ifdef SAVE_ASCII
-  /*write grids as ascii file */
-  printGridStream(filledstr, nrows, ncols,
-		  "filled_elev.asc", printElevation());
-  printGridStream(flowStream, nrows, ncols,  
-		  "direction.asc", printDirection());
-#endif
-  
-  stats->recordTime("Total compute flow direction running time", rtTotal);
-  stats->comment("compute flow directions done.");
-   
-  return flowStream;
-}
-
-
-/* ---------------------------------------------------------------------- */
-void
-recordWatersheds(AMI_STREAM<labelElevType> *labeledWater) {
-  AMI_err ae;
-  long labelCount = 0;
-  AMI_STREAM<labelElevType> *tmp;
-
-  *stats << "--- watershed stats" << endl;
-  FILL_DEBUG cout << "sort labeledWater (by wat label): ";
-  tmp = sort(labeledWater, labelCmpLabelElevType());
-
-  labelElevType *p;
-  cclabel_type prev(LABEL_UNDEF);
-  tmp->seek(0);
-  while((ae = tmp->read_item(&p)) == AMI_ERROR_NO_ERROR) {
-	if(p->getLabel() != prev) {
-	  labelCount++;
-	  prev = p->getLabel();
-	}
-  }
-  assert(ae == AMI_ERROR_END_OF_STREAM);
-
-  *stats << "watershed count = " << labelCount << endl;
-  *stats << "---" << endl;
-  stats->flush();
-
-  delete tmp;
-}
-
-
-
-
-
-/* ********************************************************************** */
-/* assign directions to plateaus that have sinks;
- * reassign labels to depressions (don't drain out).
- * all plateaus are written out to the waterstr. */
-long
-assignDirections(AMI_STREAM<plateauStats> *statstr, 
-		 AMI_STREAM<plateauType> *platstr,
-		 AMI_STREAM<waterType> *waterstr) {
-  size_t fmem;
-  AMI_err ae;
-  plateauStats *ps;
-
-  stats->comment("----------",  opt->verbose);
-  stats->comment("assigning directions on plateaus");
-  
-  labelFactory::reset();		/* we are relabeling now */
-  
-  statstr->seek(0);
-  platstr->seek(0);
-  fmem = getAvailableMemory();
-  long depressionCount=0;
-  long spillCount=0;
-  while((ae = statstr->read_item(&ps)) == AMI_ERROR_NO_ERROR) {
-    if(ps->size*sizeof(gridElement) > fmem) {
-      cerr << "WARNING: grid larger than memory (ignored)" << endl;
-    }
-    assert(ps->label != LABEL_NODATA);
-    if(ps->hasSpill) {
-      spillCount++;
-      grid *platGrid = new grid(ps->iMin, ps->jMin, ps->iMax, ps->jMax, 
-				ps->size, ps->label);
-      platGrid->load(*platstr);
-      platGrid->assignDirections(opt->d8 ? 1 : 0);
-      platGrid->save(*waterstr); /* this doesn't save labels */
-      delete platGrid;
-    } else {
-      /* depression - just give contiguous labels only */
-      depressionCount++;
-      cclabel_type label = labelFactory::getNewLabel();
-      for(int i=0; i<ps->size; i++) {
-	plateauType *pt;
-	platstr->read_item(&pt);
-	pt->cclabel = label;	/* assign new label */
-	waterType wt(*pt);		/* write it out */
-	ae = waterstr->write_item(wt);
-	assert(ae == AMI_ERROR_NO_ERROR);
-      }
-    }
-  }
-  *stats << "depression count = " << depressionCount << endl;
-  *stats << "spill count = " << spillCount << endl;
-  return depressionCount;
-}
-
-
-
-
-/* ********************************************************************** */
-/* assign directions to plateaus that have sinks;
- * check that there are no depressions.
- */
-void
-assignFinalDirections(AMI_STREAM<plateauStats> *statstr, 
-		      AMI_STREAM<plateauType> *platstr,
-		      AMI_STREAM<waterType> *waterstr) {
-  AMI_err ae;
-  plateauStats *ps;
-
-  stats->comment("assigning final directions");
-
-  statstr->seek(0);
-  platstr->seek(0);
-  while((ae = statstr->read_item(&ps)) == AMI_ERROR_NO_ERROR) {
-    
-    if(ps->hasSpill) {
-      grid *platGrid = new grid(ps->iMin, ps->jMin, ps->iMax, ps->jMax, 
-				ps->size, ps->label);
-      platGrid->load(*platstr);
-      platGrid->assignDirections(opt->d8 ? 1 : 0);
-      platGrid->save(*waterstr); /* this doesn't save labels */
-      delete platGrid;
-    } else {
-      /* could be legitimate */
-      cerr << "WARNING: depression detected: " << *ps << endl;
-      continue;
-    } 
-  }
-};
-
-
-
-/* ********************************************************************** */
-class directionElevationMerger {
-public:
-  waterGridType operator()(elevation_type el, direction_type dir, 
-			   waterType p) { 
-    /* check that no (boundary) nodata values got in here */
-    assert(el != nodataType::ELEVATION_BOUNDARY);
-    assert(!is_nodata(el));		/* p should be a valid grid cell */
-    return waterGridType(el, p.getDirection(), p.getLabel(), p.getDepth());
-  }
-  waterGridType operator()(elevation_type el, direction_type dir) {
-    waterGridType wg(el, dir);
-    if(el == nodataType::ELEVATION_BOUNDARY) { /* hack XXX (approved) */
-      wg.setLabel(LABEL_BOUNDARY); 
-    }
-    /* nodata => boundary or undef */
-    assert(!is_nodata(el) ||
-	   (wg.getLabel()==LABEL_BOUNDARY || wg.getLabel()==LABEL_UNDEF)); 
-	return wg;
-  }
-};
-
-
-
-/* ---------------------------------------------------------------------- */
-AMI_STREAM<waterGridType> *
-merge2waterGrid(AMI_STREAM<waterType> *unsortedWaterStr, 
-		AMI_STREAM<direction_type> *dirStr, 
-		AMI_STREAM<elevation_type> *elStr) {
-  AMI_STREAM<waterType> *waterStr;
-  
-  
-  FILL_DEBUG cout << "sort waterStr (by ij): ";
-  waterStr = sort(unsortedWaterStr, ijCmpWaterType());
-
-  FILL_SAVEALL printStream2Grid(waterStr, nrows, ncols, 
-				verbosedir("platlabels.asc"), printLabel());
- 
-  AMI_STREAM<waterGridType> *mergedWaterStr = new AMI_STREAM<waterGridType>();
-  mergeStreamGridGrid(elStr, dirStr,
-		      nrows, ncols,
-		      waterStr,
-		      directionElevationMerger(),
-		      mergedWaterStr);
-  delete waterStr;
-  FILL_SAVEALL printGridStream(mergedWaterStr, nrows, ncols, 
-							   verbosedir("mergedlabels.asc"), printLabel());
-
-  assert(mergedWaterStr->stream_len());
-  return mergedWaterStr;
-}
-
-
-
-/* ---------------------------------------------------------------------- */
-void
-merge2waterBase(AMI_STREAM<waterType> *unsortedWaterStr, 
-		AMI_STREAM<direction_type> *dirStr,
-		AMI_STREAM<elevation_type> *elStr, 
-		AMI_STREAM<waterWindowBaseType> *merge) {
-  AMI_STREAM<waterType> *waterStr;
-  FILL_DEBUG cout << "sort waterStr (by ij): ";
-  waterStr = sort(unsortedWaterStr, ijCmpWaterType());
-  mergeStreamGridGrid(elStr, dirStr,
-		      nrows, ncols,
-		      waterStr,
-		      directionElevationMerger(),
-		      merge);
-  delete waterStr;
-}
-
-
-
-
-/* ---------------------------------------------------------------------- */
-/*
- * merge 2 grids and a stream together to form a new grid. 
- * str should be sorted in ij order 
- */
-template<class T1, class T2, class T3, class T4, class FUN>
-void
-mergeStreamGridGrid(AMI_STREAM<T1> *grid1,
-		    AMI_STREAM<T2> *grid2,
-		    dimension_type rows, dimension_type cols, 
-		    AMI_STREAM<T3> *str,
-		    FUN fo,
-		    AMI_STREAM<T4> *outStream) {
-  T1 *t1p;
-  T2 *t2p;
-  T3 *t3p;
-  AMI_err aeUpd, ae;
-
-  
-  grid1->seek(0);
-  grid2->seek(0);
-  str->seek(0);
-  aeUpd = str->read_item(&t3p);
-  assert(aeUpd == AMI_ERROR_NO_ERROR || aeUpd == AMI_ERROR_END_OF_STREAM);
-
-  for(dimension_type row = 0; row < rows; row++) {
-    for(dimension_type col = 0; col < cols; col++) {
-      ae = grid1->read_item(&t1p);
-      assert(ae == AMI_ERROR_NO_ERROR);
-      ae = grid2->read_item(&t2p);
-      assert(ae == AMI_ERROR_NO_ERROR);
-      
-      T4 t4;
-      if(aeUpd == AMI_ERROR_NO_ERROR && t3p->i == row && t3p->j == col) {
-		/* cell present in stream */
-	t4 = fo(*t1p, *t2p, *t3p);
-	aeUpd = str->read_item(&t3p);
-	assert(aeUpd == AMI_ERROR_NO_ERROR || 
-	       aeUpd == AMI_ERROR_END_OF_STREAM);
-      } else {					
-		/* not in stream */
-		t4 = fo(*t1p, *t2p);
-      }
-      ae = outStream->write_item(t4);
-      assert(ae == AMI_ERROR_NO_ERROR);
-    }
-    /*assert(outStream->stream_len() == (row+1) * cols); */
-  }
-  assert(outStream->stream_len() == rows * cols);
-  return;
-}
-
-
-
-/* ---------------------------------------------------------------------- */
-/* make boundaryStr from labeledWater */
-AMI_STREAM<boundaryType> *
-findBoundariesMain(AMI_STREAM<labelElevType> *labeledWater) {
-  AMI_STREAM<boundaryType> *boundaryStr;
-  Rtimer rt;
-  
-  rt_start(rt);
-  boundaryStr = new AMI_STREAM<boundaryType>();
-  FILL_SAVEALL printGridStream(labeledWater, nrows, ncols,  
-			       verbosedir("labels.asc"), printLabel());
-  
-  findBoundaries(labeledWater, nrows, ncols, boundaryStr);
-  stats->recordLength("all boundaries", boundaryStr);
-  
-  FILL_SAVEALL {
-    FILL_DEBUG cout << "sort boundaryStr (by ij): ";
-    sort(&boundaryStr, ijCmpBoundaryType());
-    removeDuplicatesEx(&boundaryStr, ijCmpBoundaryType());
-    printStream2Grid(boundaryStr, nrows, ncols,
-		     verbosedir("boundary.asc"), boundaryType::print);
-  }
-  FILL_DEBUG cout << "sort boundaryStr (by wat label): ";
-  sort(&boundaryStr, waterCmpBoundaryType());
-  removeDuplicatesEx(&boundaryStr, boundaryCmpBoundaryType());
-  
-  rt_stop(rt);
-  stats->recordTime("generating boundaries", rt);
-  stats->recordLength("boundary stream", boundaryStr);
-  
-  /*if(GETOPT("veryfillverbose")) printStream(cout, boundaryStr);
-	SAVE_ON_OPTION(boundaryStr, "saveBoundaryStream");
-  */
-  return boundaryStr;
-}
-
-

Copied: grass/trunk/raster/r.terraflow/fill.cpp (from rev 48560, grass/trunk/raster/r.terraflow/fill.cc)
===================================================================
--- grass/trunk/raster/r.terraflow/fill.cpp	                        (rev 0)
+++ grass/trunk/raster/r.terraflow/fill.cpp	2011-09-29 23:36:57 UTC (rev 48562)
@@ -0,0 +1,670 @@
+/****************************************************************************
+ * 
+ *  MODULE:	r.terraflow
+ *
+ *  COPYRIGHT (C) 2007 Laura Toma
+ *   
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *****************************************************************************/
+
+#include <stdlib.h>
+#include <ctype.h>
+#include <time.h>
+
+#include <string> 
+#include "fill.h"
+#include "common.h"
+#include "water.h"
+#include "sortutils.h"
+#include "streamutils.h"
+#include "filldepr.h"
+#include "grid.h"
+
+/* globals in common.H
+
+extern statsRecorder *stats;       stats file 
+extern userOptions *opt;           command-line options 
+extern struct  Cell_head *region;  header of the region 
+extern dimension_type nrows, ncols;
+*/
+
+
+#define FILL_DEBUG if(0)
+#define FILL_SAVEALL if(0)
+
+
+/* defined in this module */
+void recordWatersheds(AMI_STREAM<labelElevType> *labeledWater);
+long assignDirections(AMI_STREAM<plateauStats> *statstr, 
+					  AMI_STREAM<plateauType> *platstr,
+					  AMI_STREAM<waterType> *waterstr);
+void assignFinalDirections(AMI_STREAM<plateauStats> *statstr, 
+			   AMI_STREAM<plateauType> *platstr,
+			   AMI_STREAM<waterType> *waterstr);
+template<class T1, class T2, class T3, class T4, class FUN>
+void mergeStreamGridGrid(AMI_STREAM<T1> *grid1,
+			 AMI_STREAM<T2> *grid2,
+			 dimension_type rows, dimension_type cols, 
+			 AMI_STREAM<T3> *str,
+			 FUN fo,
+			 AMI_STREAM<T4> *outStream);
+void merge2waterBase(AMI_STREAM<waterType> *unsortedWaterStr, 
+		     AMI_STREAM<direction_type> *dirStr,
+		     AMI_STREAM<elevation_type> *elStr, 
+		     AMI_STREAM<waterWindowBaseType> *merge);
+AMI_STREAM<waterGridType>*
+merge2waterGrid(AMI_STREAM<waterType> *unsortedWaterStr, 
+		AMI_STREAM<direction_type> *dirStr, 
+		AMI_STREAM<elevation_type> *elStr);
+AMI_STREAM<boundaryType> *
+findBoundariesMain(AMI_STREAM<labelElevType> *labeledWater);
+
+
+ 
+
+/* ********************************************************************** */
+/* some helper classes */
+/* ********************************************************************** */
+
+class printElevation {
+public:
+  char *operator()(const elevation_type &p) {
+	static char buf[20];
+	sprintf(buf, "%.1f", (float)p);
+	return buf;
+  }
+};
+
+class printDirection {
+public:
+  char *operator()(const direction_type &p) {
+	static char buf[20];
+	sprintf(buf, "%3d", p);
+	return buf;
+  }
+  char *operator()(const waterWindowBaseType &p) {
+	static char buf[20];
+	sprintf(buf, "%3d", p.dir);
+	return buf;
+  }
+#if(0)
+  char *operator()(const waterWindowBaseType &p) {
+	static char buf[3];
+	buf[0] = directionSymbol(p.dir);
+	buf[1] = '\0';
+	return buf;
+  }
+#endif
+};
+
+class printLabel {
+public: 
+  char *operator()(const labelElevType&p) {
+	static char buf[8];
+	sprintf(buf, CCLABEL_FMT, p.getLabel());
+	return buf;
+  }
+  char *operator()(const waterGridType &p) {
+	static char buf[8];
+	sprintf(buf, CCLABEL_FMT, p.getLabel());
+	return buf;
+  }
+  char *operator()(const waterType &p) {
+	static char buf[8];
+	sprintf(buf, CCLABEL_FMT, p.getLabel());
+	return buf;
+  }
+};
+
+class printDepth {
+public:
+  char *operator()(const waterGridType &p) {
+	static char buf[3];
+	sprintf(buf, "%1u", p.depth);
+	return buf;
+  }
+};
+
+
+
+
+char *
+verbosedir(std::string s) {
+  static char buf[BUFSIZ];
+  sprintf(buf, "dump/%s", s.c_str());
+  return buf;
+}
+
+
+
+/* ---------------------------------------------------------------------- */
+/* fill the terrain (if necessary) and compute flow direction stream;
+   elstr must exist and contain grid data before call, filledstr and
+   dirstr are created; elstr is deleted and replaced with the
+   classified elstr, which has boundary nodata distinguished from
+   inner nodata */
+AMI_STREAM<waterWindowBaseType>*
+computeFlowDirections(AMI_STREAM<elevation_type>*& elstr,
+		      AMI_STREAM<elevation_type>*& filledstr,
+		      AMI_STREAM<direction_type>*& dirstr,
+		      AMI_STREAM<labelElevType> *& labeledWater) {
+
+  Rtimer rt, rtTotal;
+  AMI_STREAM<elevation_type> *elstr_reclass=NULL;
+  AMI_STREAM<ElevationWindow > *winstr=NULL;
+  AMI_STREAM<plateauStats> *statstr=NULL;
+  AMI_STREAM<plateauType> *platstr=NULL;
+  AMI_STREAM<waterType> *waterstr=NULL;
+  AMI_STREAM<waterGridType> *mergedWaterStr=NULL;
+  AMI_STREAM<boundaryType> *boundaryStr=NULL;
+  AMI_STREAM<waterWindowType> *waterWindows=NULL;
+  
+  rt_start(rtTotal);
+  assert(elstr && filledstr == NULL && dirstr == NULL && labeledWater == NULL);
+  stats->comment("------------------------------");
+  stats->comment("COMPUTING FLOW DIRECTIONS");
+  
+  /* adjust nodata -- boundary nodata distinguished from inner
+     nodata */ 
+  stats->comment("classifying nodata (inner & boundary)");
+  
+  elstr_reclass = classifyNodata(elstr);
+  delete elstr;
+  elstr = elstr_reclass;
+  
+
+  /* ---------------------------------------------------------------------- */
+  /* find the plateaus. */
+  /* ---------------------------------------------------------------------- */
+  stats->comment("----------",  opt->verbose);
+  stats->comment("assigning preliminary directions");
+  
+  rt_start(rt);
+  dirstr = new AMI_STREAM<direction_type>;
+  winstr = new AMI_STREAM<ElevationWindow>();
+  statstr = new AMI_STREAM<plateauStats>;
+  
+  platstr = findPlateaus(elstr, nrows, ncols, nodataType::ELEVATION_NODATA,
+						 winstr, dirstr, statstr);
+ 
+  delete winstr; /* not used; not made */
+  rt_stop(rt);
+  
+  stats->recordTime("findingPlateaus", rt);
+  stats->recordLength("plateaus", platstr);
+  stats->recordLength("plateau stats", statstr);
+  FILL_SAVEALL {
+    /* printStream(*stats, statstr); */
+    FILL_DEBUG cout << "sort plateauStr (by ij): ";
+    AMI_STREAM<plateauType> *tmp = sort(platstr, ijCmpPlateauType());
+    printStream2Grid(tmp, nrows, ncols, 
+		     verbosedir("label1.asc"), plateauType::printLabel);
+    delete tmp;
+  }
+  
+
+  /* ---------------------------------------------------------------------- */
+  /* assign labels and directions & BFS ordering. depressions have
+     labels, but no direction information.
+  */
+  /* ---------------------------------------------------------------------- */
+  rt_start(rt);
+  waterstr = new AMI_STREAM<waterType>();
+  assignDirections(statstr, platstr, waterstr);
+  delete platstr;
+  delete statstr;
+  rt_stop(rt);
+  stats->recordTime("assigning directions", rt);
+  *stats << "maxWatershedCount=" << labelFactory::getLabelCount() << endl;
+
+  
+  rt_start(rt);
+  mergedWaterStr = merge2waterGrid(waterstr, dirstr, elstr);
+  delete dirstr;
+  delete waterstr;
+  rt_stop(rt);
+  stats->recordTime("merging", rt);
+  stats->recordLength("mergedWaterStr", mergedWaterStr);
+
+
+ /* ---------------------------------------------------------------------- */
+  /* watershed analysis */
+  /* IN: mergedWaterStr, labelFactory::... */
+  /* ---------------------------------------------------------------------- */
+  stats->comment("--------------", opt->verbose);
+  stats->comment("generating watersheds and watershed graph");
+
+  rt_start(rt);
+  waterWindows = new AMI_STREAM<waterWindowType>();
+  createWaterWindows(mergedWaterStr, nrows, ncols, waterWindows);
+  delete mergedWaterStr;
+  rt_stop(rt);
+  stats->recordTime("creating windows", rt);
+  stats->recordLength("waterWindows", waterWindows);
+
+
+  /* ---------------------------------------------------------------------- */
+  rt_start(rt);
+  labeledWater = new AMI_STREAM<labelElevType>();
+  boundaryStr = new AMI_STREAM<boundaryType>();
+  generateWatersheds(&waterWindows, nrows, ncols, labeledWater, boundaryStr);
+
+  /* do we need to make boundaries here?? */
+  delete waterWindows;
+  /* cout << "bogus boundary length = " << boundaryStr->stream_len() << endl;*/
+  assert(boundaryStr->stream_len() == 0);
+  delete boundaryStr;
+  
+  assert(labeledWater->stream_len() == nrows * ncols);
+  rt_stop(rt);
+  stats->recordTime("generating watersheds", rt);
+  
+  /* ---------------------------------------------------------------------- */
+  /* find boundaries */
+  /* ---------------------------------------------------------------------- */
+  FILL_DEBUG cerr << "sort labeledWater (by ij):";
+  sort(&labeledWater, ijCmpLabelElevType());
+
+#ifdef SAVE_ASCII  
+  cerr << "saving WATERSHED grid as watershed_grid\n";
+  printStream2Grid(labeledWater, nrows, ncols, 
+		   "watershed.asc", labelElevType::printLabel);
+#endif
+  boundaryStr = findBoundariesMain(labeledWater);
+  
+  
+  /* ---------------------------------------------------------------------- */
+  /* filling */
+  /* valid streams are: boundaryStr, labeledWater */
+  /* ---------------------------------------------------------------------- */
+  rt_start(rt);
+  elevation_type *raise;
+  /*find the raise elevations */
+  
+  FILL_DEBUG cerr << "sort boundaryStr (by elev): ";
+  sort(&boundaryStr, elevCmpBoundaryType());
+
+  raise = fill_depression(boundaryStr, labelFactory::getLabelCount());
+  delete boundaryStr;
+  rt_stop(rt);
+  stats->recordTime("filling depressions", rt);
+  
+  /*fill the terrain*/
+  rt_start(rt);
+  filledstr = new AMI_STREAM<elevation_type>();
+  commit_fill(labeledWater, raise, labelFactory::getLabelCount(), filledstr);
+  assert(filledstr->stream_len() == nrows * ncols);
+  delete [] raise;
+  rt_stop(rt);
+  stats->recordTime("updating filled grid", rt);
+  stats->recordLength("filledstr", filledstr);
+  
+
+  /* ---------------------------------------------------------------------- */
+  /* find plateaus again and reassign directions */
+  /* ---------------------------------------------------------------------- */
+
+  stats->comment("------------------------------");
+  stats->comment("REASSIGNING DIRECTIONS");
+
+  rt_start(rt);
+  winstr = NULL;
+  dirstr = new AMI_STREAM<direction_type>();
+  statstr = new AMI_STREAM<plateauStats>();
+  platstr = findPlateaus(filledstr, nrows, ncols, nodataType::ELEVATION_NODATA,
+			 winstr, dirstr, statstr);
+  rt_stop(rt);
+  stats->recordTime("findingPlateaus2", rt);
+  stats->recordLength("final plateaus", platstr);
+  stats->recordLength("final plateau stats", statstr);
+  FILL_SAVEALL {
+    FILL_DEBUG cout << "sort plateauStr (by ij): "; 
+    AMI_STREAM<plateauType> *tmp = sort(platstr, ijCmpPlateauType());
+    printStream2Grid(tmp, nrows, ncols, 
+		     verbosedir("plateaus.asc"), plateauType::printLabel);
+    delete tmp;
+  }
+
+  /* assign final directions */
+  rt_start(rt);
+  waterstr = new AMI_STREAM<waterType>();
+  long dc = assignDirections(statstr, platstr, waterstr);
+  if(dc) {
+    *stats << "WARNING: " << dc << " depressions (islands) detected\n";
+  }
+  delete platstr;
+  delete statstr;
+  rt_stop(rt);
+  stats->recordTime("final directions", rt);
+  
+  /* merge */
+  rt_start(rt);
+  AMI_STREAM<waterWindowBaseType> *flowStream;
+  /*STREAM_TO_OPTION(flowStream, "flowStream");*/
+   char path[BUFSIZ];
+  char* base_dir = getenv(STREAM_TMPDIR);
+  assert(base_dir);
+  sprintf(path, "%s/flowStream", base_dir);
+  flowStream = new AMI_STREAM<waterWindowBaseType>(path);
+  /*flowStream->persist(PERSIST_PERSISTENT); */
+  stats->comment("creating flowStream: ", flowStream->sprint());
+
+  merge2waterBase(waterstr, dirstr, filledstr, flowStream);
+  delete waterstr;
+  rt_stop(rt);
+  stats->recordTime("merge water,dir,elev to flow", rt);
+  rt_stop(rtTotal);
+  
+#ifdef SAVE_ASCII
+  /*write grids as ascii file */
+  printGridStream(filledstr, nrows, ncols,
+		  "filled_elev.asc", printElevation());
+  printGridStream(flowStream, nrows, ncols,  
+		  "direction.asc", printDirection());
+#endif
+  
+  stats->recordTime("Total compute flow direction running time", rtTotal);
+  stats->comment("compute flow directions done.");
+   
+  return flowStream;
+}
+
+
+/* ---------------------------------------------------------------------- */
+void
+recordWatersheds(AMI_STREAM<labelElevType> *labeledWater) {
+  AMI_err ae;
+  long labelCount = 0;
+  AMI_STREAM<labelElevType> *tmp;
+
+  *stats << "--- watershed stats" << endl;
+  FILL_DEBUG cout << "sort labeledWater (by wat label): ";
+  tmp = sort(labeledWater, labelCmpLabelElevType());
+
+  labelElevType *p;
+  cclabel_type prev(LABEL_UNDEF);
+  tmp->seek(0);
+  while((ae = tmp->read_item(&p)) == AMI_ERROR_NO_ERROR) {
+	if(p->getLabel() != prev) {
+	  labelCount++;
+	  prev = p->getLabel();
+	}
+  }
+  assert(ae == AMI_ERROR_END_OF_STREAM);
+
+  *stats << "watershed count = " << labelCount << endl;
+  *stats << "---" << endl;
+  stats->flush();
+
+  delete tmp;
+}
+
+
+
+
+
+/* ********************************************************************** */
+/* assign directions to plateaus that have sinks;
+ * reassign labels to depressions (don't drain out).
+ * all plateaus are written out to the waterstr. */
+long
+assignDirections(AMI_STREAM<plateauStats> *statstr, 
+		 AMI_STREAM<plateauType> *platstr,
+		 AMI_STREAM<waterType> *waterstr) {
+  size_t fmem;
+  AMI_err ae;
+  plateauStats *ps;
+
+  stats->comment("----------",  opt->verbose);
+  stats->comment("assigning directions on plateaus");
+  
+  labelFactory::reset();		/* we are relabeling now */
+  
+  statstr->seek(0);
+  platstr->seek(0);
+  fmem = getAvailableMemory();
+  long depressionCount=0;
+  long spillCount=0;
+  while((ae = statstr->read_item(&ps)) == AMI_ERROR_NO_ERROR) {
+    if(ps->size*sizeof(gridElement) > fmem) {
+      cerr << "WARNING: grid larger than memory (ignored)" << endl;
+    }
+    assert(ps->label != LABEL_NODATA);
+    if(ps->hasSpill) {
+      spillCount++;
+      grid *platGrid = new grid(ps->iMin, ps->jMin, ps->iMax, ps->jMax, 
+				ps->size, ps->label);
+      platGrid->load(*platstr);
+      platGrid->assignDirections(opt->d8 ? 1 : 0);
+      platGrid->save(*waterstr); /* this doesn't save labels */
+      delete platGrid;
+    } else {
+      /* depression - just give contiguous labels only */
+      depressionCount++;
+      cclabel_type label = labelFactory::getNewLabel();
+      for(int i=0; i<ps->size; i++) {
+	plateauType *pt;
+	platstr->read_item(&pt);
+	pt->cclabel = label;	/* assign new label */
+	waterType wt(*pt);		/* write it out */
+	ae = waterstr->write_item(wt);
+	assert(ae == AMI_ERROR_NO_ERROR);
+      }
+    }
+  }
+  *stats << "depression count = " << depressionCount << endl;
+  *stats << "spill count = " << spillCount << endl;
+  return depressionCount;
+}
+
+
+
+
+/* ********************************************************************** */
+/* assign directions to plateaus that have sinks;
+ * check that there are no depressions.
+ */
+void
+assignFinalDirections(AMI_STREAM<plateauStats> *statstr, 
+		      AMI_STREAM<plateauType> *platstr,
+		      AMI_STREAM<waterType> *waterstr) {
+  AMI_err ae;
+  plateauStats *ps;
+
+  stats->comment("assigning final directions");
+
+  statstr->seek(0);
+  platstr->seek(0);
+  while((ae = statstr->read_item(&ps)) == AMI_ERROR_NO_ERROR) {
+    
+    if(ps->hasSpill) {
+      grid *platGrid = new grid(ps->iMin, ps->jMin, ps->iMax, ps->jMax, 
+				ps->size, ps->label);
+      platGrid->load(*platstr);
+      platGrid->assignDirections(opt->d8 ? 1 : 0);
+      platGrid->save(*waterstr); /* this doesn't save labels */
+      delete platGrid;
+    } else {
+      /* could be legitimate */
+      cerr << "WARNING: depression detected: " << *ps << endl;
+      continue;
+    } 
+  }
+};
+
+
+
+/* ********************************************************************** */
+class directionElevationMerger {
+public:
+  waterGridType operator()(elevation_type el, direction_type dir, 
+			   waterType p) { 
+    /* check that no (boundary) nodata values got in here */
+    assert(el != nodataType::ELEVATION_BOUNDARY);
+    assert(!is_nodata(el));		/* p should be a valid grid cell */
+    return waterGridType(el, p.getDirection(), p.getLabel(), p.getDepth());
+  }
+  waterGridType operator()(elevation_type el, direction_type dir) {
+    waterGridType wg(el, dir);
+    if(el == nodataType::ELEVATION_BOUNDARY) { /* hack XXX (approved) */
+      wg.setLabel(LABEL_BOUNDARY); 
+    }
+    /* nodata => boundary or undef */
+    assert(!is_nodata(el) ||
+	   (wg.getLabel()==LABEL_BOUNDARY || wg.getLabel()==LABEL_UNDEF)); 
+	return wg;
+  }
+};
+
+
+
+/* ---------------------------------------------------------------------- */
+AMI_STREAM<waterGridType> *
+merge2waterGrid(AMI_STREAM<waterType> *unsortedWaterStr, 
+		AMI_STREAM<direction_type> *dirStr, 
+		AMI_STREAM<elevation_type> *elStr) {
+  AMI_STREAM<waterType> *waterStr;
+  
+  
+  FILL_DEBUG cout << "sort waterStr (by ij): ";
+  waterStr = sort(unsortedWaterStr, ijCmpWaterType());
+
+  FILL_SAVEALL printStream2Grid(waterStr, nrows, ncols, 
+				verbosedir("platlabels.asc"), printLabel());
+ 
+  AMI_STREAM<waterGridType> *mergedWaterStr = new AMI_STREAM<waterGridType>();
+  mergeStreamGridGrid(elStr, dirStr,
+		      nrows, ncols,
+		      waterStr,
+		      directionElevationMerger(),
+		      mergedWaterStr);
+  delete waterStr;
+  FILL_SAVEALL printGridStream(mergedWaterStr, nrows, ncols, 
+							   verbosedir("mergedlabels.asc"), printLabel());
+
+  assert(mergedWaterStr->stream_len());
+  return mergedWaterStr;
+}
+
+
+
+/* ---------------------------------------------------------------------- */
+void
+merge2waterBase(AMI_STREAM<waterType> *unsortedWaterStr, 
+		AMI_STREAM<direction_type> *dirStr,
+		AMI_STREAM<elevation_type> *elStr, 
+		AMI_STREAM<waterWindowBaseType> *merge) {
+  AMI_STREAM<waterType> *waterStr;
+  FILL_DEBUG cout << "sort waterStr (by ij): ";
+  waterStr = sort(unsortedWaterStr, ijCmpWaterType());
+  mergeStreamGridGrid(elStr, dirStr,
+		      nrows, ncols,
+		      waterStr,
+		      directionElevationMerger(),
+		      merge);
+  delete waterStr;
+}
+
+
+
+
+/* ---------------------------------------------------------------------- */
+/*
+ * merge 2 grids and a stream together to form a new grid. 
+ * str should be sorted in ij order 
+ */
+template<class T1, class T2, class T3, class T4, class FUN>
+void
+mergeStreamGridGrid(AMI_STREAM<T1> *grid1,
+		    AMI_STREAM<T2> *grid2,
+		    dimension_type rows, dimension_type cols, 
+		    AMI_STREAM<T3> *str,
+		    FUN fo,
+		    AMI_STREAM<T4> *outStream) {
+  T1 *t1p;
+  T2 *t2p;
+  T3 *t3p;
+  AMI_err aeUpd, ae;
+
+  
+  grid1->seek(0);
+  grid2->seek(0);
+  str->seek(0);
+  aeUpd = str->read_item(&t3p);
+  assert(aeUpd == AMI_ERROR_NO_ERROR || aeUpd == AMI_ERROR_END_OF_STREAM);
+
+  for(dimension_type row = 0; row < rows; row++) {
+    for(dimension_type col = 0; col < cols; col++) {
+      ae = grid1->read_item(&t1p);
+      assert(ae == AMI_ERROR_NO_ERROR);
+      ae = grid2->read_item(&t2p);
+      assert(ae == AMI_ERROR_NO_ERROR);
+      
+      T4 t4;
+      if(aeUpd == AMI_ERROR_NO_ERROR && t3p->i == row && t3p->j == col) {
+		/* cell present in stream */
+	t4 = fo(*t1p, *t2p, *t3p);
+	aeUpd = str->read_item(&t3p);
+	assert(aeUpd == AMI_ERROR_NO_ERROR || 
+	       aeUpd == AMI_ERROR_END_OF_STREAM);
+      } else {					
+		/* not in stream */
+		t4 = fo(*t1p, *t2p);
+      }
+      ae = outStream->write_item(t4);
+      assert(ae == AMI_ERROR_NO_ERROR);
+    }
+    /*assert(outStream->stream_len() == (row+1) * cols); */
+  }
+  assert(outStream->stream_len() == rows * cols);
+  return;
+}
+
+
+
+/* ---------------------------------------------------------------------- */
+/* make boundaryStr from labeledWater */
+AMI_STREAM<boundaryType> *
+findBoundariesMain(AMI_STREAM<labelElevType> *labeledWater) {
+  AMI_STREAM<boundaryType> *boundaryStr;
+  Rtimer rt;
+  
+  rt_start(rt);
+  boundaryStr = new AMI_STREAM<boundaryType>();
+  FILL_SAVEALL printGridStream(labeledWater, nrows, ncols,  
+			       verbosedir("labels.asc"), printLabel());
+  
+  findBoundaries(labeledWater, nrows, ncols, boundaryStr);
+  stats->recordLength("all boundaries", boundaryStr);
+  
+  FILL_SAVEALL {
+    FILL_DEBUG cout << "sort boundaryStr (by ij): ";
+    sort(&boundaryStr, ijCmpBoundaryType());
+    removeDuplicatesEx(&boundaryStr, ijCmpBoundaryType());
+    printStream2Grid(boundaryStr, nrows, ncols,
+		     verbosedir("boundary.asc"), boundaryType::print);
+  }
+  FILL_DEBUG cout << "sort boundaryStr (by wat label): ";
+  sort(&boundaryStr, waterCmpBoundaryType());
+  removeDuplicatesEx(&boundaryStr, boundaryCmpBoundaryType());
+  
+  rt_stop(rt);
+  stats->recordTime("generating boundaries", rt);
+  stats->recordLength("boundary stream", boundaryStr);
+  
+  /*if(GETOPT("veryfillverbose")) printStream(cout, boundaryStr);
+	SAVE_ON_OPTION(boundaryStr, "saveBoundaryStream");
+  */
+  return boundaryStr;
+}
+
+

Deleted: grass/trunk/raster/r.terraflow/filldepr.cc
===================================================================
--- grass/trunk/raster/r.terraflow/filldepr.cc	2011-09-29 23:35:42 UTC (rev 48561)
+++ grass/trunk/raster/r.terraflow/filldepr.cc	2011-09-29 23:36:57 UTC (rev 48562)
@@ -1,257 +0,0 @@
-/****************************************************************************
- * 
- *  MODULE:	r.terraflow
- *
- *  COPYRIGHT (C) 2007 Laura Toma
- *   
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *****************************************************************************/
-
-#include <assert.h>
-
-#include <grass/iostream/ami.h>
-#include "filldepr.h"
-#include "unionFind.h"
-#include "common.h"
-
-
-#define FLOOD_DEBUG if(0)
-
-/************************************************************/
-/* INPUT: stream containing the edgelist of watershed adjacency graph
-E={(u,v,h) | 0 <= u,v <= W-1}; W is the maximum number of watersheds
-(also counting the outside watershed 0)
-elevation_type* 
-
-h is the smallest height on the boundary between watershed u and
-watershed v;
-
-the outside face is assumed to be watershed number 0 
-
-E contains the edges between the watersheds on the boundary and the
-outside watershed 0; 
-
-E is sorted increasingly by (h,u,v)
-
-OUTPUT: allocate and returns an array raise[1..W-1], raise[i] is the
-height to which the watershed i must be raised in order to have a
-valid flow path to the outside watershed (raise[0] is 0) */
-/************************************************************/
-
-
-elevation_type* 
-fill_depression(AMI_STREAM<boundaryType> *boundaryStr,
-		cclabel_type maxWatersheds) {
-
-  stats->comment("----------",  opt->verbose);  
-  stats->comment("flooding depressions");
-  
-  /* find available memory */
-   size_t mem_avail = getAvailableMemory();
-  MM_manager.print();
-  
-  /* find how much memory filling depression uses */
-  size_t mem_usage = inmemory_fill_depression_mmusage(maxWatersheds);
-  
-  /* decide whether to run it in memory or not */
-  if (mem_avail > mem_usage) {
-    return inmemory_fill_depression(boundaryStr, maxWatersheds);
-  } else {
-    return ext_fill_depression(boundaryStr, maxWatersheds);
-  }
-}
-
-
-/************************************************************/ 
-elevation_type* 
-ext_fill_depression(AMI_STREAM<boundaryType> *boundaryStr,
-			 cclabel_type maxWatersheds) {
- 
-  fprintf(stderr, "fill_depressions: does not fit in memory\n");
-  G_fatal_error("not implemented yet");
-}
-
-
-
-/************************************************************/ 
-/* inside the function memory allocation is done with malloc/calloc
-and not with new; memory check should be done prior to this function
-to decide whether there's enough available memory to run it*/
-/************************************************************/ 
-elevation_type* 
-inmemory_fill_depression(AMI_STREAM<boundaryType> *boundaryStr,
-			 cclabel_type maxWatersheds) {
-  
-  assert(boundaryStr && maxWatersheds >= 0);
-
-  /*__________________________________________________________*/
-  /* initialize */
-  /*__________________________________________________________*/
-
-  /* allocate the raised-elevation array */
-  elevation_type* raise = new elevation_type [maxWatersheds];
-  assert(raise);
-  
-  /*allocate and initialize done; done[i] = true iff watershed i has
-    found a flow path to the outside; initially only outside watershed
-    is done */
-  int* done = (int*)calloc(maxWatersheds, sizeof(int));
-  assert(done);
-  done[LABEL_BOUNDARY] = 1;   
-  
-  /*allocate and initialize an union find structure; insert all
-    watersheds except for the outside watershed; the outside watershed
-    is not in the unionfind structure; */
-  unionFind<cclabel_type> unionf;
-  FLOOD_DEBUG printf("nb watersheds %d, bstream length %ld\n",
-    (int)maxWatersheds, (long)boundaryStr->stream_len());
-  
-  for (cclabel_type i=1; i< maxWatersheds; i++) {
-    FLOOD_DEBUG printf("makeset %d\n",i); 
-    unionf.makeSet(i);
-  }
-
-  /*__________________________________________________________*/
-  /*SCAN THE EDGES; invariant---watersheds adjacent to a 'done' watershed
-    become done */
-  /*__________________________________________________________*/
-  AMI_err ae;
-  boundaryType* nextedge;
-  elevation_type h;
-  cclabel_type u, v, ur, vr;
-  off_t nitems = boundaryStr->stream_len();
-  boundaryStr->seek(0);
-  for (size_t i=0; i< nitems; i++) {
-
-    /*read next edge*/
-    ae = boundaryStr->read_item(&nextedge);
-    assert(ae == AMI_ERROR_NO_ERROR);
-    u = nextedge->getLabel1();
-    v = nextedge->getLabel2();
-    h = nextedge->getElevation();
-    FLOOD_DEBUG {
-      printf("\nreading edge ((%d,%d),h=%d)\n",(int)u,(int)v,(int)h); 
-    }
-
-    /*find representatives;  LABEL_BOUNDARY means the outside watershed*/
-    (u==LABEL_BOUNDARY)? ur = LABEL_BOUNDARY: ur = unionf.findSet(u);
-    (v==LABEL_BOUNDARY)? vr = LABEL_BOUNDARY: vr = unionf.findSet(v);
-    FLOOD_DEBUG printf("%d is %d, %d is %d\n", u, ur, v, vr);
-
-    /*watersheds are done; just ignore it*/
-    if ((ur == vr) || (done[ur] && done[vr])) {
-      continue; 
-    }
-
-    /*union and raise colliding watersheds*/
-
-    /* if one of the watersheds is done, then raise the other one,
-    mark it as done too but do not union them; this handles also the
-    case of boundary watersheds; */
-    if (done[ur] || done[vr]) {
-      if (done[ur]) {
-	FLOOD_DEBUG printf("%d is done, %d raised to %f and done\n", 
-			   ur, vr, (double)h);
-	done[vr] = 1;
-	raise[vr] = h;
-      } else {
-	assert(done[vr]);
-	FLOOD_DEBUG printf("%d is done, %d raised to %f and done\n", 
-			   vr, ur, (double)h);
-	done[ur] = 1;
-	raise[ur] = h;
-      }
-      continue;
-    }
-    
-    /* if none of the  watersheds is done: union and raise them */
-    assert(!done[ur] && !done[vr] && ur>0 && vr>0);
-    FLOOD_DEBUG printf("union %d and %d,  raised to %f\n", ur, vr, (double)h);
-    raise[ur] = raise[vr] = h;
-    unionf.makeUnion(ur,vr);
-  }
-  
-#ifndef NDEBUG
-  for (cclabel_type i=1; i< maxWatersheds; i++) {
-    /* assert(done[unionf.findSet(i)]); sometimes this fails! */
-    if (!done[unionf.findSet(i)]) {
-      fprintf(stderr, "warning: watershed %d (R=%d) not done\n", 
-	     i, unionf.findSet(i));
-    }
-  }
-#endif
-  /* for each watershed find its raised elevation */
-  for (cclabel_type i=1; i< maxWatersheds; i++) {
-    raise[i] = raise[unionf.findSet(i)]; 
-  }
-  raise[LABEL_BOUNDARY] = 0;
-  /*__________________________________________________________*/
-  /*cleanup*/
-  /*__________________________________________________________*/
-  free(done);
-
-  return raise;
-}
-
-
-
-/************************************************************/
-/* returns the amount of mmemory allocated by
-   inmemory_fill_depression() */
-size_t
-inmemory_fill_depression_mmusage(cclabel_type maxWatersheds) {
-  
-  size_t mmusage = 0;
-
-  /*account for done array*/
-  mmusage += sizeof(int)*maxWatersheds;
-
-  /* account for raise array  */
-  mmusage  += sizeof(elevation_type)*maxWatersheds;
-
-  /*account for unionFind structure*/
-  unionFind<cclabel_type> foo;
-  mmusage += foo.mmusage(maxWatersheds);
-  
-  return mmusage;
-}
-
-
-/************************************************************/
-/* produce a new stream where each elevation e inside watershed i is
-   replaced with max(raise[i], e) */
-/************************************************************/
-void 
-commit_fill(AMI_STREAM<labelElevType>* labeledGrid, 
-	    elevation_type* raise, cclabel_type maxWatersheds, 
-	    AMI_STREAM<elevation_type>* filledGrid) {
-
-  labelElevType* pt;
-  elevation_type h;
-  
-  labeledGrid->seek(0);
-  while (labeledGrid->read_item(&pt) == AMI_ERROR_NO_ERROR) {
-	h = pt->getElevation(); 
-    if(is_nodata(h) || pt->getLabel() == LABEL_UNDEF) { 
-	  /*h = nodataType::ELEVATION_NODATA;	..unhack... XXX*/
-    } else {
-      assert(pt->getLabel() < maxWatersheds);
-      h = (pt->getElevation() < raise[pt->getLabel()])? 
-		raise[pt->getLabel()]: pt->getElevation();
-    }
-    filledGrid->write_item(h);
-  }
-  /* cout << "filled " << filledGrid->stream_len() << " points\n"; */
-}
-
-
-

Copied: grass/trunk/raster/r.terraflow/filldepr.cpp (from rev 48560, grass/trunk/raster/r.terraflow/filldepr.cc)
===================================================================
--- grass/trunk/raster/r.terraflow/filldepr.cpp	                        (rev 0)
+++ grass/trunk/raster/r.terraflow/filldepr.cpp	2011-09-29 23:36:57 UTC (rev 48562)
@@ -0,0 +1,257 @@
+/****************************************************************************
+ * 
+ *  MODULE:	r.terraflow
+ *
+ *  COPYRIGHT (C) 2007 Laura Toma
+ *   
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *****************************************************************************/
+
+#include <assert.h>
+
+#include <grass/iostream/ami.h>
+#include "filldepr.h"
+#include "unionFind.h"
+#include "common.h"
+
+
+#define FLOOD_DEBUG if(0)
+
+/************************************************************/
+/* INPUT: stream containing the edgelist of watershed adjacency graph
+E={(u,v,h) | 0 <= u,v <= W-1}; W is the maximum number of watersheds
+(also counting the outside watershed 0)
+elevation_type* 
+
+h is the smallest height on the boundary between watershed u and
+watershed v;
+
+the outside face is assumed to be watershed number 0 
+
+E contains the edges between the watersheds on the boundary and the
+outside watershed 0; 
+
+E is sorted increasingly by (h,u,v)
+
+OUTPUT: allocate and returns an array raise[1..W-1], raise[i] is the
+height to which the watershed i must be raised in order to have a
+valid flow path to the outside watershed (raise[0] is 0) */
+/************************************************************/
+
+
+elevation_type* 
+fill_depression(AMI_STREAM<boundaryType> *boundaryStr,
+		cclabel_type maxWatersheds) {
+
+  stats->comment("----------",  opt->verbose);  
+  stats->comment("flooding depressions");
+  
+  /* find available memory */
+   size_t mem_avail = getAvailableMemory();
+  MM_manager.print();
+  
+  /* find how much memory filling depression uses */
+  size_t mem_usage = inmemory_fill_depression_mmusage(maxWatersheds);
+  
+  /* decide whether to run it in memory or not */
+  if (mem_avail > mem_usage) {
+    return inmemory_fill_depression(boundaryStr, maxWatersheds);
+  } else {
+    return ext_fill_depression(boundaryStr, maxWatersheds);
+  }
+}
+
+
+/************************************************************/ 
+elevation_type* 
+ext_fill_depression(AMI_STREAM<boundaryType> *boundaryStr,
+			 cclabel_type maxWatersheds) {
+ 
+  fprintf(stderr, "fill_depressions: does not fit in memory\n");
+  G_fatal_error("not implemented yet");
+}
+
+
+
+/************************************************************/ 
+/* inside the function memory allocation is done with malloc/calloc
+and not with new; memory check should be done prior to this function
+to decide whether there's enough available memory to run it*/
+/************************************************************/ 
+elevation_type* 
+inmemory_fill_depression(AMI_STREAM<boundaryType> *boundaryStr,
+			 cclabel_type maxWatersheds) {
+  
+  assert(boundaryStr && maxWatersheds >= 0);
+
+  /*__________________________________________________________*/
+  /* initialize */
+  /*__________________________________________________________*/
+
+  /* allocate the raised-elevation array */
+  elevation_type* raise = new elevation_type [maxWatersheds];
+  assert(raise);
+  
+  /*allocate and initialize done; done[i] = true iff watershed i has
+    found a flow path to the outside; initially only outside watershed
+    is done */
+  int* done = (int*)calloc(maxWatersheds, sizeof(int));
+  assert(done);
+  done[LABEL_BOUNDARY] = 1;   
+  
+  /*allocate and initialize an union find structure; insert all
+    watersheds except for the outside watershed; the outside watershed
+    is not in the unionfind structure; */
+  unionFind<cclabel_type> unionf;
+  FLOOD_DEBUG printf("nb watersheds %d, bstream length %ld\n",
+    (int)maxWatersheds, (long)boundaryStr->stream_len());
+  
+  for (cclabel_type i=1; i< maxWatersheds; i++) {
+    FLOOD_DEBUG printf("makeset %d\n",i); 
+    unionf.makeSet(i);
+  }
+
+  /*__________________________________________________________*/
+  /*SCAN THE EDGES; invariant---watersheds adjacent to a 'done' watershed
+    become done */
+  /*__________________________________________________________*/
+  AMI_err ae;
+  boundaryType* nextedge;
+  elevation_type h;
+  cclabel_type u, v, ur, vr;
+  off_t nitems = boundaryStr->stream_len();
+  boundaryStr->seek(0);
+  for (size_t i=0; i< nitems; i++) {
+
+    /*read next edge*/
+    ae = boundaryStr->read_item(&nextedge);
+    assert(ae == AMI_ERROR_NO_ERROR);
+    u = nextedge->getLabel1();
+    v = nextedge->getLabel2();
+    h = nextedge->getElevation();
+    FLOOD_DEBUG {
+      printf("\nreading edge ((%d,%d),h=%d)\n",(int)u,(int)v,(int)h); 
+    }
+
+    /*find representatives;  LABEL_BOUNDARY means the outside watershed*/
+    (u==LABEL_BOUNDARY)? ur = LABEL_BOUNDARY: ur = unionf.findSet(u);
+    (v==LABEL_BOUNDARY)? vr = LABEL_BOUNDARY: vr = unionf.findSet(v);
+    FLOOD_DEBUG printf("%d is %d, %d is %d\n", u, ur, v, vr);
+
+    /*watersheds are done; just ignore it*/
+    if ((ur == vr) || (done[ur] && done[vr])) {
+      continue; 
+    }
+
+    /*union and raise colliding watersheds*/
+
+    /* if one of the watersheds is done, then raise the other one,
+    mark it as done too but do not union them; this handles also the
+    case of boundary watersheds; */
+    if (done[ur] || done[vr]) {
+      if (done[ur]) {
+	FLOOD_DEBUG printf("%d is done, %d raised to %f and done\n", 
+			   ur, vr, (double)h);
+	done[vr] = 1;
+	raise[vr] = h;
+      } else {
+	assert(done[vr]);
+	FLOOD_DEBUG printf("%d is done, %d raised to %f and done\n", 
+			   vr, ur, (double)h);
+	done[ur] = 1;
+	raise[ur] = h;
+      }
+      continue;
+    }
+    
+    /* if none of the  watersheds is done: union and raise them */
+    assert(!done[ur] && !done[vr] && ur>0 && vr>0);
+    FLOOD_DEBUG printf("union %d and %d,  raised to %f\n", ur, vr, (double)h);
+    raise[ur] = raise[vr] = h;
+    unionf.makeUnion(ur,vr);
+  }
+  
+#ifndef NDEBUG
+  for (cclabel_type i=1; i< maxWatersheds; i++) {
+    /* assert(done[unionf.findSet(i)]); sometimes this fails! */
+    if (!done[unionf.findSet(i)]) {
+      fprintf(stderr, "warning: watershed %d (R=%d) not done\n", 
+	     i, unionf.findSet(i));
+    }
+  }
+#endif
+  /* for each watershed find its raised elevation */
+  for (cclabel_type i=1; i< maxWatersheds; i++) {
+    raise[i] = raise[unionf.findSet(i)]; 
+  }
+  raise[LABEL_BOUNDARY] = 0;
+  /*__________________________________________________________*/
+  /*cleanup*/
+  /*__________________________________________________________*/
+  free(done);
+
+  return raise;
+}
+
+
+
+/************************************************************/
+/* returns the amount of mmemory allocated by
+   inmemory_fill_depression() */
+size_t
+inmemory_fill_depression_mmusage(cclabel_type maxWatersheds) {
+  
+  size_t mmusage = 0;
+
+  /*account for done array*/
+  mmusage += sizeof(int)*maxWatersheds;
+
+  /* account for raise array  */
+  mmusage  += sizeof(elevation_type)*maxWatersheds;
+
+  /*account for unionFind structure*/
+  unionFind<cclabel_type> foo;
+  mmusage += foo.mmusage(maxWatersheds);
+  
+  return mmusage;
+}
+
+
+/************************************************************/
+/* produce a new stream where each elevation e inside watershed i is
+   replaced with max(raise[i], e) */
+/************************************************************/
+void 
+commit_fill(AMI_STREAM<labelElevType>* labeledGrid, 
+	    elevation_type* raise, cclabel_type maxWatersheds, 
+	    AMI_STREAM<elevation_type>* filledGrid) {
+
+  labelElevType* pt;
+  elevation_type h;
+  
+  labeledGrid->seek(0);
+  while (labeledGrid->read_item(&pt) == AMI_ERROR_NO_ERROR) {
+	h = pt->getElevation(); 
+    if(is_nodata(h) || pt->getLabel() == LABEL_UNDEF) { 
+	  /*h = nodataType::ELEVATION_NODATA;	..unhack... XXX*/
+    } else {
+      assert(pt->getLabel() < maxWatersheds);
+      h = (pt->getElevation() < raise[pt->getLabel()])? 
+		raise[pt->getLabel()]: pt->getElevation();
+    }
+    filledGrid->write_item(h);
+  }
+  /* cout << "filled " << filledGrid->stream_len() << " points\n"; */
+}
+
+
+

Deleted: grass/trunk/raster/r.terraflow/flow.cc
===================================================================
--- grass/trunk/raster/r.terraflow/flow.cc	2011-09-29 23:35:42 UTC (rev 48561)
+++ grass/trunk/raster/r.terraflow/flow.cc	2011-09-29 23:36:57 UTC (rev 48562)
@@ -1,234 +0,0 @@
-/****************************************************************************
- * 
- *  MODULE:	r.terraflow
- *
- *  COPYRIGHT (C) 2007 Laura Toma
- *   
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *****************************************************************************/
-
-#include <time.h>
-#include <ctype.h>
-
-#include "flow.h"
-#include "sweep.h"
-#include "option.h"
-#include "common.h"
-#include "sortutils.h"
-#include "streamutils.h"
-#include "water.h"
-#include "3scan.h"
-
-/* globals in common.H
-
-extern statsRecorder *stats;       stats file 
-extern userOptions *opt;           command-line options 
-extern struct  Cell_head *region;  header of the region 
-extern dimension_type nrows, ncols;
-*/
-
-/* defined in this module */
-AMI_STREAM<sweepItem>* 
-fillstr2sweepstr(AMI_STREAM<waterWindowBaseType>* flowStream);
-
-
-
-
-
-/* ********************************************************************** */
-/* deletes fillStream */
-void
-computeFlowAccumulation(AMI_STREAM<waterWindowBaseType>* fillStream,
-			AMI_STREAM<sweepOutput> *& outstr) {
-  Rtimer rt, rtTotal;
-  AMI_STREAM<sweepItem> *sweepstr;
-
-  rt_start(rtTotal);
-  assert(fillStream && outstr == NULL);
-  stats->comment("------------------------------");
-  stats->comment("COMPUTING FLOW ACCUMULATION");
-  
-  { /* timestamp stats file and print memory */
-    time_t t = time(NULL);
-    char buf[BUFSIZ];
-    if(t == (time_t)-1) {
-      perror("time");
-      exit(1);
-    }
-#ifdef __MINGW32__
-    strcpy(buf, ctime(&t));
-#else
-    ctime_r(&t, buf);
-    buf[24] = '\0';
-#endif
-    stats->timestamp(buf);
-    *stats << endl;  
-    
-    size_t mm_size = (opt->mem  << 20); /* (in bytes) */
-    formatNumber(buf, mm_size);
-    *stats << "memory size: " << buf << " bytes\n";
-  }
-
-  /* create sweepstream using info from  fillStream  */
-  sweepstr = fillstr2sweepstr(fillStream); 
-  /* fillStream is deleted inside fillstr2sweepstr */
-
-  /* sweep and dump outputs into outStream; trustdir=1 */
-  outstr = sweep(sweepstr, opt->d8cut, 1);
-  assert(outstr->stream_len() == sweepstr->stream_len());
-  delete sweepstr;
-
-  /* sort output stream into a grid */
-  rt_start(rt);
-  stats->comment( "sorting sweep output stream");
-  stats->recordLength("output stream", outstr);
-  sort(&outstr, ijCmpSweepOutput());
-  rt_stop(rt);
-  stats->recordLength("output stream", outstr);
-  stats->recordTime("sorting output stream", rt);
-
-  rt_stop(rtTotal);
-  stats->recordTime("compute flow accumulation", rtTotal);
-
-#ifdef SAVE_ASCII
-  printStream2Grid(outstr, nrows, ncols, "flowaccumulation.asc", 
-		   printAccumulationAscii());
-  printStream2Grid(outstr, nrows, ncols, "tci.asc", 
-		   printTciAscii());
-#endif
-  return;
-}
-
-
-
-/****************************************************************/
-class flow_waterWindower {
- private:
-  AMI_STREAM<sweepItem> *sweep_str;
- public:
-  flow_waterWindower(AMI_STREAM<sweepItem> *str) :
-    sweep_str(str) {};
-  void processWindow(dimension_type i, dimension_type j, 
-                     waterWindowBaseType *a,
-                     waterWindowBaseType *b,
-                     waterWindowBaseType *c);
-};
-
-
-/****************************************************************/
-void
-flow_waterWindower::processWindow(dimension_type i, dimension_type j, 
-				  waterWindowBaseType *a,
-				  waterWindowBaseType *b,
-				  waterWindowBaseType *c) {
-  
-  elevation_type el1[3], el2[3], el3[3];
-  toporank_type ac1[3], ac2[3], ac3[3];
-  
-  if (is_nodata(b[1].el)) {
-    /*sweep_str does not include nodata */
-    return;
-  }
-  /*#ifdef  COMPRESSED_WINDOWS
-	sweepItem win = sweepItem(i, j, a, b, c);
-	#else
-  */
-  for (int k=0; k<3; k++) {
-    el1[k] = a[k].el;
-    ac1[k] = -a[k].depth; /*WEIRD */
-    el2[k] = b[k].el;
-    ac2[k] = -b[k].depth; /*WEIRD*/
-    el3[k] = c[k].el;
-    ac3[k] = -c[k].depth; /*WEIRD*/
-  }
-  /*
-	genericWindow<elevation_type> e_win(el);
-	genericWindow<toporank_type> a_win(ac);
-	sweepItem win = sweepItem(i, j, b[1].dir, e_win, a_win);
-  */
-  sweepItem win = sweepItem(i, j, b[1].dir, el1, el2, el3, ac1, ac2, ac3);
-  /* #endif */
- 
-  AMI_err ae = sweep_str->write_item(win);
-  assert(ae == AMI_ERROR_NO_ERROR);
-}
-
-
-
-/****************************************************************/
-void
-waterWindowBaseType2sweepItem(AMI_STREAM<waterWindowBaseType> *baseStr, 
-			      const dimension_type nrows, 
-			      const dimension_type ncols,
-			      const elevation_type nodata_value,
-			      AMI_STREAM<sweepItem> *sweep_str) {
-  flow_waterWindower winfo(sweep_str);
-  waterWindowBaseType nodata((elevation_type)nodata_value, 
-							 (direction_type)nodata_value, 
-							 DEPTH_INITIAL);
-  /* 
-	 assert(baseStr->stream_len() > 0);
-	 XXX - should check if it fits in memory technically don't need to
-	 give the template args, but seems to help the compiler 
-	 memoryScan(*baseStr, hdr, nodata,  winfo); 
-  */
-  memoryScan<waterWindowBaseType,flow_waterWindower>(*baseStr, nrows, ncols, nodata, winfo); 
-  
-}
-
-
-/****************************************************************/
-/* open fill's output stream and get all info from there; delete
-   fillStream */
-AMI_STREAM<sweepItem>*
-fillstr2sweepstr(AMI_STREAM<waterWindowBaseType>* fillStream) {
-
-  Rtimer rt;
-  AMI_STREAM<sweepItem> *sweepstr;  
-
-  rt_start(rt);
-  
-  stats->comment("creating sweep stream from fill output stream");
-  
-  assert(fillStream->stream_len() == nrows * ncols);
-  
-  /* create the sweep stream */
-  sweepstr = new AMI_STREAM<sweepItem>();
-  waterWindowBaseType2sweepItem(fillStream, nrows, ncols,
-				nodataType::ELEVATION_NODATA, sweepstr);
-  delete fillStream;
-
-  if (opt->verbose) {
-    fprintf(stderr,  "sweep stream size: %.2fMB",
-			(double)sweepstr->stream_len()*sizeof(sweepItem)/(1<<20));
-    fprintf(stderr,  " (%d items, item size=%d B\n ", 
-			(int)sweepstr->stream_len(), sizeof(sweepItem));;
-  }
-  stats->recordLength("sweep stream", sweepstr);
-  
-  /* sort sweep stream by (increasing) priority */
-  if (opt->verbose) {
-    fprintf(stderr, "sorting sweep stream (%.2fMB) in priority order\n", 
-	    (double)sweepstr->stream_len()*sizeof(sweepItem)/(1<<20));
-  }
-  stats->comment("sorting sweep stream");
-  sort(&sweepstr, PrioCmpSweepItem());
-
-  rt_stop(rt);
-  
-  stats->recordTime("create sweep stream", rt);
-  stats->recordLength("(sorted) sweep stream", sweepstr);
-
-  return sweepstr;
-}
-
-

Copied: grass/trunk/raster/r.terraflow/flow.cpp (from rev 48560, grass/trunk/raster/r.terraflow/flow.cc)
===================================================================
--- grass/trunk/raster/r.terraflow/flow.cpp	                        (rev 0)
+++ grass/trunk/raster/r.terraflow/flow.cpp	2011-09-29 23:36:57 UTC (rev 48562)
@@ -0,0 +1,234 @@
+/****************************************************************************
+ * 
+ *  MODULE:	r.terraflow
+ *
+ *  COPYRIGHT (C) 2007 Laura Toma
+ *   
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *****************************************************************************/
+
+#include <time.h>
+#include <ctype.h>
+
+#include "flow.h"
+#include "sweep.h"
+#include "option.h"
+#include "common.h"
+#include "sortutils.h"
+#include "streamutils.h"
+#include "water.h"
+#include "3scan.h"
+
+/* globals in common.H
+
+extern statsRecorder *stats;       stats file 
+extern userOptions *opt;           command-line options 
+extern struct  Cell_head *region;  header of the region 
+extern dimension_type nrows, ncols;
+*/
+
+/* defined in this module */
+AMI_STREAM<sweepItem>* 
+fillstr2sweepstr(AMI_STREAM<waterWindowBaseType>* flowStream);
+
+
+
+
+
+/* ********************************************************************** */
+/* deletes fillStream */
+void
+computeFlowAccumulation(AMI_STREAM<waterWindowBaseType>* fillStream,
+			AMI_STREAM<sweepOutput> *& outstr) {
+  Rtimer rt, rtTotal;
+  AMI_STREAM<sweepItem> *sweepstr;
+
+  rt_start(rtTotal);
+  assert(fillStream && outstr == NULL);
+  stats->comment("------------------------------");
+  stats->comment("COMPUTING FLOW ACCUMULATION");
+  
+  { /* timestamp stats file and print memory */
+    time_t t = time(NULL);
+    char buf[BUFSIZ];
+    if(t == (time_t)-1) {
+      perror("time");
+      exit(1);
+    }
+#ifdef __MINGW32__
+    strcpy(buf, ctime(&t));
+#else
+    ctime_r(&t, buf);
+    buf[24] = '\0';
+#endif
+    stats->timestamp(buf);
+    *stats << endl;  
+    
+    size_t mm_size = (opt->mem  << 20); /* (in bytes) */
+    formatNumber(buf, mm_size);
+    *stats << "memory size: " << buf << " bytes\n";
+  }
+
+  /* create sweepstream using info from  fillStream  */
+  sweepstr = fillstr2sweepstr(fillStream); 
+  /* fillStream is deleted inside fillstr2sweepstr */
+
+  /* sweep and dump outputs into outStream; trustdir=1 */
+  outstr = sweep(sweepstr, opt->d8cut, 1);
+  assert(outstr->stream_len() == sweepstr->stream_len());
+  delete sweepstr;
+
+  /* sort output stream into a grid */
+  rt_start(rt);
+  stats->comment( "sorting sweep output stream");
+  stats->recordLength("output stream", outstr);
+  sort(&outstr, ijCmpSweepOutput());
+  rt_stop(rt);
+  stats->recordLength("output stream", outstr);
+  stats->recordTime("sorting output stream", rt);
+
+  rt_stop(rtTotal);
+  stats->recordTime("compute flow accumulation", rtTotal);
+
+#ifdef SAVE_ASCII
+  printStream2Grid(outstr, nrows, ncols, "flowaccumulation.asc", 
+		   printAccumulationAscii());
+  printStream2Grid(outstr, nrows, ncols, "tci.asc", 
+		   printTciAscii());
+#endif
+  return;
+}
+
+
+
+/****************************************************************/
+class flow_waterWindower {
+ private:
+  AMI_STREAM<sweepItem> *sweep_str;
+ public:
+  flow_waterWindower(AMI_STREAM<sweepItem> *str) :
+    sweep_str(str) {};
+  void processWindow(dimension_type i, dimension_type j, 
+                     waterWindowBaseType *a,
+                     waterWindowBaseType *b,
+                     waterWindowBaseType *c);
+};
+
+
+/****************************************************************/
+void
+flow_waterWindower::processWindow(dimension_type i, dimension_type j, 
+				  waterWindowBaseType *a,
+				  waterWindowBaseType *b,
+				  waterWindowBaseType *c) {
+  
+  elevation_type el1[3], el2[3], el3[3];
+  toporank_type ac1[3], ac2[3], ac3[3];
+  
+  if (is_nodata(b[1].el)) {
+    /*sweep_str does not include nodata */
+    return;
+  }
+  /*#ifdef  COMPRESSED_WINDOWS
+	sweepItem win = sweepItem(i, j, a, b, c);
+	#else
+  */
+  for (int k=0; k<3; k++) {
+    el1[k] = a[k].el;
+    ac1[k] = -a[k].depth; /*WEIRD */
+    el2[k] = b[k].el;
+    ac2[k] = -b[k].depth; /*WEIRD*/
+    el3[k] = c[k].el;
+    ac3[k] = -c[k].depth; /*WEIRD*/
+  }
+  /*
+	genericWindow<elevation_type> e_win(el);
+	genericWindow<toporank_type> a_win(ac);
+	sweepItem win = sweepItem(i, j, b[1].dir, e_win, a_win);
+  */
+  sweepItem win = sweepItem(i, j, b[1].dir, el1, el2, el3, ac1, ac2, ac3);
+  /* #endif */
+ 
+  AMI_err ae = sweep_str->write_item(win);
+  assert(ae == AMI_ERROR_NO_ERROR);
+}
+
+
+
+/****************************************************************/
+void
+waterWindowBaseType2sweepItem(AMI_STREAM<waterWindowBaseType> *baseStr, 
+			      const dimension_type nrows, 
+			      const dimension_type ncols,
+			      const elevation_type nodata_value,
+			      AMI_STREAM<sweepItem> *sweep_str) {
+  flow_waterWindower winfo(sweep_str);
+  waterWindowBaseType nodata((elevation_type)nodata_value, 
+							 (direction_type)nodata_value, 
+							 DEPTH_INITIAL);
+  /* 
+	 assert(baseStr->stream_len() > 0);
+	 XXX - should check if it fits in memory technically don't need to
+	 give the template args, but seems to help the compiler 
+	 memoryScan(*baseStr, hdr, nodata,  winfo); 
+  */
+  memoryScan<waterWindowBaseType,flow_waterWindower>(*baseStr, nrows, ncols, nodata, winfo); 
+  
+}
+
+
+/****************************************************************/
+/* open fill's output stream and get all info from there; delete
+   fillStream */
+AMI_STREAM<sweepItem>*
+fillstr2sweepstr(AMI_STREAM<waterWindowBaseType>* fillStream) {
+
+  Rtimer rt;
+  AMI_STREAM<sweepItem> *sweepstr;  
+
+  rt_start(rt);
+  
+  stats->comment("creating sweep stream from fill output stream");
+  
+  assert(fillStream->stream_len() == nrows * ncols);
+  
+  /* create the sweep stream */
+  sweepstr = new AMI_STREAM<sweepItem>();
+  waterWindowBaseType2sweepItem(fillStream, nrows, ncols,
+				nodataType::ELEVATION_NODATA, sweepstr);
+  delete fillStream;
+
+  if (opt->verbose) {
+    fprintf(stderr,  "sweep stream size: %.2fMB",
+			(double)sweepstr->stream_len()*sizeof(sweepItem)/(1<<20));
+    fprintf(stderr,  " (%d items, item size=%d B\n ", 
+			(int)sweepstr->stream_len(), sizeof(sweepItem));;
+  }
+  stats->recordLength("sweep stream", sweepstr);
+  
+  /* sort sweep stream by (increasing) priority */
+  if (opt->verbose) {
+    fprintf(stderr, "sorting sweep stream (%.2fMB) in priority order\n", 
+	    (double)sweepstr->stream_len()*sizeof(sweepItem)/(1<<20));
+  }
+  stats->comment("sorting sweep stream");
+  sort(&sweepstr, PrioCmpSweepItem());
+
+  rt_stop(rt);
+  
+  stats->recordTime("create sweep stream", rt);
+  stats->recordLength("(sorted) sweep stream", sweepstr);
+
+  return sweepstr;
+}
+
+

Deleted: grass/trunk/raster/r.terraflow/genericWindow.cc
===================================================================
--- grass/trunk/raster/r.terraflow/genericWindow.cc	2011-09-29 23:35:42 UTC (rev 48561)
+++ grass/trunk/raster/r.terraflow/genericWindow.cc	2011-09-29 23:36:57 UTC (rev 48562)
@@ -1,40 +0,0 @@
-/****************************************************************************
- * 
- *  MODULE:	r.terraflow
- *
- *  COPYRIGHT (C) 2007 Laura Toma
- *   
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *****************************************************************************/
-
-#include "types.h"
-#include "genericWindow.h"
-
-/* ********************************************************************** */
-/* ********************************************************************** */
-
-/* if center of the wind is a pit, fill it */
-
-void 
-fillPit(ElevationWindow& win) {
-  /* find min of the 8 neighbors */
-  elevation_type min = win.get(0);
-  for (int k=1; k<9; k++) {
-    if (k != 4 && win.get(k) < min) {
-      min = win.get(k);
-    }
-  }
-  if (win.get(4) < min) {
-    win.set(4, min);
-  }
-};
-

Copied: grass/trunk/raster/r.terraflow/genericWindow.cpp (from rev 48560, grass/trunk/raster/r.terraflow/genericWindow.cc)
===================================================================
--- grass/trunk/raster/r.terraflow/genericWindow.cpp	                        (rev 0)
+++ grass/trunk/raster/r.terraflow/genericWindow.cpp	2011-09-29 23:36:57 UTC (rev 48562)
@@ -0,0 +1,40 @@
+/****************************************************************************
+ * 
+ *  MODULE:	r.terraflow
+ *
+ *  COPYRIGHT (C) 2007 Laura Toma
+ *   
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *****************************************************************************/
+
+#include "types.h"
+#include "genericWindow.h"
+
+/* ********************************************************************** */
+/* ********************************************************************** */
+
+/* if center of the wind is a pit, fill it */
+
+void 
+fillPit(ElevationWindow& win) {
+  /* find min of the 8 neighbors */
+  elevation_type min = win.get(0);
+  for (int k=1; k<9; k++) {
+    if (k != 4 && win.get(k) < min) {
+      min = win.get(k);
+    }
+  }
+  if (win.get(4) < min) {
+    win.set(4, min);
+  }
+};
+

Deleted: grass/trunk/raster/r.terraflow/grid.cc
===================================================================
--- grass/trunk/raster/r.terraflow/grid.cc	2011-09-29 23:35:42 UTC (rev 48561)
+++ grass/trunk/raster/r.terraflow/grid.cc	2011-09-29 23:36:57 UTC (rev 48562)
@@ -1,208 +0,0 @@
-/****************************************************************************
- * 
- *  MODULE:	r.terraflow
- *
- *  COPYRIGHT (C) 2007 Laura Toma
- *   
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *****************************************************************************/
-
-
-#include <string.h>
-#include <assert.h>
-#include "grid.h"
-#include "common.h"
-
-#define GRID_DEBUG if(0)
-
-/* leave a border of 1 cell around */
-grid::grid(dimension_type giMin, dimension_type gjMin,
-		   dimension_type iMax, dimension_type jMax,
-		   long gsize, cclabel_type glabel) : 
-  iMin(giMin-1), jMin(gjMin-1), label(glabel), size(gsize) {
-  width = jMax - jMin + 2;
-  height = iMax - iMin + 2;
-  assert(width*height*sizeof(gridElement) < getAvailableMemory());
-  data = new gridElement[width*height];
-  assert(data);
-  memset(data, 0, width*height*sizeof(gridElement));
-}
-
-
-
-grid::~grid() {
-  delete [] data;
-}
-
-
-
-void
-grid::load(AMI_STREAM<plateauType> &str) {
-  AMI_err ae;
-  plateauType *pt;
-
-  GRID_DEBUG cout << "loading grid" << endl;
-  for(int i=0; i<size; i++) {
-	ae = str.read_item(&pt);
-	assert(ae == AMI_ERROR_NO_ERROR);
-	/* cout << *pt << endl; */
-	assert(pt->valid);
-	assert(pt->cclabel == label);
-	dimension_type pti, ptj;
-	pti = pt->i - iMin;
-	ptj = pt->j - jMin;
-	gridElement *datap = data + pti * width + ptj;
-	datap->dir = pt->dir;
-	datap->depth = DEPTH_INITIAL;			/* initial depth */
-	datap->valid = 1;
-#ifdef KEEP_COORDS
-	datap->i = pt->i;
-	datap->j = pt->j;
-#endif
-	if(datap->dir) {			
-	  /* if it has a dir, it's on the boundary */
-	  boundaryQueue[0].enqueue(datap);
-	}
-  }
-}
-
-void
-grid::save(AMI_STREAM<waterType> &str) {
-  GRID_DEBUG cout << "saving grid" << endl;
-
-  for(dimension_type i=1; i<height-1; i++) {
-    gridElement *rowp = data + i * width;
-    for(dimension_type j=1; j<width-1; j++) {
-      gridElement *datap = rowp + j;
-      if(datap->valid) {
-		/* DONT save the label */
-	waterType wt(i+iMin, j+jMin, datap->dir, LABEL_UNDEF, datap->depth);
-	AMI_err ae = str.write_item(wt);
-	assert(ae == AMI_ERROR_NO_ERROR);
-      }
-    }
-  }
-}
-
-
-void 
-grid::print() {
-  cout << "    ";
-  for(int i=0; i<width; i++) {
-    printf("%2d", (jMin + i%10));
-  }
-  cout << endl;
-  for(int j=0; j<height; j++) {
-    printf("%3d ", j + iMin);
-    for(int i=0; i<width; i++) {
-      if(data[i+width*j].valid) {
-	cout << " " << directionSymbol(data[i+width*j].dir);
-      } else {
-	cout << " .";
-      }
-    }
-    cout << endl;
-  }
-}
-
-
-gridElement *
-grid::getNeighbour(gridElement *datap, int k) {
-  switch(k) {
-  case 0:
-    datap += 1;
-	break;
-  case 1:
-    datap += width + 1;
-    break;
-  case 2:
-    datap += width;
-    break;
-  case 3:
-    datap += width - 1;
-    break;
-  case 4:
-    datap -= 1;
-    break;
-  case 5:
-    datap -= (width + 1);
-    break;
-  case 6:
-    datap -= width;
-    break;
-  case 7:
-    datap -= (width - 1);
-    break;
-  default:
-    assert(0);
-    break;
-  }
-  return datap;
-}
-
-
-direction_type
-grid::getDirection(int k) {
-  return 1<<((k+4)%8);			/* converse direction */
-}
-
-
-
-
-void
-grid::assignDirections(int sfdmode) {
-  gridElement *datap, *np;
-  
-#ifdef KEEP_COORDS	
-  GRID_DEBUG cout << "points in queue=" << boundaryQueue[0].length() << endl;
-  GRID_DEBUG for(int i=0; i<boundaryQueue[0].length(); i++) {
-    boundaryQueue[0].peek(i,&datap);
-    cout << datap->i << "," << datap->j << endl;
-  }
-  GRID_DEBUG cout << endl;
-#endif
-  
-  int k1=0, k2=1;
-  while(!boundaryQueue[k1].isEmpty()) {
-    while(boundaryQueue[k1].dequeue(&datap)) {
-      /* should only find dominant if not on edge */
-      if(sfdmode && datap->depth > DEPTH_INITIAL) {
-	datap->dir = findDominant(datap->dir);
-      }
-#ifdef KEEP_COORDS
-      GRID_DEBUG cout << "(" << datap->i << "," << datap->j <<  ") "
-		 << "my direction is " << datap->dir;
-#endif
-      for(int i=0; i<8; i++) {
-	np = getNeighbour(datap, i);
-	if(np->valid) {
-	  if(!np->dir) {
-	    np->depth = datap->depth + 1;
-	    boundaryQueue[k2].enqueue(np);
-#ifdef KEEP_COORDS
-	    GRID_DEBUG cout << " pushing "  << "(" << np->i << "," << np->j <<  ")";
-#endif
-	  }
-	  if(np->depth == datap->depth + 1) { /* can only update ifin othr list */
-		np->dir |= getDirection(i);	/*  neighbor points to us */
-		/* if(!np->dir) np->dir |= getDirection(i); */
-	  }
-	}
-      }
-      GRID_DEBUG cout << endl;
-    }
-    k1 ^= 1;
-    k2 ^= 1;
-  }
-}
-
-

Copied: grass/trunk/raster/r.terraflow/grid.cpp (from rev 48560, grass/trunk/raster/r.terraflow/grid.cc)
===================================================================
--- grass/trunk/raster/r.terraflow/grid.cpp	                        (rev 0)
+++ grass/trunk/raster/r.terraflow/grid.cpp	2011-09-29 23:36:57 UTC (rev 48562)
@@ -0,0 +1,208 @@
+/****************************************************************************
+ * 
+ *  MODULE:	r.terraflow
+ *
+ *  COPYRIGHT (C) 2007 Laura Toma
+ *   
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *****************************************************************************/
+
+
+#include <string.h>
+#include <assert.h>
+#include "grid.h"
+#include "common.h"
+
+#define GRID_DEBUG if(0)
+
+/* leave a border of 1 cell around */
+grid::grid(dimension_type giMin, dimension_type gjMin,
+		   dimension_type iMax, dimension_type jMax,
+		   long gsize, cclabel_type glabel) : 
+  iMin(giMin-1), jMin(gjMin-1), label(glabel), size(gsize) {
+  width = jMax - jMin + 2;
+  height = iMax - iMin + 2;
+  assert(width*height*sizeof(gridElement) < getAvailableMemory());
+  data = new gridElement[width*height];
+  assert(data);
+  memset(data, 0, width*height*sizeof(gridElement));
+}
+
+
+
+grid::~grid() {
+  delete [] data;
+}
+
+
+
+void
+grid::load(AMI_STREAM<plateauType> &str) {
+  AMI_err ae;
+  plateauType *pt;
+
+  GRID_DEBUG cout << "loading grid" << endl;
+  for(int i=0; i<size; i++) {
+	ae = str.read_item(&pt);
+	assert(ae == AMI_ERROR_NO_ERROR);
+	/* cout << *pt << endl; */
+	assert(pt->valid);
+	assert(pt->cclabel == label);
+	dimension_type pti, ptj;
+	pti = pt->i - iMin;
+	ptj = pt->j - jMin;
+	gridElement *datap = data + pti * width + ptj;
+	datap->dir = pt->dir;
+	datap->depth = DEPTH_INITIAL;			/* initial depth */
+	datap->valid = 1;
+#ifdef KEEP_COORDS
+	datap->i = pt->i;
+	datap->j = pt->j;
+#endif
+	if(datap->dir) {			
+	  /* if it has a dir, it's on the boundary */
+	  boundaryQueue[0].enqueue(datap);
+	}
+  }
+}
+
+void
+grid::save(AMI_STREAM<waterType> &str) {
+  GRID_DEBUG cout << "saving grid" << endl;
+
+  for(dimension_type i=1; i<height-1; i++) {
+    gridElement *rowp = data + i * width;
+    for(dimension_type j=1; j<width-1; j++) {
+      gridElement *datap = rowp + j;
+      if(datap->valid) {
+		/* DONT save the label */
+	waterType wt(i+iMin, j+jMin, datap->dir, LABEL_UNDEF, datap->depth);
+	AMI_err ae = str.write_item(wt);
+	assert(ae == AMI_ERROR_NO_ERROR);
+      }
+    }
+  }
+}
+
+
+void 
+grid::print() {
+  cout << "    ";
+  for(int i=0; i<width; i++) {
+    printf("%2d", (jMin + i%10));
+  }
+  cout << endl;
+  for(int j=0; j<height; j++) {
+    printf("%3d ", j + iMin);
+    for(int i=0; i<width; i++) {
+      if(data[i+width*j].valid) {
+	cout << " " << directionSymbol(data[i+width*j].dir);
+      } else {
+	cout << " .";
+      }
+    }
+    cout << endl;
+  }
+}
+
+
+gridElement *
+grid::getNeighbour(gridElement *datap, int k) {
+  switch(k) {
+  case 0:
+    datap += 1;
+	break;
+  case 1:
+    datap += width + 1;
+    break;
+  case 2:
+    datap += width;
+    break;
+  case 3:
+    datap += width - 1;
+    break;
+  case 4:
+    datap -= 1;
+    break;
+  case 5:
+    datap -= (width + 1);
+    break;
+  case 6:
+    datap -= width;
+    break;
+  case 7:
+    datap -= (width - 1);
+    break;
+  default:
+    assert(0);
+    break;
+  }
+  return datap;
+}
+
+
+direction_type
+grid::getDirection(int k) {
+  return 1<<((k+4)%8);			/* converse direction */
+}
+
+
+
+
+void
+grid::assignDirections(int sfdmode) {
+  gridElement *datap, *np;
+  
+#ifdef KEEP_COORDS	
+  GRID_DEBUG cout << "points in queue=" << boundaryQueue[0].length() << endl;
+  GRID_DEBUG for(int i=0; i<boundaryQueue[0].length(); i++) {
+    boundaryQueue[0].peek(i,&datap);
+    cout << datap->i << "," << datap->j << endl;
+  }
+  GRID_DEBUG cout << endl;
+#endif
+  
+  int k1=0, k2=1;
+  while(!boundaryQueue[k1].isEmpty()) {
+    while(boundaryQueue[k1].dequeue(&datap)) {
+      /* should only find dominant if not on edge */
+      if(sfdmode && datap->depth > DEPTH_INITIAL) {
+	datap->dir = findDominant(datap->dir);
+      }
+#ifdef KEEP_COORDS
+      GRID_DEBUG cout << "(" << datap->i << "," << datap->j <<  ") "
+		 << "my direction is " << datap->dir;
+#endif
+      for(int i=0; i<8; i++) {
+	np = getNeighbour(datap, i);
+	if(np->valid) {
+	  if(!np->dir) {
+	    np->depth = datap->depth + 1;
+	    boundaryQueue[k2].enqueue(np);
+#ifdef KEEP_COORDS
+	    GRID_DEBUG cout << " pushing "  << "(" << np->i << "," << np->j <<  ")";
+#endif
+	  }
+	  if(np->depth == datap->depth + 1) { /* can only update ifin othr list */
+		np->dir |= getDirection(i);	/*  neighbor points to us */
+		/* if(!np->dir) np->dir |= getDirection(i); */
+	  }
+	}
+      }
+      GRID_DEBUG cout << endl;
+    }
+    k1 ^= 1;
+    k2 ^= 1;
+  }
+}
+
+

Deleted: grass/trunk/raster/r.terraflow/main.cc
===================================================================
--- grass/trunk/raster/r.terraflow/main.cc	2011-09-29 23:35:42 UTC (rev 48561)
+++ grass/trunk/raster/r.terraflow/main.cc	2011-09-29 23:36:57 UTC (rev 48562)
@@ -1,603 +0,0 @@
-/****************************************************************************
- * 
- *  MODULE:	r.terraflow
- *
- *  COPYRIGHT (C) 2007, 2010 Laura Toma
- *   
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *****************************************************************************/
- 
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <assert.h>
-#include <ctype.h>
-#include <time.h>
-#include <sys/types.h>
-
-#ifdef HAVE_STATVFS_H
-#include <sys/statvfs.h>
-#endif
-
-
-extern "C" {
-#include <grass/gis.h>
-#include <grass/raster.h>
-#include <grass/glocale.h>
-}
-
-#include "option.h"
-#include "common.h" /* declares the globals */
-#include "fill.h"
-#include "flow.h"
-#include "nodata.h"
-#include "grass2str.h"
-#include "water.h"
-#include "sortutils.h"
-
-
-/* globals: in common.H
-extern statsRecorder *stats; 
-extern userOptions* opt;    
-extern struct Cell_head region; 
-*/
-
-
-/* #define JUMP2FLOW */
-/* define it only if you want to skip the flow direction computation
-   and jump directly to computing flow accumulation; the flowstream
-   must exist in /STREAM_DIR/flowStream */
-
-
-/* ---------------------------------------------------------------------- */
-void 
-parse_args(int argc, char *argv[]) {
-
-  /* input elevation grid  */
-  struct Option *input_elev;
-  input_elev = G_define_standard_option(G_OPT_R_ELEV);
-
-  /* output filled elevation grid */
-  struct Option *output_elev;
-  output_elev = G_define_standard_option(G_OPT_R_OUTPUT);
-  output_elev->key        = "filled";
-  output_elev->description= _("Name for output filled (flooded) elevation raster map");
-  
- /* output direction  grid */
-  struct Option *output_dir;
-  output_dir = G_define_standard_option(G_OPT_R_OUTPUT);
-  output_dir->key        = "direction";
-  output_dir->description= _("Name for output flow direction raster map");
-
-  /* output sinkwatershed  grid */
-  struct Option *output_watershed;
-  output_watershed = G_define_standard_option(G_OPT_R_OUTPUT);
-  output_watershed->key        = "swatershed";
-  output_watershed->description= _("Name for output sink-watershed raster map");
-
-  /* output flow accumulation grid */
-  struct Option *output_accu;
-  output_accu = G_define_standard_option(G_OPT_R_OUTPUT);
-  output_accu->key        = "accumulation";
-  output_accu->description= _("Name for output flow accumulation raster map");
-
-#ifdef OUTPUT_TCI
-  struct Option *output_tci;
-  output_tci = G_define_standard_option(G_OPT_R_OUTPUT);
-  output_tci->key        = "tci";
-  output_tci->description=
-    _("Name for output topographic convergence index (tci) raster map");
-#endif
-
-  /* MFD/SFD flag */
-  struct Flag *sfd_flag;
-  sfd_flag = G_define_flag() ;
-  sfd_flag->key        = 's';
-  sfd_flag->description= _("SFD (D8) flow (default is MFD)");
-
-  /* D8CUT value*/
-  struct Option *d8cut;
-  d8cut = G_define_option();
-  d8cut->key  = "d8cut";
-  d8cut->type = TYPE_DOUBLE;
-  d8cut->required = NO;
-  d8cut->answer = G_store("infinity"); /* default value */
-  d8cut->label = _("Routing using SFD (D8) direction");
-  d8cut->description = 
-    _("If flow accumulation is larger than this value it is routed using "
-      "SFD (D8) direction (meaningfull only  for MFD flow)");
-  
-  /* main memory */
-  struct Option *mem;
-  mem = G_define_option() ;
-  mem->key         = "memory";
-  mem->type        = TYPE_INTEGER;
-  mem->required    = NO;
-  mem->answer      = G_store("300"); /* 300MB default value */
-  mem->description = _("Maximum runtime memory size (in MB)");
-
-  /* temporary STREAM path */
-  struct Option *streamdir;
-  streamdir = G_define_option() ;
-  streamdir->key        = "stream_dir";
-  streamdir->type       = TYPE_STRING;
-  streamdir->required   = NO;
-#ifdef __MINGW32__
-  streamdir->answer     = G_convert_dirseps_from_host(G_store(getenv("TEMP")));
-#else
-  streamdir->answer     = G_store("/var/tmp/");
-#endif
-  streamdir->description=
-     _("Directory to hold temporary files (they can be large)");
-
- /* stats file */
-  struct Option *stats_opt;
-  stats_opt = G_define_option() ;
-  stats_opt->key        = "stats";
-  stats_opt->type       = TYPE_STRING;
-  stats_opt->required   = NO;
-  stats_opt->description= _("Name of file containing runtime statistics");
-  stats_opt->answer     = G_store("stats.out");
-
-
-  if (G_parser(argc, argv)) {
-    exit (EXIT_FAILURE);
-  }
-  
-  /* ************************* */
-  assert(opt);
-  opt->elev_grid = input_elev->answer;
-  opt->filled_grid = output_elev->answer;
-  opt->dir_grid = output_dir->answer; 
-  opt->watershed_grid = output_watershed->answer;
-  opt->flowaccu_grid = output_accu->answer;
-#ifdef OUTPUT_TCI
-  opt->tci_grid = output_tci->answer;
-#endif
-
-  opt->d8 = sfd_flag->answer;
-  if (strcmp(d8cut->answer, "infinity") == 0) {
-    opt->d8cut = MAX_ACCU;
-  } else {
-    opt->d8cut = atof(d8cut->answer);
-  }
-
-  opt->mem = atoi(mem->answer);
-  opt->streamdir = streamdir->answer;
-
-  opt->verbose = G_verbose() == G_verbose_max();
-
-  opt->stats = stats_opt->answer;
-
-  /* somebody should delete the options */
-}
-
-
-/* ---------------------------------------------------------------------- */
-/* check compatibility of map header and region header */
-void check_header(char* cellname) {
-
-  const char *mapset;
-  mapset = G_find_raster(cellname, "");
-  if (mapset == NULL) {
-    G_fatal_error(_("Raster map <%s> not found"), cellname);
-  }
-  /* read cell header */
-  struct Cell_head cell_hd;
-  Rast_get_cellhd (cellname, mapset, &cell_hd);
-  
-  /* check compatibility with module region */
-  if (!((region->ew_res == cell_hd.ew_res)
-		&& (region->ns_res == cell_hd.ns_res))) {
-    G_fatal_error(_("cell file %s resolution differs from current region"),
-				  cellname);
-  } else {
-    if (opt->verbose) { 
-      G_message(_("cell %s header compatible with region header"),
-	      cellname);
-      fflush(stderr);
-    }
-  }
-
-
-  /* check type of input elevation raster and check if precision is lost */
-    RASTER_MAP_TYPE data_type;
-	data_type = Rast_map_type(opt->elev_grid, mapset);
-#ifdef ELEV_SHORT
-	G_verbose_message(_("Elevation stored as SHORT (%dB)"),
-		sizeof(elevation_type));
-	if (data_type == FCELL_TYPE) {
-	  G_warning(_("raster %s is of type FCELL_TYPE "
-			"--precision may be lost."), opt->elev_grid); 
-	}
-	if (data_type == DCELL_TYPE) {
-	  G_warning(_("raster %s is of type DCELL_TYPE "
-			"--precision may be lost."),  opt->elev_grid);
-	}
-#endif 
-#ifdef ELEV_FLOAT
-	G_verbose_message( _("Elevation stored as FLOAT (%dB)"), 
-			sizeof(elevation_type));
-	if (data_type == CELL_TYPE) {
-	  G_warning(_("raster %s is of type CELL_TYPE "
-		"--you should use r.terraflow.short"), opt->elev_grid); 
-	}
-	if (data_type == DCELL_TYPE) {
-	  G_warning(_("raster %s is of type DCELL_TYPE "
-		"--precision may be lost."),  opt->elev_grid);
-	}
-#endif
-	
-
-
-
-}
-
-/* ---------------------------------------------------------------------- */
-void check_args() {
-
-  /* check if filled elevation grid name is  valid */
-  if (G_legal_filename (opt->filled_grid) < 0) {
-    G_fatal_error(_("<%s> is an illegal file name"), opt->filled_grid);
-  }
-  /* check if output grid names are valid */
-  if (G_legal_filename (opt->dir_grid) < 0) {
-    G_fatal_error(_("<%s> is an illegal file name"), opt->dir_grid);
-  }
-  if (G_legal_filename (opt->filled_grid) < 0) {
-    G_fatal_error(_("<%s> is an illegal file name"), opt->filled_grid);
-  }
-  if (G_legal_filename (opt->flowaccu_grid) < 0) {
-    G_fatal_error(_("<%s> is an illegal file name"), opt->flowaccu_grid);
-  }
-  if (G_legal_filename (opt->watershed_grid) < 0) {
-    G_fatal_error(_("<%s> is an illegal file name"), opt->watershed_grid);
-  }
-#ifdef OUTPU_TCI
-  if (G_legal_filename (opt->tci_grid) < 0) {
-  G_fatal_error(_("<%s> is an illegal file name"), opt->tci_grid);
-  }
-#endif
-  
-  /* check compatibility with region */
-  check_header(opt->elev_grid);
-
-  /* what else ? */  
-
-
-}
-
-
-
-/* ---------------------------------------------------------------------- */
-void record_args(int argc, char **argv) {
-
-  time_t t = time(NULL);
-  char buf[BUFSIZ];
-  if(t == (time_t)-1) {
-    perror("time");
-    exit(1);
-  }
-
-#ifdef __MINGW32__
-  strcpy(buf, ctime(&t));
-#else
-  ctime_r(&t, buf);
-  buf[24] = '\0';
-#endif
-  stats->timestamp(buf);
-  
-  *stats << "Command Line: " << endl;
-  for(int i=0; i<argc; i++) {
-    *stats << argv[i] << " ";
-  }
-  *stats << endl;
-  
-  *stats << "input elevation grid: " << opt->elev_grid << "\n";
-  *stats << "output (flooded) elevations grid: " << opt->filled_grid << "\n";
-  *stats << "output directions grid: " << opt->dir_grid << "\n";
-  *stats << "output sinkwatershed grid: " << opt->watershed_grid << "\n";
-  *stats << "output accumulation grid: " << opt->flowaccu_grid << "\n";
-#ifdef OUTPUT_TCI
-  *stats <<  "output tci grid: " << opt->tci_grid << "\n";
-#endif
-  if (opt->d8) {
-    stats ->comment("SFD (D8) flow direction");
-  } else {
-    stats->comment("MFD flow direction");
-  }
-
-  sprintf(buf, "D8CUT=%f", opt->d8cut);
-  stats->comment(buf);
-
-  size_t mm_size = (size_t) opt->mem  << 20; /* (in bytes) */
-  char tmp[100];
-  formatNumber(tmp, mm_size);
-  sprintf(buf, "Memory size: %s bytes", tmp);
-  stats->comment(buf);
-}
-
-
-
-/* ---------------------------------------------------------------------- */
-void 
-setFlowAccuColorTable(char* cellname) {
-  struct Colors colors;
-  const char *mapset;
-  struct Range r;
-
-  mapset = G_find_raster(cellname, "");
-  if (mapset == NULL) {
-    G_fatal_error (_("Raster map <%s> not found"), cellname);
-  }
-  if (Rast_read_range(cellname, mapset, &r) == -1) {
-    G_fatal_error(_("cannot read range"));
-  }
-  /*fprintf(stderr, "%s range is: min=%d, max=%d\n", cellname, r.min, r.max);*/
-  int v[6];
-  v[0] = r.min;
-  v[1] = 5;
-  v[2] = 30;
-  v[3] = 100;
-  v[4] = 1000;
-  v[5] = r.max;
-  
-
-  Rast_init_colors(&colors);
- 
-  Rast_add_c_color_rule(&v[0], 255,255,255,  &v[1],     255,255,0, &colors);
-  Rast_add_c_color_rule(&v[1], 255,255,0,    &v[2],       0,255,255, &colors);
-  Rast_add_c_color_rule(&v[2],   0,255,255,  &v[3],       0,127,255, &colors);
-  Rast_add_c_color_rule(&v[3],   0,127,255,  &v[4],       0,0,255,   &colors);
-  Rast_add_c_color_rule(&v[4],   0,0,255,    &v[5],   0,0,0,     &colors);
-
-  Rast_write_colors(cellname, mapset, &colors);
-
-  Rast_free_colors(&colors);
-}
-
-
-/* ---------------------------------------------------------------------- */
-void
-setSinkWatershedColorTable(char* cellname) {
-  struct  Colors colors;
-  const char *mapset;
-  struct Range r;
-
-  mapset = G_find_raster(cellname, "");
-  if (mapset == NULL) {
-    G_fatal_error (_("Raster map <%s> not found"), cellname);
-  }
-  if (Rast_read_range(cellname, mapset, &r) == -1) {
-    G_fatal_error(_("cannot read range"));
-  }
-
-  Rast_init_colors(&colors);
-  Rast_make_random_colors(&colors, 1, r.max);
-
-  Rast_write_colors(cellname, mapset, &colors);
-
-  Rast_free_colors(&colors);
-}
-
-
-
-/* print the largest interm file that will be generated during
-   r.terraflow */
-void
-printMaxSortSize(long nodata_count) {
-  char buf[BUFSIZ];
-  long long  fillmaxsize = (long long)nrows*ncols*sizeof(waterWindowType);
-  long long  flowmaxsize = (long long)(nrows*ncols - nodata_count)*sizeof(sweepItem);
-  long long maxneed = (fillmaxsize > flowmaxsize) ? fillmaxsize: flowmaxsize;
-  maxneed =  2*maxneed; /* need 2*N to sort */
-
-  G_message( "total elements=%ld, nodata elements=%ld",
-		(long)nrows*ncols, nodata_count);
-  G_message( "largest temporary files: ");
-  G_message( "\t\t FILL: %s [%d elements, %dB each]",
-		  formatNumber(buf, fillmaxsize),
-		  nrows * ncols, sizeof(waterWindowType));
-  G_message( "\t\t FLOW: %s [%ld elements, %dB each]",
-		  formatNumber(buf, flowmaxsize),
-		  (long)(nrows * ncols - nodata_count), sizeof(sweepItem));
-  G_message( "Will need at least %s space available in %s",
-		  formatNumber(buf, maxneed),  	  /* need 2*N to sort */
-		  getenv(STREAM_TMPDIR));
-
-#ifdef HAVE_STATVFS_H
-  fprintf(stderr, "Checking current space in %s: ", getenv(STREAM_TMPDIR));
-  struct statvfs statbuf;
-  statvfs(getenv(STREAM_TMPDIR), &statbuf);
-
-  float avail = statbuf.f_bsize*statbuf.f_bavail;
-  fprintf(stderr, "available %ld blocks x %ldB = %.0fB",
-		  (long)statbuf.f_bavail, statbuf.f_bsize, avail);
-  if (avail > maxneed) {
-	fprintf(stderr, ". OK.\n");
-  } else {
-	fprintf(stderr, ". Not enough space available.\n");
-	exit(EXIT_FAILURE);
-  }
-#endif
-}
-
-
-
-/* ---------------------------------------------------------------------- */
-int
-main(int argc, char *argv[]) {
-  struct GModule *module;
-  Rtimer rtTotal;    
-  char buf[BUFSIZ];
-
-  /* initialize GIS library */
-  G_gisinit(argv[0]);
-
- 
-  module = G_define_module();
-#ifdef ELEV_SHORT
-  module->description = _("Flow computation for massive grids (integer version).");
-#endif
-#ifdef ELEV_FLOAT
-  module->description = _("Flow computation for massive grids (float version).");
-#endif
-  G_add_keyword(_("raster"));
-  G_add_keyword(_("hydrology"));
-
-  /* read user options; fill in global <opt> */  
-  opt = (userOptions*)malloc(sizeof(userOptions));
-  assert(opt);
-  
-  region = (struct Cell_head*)malloc(sizeof(struct Cell_head));
-  assert(region);
-
-  parse_args(argc, argv);
-
-  /* get the current region and dimensions */  
-  G_get_set_window(region);
-
-  check_args();
-
-  int nr = Rast_window_rows();
-  int nc = Rast_window_cols();
-  if ((nr > dimension_type_max) || (nc > dimension_type_max)) {
-    G_fatal_error(_("[nrows=%d, ncols=%d] dimension_type overflow -- "
-	"change dimension_type and recompile"), nr, nc);
-  } else {
-    nrows = (dimension_type)nr;
-    ncols = (dimension_type)nc;
-  }
-
-  G_verbose_message( _("Region size is %d x %d"), nrows, ncols);
- 
-  /* check STREAM path (the place where intermediate STREAMs are placed) */
-  sprintf(buf, "%s=%s",STREAM_TMPDIR, opt->streamdir);
-  /* don't pass an automatic variable; putenv() isn't guaranteed to make a copy */
-  putenv(G_store(buf));
-  if (getenv(STREAM_TMPDIR) == NULL) {
-    fprintf(stderr, "%s:", STREAM_TMPDIR);
-    G_fatal_error("not set");
-  } else {
-    fprintf(stderr, "STREAM temporary files in %s  ",
-	    getenv(STREAM_TMPDIR)); 
-	fprintf(stderr, "(THESE INTERMEDIATE STREAMS WILL NOT BE DELETED IN CASE OF ABNORMAL TERMINATION OF THE PROGRAM. TO SAVE SPACE PLEASE DELETE THESE FILES MANUALLY!)\n");
-  }
-  
-  /* open the stats file */
-  stats = new statsRecorder(opt->stats);
-  record_args(argc, argv);
-  {
-    char buf[BUFSIZ];
-    long grid_size = nrows * ncols;
-    *stats << "region size = " <<  formatNumber(buf, grid_size) << " elts "
-	   << "(" << nrows << " rows x " << ncols << " cols)\n";
-
-    stats->flush();
-  }
-
-  /* set up STREAM memory manager */
-  size_t mm_size = (size_t) opt->mem << 20; /* opt->mem is in MB */
-  MM_manager.set_memory_limit(mm_size);
-  if (opt->verbose) {
-	MM_manager.warn_memory_limit();
-  } else {
-	MM_manager.ignore_memory_limit();
-  }
-  MM_manager.print_limit_mode();
-
-
-  /* initialize nodata */
-  nodataType::init();
-  *stats << "internal nodata value: " << nodataType::ELEVATION_NODATA << endl;
-   
-  /* start timing -- after parse_args, which are interactive */
-  rt_start(rtTotal);
-
-#ifndef JUMP2FLOW 
-  /* read elevation into a stream */
-  AMI_STREAM<elevation_type> *elstr=NULL;
-  long nodata_count;
-  elstr = cell2stream<elevation_type>(opt->elev_grid, elevation_type_max,
-									  &nodata_count);
-  /* print the largest interm file that will be generated */
-  printMaxSortSize(nodata_count);
-  
-
-  /* -------------------------------------------------- */
-  /* compute flow direction and filled elevation (and watersheds) */
-  AMI_STREAM<direction_type> *dirstr=NULL;
-  AMI_STREAM<elevation_type> *filledstr=NULL;
-  AMI_STREAM<waterWindowBaseType> *flowStream=NULL;
-  AMI_STREAM<labelElevType> *labeledWater = NULL;
-
-  flowStream=computeFlowDirections(elstr, filledstr, dirstr, labeledWater);
-
-  delete elstr;
-
-  /* write streams to GRASS raster maps */
-  stream2_CELL(dirstr, nrows, ncols, opt->dir_grid);
-  delete dirstr;
-#ifdef ELEV_SHORT
-  stream2_CELL(filledstr, nrows, ncols, opt->filled_grid);
-#else
-  stream2_CELL(filledstr, nrows, ncols, opt->filled_grid,true);
-#endif
-  delete filledstr; 
-
-  stream2_CELL(labeledWater, nrows, ncols, labelElevTypePrintLabel(), 
-			   opt->watershed_grid);
-  setSinkWatershedColorTable(opt->watershed_grid);
-  delete labeledWater;
-  
-#else 
-  AMI_STREAM<waterWindowBaseType> *flowStream;
-  char path[GPATH_MAX];
-
-  sprintf(path, "%s/flowStream", streamdir->answer);
-  flowStream = new AMI_STREAM<waterWindowBaseType>(path);
-  fprintf(stderr, "flowStream opened: len=%d\n", flowStream->stream_len());
-  fprintf(stderr, "jumping to flow accumulation computation\n");
-#endif
-  
-  /* -------------------------------------------------- */
-  /* compute flow accumulation (and tci) */
-  AMI_STREAM<sweepOutput> *outstr=NULL;
-  
-  computeFlowAccumulation(flowStream, outstr);
-  /* delete flowStream -- deleted inside */
-
-  /* write output stream to GRASS raster maps */
-#ifdef OUTPUT_TCI
-  stream2_FCELL(outstr, nrows, ncols, printAccumulation(), printTci(),
-		opt->flowaccu_grid, opt->tci_grid);
-#else 
-  stream2_FCELL(outstr, nrows, ncols, printAccumulation(), opt->flowaccu_grid);
-#endif
-
-  setFlowAccuColorTable(opt->flowaccu_grid);
-
-  delete outstr;
-  
-  rt_stop(rtTotal);
-  stats->recordTime("Total running time: ", rtTotal);
-  stats->timestamp("end");
-
-  G_done_msg(" ");
-  
-  /* free the globals */
-  free(region);
-  free(opt);
-  delete stats;
-
-  return 0;
-}

Copied: grass/trunk/raster/r.terraflow/main.cpp (from rev 48560, grass/trunk/raster/r.terraflow/main.cc)
===================================================================
--- grass/trunk/raster/r.terraflow/main.cpp	                        (rev 0)
+++ grass/trunk/raster/r.terraflow/main.cpp	2011-09-29 23:36:57 UTC (rev 48562)
@@ -0,0 +1,603 @@
+/****************************************************************************
+ * 
+ *  MODULE:	r.terraflow
+ *
+ *  COPYRIGHT (C) 2007, 2010 Laura Toma
+ *   
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *****************************************************************************/
+ 
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <ctype.h>
+#include <time.h>
+#include <sys/types.h>
+
+#ifdef HAVE_STATVFS_H
+#include <sys/statvfs.h>
+#endif
+
+
+extern "C" {
+#include <grass/gis.h>
+#include <grass/raster.h>
+#include <grass/glocale.h>
+}
+
+#include "option.h"
+#include "common.h" /* declares the globals */
+#include "fill.h"
+#include "flow.h"
+#include "nodata.h"
+#include "grass2str.h"
+#include "water.h"
+#include "sortutils.h"
+
+
+/* globals: in common.H
+extern statsRecorder *stats; 
+extern userOptions* opt;    
+extern struct Cell_head region; 
+*/
+
+
+/* #define JUMP2FLOW */
+/* define it only if you want to skip the flow direction computation
+   and jump directly to computing flow accumulation; the flowstream
+   must exist in /STREAM_DIR/flowStream */
+
+
+/* ---------------------------------------------------------------------- */
+void 
+parse_args(int argc, char *argv[]) {
+
+  /* input elevation grid  */
+  struct Option *input_elev;
+  input_elev = G_define_standard_option(G_OPT_R_ELEV);
+
+  /* output filled elevation grid */
+  struct Option *output_elev;
+  output_elev = G_define_standard_option(G_OPT_R_OUTPUT);
+  output_elev->key        = "filled";
+  output_elev->description= _("Name for output filled (flooded) elevation raster map");
+  
+ /* output direction  grid */
+  struct Option *output_dir;
+  output_dir = G_define_standard_option(G_OPT_R_OUTPUT);
+  output_dir->key        = "direction";
+  output_dir->description= _("Name for output flow direction raster map");
+
+  /* output sinkwatershed  grid */
+  struct Option *output_watershed;
+  output_watershed = G_define_standard_option(G_OPT_R_OUTPUT);
+  output_watershed->key        = "swatershed";
+  output_watershed->description= _("Name for output sink-watershed raster map");
+
+  /* output flow accumulation grid */
+  struct Option *output_accu;
+  output_accu = G_define_standard_option(G_OPT_R_OUTPUT);
+  output_accu->key        = "accumulation";
+  output_accu->description= _("Name for output flow accumulation raster map");
+
+#ifdef OUTPUT_TCI
+  struct Option *output_tci;
+  output_tci = G_define_standard_option(G_OPT_R_OUTPUT);
+  output_tci->key        = "tci";
+  output_tci->description=
+    _("Name for output topographic convergence index (tci) raster map");
+#endif
+
+  /* MFD/SFD flag */
+  struct Flag *sfd_flag;
+  sfd_flag = G_define_flag() ;
+  sfd_flag->key        = 's';
+  sfd_flag->description= _("SFD (D8) flow (default is MFD)");
+
+  /* D8CUT value*/
+  struct Option *d8cut;
+  d8cut = G_define_option();
+  d8cut->key  = "d8cut";
+  d8cut->type = TYPE_DOUBLE;
+  d8cut->required = NO;
+  d8cut->answer = G_store("infinity"); /* default value */
+  d8cut->label = _("Routing using SFD (D8) direction");
+  d8cut->description = 
+    _("If flow accumulation is larger than this value it is routed using "
+      "SFD (D8) direction (meaningfull only  for MFD flow)");
+  
+  /* main memory */
+  struct Option *mem;
+  mem = G_define_option() ;
+  mem->key         = "memory";
+  mem->type        = TYPE_INTEGER;
+  mem->required    = NO;
+  mem->answer      = G_store("300"); /* 300MB default value */
+  mem->description = _("Maximum runtime memory size (in MB)");
+
+  /* temporary STREAM path */
+  struct Option *streamdir;
+  streamdir = G_define_option() ;
+  streamdir->key        = "stream_dir";
+  streamdir->type       = TYPE_STRING;
+  streamdir->required   = NO;
+#ifdef __MINGW32__
+  streamdir->answer     = G_convert_dirseps_from_host(G_store(getenv("TEMP")));
+#else
+  streamdir->answer     = G_store("/var/tmp/");
+#endif
+  streamdir->description=
+     _("Directory to hold temporary files (they can be large)");
+
+ /* stats file */
+  struct Option *stats_opt;
+  stats_opt = G_define_option() ;
+  stats_opt->key        = "stats";
+  stats_opt->type       = TYPE_STRING;
+  stats_opt->required   = NO;
+  stats_opt->description= _("Name of file containing runtime statistics");
+  stats_opt->answer     = G_store("stats.out");
+
+
+  if (G_parser(argc, argv)) {
+    exit (EXIT_FAILURE);
+  }
+  
+  /* ************************* */
+  assert(opt);
+  opt->elev_grid = input_elev->answer;
+  opt->filled_grid = output_elev->answer;
+  opt->dir_grid = output_dir->answer; 
+  opt->watershed_grid = output_watershed->answer;
+  opt->flowaccu_grid = output_accu->answer;
+#ifdef OUTPUT_TCI
+  opt->tci_grid = output_tci->answer;
+#endif
+
+  opt->d8 = sfd_flag->answer;
+  if (strcmp(d8cut->answer, "infinity") == 0) {
+    opt->d8cut = MAX_ACCU;
+  } else {
+    opt->d8cut = atof(d8cut->answer);
+  }
+
+  opt->mem = atoi(mem->answer);
+  opt->streamdir = streamdir->answer;
+
+  opt->verbose = G_verbose() == G_verbose_max();
+
+  opt->stats = stats_opt->answer;
+
+  /* somebody should delete the options */
+}
+
+
+/* ---------------------------------------------------------------------- */
+/* check compatibility of map header and region header */
+void check_header(char* cellname) {
+
+  const char *mapset;
+  mapset = G_find_raster(cellname, "");
+  if (mapset == NULL) {
+    G_fatal_error(_("Raster map <%s> not found"), cellname);
+  }
+  /* read cell header */
+  struct Cell_head cell_hd;
+  Rast_get_cellhd (cellname, mapset, &cell_hd);
+  
+  /* check compatibility with module region */
+  if (!((region->ew_res == cell_hd.ew_res)
+		&& (region->ns_res == cell_hd.ns_res))) {
+    G_fatal_error(_("cell file %s resolution differs from current region"),
+				  cellname);
+  } else {
+    if (opt->verbose) { 
+      G_message(_("cell %s header compatible with region header"),
+	      cellname);
+      fflush(stderr);
+    }
+  }
+
+
+  /* check type of input elevation raster and check if precision is lost */
+    RASTER_MAP_TYPE data_type;
+	data_type = Rast_map_type(opt->elev_grid, mapset);
+#ifdef ELEV_SHORT
+	G_verbose_message(_("Elevation stored as SHORT (%dB)"),
+		sizeof(elevation_type));
+	if (data_type == FCELL_TYPE) {
+	  G_warning(_("raster %s is of type FCELL_TYPE "
+			"--precision may be lost."), opt->elev_grid); 
+	}
+	if (data_type == DCELL_TYPE) {
+	  G_warning(_("raster %s is of type DCELL_TYPE "
+			"--precision may be lost."),  opt->elev_grid);
+	}
+#endif 
+#ifdef ELEV_FLOAT
+	G_verbose_message( _("Elevation stored as FLOAT (%dB)"), 
+			sizeof(elevation_type));
+	if (data_type == CELL_TYPE) {
+	  G_warning(_("raster %s is of type CELL_TYPE "
+		"--you should use r.terraflow.short"), opt->elev_grid); 
+	}
+	if (data_type == DCELL_TYPE) {
+	  G_warning(_("raster %s is of type DCELL_TYPE "
+		"--precision may be lost."),  opt->elev_grid);
+	}
+#endif
+	
+
+
+
+}
+
+/* ---------------------------------------------------------------------- */
+void check_args() {
+
+  /* check if filled elevation grid name is  valid */
+  if (G_legal_filename (opt->filled_grid) < 0) {
+    G_fatal_error(_("<%s> is an illegal file name"), opt->filled_grid);
+  }
+  /* check if output grid names are valid */
+  if (G_legal_filename (opt->dir_grid) < 0) {
+    G_fatal_error(_("<%s> is an illegal file name"), opt->dir_grid);
+  }
+  if (G_legal_filename (opt->filled_grid) < 0) {
+    G_fatal_error(_("<%s> is an illegal file name"), opt->filled_grid);
+  }
+  if (G_legal_filename (opt->flowaccu_grid) < 0) {
+    G_fatal_error(_("<%s> is an illegal file name"), opt->flowaccu_grid);
+  }
+  if (G_legal_filename (opt->watershed_grid) < 0) {
+    G_fatal_error(_("<%s> is an illegal file name"), opt->watershed_grid);
+  }
+#ifdef OUTPU_TCI
+  if (G_legal_filename (opt->tci_grid) < 0) {
+  G_fatal_error(_("<%s> is an illegal file name"), opt->tci_grid);
+  }
+#endif
+  
+  /* check compatibility with region */
+  check_header(opt->elev_grid);
+
+  /* what else ? */  
+
+
+}
+
+
+
+/* ---------------------------------------------------------------------- */
+void record_args(int argc, char **argv) {
+
+  time_t t = time(NULL);
+  char buf[BUFSIZ];
+  if(t == (time_t)-1) {
+    perror("time");
+    exit(1);
+  }
+
+#ifdef __MINGW32__
+  strcpy(buf, ctime(&t));
+#else
+  ctime_r(&t, buf);
+  buf[24] = '\0';
+#endif
+  stats->timestamp(buf);
+  
+  *stats << "Command Line: " << endl;
+  for(int i=0; i<argc; i++) {
+    *stats << argv[i] << " ";
+  }
+  *stats << endl;
+  
+  *stats << "input elevation grid: " << opt->elev_grid << "\n";
+  *stats << "output (flooded) elevations grid: " << opt->filled_grid << "\n";
+  *stats << "output directions grid: " << opt->dir_grid << "\n";
+  *stats << "output sinkwatershed grid: " << opt->watershed_grid << "\n";
+  *stats << "output accumulation grid: " << opt->flowaccu_grid << "\n";
+#ifdef OUTPUT_TCI
+  *stats <<  "output tci grid: " << opt->tci_grid << "\n";
+#endif
+  if (opt->d8) {
+    stats ->comment("SFD (D8) flow direction");
+  } else {
+    stats->comment("MFD flow direction");
+  }
+
+  sprintf(buf, "D8CUT=%f", opt->d8cut);
+  stats->comment(buf);
+
+  size_t mm_size = (size_t) opt->mem  << 20; /* (in bytes) */
+  char tmp[100];
+  formatNumber(tmp, mm_size);
+  sprintf(buf, "Memory size: %s bytes", tmp);
+  stats->comment(buf);
+}
+
+
+
+/* ---------------------------------------------------------------------- */
+void 
+setFlowAccuColorTable(char* cellname) {
+  struct Colors colors;
+  const char *mapset;
+  struct Range r;
+
+  mapset = G_find_raster(cellname, "");
+  if (mapset == NULL) {
+    G_fatal_error (_("Raster map <%s> not found"), cellname);
+  }
+  if (Rast_read_range(cellname, mapset, &r) == -1) {
+    G_fatal_error(_("cannot read range"));
+  }
+  /*fprintf(stderr, "%s range is: min=%d, max=%d\n", cellname, r.min, r.max);*/
+  int v[6];
+  v[0] = r.min;
+  v[1] = 5;
+  v[2] = 30;
+  v[3] = 100;
+  v[4] = 1000;
+  v[5] = r.max;
+  
+
+  Rast_init_colors(&colors);
+ 
+  Rast_add_c_color_rule(&v[0], 255,255,255,  &v[1],     255,255,0, &colors);
+  Rast_add_c_color_rule(&v[1], 255,255,0,    &v[2],       0,255,255, &colors);
+  Rast_add_c_color_rule(&v[2],   0,255,255,  &v[3],       0,127,255, &colors);
+  Rast_add_c_color_rule(&v[3],   0,127,255,  &v[4],       0,0,255,   &colors);
+  Rast_add_c_color_rule(&v[4],   0,0,255,    &v[5],   0,0,0,     &colors);
+
+  Rast_write_colors(cellname, mapset, &colors);
+
+  Rast_free_colors(&colors);
+}
+
+
+/* ---------------------------------------------------------------------- */
+void
+setSinkWatershedColorTable(char* cellname) {
+  struct  Colors colors;
+  const char *mapset;
+  struct Range r;
+
+  mapset = G_find_raster(cellname, "");
+  if (mapset == NULL) {
+    G_fatal_error (_("Raster map <%s> not found"), cellname);
+  }
+  if (Rast_read_range(cellname, mapset, &r) == -1) {
+    G_fatal_error(_("cannot read range"));
+  }
+
+  Rast_init_colors(&colors);
+  Rast_make_random_colors(&colors, 1, r.max);
+
+  Rast_write_colors(cellname, mapset, &colors);
+
+  Rast_free_colors(&colors);
+}
+
+
+
+/* print the largest interm file that will be generated during
+   r.terraflow */
+void
+printMaxSortSize(long nodata_count) {
+  char buf[BUFSIZ];
+  long long  fillmaxsize = (long long)nrows*ncols*sizeof(waterWindowType);
+  long long  flowmaxsize = (long long)(nrows*ncols - nodata_count)*sizeof(sweepItem);
+  long long maxneed = (fillmaxsize > flowmaxsize) ? fillmaxsize: flowmaxsize;
+  maxneed =  2*maxneed; /* need 2*N to sort */
+
+  G_message( "total elements=%ld, nodata elements=%ld",
+		(long)nrows*ncols, nodata_count);
+  G_message( "largest temporary files: ");
+  G_message( "\t\t FILL: %s [%d elements, %dB each]",
+		  formatNumber(buf, fillmaxsize),
+		  nrows * ncols, sizeof(waterWindowType));
+  G_message( "\t\t FLOW: %s [%ld elements, %dB each]",
+		  formatNumber(buf, flowmaxsize),
+		  (long)(nrows * ncols - nodata_count), sizeof(sweepItem));
+  G_message( "Will need at least %s space available in %s",
+		  formatNumber(buf, maxneed),  	  /* need 2*N to sort */
+		  getenv(STREAM_TMPDIR));
+
+#ifdef HAVE_STATVFS_H
+  fprintf(stderr, "Checking current space in %s: ", getenv(STREAM_TMPDIR));
+  struct statvfs statbuf;
+  statvfs(getenv(STREAM_TMPDIR), &statbuf);
+
+  float avail = statbuf.f_bsize*statbuf.f_bavail;
+  fprintf(stderr, "available %ld blocks x %ldB = %.0fB",
+		  (long)statbuf.f_bavail, statbuf.f_bsize, avail);
+  if (avail > maxneed) {
+	fprintf(stderr, ". OK.\n");
+  } else {
+	fprintf(stderr, ". Not enough space available.\n");
+	exit(EXIT_FAILURE);
+  }
+#endif
+}
+
+
+
+/* ---------------------------------------------------------------------- */
+int
+main(int argc, char *argv[]) {
+  struct GModule *module;
+  Rtimer rtTotal;    
+  char buf[BUFSIZ];
+
+  /* initialize GIS library */
+  G_gisinit(argv[0]);
+
+ 
+  module = G_define_module();
+#ifdef ELEV_SHORT
+  module->description = _("Flow computation for massive grids (integer version).");
+#endif
+#ifdef ELEV_FLOAT
+  module->description = _("Flow computation for massive grids (float version).");
+#endif
+  G_add_keyword(_("raster"));
+  G_add_keyword(_("hydrology"));
+
+  /* read user options; fill in global <opt> */  
+  opt = (userOptions*)malloc(sizeof(userOptions));
+  assert(opt);
+  
+  region = (struct Cell_head*)malloc(sizeof(struct Cell_head));
+  assert(region);
+
+  parse_args(argc, argv);
+
+  /* get the current region and dimensions */  
+  G_get_set_window(region);
+
+  check_args();
+
+  int nr = Rast_window_rows();
+  int nc = Rast_window_cols();
+  if ((nr > dimension_type_max) || (nc > dimension_type_max)) {
+    G_fatal_error(_("[nrows=%d, ncols=%d] dimension_type overflow -- "
+	"change dimension_type and recompile"), nr, nc);
+  } else {
+    nrows = (dimension_type)nr;
+    ncols = (dimension_type)nc;
+  }
+
+  G_verbose_message( _("Region size is %d x %d"), nrows, ncols);
+ 
+  /* check STREAM path (the place where intermediate STREAMs are placed) */
+  sprintf(buf, "%s=%s",STREAM_TMPDIR, opt->streamdir);
+  /* don't pass an automatic variable; putenv() isn't guaranteed to make a copy */
+  putenv(G_store(buf));
+  if (getenv(STREAM_TMPDIR) == NULL) {
+    fprintf(stderr, "%s:", STREAM_TMPDIR);
+    G_fatal_error("not set");
+  } else {
+    fprintf(stderr, "STREAM temporary files in %s  ",
+	    getenv(STREAM_TMPDIR)); 
+	fprintf(stderr, "(THESE INTERMEDIATE STREAMS WILL NOT BE DELETED IN CASE OF ABNORMAL TERMINATION OF THE PROGRAM. TO SAVE SPACE PLEASE DELETE THESE FILES MANUALLY!)\n");
+  }
+  
+  /* open the stats file */
+  stats = new statsRecorder(opt->stats);
+  record_args(argc, argv);
+  {
+    char buf[BUFSIZ];
+    long grid_size = nrows * ncols;
+    *stats << "region size = " <<  formatNumber(buf, grid_size) << " elts "
+	   << "(" << nrows << " rows x " << ncols << " cols)\n";
+
+    stats->flush();
+  }
+
+  /* set up STREAM memory manager */
+  size_t mm_size = (size_t) opt->mem << 20; /* opt->mem is in MB */
+  MM_manager.set_memory_limit(mm_size);
+  if (opt->verbose) {
+	MM_manager.warn_memory_limit();
+  } else {
+	MM_manager.ignore_memory_limit();
+  }
+  MM_manager.print_limit_mode();
+
+
+  /* initialize nodata */
+  nodataType::init();
+  *stats << "internal nodata value: " << nodataType::ELEVATION_NODATA << endl;
+   
+  /* start timing -- after parse_args, which are interactive */
+  rt_start(rtTotal);
+
+#ifndef JUMP2FLOW 
+  /* read elevation into a stream */
+  AMI_STREAM<elevation_type> *elstr=NULL;
+  long nodata_count;
+  elstr = cell2stream<elevation_type>(opt->elev_grid, elevation_type_max,
+									  &nodata_count);
+  /* print the largest interm file that will be generated */
+  printMaxSortSize(nodata_count);
+  
+
+  /* -------------------------------------------------- */
+  /* compute flow direction and filled elevation (and watersheds) */
+  AMI_STREAM<direction_type> *dirstr=NULL;
+  AMI_STREAM<elevation_type> *filledstr=NULL;
+  AMI_STREAM<waterWindowBaseType> *flowStream=NULL;
+  AMI_STREAM<labelElevType> *labeledWater = NULL;
+
+  flowStream=computeFlowDirections(elstr, filledstr, dirstr, labeledWater);
+
+  delete elstr;
+
+  /* write streams to GRASS raster maps */
+  stream2_CELL(dirstr, nrows, ncols, opt->dir_grid);
+  delete dirstr;
+#ifdef ELEV_SHORT
+  stream2_CELL(filledstr, nrows, ncols, opt->filled_grid);
+#else
+  stream2_CELL(filledstr, nrows, ncols, opt->filled_grid,true);
+#endif
+  delete filledstr; 
+
+  stream2_CELL(labeledWater, nrows, ncols, labelElevTypePrintLabel(), 
+			   opt->watershed_grid);
+  setSinkWatershedColorTable(opt->watershed_grid);
+  delete labeledWater;
+  
+#else 
+  AMI_STREAM<waterWindowBaseType> *flowStream;
+  char path[GPATH_MAX];
+
+  sprintf(path, "%s/flowStream", streamdir->answer);
+  flowStream = new AMI_STREAM<waterWindowBaseType>(path);
+  fprintf(stderr, "flowStream opened: len=%d\n", flowStream->stream_len());
+  fprintf(stderr, "jumping to flow accumulation computation\n");
+#endif
+  
+  /* -------------------------------------------------- */
+  /* compute flow accumulation (and tci) */
+  AMI_STREAM<sweepOutput> *outstr=NULL;
+  
+  computeFlowAccumulation(flowStream, outstr);
+  /* delete flowStream -- deleted inside */
+
+  /* write output stream to GRASS raster maps */
+#ifdef OUTPUT_TCI
+  stream2_FCELL(outstr, nrows, ncols, printAccumulation(), printTci(),
+		opt->flowaccu_grid, opt->tci_grid);
+#else 
+  stream2_FCELL(outstr, nrows, ncols, printAccumulation(), opt->flowaccu_grid);
+#endif
+
+  setFlowAccuColorTable(opt->flowaccu_grid);
+
+  delete outstr;
+  
+  rt_stop(rtTotal);
+  stats->recordTime("Total running time: ", rtTotal);
+  stats->timestamp("end");
+
+  G_done_msg(" ");
+  
+  /* free the globals */
+  free(region);
+  free(opt);
+  delete stats;
+
+  return 0;
+}

Deleted: grass/trunk/raster/r.terraflow/nodata.cc
===================================================================
--- grass/trunk/raster/r.terraflow/nodata.cc	2011-09-29 23:35:42 UTC (rev 48561)
+++ grass/trunk/raster/r.terraflow/nodata.cc	2011-09-29 23:36:57 UTC (rev 48562)
@@ -1,349 +0,0 @@
-/****************************************************************************
- * 
- *  MODULE:	r.terraflow
- *
- *  COPYRIGHT (C) 2007 Laura Toma
- *   
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *****************************************************************************/
-
-#include <grass/iostream/ami.h> 
-
-#include "nodata.h"
-#include "common.h"
-#include "sortutils.h"
-#include "streamutils.h"
-#include "ccforest.h"
-#include "3scan.h"
-/* #include "plateau.h" */
-#include "genericWindow.h"
-
-/* globals 
-extern statsRecorder *stats;     
-extern userOptions *opt;         
-extern struct  Cell_head *region; 
-extern dimension_type nrows, ncols;
-*/
-
-
-#define NODATA_DEBUG if(0)
-
-
-
-/* ********************************************************************** */
-
-elevation_type nodataType::ELEVATION_BOUNDARY;
-elevation_type nodataType::ELEVATION_NODATA;
-
-/* ********************************************************************** */
-
-/*  int */
-/*  is_nodata(elevation_type el) { */
-/*    return (el == nodataType::ELEVATION_BOUNDARY || */
-/*  		  el == nodataType::ELEVATION_NODATA); */
-/*  } */
-
-
-int
-is_nodata(short x) {
-  return (x == nodataType::ELEVATION_BOUNDARY ||
-		  x == nodataType::ELEVATION_NODATA);
-}
-int
-is_nodata(int x) {
-  return (x == nodataType::ELEVATION_BOUNDARY ||
-		  x == nodataType::ELEVATION_NODATA);
-}
-
-
-int
-is_nodata(float x) {
-  return (x == nodataType::ELEVATION_BOUNDARY ||
-		  x == nodataType::ELEVATION_NODATA);
-}
-
-
-int
-is_void(elevation_type el) {
-  return (el == nodataType::ELEVATION_NODATA);
-}
-
-
-
-
-/* ********************************************************************** */
-class detectEdgeNodata {
-private:
-  AMI_STREAM<nodataType> *nodataStream;
-  AMI_STREAM<elevation_type> *elevStream;
-  queue<nodataType> *nodataQueue;
-  ccforest<cclabel_type> colTree;
-  nodataType *getNodataForward(dimension_type i, dimension_type j,
-			       dimension_type nr, dimension_type n);
-  const dimension_type nr, nc;
-  const elevation_type nodata;
-public:
-  detectEdgeNodata(const dimension_type nrows, const dimension_type nc, 
-		   const elevation_type nodata);
-  ~detectEdgeNodata();
-  void processWindow(dimension_type row, dimension_type col,
-		     elevation_type &point,
-		     elevation_type *a,
-		     elevation_type *b,
-		     elevation_type *c);
-  void generateNodata(AMI_STREAM<elevation_type> &elstr);
-  void relabelNodata();
-  AMI_STREAM<elevation_type> *merge();
-  AMI_STREAM<nodataType> *getNodata() { return nodataStream; }
-};
-
-
-/* ********************************************************************** */
-detectEdgeNodata::detectEdgeNodata(const dimension_type nrows, 
-				   const dimension_type ncols, 
-				   const elevation_type gnodata)
-  : nr(nrows), nc(ncols), nodata(gnodata)  {
-  nodataStream = new AMI_STREAM<nodataType>();
-  elevStream = new AMI_STREAM<elevation_type>();
-}
-
-
-/* ********************************************************************** */
-detectEdgeNodata::~detectEdgeNodata() {
-  delete nodataStream;
-  delete elevStream;
-}
-
-
-/* ********************************************************************** */
-/* return a pointer to three plateauType structures, starting at
-   location i,j. caller should check valid field in returned
-   structs. */
-nodataType *
-detectEdgeNodata::getNodataForward(dimension_type i, dimension_type j,
-				   dimension_type nr, dimension_type nc) {
-  bool ok;
-  static nodataType ptarr[3];	/* return value */
-  nodataType pt;
-
-  ok = nodataQueue->peek(0, &pt);
-  while(ok && (pt.i < i || (pt.i==i && pt.j<j))) {
-	nodataQueue->dequeue(&pt);		/* past needing this, so remove */
-	ok = nodataQueue->peek(0, &pt);
-  }
-  if(ok && pt.i == i && pt.j == j) {
-	nodataQueue->dequeue(&pt);		/* found it, so remove */
-	ptarr[0] = pt;
-  } else {
-	ptarr[0].invalidate();
-  }
-  /* locate next two, if possible */
-  for(int kk=0,k=1; k<3; k++) {
-	ok = nodataQueue->peek(kk, &pt);
-	if(ok && pt.i == i && pt.j == j+k) {
-	  ptarr[k] = pt;
-	  kk++; /* found something, so need to peek further forward */
-	} else {
-	  ptarr[k].invalidate();
-	}
-  }
-
-#if(0)
-  cout << "request at " << i << "," << j << " returns: " <<
-	ptarr[0] << ptarr[1] << ptarr[2] << endl;
-  nodataQueue->peek(0, &pt);
-  cout << "queue length = " << nodataQueue->length() 
-	   << "; head=" << pt << endl;
-#endif
-  return ptarr;  
-}
-
-
-/* ********************************************************************** */
-
-
-void
-detectEdgeNodata::processWindow(dimension_type row, dimension_type col,
-				elevation_type &point,
-				elevation_type *a,
-				elevation_type *b,
-				elevation_type *c) {
-  AMI_err ae;
-  static nodataType prevCell;	/* cell on left (gets initialized) */
-
-  assert(row>=0);
-  assert(col>=0);
-
-  /* create window and write out */
-  ElevationWindow win(a, b, c);
-  fillPit(win);          /* fill pit in window */
-  ae = elevStream->write_item(win.get());
-  assert(ae == AMI_ERROR_NO_ERROR);
-
-
-  /* only interested in nodata in this pass */
-  if(win.get() !=  nodata) {
-	prevCell.label = LABEL_UNDEF;
-	return;
-  }
-
-  if(col == 0) prevCell.label = LABEL_UNDEF; /* no left cell */
-
-  /* now check for continuing plateaus */
-  nodataType *ptarr = 
-	getNodataForward(row-1, col-1, nr, nc);
-
-  /* make sure we use boundary label if appropriate */
-  cclabel_type crtlabel;
-  crtlabel = (IS_BOUNDARY(row,col,nr, nc) ? LABEL_BOUNDARY : LABEL_UNDEF);
-
-  for(int i=0; i<4; i++) {
-	if(win.get(i) != win.get()) continue; /* only interesting if same elev */
-
-	/* determine label for cell */
-	cclabel_type label = LABEL_UNDEF;
-	if(i<3) {
-	  if(ptarr[i].valid) label = ptarr[i].label;
-	} else {
-	  if(prevCell.valid) label = prevCell.label;
-	}
-
-	/* check for collisions */
-	if(label != LABEL_UNDEF) {
-	  if (crtlabel == LABEL_UNDEF) {
-		crtlabel = label;
-	  } else if(crtlabel != label) {  		  /* collision!! */
-		/* pick smaller label, but prefer nodata */
-		if(crtlabel==LABEL_BOUNDARY || crtlabel<label) { 
-		  colTree.insert(crtlabel, label);
-		} else {
-		  colTree.insert(label, crtlabel);
-		  crtlabel = label;
-		}
-	  }
-	}
-  }
-  
-  /* assign label if required */
-  if(crtlabel == LABEL_UNDEF) {
-	crtlabel = labelFactory::getNewLabel();
-  }
-
-  /* write this plateau point to the plateau stream */
-  nodataType pt;
-  prevCell = pt = nodataType(row, col, crtlabel);
-  nodataQueue->enqueue(pt);
-
-  /* NODATA_DEBUG *stats << "inserting " << pt << endl; */
-  
-  nodataStream->write_item(pt);	/*  save to file for later use */
-}
-
-
-/* ********************************************************************** */
-void
-detectEdgeNodata::generateNodata(AMI_STREAM<elevation_type> &elstr) { 
-  nodataQueue = new queue<nodataType>();
-  scan3(elstr, nr, nc, nodata, *this); 
-  delete nodataQueue;
-}
-
-
-/* ********************************************************************** */
-/* collapse labels; remove nodata regions */
-void
-detectEdgeNodata::relabelNodata() {
-  AMI_err ae;
-  nodataType *pt;
-
-  /* sort by label */
-  NODATA_DEBUG *stats << "sort nodataStream (by nodata label): ";
-  AMI_STREAM<nodataType> *sortedInStream;
-  sortedInStream = sort(nodataStream, labelCmpNodataType());
-  delete nodataStream;
-
-  nodataStream = new AMI_STREAM<nodataType>();
-
-  while((ae = sortedInStream->read_item(&pt)) == AMI_ERROR_NO_ERROR) {
-	cclabel_type root = colTree.findNextRoot(pt->label);
-	assert(root <= pt->label);
-	pt->label = root;
-	ae = nodataStream->write_item(*pt);
-	assert(ae == AMI_ERROR_NO_ERROR);
-  }
-
-  delete sortedInStream;
-}
-
-
-/* ********************************************************************** */
-AMI_STREAM<elevation_type> *
-detectEdgeNodata::merge() {
- 
-  NODATA_DEBUG *stats << "sort  nodataStream (by ij): ";
-  /*
-    AMI_STREAM<nodataType> *sortedNodataStream;
-    sortedNodataStream = sort(nodataStream, ijCmpNodataType());
-    delete nodataStream;
-    nodataStream=sortedNodataStream;
-  */
-  sort(&nodataStream, ijCmpNodataType());
-  //note: nodataStream gets deleted and replaced with the sorted stream
-
-  AMI_STREAM<elevation_type> *mergeStr;
-  mergeStr = mergeStream2Grid(elevStream, nrows, ncols, 
-			      nodataStream, nodataType2elevation_type());
-
-  return mergeStr;
-}
-
-
-
-/* ********************************************************************** */
-/* ********************************************************************** */
-
-
-AMI_STREAM<elevation_type> *
-classifyNodata(AMI_STREAM<elevation_type> *elstr) {
-  Rtimer rt;
-
-  rt_start(rt);
-  stats->comment("finding nodata", opt->verbose);
-  detectEdgeNodata md(nrows, ncols, nodataType::ELEVATION_NODATA);
-  md.generateNodata(*elstr);
-  *stats << "nodata stream length = " << md.getNodata()->stream_len() << endl;
-  {
-    char * foo;
-    md.getNodata()->name(&foo); 
-    *stats << "nodata stream name: " << foo << endl;
-  }
-  rt_stop(rt);
-  stats->recordTime("classifyNodata::generate nodata", rt);
-
-  rt_start(rt);
-  stats->comment("relabeling nodata",  opt->verbose);
-  md.relabelNodata();  /* re-assign labels (combine connected plateaus) */
-  rt_stop(rt);
-  stats->recordTime("classifyNodata::relabeling",  rt);
-  
-  rt_start(rt);
-  stats->comment("merging relabeled grid",  opt->verbose);
-  AMI_STREAM<elevation_type> *mergeStr;
-  mergeStr = md.merge();
-  rt_stop(rt);
-  stats->recordTime("classifyNodata::merge",  rt);
-
-  mergeStr->seek(0);
-  return mergeStr;
-}
-
-/* ********************************************************************** */

Copied: grass/trunk/raster/r.terraflow/nodata.cpp (from rev 48560, grass/trunk/raster/r.terraflow/nodata.cc)
===================================================================
--- grass/trunk/raster/r.terraflow/nodata.cpp	                        (rev 0)
+++ grass/trunk/raster/r.terraflow/nodata.cpp	2011-09-29 23:36:57 UTC (rev 48562)
@@ -0,0 +1,349 @@
+/****************************************************************************
+ * 
+ *  MODULE:	r.terraflow
+ *
+ *  COPYRIGHT (C) 2007 Laura Toma
+ *   
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *****************************************************************************/
+
+#include <grass/iostream/ami.h> 
+
+#include "nodata.h"
+#include "common.h"
+#include "sortutils.h"
+#include "streamutils.h"
+#include "ccforest.h"
+#include "3scan.h"
+/* #include "plateau.h" */
+#include "genericWindow.h"
+
+/* globals 
+extern statsRecorder *stats;     
+extern userOptions *opt;         
+extern struct  Cell_head *region; 
+extern dimension_type nrows, ncols;
+*/
+
+
+#define NODATA_DEBUG if(0)
+
+
+
+/* ********************************************************************** */
+
+elevation_type nodataType::ELEVATION_BOUNDARY;
+elevation_type nodataType::ELEVATION_NODATA;
+
+/* ********************************************************************** */
+
+/*  int */
+/*  is_nodata(elevation_type el) { */
+/*    return (el == nodataType::ELEVATION_BOUNDARY || */
+/*  		  el == nodataType::ELEVATION_NODATA); */
+/*  } */
+
+
+int
+is_nodata(short x) {
+  return (x == nodataType::ELEVATION_BOUNDARY ||
+		  x == nodataType::ELEVATION_NODATA);
+}
+int
+is_nodata(int x) {
+  return (x == nodataType::ELEVATION_BOUNDARY ||
+		  x == nodataType::ELEVATION_NODATA);
+}
+
+
+int
+is_nodata(float x) {
+  return (x == nodataType::ELEVATION_BOUNDARY ||
+		  x == nodataType::ELEVATION_NODATA);
+}
+
+
+int
+is_void(elevation_type el) {
+  return (el == nodataType::ELEVATION_NODATA);
+}
+
+
+
+
+/* ********************************************************************** */
+class detectEdgeNodata {
+private:
+  AMI_STREAM<nodataType> *nodataStream;
+  AMI_STREAM<elevation_type> *elevStream;
+  queue<nodataType> *nodataQueue;
+  ccforest<cclabel_type> colTree;
+  nodataType *getNodataForward(dimension_type i, dimension_type j,
+			       dimension_type nr, dimension_type n);
+  const dimension_type nr, nc;
+  const elevation_type nodata;
+public:
+  detectEdgeNodata(const dimension_type nrows, const dimension_type nc, 
+		   const elevation_type nodata);
+  ~detectEdgeNodata();
+  void processWindow(dimension_type row, dimension_type col,
+		     elevation_type &point,
+		     elevation_type *a,
+		     elevation_type *b,
+		     elevation_type *c);
+  void generateNodata(AMI_STREAM<elevation_type> &elstr);
+  void relabelNodata();
+  AMI_STREAM<elevation_type> *merge();
+  AMI_STREAM<nodataType> *getNodata() { return nodataStream; }
+};
+
+
+/* ********************************************************************** */
+detectEdgeNodata::detectEdgeNodata(const dimension_type nrows, 
+				   const dimension_type ncols, 
+				   const elevation_type gnodata)
+  : nr(nrows), nc(ncols), nodata(gnodata)  {
+  nodataStream = new AMI_STREAM<nodataType>();
+  elevStream = new AMI_STREAM<elevation_type>();
+}
+
+
+/* ********************************************************************** */
+detectEdgeNodata::~detectEdgeNodata() {
+  delete nodataStream;
+  delete elevStream;
+}
+
+
+/* ********************************************************************** */
+/* return a pointer to three plateauType structures, starting at
+   location i,j. caller should check valid field in returned
+   structs. */
+nodataType *
+detectEdgeNodata::getNodataForward(dimension_type i, dimension_type j,
+				   dimension_type nr, dimension_type nc) {
+  bool ok;
+  static nodataType ptarr[3];	/* return value */
+  nodataType pt;
+
+  ok = nodataQueue->peek(0, &pt);
+  while(ok && (pt.i < i || (pt.i==i && pt.j<j))) {
+	nodataQueue->dequeue(&pt);		/* past needing this, so remove */
+	ok = nodataQueue->peek(0, &pt);
+  }
+  if(ok && pt.i == i && pt.j == j) {
+	nodataQueue->dequeue(&pt);		/* found it, so remove */
+	ptarr[0] = pt;
+  } else {
+	ptarr[0].invalidate();
+  }
+  /* locate next two, if possible */
+  for(int kk=0,k=1; k<3; k++) {
+	ok = nodataQueue->peek(kk, &pt);
+	if(ok && pt.i == i && pt.j == j+k) {
+	  ptarr[k] = pt;
+	  kk++; /* found something, so need to peek further forward */
+	} else {
+	  ptarr[k].invalidate();
+	}
+  }
+
+#if(0)
+  cout << "request at " << i << "," << j << " returns: " <<
+	ptarr[0] << ptarr[1] << ptarr[2] << endl;
+  nodataQueue->peek(0, &pt);
+  cout << "queue length = " << nodataQueue->length() 
+	   << "; head=" << pt << endl;
+#endif
+  return ptarr;  
+}
+
+
+/* ********************************************************************** */
+
+
+void
+detectEdgeNodata::processWindow(dimension_type row, dimension_type col,
+				elevation_type &point,
+				elevation_type *a,
+				elevation_type *b,
+				elevation_type *c) {
+  AMI_err ae;
+  static nodataType prevCell;	/* cell on left (gets initialized) */
+
+  assert(row>=0);
+  assert(col>=0);
+
+  /* create window and write out */
+  ElevationWindow win(a, b, c);
+  fillPit(win);          /* fill pit in window */
+  ae = elevStream->write_item(win.get());
+  assert(ae == AMI_ERROR_NO_ERROR);
+
+
+  /* only interested in nodata in this pass */
+  if(win.get() !=  nodata) {
+	prevCell.label = LABEL_UNDEF;
+	return;
+  }
+
+  if(col == 0) prevCell.label = LABEL_UNDEF; /* no left cell */
+
+  /* now check for continuing plateaus */
+  nodataType *ptarr = 
+	getNodataForward(row-1, col-1, nr, nc);
+
+  /* make sure we use boundary label if appropriate */
+  cclabel_type crtlabel;
+  crtlabel = (IS_BOUNDARY(row,col,nr, nc) ? LABEL_BOUNDARY : LABEL_UNDEF);
+
+  for(int i=0; i<4; i++) {
+	if(win.get(i) != win.get()) continue; /* only interesting if same elev */
+
+	/* determine label for cell */
+	cclabel_type label = LABEL_UNDEF;
+	if(i<3) {
+	  if(ptarr[i].valid) label = ptarr[i].label;
+	} else {
+	  if(prevCell.valid) label = prevCell.label;
+	}
+
+	/* check for collisions */
+	if(label != LABEL_UNDEF) {
+	  if (crtlabel == LABEL_UNDEF) {
+		crtlabel = label;
+	  } else if(crtlabel != label) {  		  /* collision!! */
+		/* pick smaller label, but prefer nodata */
+		if(crtlabel==LABEL_BOUNDARY || crtlabel<label) { 
+		  colTree.insert(crtlabel, label);
+		} else {
+		  colTree.insert(label, crtlabel);
+		  crtlabel = label;
+		}
+	  }
+	}
+  }
+  
+  /* assign label if required */
+  if(crtlabel == LABEL_UNDEF) {
+	crtlabel = labelFactory::getNewLabel();
+  }
+
+  /* write this plateau point to the plateau stream */
+  nodataType pt;
+  prevCell = pt = nodataType(row, col, crtlabel);
+  nodataQueue->enqueue(pt);
+
+  /* NODATA_DEBUG *stats << "inserting " << pt << endl; */
+  
+  nodataStream->write_item(pt);	/*  save to file for later use */
+}
+
+
+/* ********************************************************************** */
+void
+detectEdgeNodata::generateNodata(AMI_STREAM<elevation_type> &elstr) { 
+  nodataQueue = new queue<nodataType>();
+  scan3(elstr, nr, nc, nodata, *this); 
+  delete nodataQueue;
+}
+
+
+/* ********************************************************************** */
+/* collapse labels; remove nodata regions */
+void
+detectEdgeNodata::relabelNodata() {
+  AMI_err ae;
+  nodataType *pt;
+
+  /* sort by label */
+  NODATA_DEBUG *stats << "sort nodataStream (by nodata label): ";
+  AMI_STREAM<nodataType> *sortedInStream;
+  sortedInStream = sort(nodataStream, labelCmpNodataType());
+  delete nodataStream;
+
+  nodataStream = new AMI_STREAM<nodataType>();
+
+  while((ae = sortedInStream->read_item(&pt)) == AMI_ERROR_NO_ERROR) {
+	cclabel_type root = colTree.findNextRoot(pt->label);
+	assert(root <= pt->label);
+	pt->label = root;
+	ae = nodataStream->write_item(*pt);
+	assert(ae == AMI_ERROR_NO_ERROR);
+  }
+
+  delete sortedInStream;
+}
+
+
+/* ********************************************************************** */
+AMI_STREAM<elevation_type> *
+detectEdgeNodata::merge() {
+ 
+  NODATA_DEBUG *stats << "sort  nodataStream (by ij): ";
+  /*
+    AMI_STREAM<nodataType> *sortedNodataStream;
+    sortedNodataStream = sort(nodataStream, ijCmpNodataType());
+    delete nodataStream;
+    nodataStream=sortedNodataStream;
+  */
+  sort(&nodataStream, ijCmpNodataType());
+  //note: nodataStream gets deleted and replaced with the sorted stream
+
+  AMI_STREAM<elevation_type> *mergeStr;
+  mergeStr = mergeStream2Grid(elevStream, nrows, ncols, 
+			      nodataStream, nodataType2elevation_type());
+
+  return mergeStr;
+}
+
+
+
+/* ********************************************************************** */
+/* ********************************************************************** */
+
+
+AMI_STREAM<elevation_type> *
+classifyNodata(AMI_STREAM<elevation_type> *elstr) {
+  Rtimer rt;
+
+  rt_start(rt);
+  stats->comment("finding nodata", opt->verbose);
+  detectEdgeNodata md(nrows, ncols, nodataType::ELEVATION_NODATA);
+  md.generateNodata(*elstr);
+  *stats << "nodata stream length = " << md.getNodata()->stream_len() << endl;
+  {
+    char * foo;
+    md.getNodata()->name(&foo); 
+    *stats << "nodata stream name: " << foo << endl;
+  }
+  rt_stop(rt);
+  stats->recordTime("classifyNodata::generate nodata", rt);
+
+  rt_start(rt);
+  stats->comment("relabeling nodata",  opt->verbose);
+  md.relabelNodata();  /* re-assign labels (combine connected plateaus) */
+  rt_stop(rt);
+  stats->recordTime("classifyNodata::relabeling",  rt);
+  
+  rt_start(rt);
+  stats->comment("merging relabeled grid",  opt->verbose);
+  AMI_STREAM<elevation_type> *mergeStr;
+  mergeStr = md.merge();
+  rt_stop(rt);
+  stats->recordTime("classifyNodata::merge",  rt);
+
+  mergeStr->seek(0);
+  return mergeStr;
+}
+
+/* ********************************************************************** */

Deleted: grass/trunk/raster/r.terraflow/plateau.cc
===================================================================
--- grass/trunk/raster/r.terraflow/plateau.cc	2011-09-29 23:35:42 UTC (rev 48561)
+++ grass/trunk/raster/r.terraflow/plateau.cc	2011-09-29 23:36:57 UTC (rev 48562)
@@ -1,468 +0,0 @@
-/****************************************************************************
- * 
- *  MODULE:	r.terraflow
- *
- *  COPYRIGHT (C) 2007 Laura Toma
- *   
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *****************************************************************************/
-
-#include <grass/iostream/ami.h> /* for queue */
-
-#include "plateau.h"
-#include "common.h"
-#include "streamutils.h"
-#include "sortutils.h"
-#include "types.h"
-#include "ccforest.h"
-#include "3scan.h"
-
-#define PLAT_DEBUG if(0)
-
-
-
-
-/* ********************************************************************** */
-/* ********************************************************************** */
-
-/* this is a function object to create the direction and plateau
- * streams given a window */
-
-class detectPlateaus {
-private:
-  AMI_STREAM<direction_type> *dirStream;
-  AMI_STREAM<plateauType> *platStream;
-  AMI_STREAM<ElevationWindow > *winStream;
-  queue<direction_type> *dirQueue;
-  queue<plateauType> *platQueue;
-  ccforest<cclabel_type> colTree;
-  plateauType *getPlateauForward(dimension_type i, dimension_type j,
-				 dimension_type nr, dimension_type n);
-  direction_type *getDirectionForward(dimension_type i, dimension_type j,
-				      dimension_type nr, dimension_type n);
-  const dimension_type nrows;
-  const dimension_type ncols;
-  const elevation_type nodata_value;
-public:
-  detectPlateaus(const dimension_type gnrows,const dimension_type gncols,
-				 const elevation_type gnodata_value,
-				 AMI_STREAM<direction_type>* dirstr,
-				 AMI_STREAM<ElevationWindow > *winstr);
-  ~detectPlateaus();
-  void processWindow(dimension_type row, dimension_type col,
-					 elevation_type *a,
-					 elevation_type *b,
-					 elevation_type *c);
-  void generatePlateaus(AMI_STREAM<elevation_type> &elstr);
-  void removeDuplicates();
-  void relabelPlateaus();
-  void generateStats(AMI_STREAM<plateauStats> *statStr);
-  AMI_STREAM<plateauType> *getPlateaus() { return platStream; }
-};
-
-
-/* ********************************************************************** */
-
-
-detectPlateaus::detectPlateaus(const dimension_type gnrows,
-							   const dimension_type gncols,
-							   const elevation_type gnodata_value,
-							   AMI_STREAM<direction_type>* gdirstr,
-							   AMI_STREAM<ElevationWindow > *gwinstr):
-  dirStream(gdirstr), winStream(gwinstr), 
-  nrows(gnrows), ncols(gncols), nodata_value(gnodata_value) {
-  platStream = new AMI_STREAM<plateauType>();
-}
-
-detectPlateaus::~detectPlateaus() {
-  /*delete platStream;	*/		/* user must delete */
-}
-
-
-
-/* ********************************************************************** */
-/* return a pointer to three plateauType structures, starting at
-   location i,j. caller should check valid field in returned
-   structs. */
-plateauType *
-detectPlateaus::getPlateauForward(dimension_type i, dimension_type j,
-				  dimension_type nr, dimension_type nc) {
-  bool ok;
-  static plateauType ptarr[3];	/* return value */
-  plateauType pt;
-  
-  ok = platQueue->peek(0, &pt);
-  while(ok && (pt.i < i || (pt.i==i && pt.j<j))) {
-	platQueue->dequeue(&pt);		/* past needing this, so remove */
-	ok = platQueue->peek(0, &pt);
-  }
-  if(ok && pt.i == i && pt.j == j) {
-	platQueue->dequeue(&pt);		/* found it, so remove */
-	ptarr[0] = pt;
-  } else {
-	ptarr[0].invalidate();
-  }
-  /* locate next two, if possible */
-  for(int kk=0,k=1; k<3; k++) {
-	ok = platQueue->peek(kk, &pt);
-	if(ok && pt.i == i && pt.j == j+k) {
-	  ptarr[k] = pt;
-	  kk++; /* found something, so need to peek further forward */
-	} else {
-	  ptarr[k].invalidate();
-	}
-  }
-
-#if(0)
-  cout << "request at " << i << "," << j << " returns: " <<
-	ptarr[0] << ptarr[1] << ptarr[2] << endl;
-  platQueue->peek(0, &pt);
-  cout << "queue length = " << platQueue->length() 
-	   << "; head=" << pt << endl;
-#endif
-  return ptarr;  
-}
-
-
-
-/* ********************************************************************** */
-/* should be called for each element in the grid */
-direction_type *
-detectPlateaus::getDirectionForward(dimension_type i, dimension_type j,
-				    dimension_type nr, dimension_type nc) {
-  static direction_type dirarr[3]; /* return value */
-  
-  dirarr[0] = 0;
-  dirarr[1] = 0;
-  dirarr[2] = 0;
-  
-  assert(i<nr-1);
-  assert(nc>3);
-
-  if(i>=0) {
-	if(!(i==0 && j==-1)) dirQueue->dequeue(dirarr);
-	if(j == -1) dirarr[0] = 0;
-	if(j+1 < nc) dirQueue->peek(0, dirarr+1);
-	if(j+2 < nc) dirQueue->peek(1, dirarr+2);
-  }
-
-#if(0)
-  cout << "\t\t\trequest at " << i << "," << j << " returns: " <<
-	dirarr[0] << " " << dirarr[1] << " " << dirarr[2] << "\t";
-  direction_type dir;
-  dirQueue->peek(0, &dir);
-  cout << "queue length = " << dirQueue->length() 
-	   << "; head=" << dir << endl;
-#endif
-
-  return dirarr;
-}
-
-
-
-/* ********************************************************************** */
-void
-detectPlateaus::processWindow(dimension_type row, dimension_type col,
-			      elevation_type *a,
-			      elevation_type *b,
-			      elevation_type *c) {
-  AMI_err ae;
-  static plateauType prevPlat;	/*  cell on left (auto-initialized) */
-  direction_type dir;
-
-  assert(row>=0);
-  assert(col>=0);
-
-  /* create window and write out */
-  ElevationWindow win(a, b, c);
-
-  /* compute direction; pits should have been filled */
-  dir = encodeDirection(win, nrows, ncols, row, col);
-  dirQueue->enqueue(dir); /* write dir to dir stream */
-  ae = dirStream->write_item(dir);	/* save to file for later use */
-  assert(ae == AMI_ERROR_NO_ERROR);
-
-  /* must always read to keep in sync */
-  direction_type *dirarr =
-	getDirectionForward(row-1, col-1, nrows, ncols);
-  
-  /* if(dir == DIRECTION_UNDEF) return; */
-  if(is_nodata(win.get())) {	/* if nodata, get outa here */
-	prevPlat.cclabel = LABEL_UNDEF;
-	return;
-  }
-
-  if(col == 0) prevPlat.cclabel = LABEL_UNDEF; /* no left cell */
-  
-  /* now check for continuing plateaus */
-  plateauType *ptarr = 
-	getPlateauForward(row-1, col-1, nrows, ncols);
-  cclabel_type crtlabel=LABEL_UNDEF;
-  for(int i=0; i<4; i++) {
-	if(win.get(i) != win.get()) continue; /* only interesting if same elev */
-
-	/* determine label for cell */
-	cclabel_type label = LABEL_UNDEF;
-	if(i<3) {
-	  if(ptarr[i].valid) label = ptarr[i].cclabel;
-	} else {
-	  if(prevPlat.valid) label = prevPlat.cclabel;
-	}
-
-	/* check for collisions */
-	if(label != LABEL_UNDEF) {
-	  if (crtlabel == LABEL_UNDEF) {
-		crtlabel = label;
-	  } else if(crtlabel != label) {  		  /* collision!! */
-		/* pick smaller label */
-		if(crtlabel<label) { 
-		  colTree.insert(crtlabel, label);
-		} else {
-		  colTree.insert(label, crtlabel);
-		  crtlabel = label;
-		}
-	  }
-	}
-  }
-  
-  /* assign label if required */
-  if(crtlabel == LABEL_UNDEF) {
-    /* if we have a direction, we're done.  we are not part of a known
-       plateau. if we are part(neighbor) of a plateau to be identified
-       later, our neighbor will write us later. */
-    if(dir > 0) {
-      prevPlat = plateauType(row, col, dir);
-      PLAT_DEBUG cout << "skipping " << prevPlat << endl;
-      return;
-    }
-    crtlabel = labelFactory::getNewLabel();
-  }
-
-  /* check boundaries that are also part of plateau (but didnt know it) */
-  for(int i=0; i<4; i++) {
-	direction_type ndir(0);
-	if(win.get(i) != win.get()) continue; /* only interesting if same elev */
-	
-	/* determine direction for cell */
-	if(i<3) {
-	  ndir = dirarr[i];
-	} else {
-	  if(prevPlat.valid) ndir = prevPlat.dir;
-	}
-
-	/* check for boundaries */
-	if(ndir > 0) {				/* has direction */
-	  plateauType nbor;
-	  if(i<3) {
-	    nbor = plateauType(row-1, col+i-1, ndir, crtlabel);
-	  } else {
-	    nbor = plateauType(row, col-1, ndir, crtlabel);
-	  }	 
-	  if((nbor.i >= 0) & (nbor.j >= 0)) { /* make sure nbor on grid;
-											 this can happen because
-											 we pad the grid with
-											 nodata */
-	    PLAT_DEBUG cout << "neighbor insert " << nbor << endl;
-	    ae = platStream->write_item(nbor);
-	    assert(ae == AMI_ERROR_NO_ERROR);
-	  }
-	}
-  } /* for i */
-
-  /* write this plateau point to the plateau stream */
-  plateauType pt;
-  prevPlat = pt = plateauType(row, col, dir, crtlabel);
-  platQueue->enqueue(pt);
-  
-  PLAT_DEBUG cout << "inserting " << pt << endl;
-  
-  platStream->write_item(pt);	/* save to file for later use */
-}
-
-
-
-/* ********************************************************************** */
-void
-detectPlateaus::generatePlateaus(AMI_STREAM<elevation_type> &elstr) { 
-  dirQueue = new queue<direction_type>();
-  platQueue = new queue<plateauType>();
-  /* scan3(elstr, hdr, hdr.get_nodata(), *this);  */
-  if (opt->verbose) STRACE("starting memscan");
-  memoryScan(elstr, nrows, ncols, nodata_value, *this); 
-  if (opt->verbose) STRACE("memscan done");
-  delete dirQueue;
-  delete platQueue;
-}
-
-
-
-
-/* ********************************************************************** */
-class duplicateFixer {
-  ccforest<cclabel_type> *colTree;
-public:
-  duplicateFixer(ccforest<cclabel_type> *p) : colTree(p) {};
-  int compare(const plateauType &a, const plateauType &b) {
-	int c = ijCmpPlateauType::compare(a,b);
-	if(c==0 && 	(a.cclabel != b.cclabel)) {	/* collision	   */
-	  if(a.cclabel<b.cclabel) { 
-		colTree->insert(a.cclabel, b.cclabel);
-	  } else {
-		colTree->insert(b.cclabel, a.cclabel);
-	  }
-	}
-	return c;
-  }
-};
-
-
-
-/* ********************************************************************** */
-/* take out plateau elements that were generated multiple times */
-void
-detectPlateaus::removeDuplicates() {
-  PLAT_DEBUG cout << "sort plateauStream (by ij): ";
-  sort(&platStream, ijCmpPlateauType());
-  ::removeDuplicatesEx(&platStream, duplicateFixer(&colTree));
-}
-
-
-
-
-/* ********************************************************************** */
-/* collapse labels; remove nodata regions */
-void
-detectPlateaus::relabelPlateaus() {
-  AMI_err ae;
-  plateauType *pt;
-
-  AMI_STREAM<plateauType> *sortedInStr;
-  PLAT_DEBUG cout << "sort plateauStream (by label): "; 
-  sortedInStr = sort(platStream, labelCmpPlateauType());
-  delete platStream;
-
-  platStream = new AMI_STREAM<plateauType>;
-  sortedInStr->seek(0);
-  
-  /* 
-	 cout << "EDGESTREAM:" << endl; colTree.printEdgeStream();
-	 cout << "ROOTSTREAM:" << endl; colTree.printRootStream();
-	 cout << "RELABELING:" << endl;
-  */
-  while((ae = sortedInStr->read_item(&pt)) == AMI_ERROR_NO_ERROR) {
-	cclabel_type root = colTree.findNextRoot(pt->cclabel);
-	assert(root <= pt->cclabel);
-	assert(root >= LABEL_START);
-	pt->cclabel = root;
-	ae = platStream->write_item(*pt);
-	assert(ae == AMI_ERROR_NO_ERROR);
-	/* cout << *pt << endl; */
-  }
-  delete sortedInStr;
-}
-
-
-
-/* ********************************************************************** */
-
-void
-detectPlateaus::generateStats(AMI_STREAM<plateauStats> *statStr) {
-  AMI_err ae;
-  plateauType *pt;
-
-  /* sort by label */
-  AMI_STREAM<plateauType> *sortedStream;
-  PLAT_DEBUG cout << "sort plateauStream (by label): ";
-  sortedStream = sort(platStream, labelCmpPlateauType());
-  delete platStream;
-
-  plateauStats labelStats = plateauStats();
-  sortedStream->seek(0);
-  while((ae = sortedStream->read_item(&pt)) == AMI_ERROR_NO_ERROR) {
-	if(pt->cclabel != labelStats.label) {
-	  if(labelStats.label != LABEL_UNDEF) {
-		ae = statStr->write_item(labelStats);
-		assert(ae == AMI_ERROR_NO_ERROR);
-	  }
-	  labelStats = plateauStats(pt->cclabel);
-	}
-	labelStats.add(*pt);
-  }
-	
-  ae = statStr->write_item(labelStats);
-  assert(ae == AMI_ERROR_NO_ERROR);
-
-  platStream = sortedStream;
-}
-
-
-
-/* ********************************************************************** */
-/* ********************************************************************** */
-
-AMI_STREAM<plateauType> *
-findPlateaus(AMI_STREAM<elevation_type> *elstr,
-	     const dimension_type nrows, const dimension_type ncols,
-	     const elevation_type nodata_value,
-	     AMI_STREAM<ElevationWindow > *winstr,
-	     AMI_STREAM<direction_type> *dirStr,
-	     AMI_STREAM<plateauStats> *statStr) {
-  Rtimer rt;
-  
-  labelFactory::reset();
-  
-  /* find plateaus */
-  rt_start(rt);
-  stats->comment("----------",  opt->verbose);
-  stats->comment("finding flat areas (plateaus and depressions)");
-  detectPlateaus md(nrows, ncols,nodata_value, dirStr, winstr);
-  md.generatePlateaus(*elstr);
-  rt_stop(rt);
-  stats->recordTime("findPlateaus::generate plateaus", rt);
-  stats->recordLength("plateaus", md.getPlateaus());
-
-  rt_start(rt);
-  stats->comment("removing duplicate plateaus",  opt->verbose);
-  md.removeDuplicates(); /* get rid of duplicates of same plateau point */
-  rt_stop(rt);
-  stats->recordTime("findPlateaus::removing duplicates",  rt);
-  stats->recordLength("plateaus", md.getPlateaus());
-  
-#if(0)
-  { /* XXX */
-    AMI_STREAM<plateauType> *tmp = sort(md.getPlateaus(), ijCmpPlateauType());
-    printStream2Grid(tmp, nrows, ncols,
-		     "label0.asc", plateauType::printLabel);
-    delete tmp;
-  }
-#endif
-
-  rt_start(rt);
-  stats->comment("relabeling plateaus",  opt->verbose);
-  md.relabelPlateaus();  /* re-assign labels (combine connected plateaus) */
-  rt_stop(rt);
-  stats->recordTime("findPlateaus::relabeling",  rt);
-  stats->recordLength("plateaus", md.getPlateaus());
-  
-  rt_start(rt);
-  stats->comment("generating plateau statistics",  opt->verbose);
-  md.generateStats(statStr);
-  rt_stop(rt);
-  stats->recordTime("findPlateaus::generating stats",  rt);
-  stats->recordLength("plateaus", md.getPlateaus());
-
-  dirStr->seek(0);
-  return md.getPlateaus();
-}
-
-/* ********************************************************************** */
-

Copied: grass/trunk/raster/r.terraflow/plateau.cpp (from rev 48560, grass/trunk/raster/r.terraflow/plateau.cc)
===================================================================
--- grass/trunk/raster/r.terraflow/plateau.cpp	                        (rev 0)
+++ grass/trunk/raster/r.terraflow/plateau.cpp	2011-09-29 23:36:57 UTC (rev 48562)
@@ -0,0 +1,468 @@
+/****************************************************************************
+ * 
+ *  MODULE:	r.terraflow
+ *
+ *  COPYRIGHT (C) 2007 Laura Toma
+ *   
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *****************************************************************************/
+
+#include <grass/iostream/ami.h> /* for queue */
+
+#include "plateau.h"
+#include "common.h"
+#include "streamutils.h"
+#include "sortutils.h"
+#include "types.h"
+#include "ccforest.h"
+#include "3scan.h"
+
+#define PLAT_DEBUG if(0)
+
+
+
+
+/* ********************************************************************** */
+/* ********************************************************************** */
+
+/* this is a function object to create the direction and plateau
+ * streams given a window */
+
+class detectPlateaus {
+private:
+  AMI_STREAM<direction_type> *dirStream;
+  AMI_STREAM<plateauType> *platStream;
+  AMI_STREAM<ElevationWindow > *winStream;
+  queue<direction_type> *dirQueue;
+  queue<plateauType> *platQueue;
+  ccforest<cclabel_type> colTree;
+  plateauType *getPlateauForward(dimension_type i, dimension_type j,
+				 dimension_type nr, dimension_type n);
+  direction_type *getDirectionForward(dimension_type i, dimension_type j,
+				      dimension_type nr, dimension_type n);
+  const dimension_type nrows;
+  const dimension_type ncols;
+  const elevation_type nodata_value;
+public:
+  detectPlateaus(const dimension_type gnrows,const dimension_type gncols,
+				 const elevation_type gnodata_value,
+				 AMI_STREAM<direction_type>* dirstr,
+				 AMI_STREAM<ElevationWindow > *winstr);
+  ~detectPlateaus();
+  void processWindow(dimension_type row, dimension_type col,
+					 elevation_type *a,
+					 elevation_type *b,
+					 elevation_type *c);
+  void generatePlateaus(AMI_STREAM<elevation_type> &elstr);
+  void removeDuplicates();
+  void relabelPlateaus();
+  void generateStats(AMI_STREAM<plateauStats> *statStr);
+  AMI_STREAM<plateauType> *getPlateaus() { return platStream; }
+};
+
+
+/* ********************************************************************** */
+
+
+detectPlateaus::detectPlateaus(const dimension_type gnrows,
+							   const dimension_type gncols,
+							   const elevation_type gnodata_value,
+							   AMI_STREAM<direction_type>* gdirstr,
+							   AMI_STREAM<ElevationWindow > *gwinstr):
+  dirStream(gdirstr), winStream(gwinstr), 
+  nrows(gnrows), ncols(gncols), nodata_value(gnodata_value) {
+  platStream = new AMI_STREAM<plateauType>();
+}
+
+detectPlateaus::~detectPlateaus() {
+  /*delete platStream;	*/		/* user must delete */
+}
+
+
+
+/* ********************************************************************** */
+/* return a pointer to three plateauType structures, starting at
+   location i,j. caller should check valid field in returned
+   structs. */
+plateauType *
+detectPlateaus::getPlateauForward(dimension_type i, dimension_type j,
+				  dimension_type nr, dimension_type nc) {
+  bool ok;
+  static plateauType ptarr[3];	/* return value */
+  plateauType pt;
+  
+  ok = platQueue->peek(0, &pt);
+  while(ok && (pt.i < i || (pt.i==i && pt.j<j))) {
+	platQueue->dequeue(&pt);		/* past needing this, so remove */
+	ok = platQueue->peek(0, &pt);
+  }
+  if(ok && pt.i == i && pt.j == j) {
+	platQueue->dequeue(&pt);		/* found it, so remove */
+	ptarr[0] = pt;
+  } else {
+	ptarr[0].invalidate();
+  }
+  /* locate next two, if possible */
+  for(int kk=0,k=1; k<3; k++) {
+	ok = platQueue->peek(kk, &pt);
+	if(ok && pt.i == i && pt.j == j+k) {
+	  ptarr[k] = pt;
+	  kk++; /* found something, so need to peek further forward */
+	} else {
+	  ptarr[k].invalidate();
+	}
+  }
+
+#if(0)
+  cout << "request at " << i << "," << j << " returns: " <<
+	ptarr[0] << ptarr[1] << ptarr[2] << endl;
+  platQueue->peek(0, &pt);
+  cout << "queue length = " << platQueue->length() 
+	   << "; head=" << pt << endl;
+#endif
+  return ptarr;  
+}
+
+
+
+/* ********************************************************************** */
+/* should be called for each element in the grid */
+direction_type *
+detectPlateaus::getDirectionForward(dimension_type i, dimension_type j,
+				    dimension_type nr, dimension_type nc) {
+  static direction_type dirarr[3]; /* return value */
+  
+  dirarr[0] = 0;
+  dirarr[1] = 0;
+  dirarr[2] = 0;
+  
+  assert(i<nr-1);
+  assert(nc>3);
+
+  if(i>=0) {
+	if(!(i==0 && j==-1)) dirQueue->dequeue(dirarr);
+	if(j == -1) dirarr[0] = 0;
+	if(j+1 < nc) dirQueue->peek(0, dirarr+1);
+	if(j+2 < nc) dirQueue->peek(1, dirarr+2);
+  }
+
+#if(0)
+  cout << "\t\t\trequest at " << i << "," << j << " returns: " <<
+	dirarr[0] << " " << dirarr[1] << " " << dirarr[2] << "\t";
+  direction_type dir;
+  dirQueue->peek(0, &dir);
+  cout << "queue length = " << dirQueue->length() 
+	   << "; head=" << dir << endl;
+#endif
+
+  return dirarr;
+}
+
+
+
+/* ********************************************************************** */
+void
+detectPlateaus::processWindow(dimension_type row, dimension_type col,
+			      elevation_type *a,
+			      elevation_type *b,
+			      elevation_type *c) {
+  AMI_err ae;
+  static plateauType prevPlat;	/*  cell on left (auto-initialized) */
+  direction_type dir;
+
+  assert(row>=0);
+  assert(col>=0);
+
+  /* create window and write out */
+  ElevationWindow win(a, b, c);
+
+  /* compute direction; pits should have been filled */
+  dir = encodeDirection(win, nrows, ncols, row, col);
+  dirQueue->enqueue(dir); /* write dir to dir stream */
+  ae = dirStream->write_item(dir);	/* save to file for later use */
+  assert(ae == AMI_ERROR_NO_ERROR);
+
+  /* must always read to keep in sync */
+  direction_type *dirarr =
+	getDirectionForward(row-1, col-1, nrows, ncols);
+  
+  /* if(dir == DIRECTION_UNDEF) return; */
+  if(is_nodata(win.get())) {	/* if nodata, get outa here */
+	prevPlat.cclabel = LABEL_UNDEF;
+	return;
+  }
+
+  if(col == 0) prevPlat.cclabel = LABEL_UNDEF; /* no left cell */
+  
+  /* now check for continuing plateaus */
+  plateauType *ptarr = 
+	getPlateauForward(row-1, col-1, nrows, ncols);
+  cclabel_type crtlabel=LABEL_UNDEF;
+  for(int i=0; i<4; i++) {
+	if(win.get(i) != win.get()) continue; /* only interesting if same elev */
+
+	/* determine label for cell */
+	cclabel_type label = LABEL_UNDEF;
+	if(i<3) {
+	  if(ptarr[i].valid) label = ptarr[i].cclabel;
+	} else {
+	  if(prevPlat.valid) label = prevPlat.cclabel;
+	}
+
+	/* check for collisions */
+	if(label != LABEL_UNDEF) {
+	  if (crtlabel == LABEL_UNDEF) {
+		crtlabel = label;
+	  } else if(crtlabel != label) {  		  /* collision!! */
+		/* pick smaller label */
+		if(crtlabel<label) { 
+		  colTree.insert(crtlabel, label);
+		} else {
+		  colTree.insert(label, crtlabel);
+		  crtlabel = label;
+		}
+	  }
+	}
+  }
+  
+  /* assign label if required */
+  if(crtlabel == LABEL_UNDEF) {
+    /* if we have a direction, we're done.  we are not part of a known
+       plateau. if we are part(neighbor) of a plateau to be identified
+       later, our neighbor will write us later. */
+    if(dir > 0) {
+      prevPlat = plateauType(row, col, dir);
+      PLAT_DEBUG cout << "skipping " << prevPlat << endl;
+      return;
+    }
+    crtlabel = labelFactory::getNewLabel();
+  }
+
+  /* check boundaries that are also part of plateau (but didnt know it) */
+  for(int i=0; i<4; i++) {
+	direction_type ndir(0);
+	if(win.get(i) != win.get()) continue; /* only interesting if same elev */
+	
+	/* determine direction for cell */
+	if(i<3) {
+	  ndir = dirarr[i];
+	} else {
+	  if(prevPlat.valid) ndir = prevPlat.dir;
+	}
+
+	/* check for boundaries */
+	if(ndir > 0) {				/* has direction */
+	  plateauType nbor;
+	  if(i<3) {
+	    nbor = plateauType(row-1, col+i-1, ndir, crtlabel);
+	  } else {
+	    nbor = plateauType(row, col-1, ndir, crtlabel);
+	  }	 
+	  if((nbor.i >= 0) & (nbor.j >= 0)) { /* make sure nbor on grid;
+											 this can happen because
+											 we pad the grid with
+											 nodata */
+	    PLAT_DEBUG cout << "neighbor insert " << nbor << endl;
+	    ae = platStream->write_item(nbor);
+	    assert(ae == AMI_ERROR_NO_ERROR);
+	  }
+	}
+  } /* for i */
+
+  /* write this plateau point to the plateau stream */
+  plateauType pt;
+  prevPlat = pt = plateauType(row, col, dir, crtlabel);
+  platQueue->enqueue(pt);
+  
+  PLAT_DEBUG cout << "inserting " << pt << endl;
+  
+  platStream->write_item(pt);	/* save to file for later use */
+}
+
+
+
+/* ********************************************************************** */
+void
+detectPlateaus::generatePlateaus(AMI_STREAM<elevation_type> &elstr) { 
+  dirQueue = new queue<direction_type>();
+  platQueue = new queue<plateauType>();
+  /* scan3(elstr, hdr, hdr.get_nodata(), *this);  */
+  if (opt->verbose) STRACE("starting memscan");
+  memoryScan(elstr, nrows, ncols, nodata_value, *this); 
+  if (opt->verbose) STRACE("memscan done");
+  delete dirQueue;
+  delete platQueue;
+}
+
+
+
+
+/* ********************************************************************** */
+class duplicateFixer {
+  ccforest<cclabel_type> *colTree;
+public:
+  duplicateFixer(ccforest<cclabel_type> *p) : colTree(p) {};
+  int compare(const plateauType &a, const plateauType &b) {
+	int c = ijCmpPlateauType::compare(a,b);
+	if(c==0 && 	(a.cclabel != b.cclabel)) {	/* collision	   */
+	  if(a.cclabel<b.cclabel) { 
+		colTree->insert(a.cclabel, b.cclabel);
+	  } else {
+		colTree->insert(b.cclabel, a.cclabel);
+	  }
+	}
+	return c;
+  }
+};
+
+
+
+/* ********************************************************************** */
+/* take out plateau elements that were generated multiple times */
+void
+detectPlateaus::removeDuplicates() {
+  PLAT_DEBUG cout << "sort plateauStream (by ij): ";
+  sort(&platStream, ijCmpPlateauType());
+  ::removeDuplicatesEx(&platStream, duplicateFixer(&colTree));
+}
+
+
+
+
+/* ********************************************************************** */
+/* collapse labels; remove nodata regions */
+void
+detectPlateaus::relabelPlateaus() {
+  AMI_err ae;
+  plateauType *pt;
+
+  AMI_STREAM<plateauType> *sortedInStr;
+  PLAT_DEBUG cout << "sort plateauStream (by label): "; 
+  sortedInStr = sort(platStream, labelCmpPlateauType());
+  delete platStream;
+
+  platStream = new AMI_STREAM<plateauType>;
+  sortedInStr->seek(0);
+  
+  /* 
+	 cout << "EDGESTREAM:" << endl; colTree.printEdgeStream();
+	 cout << "ROOTSTREAM:" << endl; colTree.printRootStream();
+	 cout << "RELABELING:" << endl;
+  */
+  while((ae = sortedInStr->read_item(&pt)) == AMI_ERROR_NO_ERROR) {
+	cclabel_type root = colTree.findNextRoot(pt->cclabel);
+	assert(root <= pt->cclabel);
+	assert(root >= LABEL_START);
+	pt->cclabel = root;
+	ae = platStream->write_item(*pt);
+	assert(ae == AMI_ERROR_NO_ERROR);
+	/* cout << *pt << endl; */
+  }
+  delete sortedInStr;
+}
+
+
+
+/* ********************************************************************** */
+
+void
+detectPlateaus::generateStats(AMI_STREAM<plateauStats> *statStr) {
+  AMI_err ae;
+  plateauType *pt;
+
+  /* sort by label */
+  AMI_STREAM<plateauType> *sortedStream;
+  PLAT_DEBUG cout << "sort plateauStream (by label): ";
+  sortedStream = sort(platStream, labelCmpPlateauType());
+  delete platStream;
+
+  plateauStats labelStats = plateauStats();
+  sortedStream->seek(0);
+  while((ae = sortedStream->read_item(&pt)) == AMI_ERROR_NO_ERROR) {
+	if(pt->cclabel != labelStats.label) {
+	  if(labelStats.label != LABEL_UNDEF) {
+		ae = statStr->write_item(labelStats);
+		assert(ae == AMI_ERROR_NO_ERROR);
+	  }
+	  labelStats = plateauStats(pt->cclabel);
+	}
+	labelStats.add(*pt);
+  }
+	
+  ae = statStr->write_item(labelStats);
+  assert(ae == AMI_ERROR_NO_ERROR);
+
+  platStream = sortedStream;
+}
+
+
+
+/* ********************************************************************** */
+/* ********************************************************************** */
+
+AMI_STREAM<plateauType> *
+findPlateaus(AMI_STREAM<elevation_type> *elstr,
+	     const dimension_type nrows, const dimension_type ncols,
+	     const elevation_type nodata_value,
+	     AMI_STREAM<ElevationWindow > *winstr,
+	     AMI_STREAM<direction_type> *dirStr,
+	     AMI_STREAM<plateauStats> *statStr) {
+  Rtimer rt;
+  
+  labelFactory::reset();
+  
+  /* find plateaus */
+  rt_start(rt);
+  stats->comment("----------",  opt->verbose);
+  stats->comment("finding flat areas (plateaus and depressions)");
+  detectPlateaus md(nrows, ncols,nodata_value, dirStr, winstr);
+  md.generatePlateaus(*elstr);
+  rt_stop(rt);
+  stats->recordTime("findPlateaus::generate plateaus", rt);
+  stats->recordLength("plateaus", md.getPlateaus());
+
+  rt_start(rt);
+  stats->comment("removing duplicate plateaus",  opt->verbose);
+  md.removeDuplicates(); /* get rid of duplicates of same plateau point */
+  rt_stop(rt);
+  stats->recordTime("findPlateaus::removing duplicates",  rt);
+  stats->recordLength("plateaus", md.getPlateaus());
+  
+#if(0)
+  { /* XXX */
+    AMI_STREAM<plateauType> *tmp = sort(md.getPlateaus(), ijCmpPlateauType());
+    printStream2Grid(tmp, nrows, ncols,
+		     "label0.asc", plateauType::printLabel);
+    delete tmp;
+  }
+#endif
+
+  rt_start(rt);
+  stats->comment("relabeling plateaus",  opt->verbose);
+  md.relabelPlateaus();  /* re-assign labels (combine connected plateaus) */
+  rt_stop(rt);
+  stats->recordTime("findPlateaus::relabeling",  rt);
+  stats->recordLength("plateaus", md.getPlateaus());
+  
+  rt_start(rt);
+  stats->comment("generating plateau statistics",  opt->verbose);
+  md.generateStats(statStr);
+  rt_stop(rt);
+  stats->recordTime("findPlateaus::generating stats",  rt);
+  stats->recordLength("plateaus", md.getPlateaus());
+
+  dirStr->seek(0);
+  return md.getPlateaus();
+}
+
+/* ********************************************************************** */
+

Deleted: grass/trunk/raster/r.terraflow/stats.cc
===================================================================
--- grass/trunk/raster/r.terraflow/stats.cc	2011-09-29 23:35:42 UTC (rev 48561)
+++ grass/trunk/raster/r.terraflow/stats.cc	2011-09-29 23:36:57 UTC (rev 48562)
@@ -1,276 +0,0 @@
-/****************************************************************************
- * 
- *  MODULE:	r.terraflow
- *
- *  COPYRIGHT (C) 2007 Laura Toma
- *   
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *****************************************************************************/
-
-
-#include <fcntl.h>
-#include <unistd.h>
-#include <sys/types.h>
-#include <sys/time.h>
-#ifndef __MINGW32__
-#include <sys/resource.h>
-#endif
-#include <stdio.h>
-#include <errno.h>
-
-#include "stats.h"
-
-
-#ifdef HAS_UTRACE
-
-struct ut { char buf[8]; };
-
-void utrace __P((void *, int));
-
-#define UTRACE(s) \
-         {struct ut u; strncpy(u.buf,s,8); utrace((void*)&u, sizeof u);}
-#else /* !HAS_UTRACE */
-#define UTRACE(s)
-#endif /* HAS_UTRACE */
-
-#undef UTRACE
-
-#ifdef UTRACE_ENABLE
-#define UTRACE(s) utrace(s)
-#else
-#define UTRACE(s)
-#endif
-
-void
-utrace(const char *s) {
-  void *p;
-  int len = strlen(s);
-  assert(len < 80);
-
-  /* cerr << "UT " << len << endl; */
-  p = malloc(0);
-  /* assert(p); */
-  free(p);
-  p = malloc(len);
-  /* assert(p); */
-  free(p);
-  
-  for(int i=0; i<len; i++) {
-	p = malloc(s[i]);
-	/* assert(p); */
-	free(p);
-  }
-}
-
-
-
-int
-noclobberFile(char *fname) {
-  int fd=-1;
-  
-  while(fd<0) {
-    fd = open(fname, O_WRONLY|O_CREAT|O_EXCL, 0644);
-    if(fd < 0) {
-      if(errno != EEXIST) {
-	perror(fname);
-	exit(1);
-      } else { /* file exists */
-	char buf[BUFSIZ];
-	fprintf(stderr, "file %s exists - renaming.\n", fname);
-	sprintf(buf, "%s.old", fname);
-	if(rename(fname, buf) != 0) {
-	  perror(fname);
-	  exit(1);
-	}
-      }
-    }
-  }
-  return fd;
-}
-
-char* 
-noclobberFileName(char *fname) {
-  int fd;
-  fd = open(fname, O_WRONLY|O_CREAT|O_EXCL, 0644);
-  if(fd < 0) {
-    if(errno != EEXIST) {
-      perror(fname);
-      exit(1);
-    } else { /* file exists */
-      char buf[BUFSIZ];
-      fprintf(stderr, "file %s exists - renaming.\n", fname);
-      sprintf(buf, "%s.old", fname);
-      if(rename(fname, buf) != 0) {
-	perror(fname);
-	exit(1);
-      }
-      close(fd);
-    }
-  }
-  return fname;
-}
-
-
-
-/* ********************************************************************** */
-
-statsRecorder::statsRecorder(char *fname) : ofstream(noclobberFileName(fname)){
-  //note: in the new version of gcc there is not constructor for
-  //ofstream that takes an fd; wrote another noclobber() function that
-  //closes fd and returns the name;
-  rt_start(tm);
-#ifndef __MINGW32__
-  bss = sbrk(0);
-#endif
-  char buf[BUFSIZ];
-  *this << freeMem(buf) << endl;
-}
-
-/* ********************************************************************** */
-
-long 
-statsRecorder::freeMem() {
-#ifdef __MINGW32__
-  return -1;
-#else
-  struct rlimit rlim;
-  if (getrlimit(RLIMIT_DATA, &rlim) == -1) {
-	perror("getrlimit: ");
-	return -1;
-  } 	
-  /* printf("getrlimit returns: %d \n", rlim.rlim_cur); */
-  if (rlim.rlim_cur == RLIM_INFINITY) {
-	/* printf("rlim is infinity\n"); */
-	/* should fix this */
-	return -1; 
-  } 
-  long freeMem = rlim.rlim_cur - ((char*)sbrk(0)-(char*)bss);
-  return freeMem;
-#endif /* __MINGW32__ */
-}
-
-char *
-statsRecorder::freeMem(char *buf) {
-  char buf2[BUFSIZ];
-  sprintf(buf, "Free Memory=%s", formatNumber(buf2, freeMem()));
-  return buf;
-}
-
-
-
-/* ********************************************************************** */
-
-char *
-statsRecorder::timestamp() {
-  static char buf[BUFSIZ];
-  rt_stop(tm);
-  sprintf(buf, "[%.1f] ", rt_seconds(tm));
-  return buf;
-}
-
-void 
-statsRecorder::timestamp(const char *s) {
-  *this << timestamp() << s << endl;
-}
-
-
-void 
-statsRecorder::comment(const char *s, const int verbose) {
-  *this << timestamp() << s << endl;
-  if (verbose) {
-    cout << s << endl;
-  }
-  UTRACE(s);
-  cout.flush();
-}
-
-
-void 
-statsRecorder::comment(const char *s1, const char *s2) {
-  char buf[BUFSIZ];
-  sprintf(buf, "%s%s", s1, s2);
-  comment(buf);
-}
-
-void 
-statsRecorder::comment(const int n) {
-  char buf[BUFSIZ];
-  sprintf(buf, "%d", n);
-  comment(buf);
-}
-
-
-
-#if __FreeBSD__ &&  __i386__
-#define LDFMT "%qd"
-#else
-#if __linux__
-#define LDFMT "%lld"
-#else
-#define LDFMT "%ld"
-#endif
-#endif
-char *
-formatNumber(char *buf, off_t val) {
-  if(val > (1<<30)) {
-	sprintf(buf, "%.2fG (" LDFMT ")", (double)val/(1<<30), val);
-  } else if(val > (1<<20)) {
-	sprintf(buf, "%.2fM (" LDFMT ")", (double)val/(1<<20), val);
-  } else if(val > (1<<10)) {
-	sprintf(buf, "%.2fK (" LDFMT ")", (double)val/(1<<10), val);
-  } else {
-	sprintf(buf, LDFMT, val);
-  }
-  return buf;
-}
-
-
-
-void
-statsRecorder::recordTime(const char *label, long secs) {
-  *this << timestamp() << "TIME " << label << ": " << secs << " secs" << endl;
-  this->flush();
-
-  UTRACE(label);
-}
-
-void
-statsRecorder::recordTime(const char *label, Rtimer rt) {
-  char buf[BUFSIZ];
-  *this << timestamp() << "TIME " << label << ": ";
-  *this << rt_sprint(buf, rt) << endl;
-  this->flush();
-
-  UTRACE(label);
-}
-
-void
-statsRecorder::recordLength(const char *label, off_t len, int siz,
-			    char *sname) {
-  UTRACE(label);
-  UTRACE(sname);
-  
-  char lenstr[100];
-  char suffix[100]="";
-  if(siz) {
-	formatNumber(suffix, len*siz);
-	strcat(suffix, " bytes");
-  }
-  formatNumber(lenstr, len);  
-  *this << timestamp() << "LEN " << label << ": " << lenstr << " elts "
-		<< suffix;
-  if(sname) *this << " " << sname;
-  *this << endl;
-  this->flush();
-}
-
-

Copied: grass/trunk/raster/r.terraflow/stats.cpp (from rev 48560, grass/trunk/raster/r.terraflow/stats.cc)
===================================================================
--- grass/trunk/raster/r.terraflow/stats.cpp	                        (rev 0)
+++ grass/trunk/raster/r.terraflow/stats.cpp	2011-09-29 23:36:57 UTC (rev 48562)
@@ -0,0 +1,276 @@
+/****************************************************************************
+ * 
+ *  MODULE:	r.terraflow
+ *
+ *  COPYRIGHT (C) 2007 Laura Toma
+ *   
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *****************************************************************************/
+
+
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#ifndef __MINGW32__
+#include <sys/resource.h>
+#endif
+#include <stdio.h>
+#include <errno.h>
+
+#include "stats.h"
+
+
+#ifdef HAS_UTRACE
+
+struct ut { char buf[8]; };
+
+void utrace __P((void *, int));
+
+#define UTRACE(s) \
+         {struct ut u; strncpy(u.buf,s,8); utrace((void*)&u, sizeof u);}
+#else /* !HAS_UTRACE */
+#define UTRACE(s)
+#endif /* HAS_UTRACE */
+
+#undef UTRACE
+
+#ifdef UTRACE_ENABLE
+#define UTRACE(s) utrace(s)
+#else
+#define UTRACE(s)
+#endif
+
+void
+utrace(const char *s) {
+  void *p;
+  int len = strlen(s);
+  assert(len < 80);
+
+  /* cerr << "UT " << len << endl; */
+  p = malloc(0);
+  /* assert(p); */
+  free(p);
+  p = malloc(len);
+  /* assert(p); */
+  free(p);
+  
+  for(int i=0; i<len; i++) {
+	p = malloc(s[i]);
+	/* assert(p); */
+	free(p);
+  }
+}
+
+
+
+int
+noclobberFile(char *fname) {
+  int fd=-1;
+  
+  while(fd<0) {
+    fd = open(fname, O_WRONLY|O_CREAT|O_EXCL, 0644);
+    if(fd < 0) {
+      if(errno != EEXIST) {
+	perror(fname);
+	exit(1);
+      } else { /* file exists */
+	char buf[BUFSIZ];
+	fprintf(stderr, "file %s exists - renaming.\n", fname);
+	sprintf(buf, "%s.old", fname);
+	if(rename(fname, buf) != 0) {
+	  perror(fname);
+	  exit(1);
+	}
+      }
+    }
+  }
+  return fd;
+}
+
+char* 
+noclobberFileName(char *fname) {
+  int fd;
+  fd = open(fname, O_WRONLY|O_CREAT|O_EXCL, 0644);
+  if(fd < 0) {
+    if(errno != EEXIST) {
+      perror(fname);
+      exit(1);
+    } else { /* file exists */
+      char buf[BUFSIZ];
+      fprintf(stderr, "file %s exists - renaming.\n", fname);
+      sprintf(buf, "%s.old", fname);
+      if(rename(fname, buf) != 0) {
+	perror(fname);
+	exit(1);
+      }
+      close(fd);
+    }
+  }
+  return fname;
+}
+
+
+
+/* ********************************************************************** */
+
+statsRecorder::statsRecorder(char *fname) : ofstream(noclobberFileName(fname)){
+  //note: in the new version of gcc there is not constructor for
+  //ofstream that takes an fd; wrote another noclobber() function that
+  //closes fd and returns the name;
+  rt_start(tm);
+#ifndef __MINGW32__
+  bss = sbrk(0);
+#endif
+  char buf[BUFSIZ];
+  *this << freeMem(buf) << endl;
+}
+
+/* ********************************************************************** */
+
+long 
+statsRecorder::freeMem() {
+#ifdef __MINGW32__
+  return -1;
+#else
+  struct rlimit rlim;
+  if (getrlimit(RLIMIT_DATA, &rlim) == -1) {
+	perror("getrlimit: ");
+	return -1;
+  } 	
+  /* printf("getrlimit returns: %d \n", rlim.rlim_cur); */
+  if (rlim.rlim_cur == RLIM_INFINITY) {
+	/* printf("rlim is infinity\n"); */
+	/* should fix this */
+	return -1; 
+  } 
+  long freeMem = rlim.rlim_cur - ((char*)sbrk(0)-(char*)bss);
+  return freeMem;
+#endif /* __MINGW32__ */
+}
+
+char *
+statsRecorder::freeMem(char *buf) {
+  char buf2[BUFSIZ];
+  sprintf(buf, "Free Memory=%s", formatNumber(buf2, freeMem()));
+  return buf;
+}
+
+
+
+/* ********************************************************************** */
+
+char *
+statsRecorder::timestamp() {
+  static char buf[BUFSIZ];
+  rt_stop(tm);
+  sprintf(buf, "[%.1f] ", rt_seconds(tm));
+  return buf;
+}
+
+void 
+statsRecorder::timestamp(const char *s) {
+  *this << timestamp() << s << endl;
+}
+
+
+void 
+statsRecorder::comment(const char *s, const int verbose) {
+  *this << timestamp() << s << endl;
+  if (verbose) {
+    cout << s << endl;
+  }
+  UTRACE(s);
+  cout.flush();
+}
+
+
+void 
+statsRecorder::comment(const char *s1, const char *s2) {
+  char buf[BUFSIZ];
+  sprintf(buf, "%s%s", s1, s2);
+  comment(buf);
+}
+
+void 
+statsRecorder::comment(const int n) {
+  char buf[BUFSIZ];
+  sprintf(buf, "%d", n);
+  comment(buf);
+}
+
+
+
+#if __FreeBSD__ &&  __i386__
+#define LDFMT "%qd"
+#else
+#if __linux__
+#define LDFMT "%lld"
+#else
+#define LDFMT "%ld"
+#endif
+#endif
+char *
+formatNumber(char *buf, off_t val) {
+  if(val > (1<<30)) {
+	sprintf(buf, "%.2fG (" LDFMT ")", (double)val/(1<<30), val);
+  } else if(val > (1<<20)) {
+	sprintf(buf, "%.2fM (" LDFMT ")", (double)val/(1<<20), val);
+  } else if(val > (1<<10)) {
+	sprintf(buf, "%.2fK (" LDFMT ")", (double)val/(1<<10), val);
+  } else {
+	sprintf(buf, LDFMT, val);
+  }
+  return buf;
+}
+
+
+
+void
+statsRecorder::recordTime(const char *label, long secs) {
+  *this << timestamp() << "TIME " << label << ": " << secs << " secs" << endl;
+  this->flush();
+
+  UTRACE(label);
+}
+
+void
+statsRecorder::recordTime(const char *label, Rtimer rt) {
+  char buf[BUFSIZ];
+  *this << timestamp() << "TIME " << label << ": ";
+  *this << rt_sprint(buf, rt) << endl;
+  this->flush();
+
+  UTRACE(label);
+}
+
+void
+statsRecorder::recordLength(const char *label, off_t len, int siz,
+			    char *sname) {
+  UTRACE(label);
+  UTRACE(sname);
+  
+  char lenstr[100];
+  char suffix[100]="";
+  if(siz) {
+	formatNumber(suffix, len*siz);
+	strcat(suffix, " bytes");
+  }
+  formatNumber(lenstr, len);  
+  *this << timestamp() << "LEN " << label << ": " << lenstr << " elts "
+		<< suffix;
+  if(sname) *this << " " << sname;
+  *this << endl;
+  this->flush();
+}
+
+

Deleted: grass/trunk/raster/r.terraflow/sweep.cc
===================================================================
--- grass/trunk/raster/r.terraflow/sweep.cc	2011-09-29 23:35:42 UTC (rev 48561)
+++ grass/trunk/raster/r.terraflow/sweep.cc	2011-09-29 23:36:57 UTC (rev 48562)
@@ -1,398 +0,0 @@
-/****************************************************************************
- * 
- *  MODULE:	r.terraflow
- *
- *  COPYRIGHT (C) 2007 Laura Toma
- *   
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *****************************************************************************/
-
-
-#include <stdlib.h>
-#include <assert.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <string.h>
-
-#include <grass/iostream/ami.h>
-
-#include "option.h"
-#include "stats.h"
-#include "sweep.h"
-#include "common.h"
-#include "weightWindow.h"
-#include "nodata.h"
-#include "sortutils.h"
-
-
-/* 
-   #define CHECKPARAM        //output the parameters during sweeping 
-   #define CHECK_WEIGHTS     //output weights as computed
-   #define SWEEP_PRINT_PQSIZE      //output priority queue size during sweeping
-   #define CHECK_MEMORY  //enables printing available memory in between steps
-*/
-
-/* frequency; used to print progress dots */
-static const int DOT_CYCLE = 50;
-static const int PQSIZE_CYCLE = 100;
-
-
-/* globals in common.H
-
-extern statsRecorder *stats;       stats file 
-extern userOptions *opt;           command-line options 
-extern struct  Cell_head *region;  header of the region 
-extern dimension_type nrows, ncols;
-*/
-
-
-
-/* SELECT FLOW DATA STRUCTURE */
-#ifdef IM_PQUEUE
-typedef pqheap_t1<flowStructure> FLOW_DATASTR;
-#endif
-#ifdef EM_PQUEUE
-typedef em_pqueue<flowStructure, flowPriority> FLOW_DATASTR;
-#endif
-#ifdef EMPQ_ADAPTIVE
-typedef EMPQueueAdaptive<flowStructure, flowPriority> FLOW_DATASTR;
-#endif
-
-
-/* defined in this module */
-void pushFlow(const sweepItem& swit, const flowValue &flow, 
-	      FLOW_DATASTR* flowpq, const weightWindow &weight);
-
-
-
-
-/* ------------------------------------------------------------*/
-sweepOutput::sweepOutput() {
-  i = (dimension_type) nodataType::ELEVATION_NODATA;
-  j = (dimension_type) nodataType::ELEVATION_NODATA;
-  accu = (flowaccumulation_type) nodataType::ELEVATION_NODATA;  
-#ifdef OUTPUT_TCI
-  tci = (tci_type) nodataType::ELEVATION_NODATA;
-#endif
-};
-
-
-/* ------------------------------------------------------------ */
-/* computes output parameters of cell (i,j) given the flow value, the
-   elevation of that cell and the weights of that cell; */
-void
-sweepOutput::compute(elevation_type elev, 
-		    dimension_type i_crt, dimension_type j_crt, 
-		    const flowValue &flow, 
-		    const weightWindow &weight, 
-		    const  elevation_type nodata) {
-  
-  float correct_tci; /* this the correct value of tci; we're going to
-  truncate this on current precision tci_type set by user in types.H*/
-
-  assert(elev != nodata);
-  assert(flow.get() >= 0);
-  assert(weight.sumweight >= 0 && weight.sumcontour >= 0);
-
-  i = i_crt;
-  j = j_crt;
-  
-  if (weight.sumweight == 0 || weight.sumcontour == 0) {
-    accu = (flowaccumulation_type)nodata;
-#ifdef OUTPUT_TCI
-    tci = (tci_type)nodata;
-#endif
-    
-  } else {
-    accu = flow.get();
-#ifdef OUTPUT_TCI
-    correct_tci = log(flow.get()*weight.dx()*weight.dy()/weight.totalContour());
-    /* assert(correct_tci > 0); //is this true? */
-    /* there is no need for this warning. tci can be negative if the flow is small. */
-    /* if (correct_tci < 0) {
-       fprintf(stderr, "warning: tci negative, [flow=%f,dx=%f,dy=%f,cont=%f]\n",
-       flow.get(), weight.dx(), weight.dy(), weight.totalContour());
-       }
-    */
-    tci = (tci_type)correct_tci;
-#endif
-  }
-  
-  return;
-}
-
-
-
-
-FLOW_DATASTR* 
-initializePQ() {
-   
-  stats->comment("sweep:initialize flow data structure", opt->verbose);
-  
-  FLOW_DATASTR *flowpq;
-#ifdef IM_PQUEUE
-  stats->comment("FLOW_DATASTRUCTURE: in-memory pqueue");
-  flowpq = new FLOW_DATASTR(PQ_SIZE);
-  char buf[1024]; 
-  sprintf(buf, "initialized to %.2fMB\n", (float)PQ_SIZE / (1<<20));
-  *stats << buf; 
-
-#endif
-#ifdef EM_PQUEUE
-  stats->comment("FLOW_DATASTRUCTURE: ext-memory pqueue");
-  flowpq = new FLOW_DATASTR(nrows * ncols);  
-#endif
-#ifdef EMPQ_ADAPTIVE
-  if (opt->verbose) stats->comment("FLOW_DATASTRUCTURE: adaptive pqueue");
-  flowpq = new FLOW_DATASTR(); 
-#endif
-  return flowpq;
-}
-  
-
-#define INIT_PRINT_PROGRESS()						\
-  long out_frequency, pqsize_frequency;					\
-  out_frequency = nrows*ncols / DOT_CYCLE;		\
-  pqsize_frequency = nrows*ncols / PQSIZE_CYCLE;	\
-  assert(out_frequency);						\
-  assert(pqsize_frequency);
-
-#define PRINT_PROGRESS(k) 			\
-  if ((k) % out_frequency == 0) {		\
-    fprintf(stderr,"."); 				\
-    fflush(stderr);				\
-  };
-
-#ifdef SWEEP_PRINT_PQSIZE
-#define PRINT_PQSIZE(k,flowpq)			\
-  if ((k) % pqsize_frequency == 0) {		\
-    fprintf(stderr," %ld ", (long)(flowpq)->size());	\
-    fflush(stderr);				\
-  }
-#else
-#define PRINT_PQSIZE(k,flowpq)
-#endif
-
-
-
-/***************************************************************/
-/* Read the points in order from the sweep stream and process them.
-   If trustdir = 1 then trust and use the directions contained in the
-   sweep stream. Otherwise push flow to all downslope neighbors and
-   use the direction only for points without downslope neighbors. */
-/***************************************************************/
-
-AMI_STREAM<sweepOutput>* 
-sweep(AMI_STREAM<sweepItem> *sweepstr, const flowaccumulation_type D8CUT,
-      const int trustdir) {
-  flowPriority prio;
-  flowValue flow;
-  sweepItem* crtpoint;
-  AMI_err ae;
-  flowStructure x;	
-  long nitems;
-  Rtimer rt;
-  AMI_STREAM<sweepOutput>* outstr;
-
-  /* INIT_PRINT_PROGRESS(); */
-
-  rt_start(rt);
-
-  assert(sweepstr);
-
-  *stats << "sweeping\n";
-  fprintf(stderr,  "sweeping: ");
-  /* create and initialize flow data structure */
-  FLOW_DATASTR *flowpq;
-  flowpq = initializePQ();
-  
-  /* create output stream */
-  outstr = new AMI_STREAM<sweepOutput>();
-  
-  /* initialize weights and output */
-  weightWindow weight(region->ew_res, region->ns_res);
-  sweepOutput output;
-  nitems = sweepstr->stream_len();
-
-#ifndef NDEBUG
-  flowPriority prevprio = flowPriority(SHRT_MAX);	/* XXX      */
-#endif
-  /* scan the sweep stream  */
-  ae = sweepstr->seek(0);
-  assert(ae == AMI_ERROR_NO_ERROR);
-  for (long k = 0; k < nitems; k++) {
-    
-    /* cout << k << endl; cout.flush(); */
-    /* read next sweepItem = (prio, elevwin, topoRankwin, dir) */
-    ae = sweepstr->read_item(&crtpoint);
-    if (ae != AMI_ERROR_NO_ERROR) {
-      fprintf(stderr, "sweep: k=%ld: cannot read next item..\n", k);
-      exit(1);
-    }
-    /* cout << "k=" << k << " prio =" << crtpoint->getPriority() << "\n"; */
-    /* nodata points should not be in sweep stream */
-    assert(!is_nodata(crtpoint->getElev()));
-#ifndef NDEBUG    
-    assert(crtpoint->getPriority() > prevprio); /* XXX */
-    prevprio = crtpoint->getPriority(); /* XXX */
-#endif
-    
-    
-    /* compute flow accumulation of current point; initial flow value
-       is 1 */
-    flowValue flowini((double)1);
-    /* add flow which was pushed into current point by upslope
-       neighbours */
-    assert(flowpq->is_empty() || 
-		   (flowpq->min(x), x.getPriority() >= crtpoint->getPriority())); /* XXX */
-    assert(flowpq->is_empty() != flowpq->min(x));	/* XXX */
-    if (flowpq->min(x) && ((prio=x.getPriority()) == crtpoint->getPriority())) {
-      flowpq->extract_all_min(x);
-      /* cout << "EXTRACT: " << x << endl; */
-      flow = x.getValue();
-      flow = flow + flowini;
-    } else {
-      flow = flowini;
-    }
-    assert(flowpq->is_empty() || 
-		   (flowpq->min(x), x.getPriority() > crtpoint->getPriority())); /* XXX */
-	
-
-
-    /* compute weights of current point given its direction */
-    if (flow > D8CUT) {
-      /* consider just the dominant direction */
-      weight.makeD8(crtpoint->getI(), crtpoint->getJ(), 
-		    crtpoint->getElevWindow(), crtpoint->getDir(), trustdir);
-    } else {
-      /* consider multiple flow directions */
-      weight.compute(crtpoint->getI(), crtpoint->getJ(), 
-		     crtpoint->getElevWindow(), crtpoint->getDir(), trustdir);
-    }    
-    
-    
-    /* distribute the flow to its downslope neighbours  */
-    pushFlow(*crtpoint, flow, flowpq, weight);
-
-    
-    /* compute parameters  */
-    output.compute(crtpoint->getElev(), crtpoint->getI(), crtpoint->getJ(),
-		   flow, weight, nodataType::ELEVATION_NODATA);
-#ifdef CHECKPARAM   
-    printf("%7ld: (%5d, %5d, %5d) flow: %7.3f, weights:[",
-	   k, crtpoint->getElev(), crtpoint->getI(),crtpoint->getJ(), 
-	   flow.get());
-    for (int l=0;l<9;l++) printf("%2.1f ",weight.get(l));
-    cout <<"] ";
-    cout << output << "\n";
-#endif        
-
-    /* write output to sweep output stream */
-    ae = outstr->write_item(output);
-    assert(ae == AMI_ERROR_NO_ERROR);
-    
-    /* PRINT_PROGRESS(k); */
-    /* PRINT_PQSIZE(k, flowpq); */
-    
-    G_percent(k, nitems, 2);
-  } /* for k  */
-  
-  G_percent(1, 1, 2); /* finish it */
-
-  *stats << "sweeping done\n";
-  char buf[1024];
-  sprintf(buf, "pqsize = %ld \n", (long)flowpq->size());
-  *stats << buf;
-  
-  assert(outstr->stream_len() == nitems);
-  delete flowpq; 
-
-  rt_stop(rt);
-  stats->recordTime("sweeping", rt);
-  stats->recordLength("sweep output stream", outstr);
-
-  return outstr;
-}
-
-
-
-
-
-
-
-/***************************************************************/
-/* push flow to neighbors as indicated by flow direction and reflected
-   by the weights of the neighbors; flow is the accumulated flow value
-   of current point; The neighbours which receive flow from current
-   point are inserted in the FLOW_DATASTR */
-/***************************************************************/
-void 
-pushFlow(const sweepItem& swit, const flowValue &flow, 
-	 FLOW_DATASTR *flowpq, 
-	 const weightWindow &weight) {
-  
-  dimension_type  i_crt, j_crt, i_neighb, j_neighb;
-  short di, dj;
-  elevation_type elev_crt, elev_neighb;
-  toporank_type toporank_crt;
- 
-  assert(flow >= 0);
-  /* get current coordinates, elevation, topological rank */
-  i_crt = swit.getI(); 
-  j_crt = swit.getJ();
-  elev_crt = swit.getElev();
-  toporank_crt = swit.getTopoRank();
-  assert(!is_nodata(elev_crt)); 
-
-  for (di = -1; di <= 1; di++) {
-    for (dj = -1; dj <= 1; dj++) {
-      if (weight.get(di,dj) > 0) {
-
-		/* push flow to this neighbor  */
-	i_neighb = i_crt + di;  
-	j_neighb = j_crt + dj;
-	elev_neighb = swit.getElev(di,dj);
-	
-	/*assert(IS_BOUNDARY(i_crt,j_crt,hdr) || elev_neighb !=hdr.get_nodata());*/
-	/* it's not simple to check what nodata is on boundary, so we'll
-	just assume directions are correct even if they point to nodata
-	elevation values. */
-
-	if (!is_nodata(elev_neighb)) {
-	  flowPriority prio(elev_neighb, swit.getTopoRank(di,dj), 
-			    i_neighb, j_neighb);
-	  flowPriority prio_crt(elev_crt,toporank_crt, i_crt, j_crt);
-	  /* assert(prio >= prio_crt); */
-#if (defined WARNING_FLAG)
-	  if (prio < prio_crt) {
-	    printf("\n(row=%d,col=%d,ele=%d): ",
-		   i_crt, j_crt, elev_crt);
-	    cout << "attempt to push flow uphill\n";
-	  }
-#endif
-	  flowValue elt(weight.get(di,dj)*flow.get());
-	  flowStructure x(prio, elt);
-	  assert(x.getPriority() > swit.getPriority());
-	  flowpq->insert(x);
-	  /* cout << "INSERT: " << x << endl;  */
-	} /* if (!is_nodata(elev_neighb)) */
-      }
-    } /* for dj */
-  } /* for di */
-  return;
-}
-
-
-
-
-
-

Copied: grass/trunk/raster/r.terraflow/sweep.cpp (from rev 48560, grass/trunk/raster/r.terraflow/sweep.cc)
===================================================================
--- grass/trunk/raster/r.terraflow/sweep.cpp	                        (rev 0)
+++ grass/trunk/raster/r.terraflow/sweep.cpp	2011-09-29 23:36:57 UTC (rev 48562)
@@ -0,0 +1,398 @@
+/****************************************************************************
+ * 
+ *  MODULE:	r.terraflow
+ *
+ *  COPYRIGHT (C) 2007 Laura Toma
+ *   
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *****************************************************************************/
+
+
+#include <stdlib.h>
+#include <assert.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+
+#include <grass/iostream/ami.h>
+
+#include "option.h"
+#include "stats.h"
+#include "sweep.h"
+#include "common.h"
+#include "weightWindow.h"
+#include "nodata.h"
+#include "sortutils.h"
+
+
+/* 
+   #define CHECKPARAM        //output the parameters during sweeping 
+   #define CHECK_WEIGHTS     //output weights as computed
+   #define SWEEP_PRINT_PQSIZE      //output priority queue size during sweeping
+   #define CHECK_MEMORY  //enables printing available memory in between steps
+*/
+
+/* frequency; used to print progress dots */
+static const int DOT_CYCLE = 50;
+static const int PQSIZE_CYCLE = 100;
+
+
+/* globals in common.H
+
+extern statsRecorder *stats;       stats file 
+extern userOptions *opt;           command-line options 
+extern struct  Cell_head *region;  header of the region 
+extern dimension_type nrows, ncols;
+*/
+
+
+
+/* SELECT FLOW DATA STRUCTURE */
+#ifdef IM_PQUEUE
+typedef pqheap_t1<flowStructure> FLOW_DATASTR;
+#endif
+#ifdef EM_PQUEUE
+typedef em_pqueue<flowStructure, flowPriority> FLOW_DATASTR;
+#endif
+#ifdef EMPQ_ADAPTIVE
+typedef EMPQueueAdaptive<flowStructure, flowPriority> FLOW_DATASTR;
+#endif
+
+
+/* defined in this module */
+void pushFlow(const sweepItem& swit, const flowValue &flow, 
+	      FLOW_DATASTR* flowpq, const weightWindow &weight);
+
+
+
+
+/* ------------------------------------------------------------*/
+sweepOutput::sweepOutput() {
+  i = (dimension_type) nodataType::ELEVATION_NODATA;
+  j = (dimension_type) nodataType::ELEVATION_NODATA;
+  accu = (flowaccumulation_type) nodataType::ELEVATION_NODATA;  
+#ifdef OUTPUT_TCI
+  tci = (tci_type) nodataType::ELEVATION_NODATA;
+#endif
+};
+
+
+/* ------------------------------------------------------------ */
+/* computes output parameters of cell (i,j) given the flow value, the
+   elevation of that cell and the weights of that cell; */
+void
+sweepOutput::compute(elevation_type elev, 
+		    dimension_type i_crt, dimension_type j_crt, 
+		    const flowValue &flow, 
+		    const weightWindow &weight, 
+		    const  elevation_type nodata) {
+  
+  float correct_tci; /* this the correct value of tci; we're going to
+  truncate this on current precision tci_type set by user in types.H*/
+
+  assert(elev != nodata);
+  assert(flow.get() >= 0);
+  assert(weight.sumweight >= 0 && weight.sumcontour >= 0);
+
+  i = i_crt;
+  j = j_crt;
+  
+  if (weight.sumweight == 0 || weight.sumcontour == 0) {
+    accu = (flowaccumulation_type)nodata;
+#ifdef OUTPUT_TCI
+    tci = (tci_type)nodata;
+#endif
+    
+  } else {
+    accu = flow.get();
+#ifdef OUTPUT_TCI
+    correct_tci = log(flow.get()*weight.dx()*weight.dy()/weight.totalContour());
+    /* assert(correct_tci > 0); //is this true? */
+    /* there is no need for this warning. tci can be negative if the flow is small. */
+    /* if (correct_tci < 0) {
+       fprintf(stderr, "warning: tci negative, [flow=%f,dx=%f,dy=%f,cont=%f]\n",
+       flow.get(), weight.dx(), weight.dy(), weight.totalContour());
+       }
+    */
+    tci = (tci_type)correct_tci;
+#endif
+  }
+  
+  return;
+}
+
+
+
+
+FLOW_DATASTR* 
+initializePQ() {
+   
+  stats->comment("sweep:initialize flow data structure", opt->verbose);
+  
+  FLOW_DATASTR *flowpq;
+#ifdef IM_PQUEUE
+  stats->comment("FLOW_DATASTRUCTURE: in-memory pqueue");
+  flowpq = new FLOW_DATASTR(PQ_SIZE);
+  char buf[1024]; 
+  sprintf(buf, "initialized to %.2fMB\n", (float)PQ_SIZE / (1<<20));
+  *stats << buf; 
+
+#endif
+#ifdef EM_PQUEUE
+  stats->comment("FLOW_DATASTRUCTURE: ext-memory pqueue");
+  flowpq = new FLOW_DATASTR(nrows * ncols);  
+#endif
+#ifdef EMPQ_ADAPTIVE
+  if (opt->verbose) stats->comment("FLOW_DATASTRUCTURE: adaptive pqueue");
+  flowpq = new FLOW_DATASTR(); 
+#endif
+  return flowpq;
+}
+  
+
+#define INIT_PRINT_PROGRESS()						\
+  long out_frequency, pqsize_frequency;					\
+  out_frequency = nrows*ncols / DOT_CYCLE;		\
+  pqsize_frequency = nrows*ncols / PQSIZE_CYCLE;	\
+  assert(out_frequency);						\
+  assert(pqsize_frequency);
+
+#define PRINT_PROGRESS(k) 			\
+  if ((k) % out_frequency == 0) {		\
+    fprintf(stderr,"."); 				\
+    fflush(stderr);				\
+  };
+
+#ifdef SWEEP_PRINT_PQSIZE
+#define PRINT_PQSIZE(k,flowpq)			\
+  if ((k) % pqsize_frequency == 0) {		\
+    fprintf(stderr," %ld ", (long)(flowpq)->size());	\
+    fflush(stderr);				\
+  }
+#else
+#define PRINT_PQSIZE(k,flowpq)
+#endif
+
+
+
+/***************************************************************/
+/* Read the points in order from the sweep stream and process them.
+   If trustdir = 1 then trust and use the directions contained in the
+   sweep stream. Otherwise push flow to all downslope neighbors and
+   use the direction only for points without downslope neighbors. */
+/***************************************************************/
+
+AMI_STREAM<sweepOutput>* 
+sweep(AMI_STREAM<sweepItem> *sweepstr, const flowaccumulation_type D8CUT,
+      const int trustdir) {
+  flowPriority prio;
+  flowValue flow;
+  sweepItem* crtpoint;
+  AMI_err ae;
+  flowStructure x;	
+  long nitems;
+  Rtimer rt;
+  AMI_STREAM<sweepOutput>* outstr;
+
+  /* INIT_PRINT_PROGRESS(); */
+
+  rt_start(rt);
+
+  assert(sweepstr);
+
+  *stats << "sweeping\n";
+  fprintf(stderr,  "sweeping: ");
+  /* create and initialize flow data structure */
+  FLOW_DATASTR *flowpq;
+  flowpq = initializePQ();
+  
+  /* create output stream */
+  outstr = new AMI_STREAM<sweepOutput>();
+  
+  /* initialize weights and output */
+  weightWindow weight(region->ew_res, region->ns_res);
+  sweepOutput output;
+  nitems = sweepstr->stream_len();
+
+#ifndef NDEBUG
+  flowPriority prevprio = flowPriority(SHRT_MAX);	/* XXX      */
+#endif
+  /* scan the sweep stream  */
+  ae = sweepstr->seek(0);
+  assert(ae == AMI_ERROR_NO_ERROR);
+  for (long k = 0; k < nitems; k++) {
+    
+    /* cout << k << endl; cout.flush(); */
+    /* read next sweepItem = (prio, elevwin, topoRankwin, dir) */
+    ae = sweepstr->read_item(&crtpoint);
+    if (ae != AMI_ERROR_NO_ERROR) {
+      fprintf(stderr, "sweep: k=%ld: cannot read next item..\n", k);
+      exit(1);
+    }
+    /* cout << "k=" << k << " prio =" << crtpoint->getPriority() << "\n"; */
+    /* nodata points should not be in sweep stream */
+    assert(!is_nodata(crtpoint->getElev()));
+#ifndef NDEBUG    
+    assert(crtpoint->getPriority() > prevprio); /* XXX */
+    prevprio = crtpoint->getPriority(); /* XXX */
+#endif
+    
+    
+    /* compute flow accumulation of current point; initial flow value
+       is 1 */
+    flowValue flowini((double)1);
+    /* add flow which was pushed into current point by upslope
+       neighbours */
+    assert(flowpq->is_empty() || 
+		   (flowpq->min(x), x.getPriority() >= crtpoint->getPriority())); /* XXX */
+    assert(flowpq->is_empty() != flowpq->min(x));	/* XXX */
+    if (flowpq->min(x) && ((prio=x.getPriority()) == crtpoint->getPriority())) {
+      flowpq->extract_all_min(x);
+      /* cout << "EXTRACT: " << x << endl; */
+      flow = x.getValue();
+      flow = flow + flowini;
+    } else {
+      flow = flowini;
+    }
+    assert(flowpq->is_empty() || 
+		   (flowpq->min(x), x.getPriority() > crtpoint->getPriority())); /* XXX */
+	
+
+
+    /* compute weights of current point given its direction */
+    if (flow > D8CUT) {
+      /* consider just the dominant direction */
+      weight.makeD8(crtpoint->getI(), crtpoint->getJ(), 
+		    crtpoint->getElevWindow(), crtpoint->getDir(), trustdir);
+    } else {
+      /* consider multiple flow directions */
+      weight.compute(crtpoint->getI(), crtpoint->getJ(), 
+		     crtpoint->getElevWindow(), crtpoint->getDir(), trustdir);
+    }    
+    
+    
+    /* distribute the flow to its downslope neighbours  */
+    pushFlow(*crtpoint, flow, flowpq, weight);
+
+    
+    /* compute parameters  */
+    output.compute(crtpoint->getElev(), crtpoint->getI(), crtpoint->getJ(),
+		   flow, weight, nodataType::ELEVATION_NODATA);
+#ifdef CHECKPARAM   
+    printf("%7ld: (%5d, %5d, %5d) flow: %7.3f, weights:[",
+	   k, crtpoint->getElev(), crtpoint->getI(),crtpoint->getJ(), 
+	   flow.get());
+    for (int l=0;l<9;l++) printf("%2.1f ",weight.get(l));
+    cout <<"] ";
+    cout << output << "\n";
+#endif        
+
+    /* write output to sweep output stream */
+    ae = outstr->write_item(output);
+    assert(ae == AMI_ERROR_NO_ERROR);
+    
+    /* PRINT_PROGRESS(k); */
+    /* PRINT_PQSIZE(k, flowpq); */
+    
+    G_percent(k, nitems, 2);
+  } /* for k  */
+  
+  G_percent(1, 1, 2); /* finish it */
+
+  *stats << "sweeping done\n";
+  char buf[1024];
+  sprintf(buf, "pqsize = %ld \n", (long)flowpq->size());
+  *stats << buf;
+  
+  assert(outstr->stream_len() == nitems);
+  delete flowpq; 
+
+  rt_stop(rt);
+  stats->recordTime("sweeping", rt);
+  stats->recordLength("sweep output stream", outstr);
+
+  return outstr;
+}
+
+
+
+
+
+
+
+/***************************************************************/
+/* push flow to neighbors as indicated by flow direction and reflected
+   by the weights of the neighbors; flow is the accumulated flow value
+   of current point; The neighbours which receive flow from current
+   point are inserted in the FLOW_DATASTR */
+/***************************************************************/
+void 
+pushFlow(const sweepItem& swit, const flowValue &flow, 
+	 FLOW_DATASTR *flowpq, 
+	 const weightWindow &weight) {
+  
+  dimension_type  i_crt, j_crt, i_neighb, j_neighb;
+  short di, dj;
+  elevation_type elev_crt, elev_neighb;
+  toporank_type toporank_crt;
+ 
+  assert(flow >= 0);
+  /* get current coordinates, elevation, topological rank */
+  i_crt = swit.getI(); 
+  j_crt = swit.getJ();
+  elev_crt = swit.getElev();
+  toporank_crt = swit.getTopoRank();
+  assert(!is_nodata(elev_crt)); 
+
+  for (di = -1; di <= 1; di++) {
+    for (dj = -1; dj <= 1; dj++) {
+      if (weight.get(di,dj) > 0) {
+
+		/* push flow to this neighbor  */
+	i_neighb = i_crt + di;  
+	j_neighb = j_crt + dj;
+	elev_neighb = swit.getElev(di,dj);
+	
+	/*assert(IS_BOUNDARY(i_crt,j_crt,hdr) || elev_neighb !=hdr.get_nodata());*/
+	/* it's not simple to check what nodata is on boundary, so we'll
+	just assume directions are correct even if they point to nodata
+	elevation values. */
+
+	if (!is_nodata(elev_neighb)) {
+	  flowPriority prio(elev_neighb, swit.getTopoRank(di,dj), 
+			    i_neighb, j_neighb);
+	  flowPriority prio_crt(elev_crt,toporank_crt, i_crt, j_crt);
+	  /* assert(prio >= prio_crt); */
+#if (defined WARNING_FLAG)
+	  if (prio < prio_crt) {
+	    printf("\n(row=%d,col=%d,ele=%d): ",
+		   i_crt, j_crt, elev_crt);
+	    cout << "attempt to push flow uphill\n";
+	  }
+#endif
+	  flowValue elt(weight.get(di,dj)*flow.get());
+	  flowStructure x(prio, elt);
+	  assert(x.getPriority() > swit.getPriority());
+	  flowpq->insert(x);
+	  /* cout << "INSERT: " << x << endl;  */
+	} /* if (!is_nodata(elev_neighb)) */
+      }
+    } /* for dj */
+  } /* for di */
+  return;
+}
+
+
+
+
+
+

Deleted: grass/trunk/raster/r.terraflow/types.cc
===================================================================
--- grass/trunk/raster/r.terraflow/types.cc	2011-09-29 23:35:42 UTC (rev 48561)
+++ grass/trunk/raster/r.terraflow/types.cc	2011-09-29 23:36:57 UTC (rev 48562)
@@ -1,45 +0,0 @@
-/****************************************************************************
- * 
- *  MODULE:	r.terraflow
- *
- *  COPYRIGHT (C) 2007 Laura Toma
- *   
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *****************************************************************************/
-
-
-#include "types.h"
-
-
-cclabel_type labelFactory::label = labelFactory::getLabelInit();
-
-/* ---------------------------------------------------------------------- */
-
-int 
-ijBaseType::compare(const ijBaseType &a, const ijBaseType &b) {
-  if(a.i < b.i) return -1;
-  if(a.i > b.i) return 1;
-  
-  if(a.j < b.j) return -1;
-  if(a.j > b.j) return 1;
-  
-  return 0;
-}
-
-
-
-ostream&
-operator << (ostream& s, const ijBaseType &p) {
-  return s << "(" << p.i << "," << p.j << ")";
-}
-
-/* ---------------------------------------------------------------------- */

Copied: grass/trunk/raster/r.terraflow/types.cpp (from rev 48560, grass/trunk/raster/r.terraflow/types.cc)
===================================================================
--- grass/trunk/raster/r.terraflow/types.cpp	                        (rev 0)
+++ grass/trunk/raster/r.terraflow/types.cpp	2011-09-29 23:36:57 UTC (rev 48562)
@@ -0,0 +1,45 @@
+/****************************************************************************
+ * 
+ *  MODULE:	r.terraflow
+ *
+ *  COPYRIGHT (C) 2007 Laura Toma
+ *   
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *****************************************************************************/
+
+
+#include "types.h"
+
+
+cclabel_type labelFactory::label = labelFactory::getLabelInit();
+
+/* ---------------------------------------------------------------------- */
+
+int 
+ijBaseType::compare(const ijBaseType &a, const ijBaseType &b) {
+  if(a.i < b.i) return -1;
+  if(a.i > b.i) return 1;
+  
+  if(a.j < b.j) return -1;
+  if(a.j > b.j) return 1;
+  
+  return 0;
+}
+
+
+
+ostream&
+operator << (ostream& s, const ijBaseType &p) {
+  return s << "(" << p.i << "," << p.j << ")";
+}
+
+/* ---------------------------------------------------------------------- */

Deleted: grass/trunk/raster/r.terraflow/water.cc
===================================================================
--- grass/trunk/raster/r.terraflow/water.cc	2011-09-29 23:35:42 UTC (rev 48561)
+++ grass/trunk/raster/r.terraflow/water.cc	2011-09-29 23:36:57 UTC (rev 48562)
@@ -1,586 +0,0 @@
-/****************************************************************************
- * 
- *  MODULE:	r.terraflow
- *
- *  COPYRIGHT (C) 2007 Laura Toma
- *   
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *****************************************************************************/
-
-
-#include <assert.h>
-#include <iostream>
-using namespace std;
-
-#include <grass/iostream/ami.h>
-
-
-#include "3scan.h"
-#include "water.h"
-#include "streamutils.h"
-#include "sortutils.h"
-
-#define WATER_DEBUG if(0)
-#define XXX if(0)
-
-
-char *
-labelElevType::printLabel(const  labelElevType  &p) {
-  static char buf[8];
-  sprintf(buf, CCLABEL_FMT, p.label);
-  return buf;
-}
-
-
-
-
-
-
-/* smaller elevation, depth is smaller priority */
-int 
-fillPriority::compare(const fillPriority &a, const fillPriority &b) {
-  if(a.el < b.el) return -1;
-  if(a.el > b.el) return 1;
-  
-  if(a.depth < b.depth) return -1;
-  if(a.depth > b.depth) return 1;
-  
-  if(a.i < b.i) return -1;
-  if(a.i > b.i) return 1;
-  
-  if(a.j < b.j) return -1;
-  if(a.j > b.j) return 1;
-  
-  return 0;
-}
-
-int
-fillPriority::qscompare(const void *a, const void *b) {
-  fillPriority *x = (fillPriority*)a;
-  fillPriority *y = (fillPriority*)b;
-  return compare(*x, *y);
-}
-
-int 
-operator<(const fillPriority &a, const fillPriority &b) {
-  if(a.el < b.el) return 1;
-  if(a.el > b.el) return 0;
-  
-  if(a.depth < b.depth) return 1;
-  if(a.depth > b.depth) return 0;
-  
-  if(a.i < b.i) return 1;
-  if(a.i > b.i) return 0;
-  
-  if(a.j < b.j) return 1;
-  if(a.j > b.j) return 0;
-  
-  return 0;
-}
-
-int
-operator<=(const fillPriority &a, const fillPriority &b) {
-  if(a.el < b.el) return 1;
-  if(a.el > b.el) return 0;
-  
-  if(a.depth < b.depth) return 1;
-  if(a.depth > b.depth) return 0;
-  
-  if(a.i < b.i) return 1;
-  if(a.i > b.i) return 0;
-  
-  if(a.j < b.j) return 1;
-  if(a.j > b.j) return 0;
-  
-  return 1;
-}
-
-int 
-operator>(const fillPriority &a, const fillPriority &b) {
-  if(a.el < b.el) return 0;
-  if(a.el > b.el) return 1;
-  
-  if(a.depth < b.depth) return 0;
-  if(a.depth > b.depth) return 1;
-  
-  if(a.i < b.i) return 0;
-  if(a.i > b.i) return 1;
-  
-  if(a.j < b.j) return 0;
-  if(a.j > b.j) return 1;
-  
-  return 0;
-}
-
-
-int 
-operator==(const fillPriority &a, const fillPriority &b) {
-  return (a.el == b.el) 
-	&& (a.depth == b.depth) 
-	&& (a.i == b.i)
-	&& (a.j == b.j);
-}
-
-
-int 
-operator!=(const fillPriority &a, const fillPriority &b) {
-  return (a.el != b.el) 
-	|| (a.depth != b.depth) 
-	|| (a.i != b.i)
-	|| (a.j != b.j);	
-}
-
-
-ostream&
-operator << (ostream& s, const fillPriority &p) {
-  return s << "[fillPriority el=" << p.el 
-		   << ", d=" << p.depth << ", "
-		   << p.i  << ","
-		   << p.j << "]";
-}
-
-
-
-/* ********************************************************************** */
-
-
-ostream&
-operator << (ostream& s, const labelElevType &p) {
-  return s << (ijBaseType)p << " "
-		   << "el=" << p.el << ", "
-		   << p.label;
-}
-
-/* ********************************************************************** */
-
-char *
-waterType::printLabel(const waterType &p) {
-  static char buf[8];
-  sprintf(buf, CCLABEL_FMT, p.label);
-  return buf;
-}
-
-/* ********************************************************************** */
-
-
-char *
-boundaryType::print(const boundaryType &p) {
-  static char buf[4];
-  if(p.isValid()) {
-	buf[0] = '1';
-  } else {
-	buf[0] = '0';
-  }
-  buf[1] = '\0';
-  
-  return buf;
-}
-
-
-ostream&
-operator << (ostream& s, const boundaryType &p) {
-  return s << "[boundaryType "  
-		   << (labelElevType)p << ", "
-		   << p.label2 << "]";
-}
-
-
-
-/* ********************************************************************** */
-/* ********************************************************************** */
-
-class waterWindower {
-private:
-  AMI_STREAM<waterWindowType> *waterWindows;
-public:
-  waterWindower(AMI_STREAM<waterWindowType> *str) :
-	waterWindows(str) {};
-  void processWindow(dimension_type i, dimension_type j, 
-		     waterGridType &point,
-		     waterWindowBaseType *a,
-		     waterWindowBaseType *b,
-		     waterWindowBaseType *c);
-};
-
-void
-waterWindower::processWindow(dimension_type i, dimension_type j, 
-			     waterGridType &point,
-			     waterWindowBaseType *a,
-			     waterWindowBaseType *b,
-			     waterWindowBaseType *c) {
-  waterWindowType win = waterWindowType(i, j, point.getLabel(), a, b, c);
-  AMI_err ae = waterWindows->write_item(win);
-  assert(ae == AMI_ERROR_NO_ERROR);
-}
-
-void
-createWaterWindows(AMI_STREAM<waterGridType> *mergedWaterStr, 
-		   const dimension_type nrows, const dimension_type ncols,
-		   AMI_STREAM<waterWindowType> *waterWindows) {
-  stats->comment("creating windows", opt->verbose);
-  waterWindower winfo(waterWindows);
-  waterWindowBaseType nodata;
-  assert(mergedWaterStr->stream_len() > 0);
-  stats->comment("warning: using slower scan", opt->verbose);
-  scan3(*mergedWaterStr, nrows, ncols, nodata, winfo);
-}
-
-
-/* ********************************************************************** */
-/* ********************************************************************** */
-
-
-/*
- * push labels to upslope neighbors 
- */
-void
-generateWatersheds(AMI_STREAM<waterWindowType> **waterWindows,
-				   const dimension_type nrows, const dimension_type ncols,
-				   AMI_STREAM<labelElevType> *labeledWater, 
-				   AMI_STREAM<boundaryType> *boundaryStr) {
-  AMI_err ae;
-  waterWindowType *winp, prevWin;
-  assert(prevWin.getDepth() == DEPTH_INITIAL);
-  EMPQueueAdaptive<fillPLabel, fillPriority> *pq;
-
-  stats->comment("generateWatersheds", opt->verbose);
-
-  assert((*waterWindows)->stream_len() == (nrows * ncols));
-
-  WATER_DEBUG cout << "sort waterWindowsStream (by priority): ";
-  sort(waterWindows, priorityCmpWaterWindowType());
-  
-  pq = new EMPQueueAdaptive<fillPLabel, fillPriority>();
-  
-/*   if(GETOPT("alwaysUseExternalPQ")) { */
-/*      pq->makeExternal(); */
-/*    } */
-/*    if(GETOPT("useDebugPQ")) { */
-/*      pq->makeExternalDebug(); */
-/*    } */
-  
-  stats->comment("starting generate watersheds main loop", opt->verbose);
-  
-  assert((*waterWindows)->stream_len() == (nrows * ncols));
-  /* not really in a grid, so row, col are not valid (but count correct) */
-  for(dimension_type row=0; row<nrows; row++) {
-    for(dimension_type col=0; col<ncols; col++) {
-      ae = (*waterWindows)->read_item(&winp);
-      assert(ae == AMI_ERROR_NO_ERROR);
-      
-      /* make sure it's sorted; prevWin default constructor should be ok */
-      assert(winp->getPriority() > prevWin.getPriority());
-      prevWin = *winp;
-      
-      XXX winp->sanityCheck();
-      /* cout << "--- PROC: " << *winp << endl; */
-      /* get my label(s) */
-      fillPLabel plabel;		/* from the PQ */
-      fillPriority prio;
-      cclabel_type label = winp->getLabel();
-#ifndef NDEBUG
-      {
-	/* check to see if things are coming out of the pq in
-	   order. just peek at the next one */
-	fillPLabel tmp;
-	XXX winp->sanityCheck();
-	pq->min(tmp);
-	/* XXX pq->verify(); */
-	XXX winp->sanityCheck();
-	assert(pq->is_empty() || winp->getPriority() <= tmp.getPriority());
-      }
-#endif
-      while(pq->min(plabel) &&
-			((prio=plabel.getPriority()) == winp->getPriority())) {
-		/* XXX pq->verify(); */
-		XXX winp->sanityCheck();
-		pq->extract_min(plabel);
-		/* XXX pq->verify(); */
-		XXX winp->sanityCheck();
-		if(label == LABEL_UNDEF) label = plabel.getLabel();
-      } 
-      /* no label! assign a new one */
-      if((label==LABEL_UNDEF) && (!is_nodata(winp->getElevation()))) {
-#ifndef NDEBUG
-	{
-	  /* check to see if things are coming out of the pq in
-	     order. just peek at the next one */
-	  fillPLabel tmp;		
-	  XXX winp->sanityCheck();
-	  pq->min(tmp);
-	  /* XXX pq->verify(); */
-	  XXX winp->sanityCheck();
-	  assert(pq->is_empty() || winp->getPriority() <= tmp.getPriority());
-	}
-#endif
-	if(IS_BOUNDARY(winp->i,winp->j,nrows, ncols)) {  /* edge of grid */
-	  assert(!is_nodata(winp->getElevation()));
-	  label = LABEL_BOUNDARY; /* reserved for watersheds draining
-				     out of grid */
-	} else {
-	  label = labelFactory::getNewLabel();
-	}
-      }
-      winp->setLabel(label);
-      
-      /* push label to 'upslope' neighbors.  let's assume that the
-       * edges cause no problems, since they have no directions...  */
-      if(label != LABEL_UNDEF) {
-	int k=0;
-	for(int i=-1; i<2; i++) {
-	  for(int j=-1; j<2; j++) {
-	    assert(k==linear(i,j));
-	    if(!is_nodata(winp->getElevation(k))
-	       && winp->drainsFrom(i,j)) { /* points to me */
-	      assert(i || j);
-	      prio = fillPriority(winp->getElevation(k),
-				  winp->getDepth(k),
-				  winp->i + i, winp->j + j);
-#ifndef NDEBUG
-	      /* dont insert if preceeds us */
-	      if(winp->getPriority() < prio) {
-		fillPLabel plabel(prio, label);
-		pq->insert(plabel);
-	      } else {			/* trying to send a label backward */
-		cerr << "WARNING: time travel attempted" << endl; 
-		cerr << "inst priority is " << prio << endl;
-		cerr << "source is " << *winp << "; prio=" 
-		     << winp->getPriority() << endl;
-		assert(0);
-	      }
-#else
-	      fillPLabel plabel(prio, label);
-	      pq->insert(plabel);
-#endif
-	    }
-	    k++;
-	  }
-	}
-      }
-      
-      /* write myself to output */
-      ae = labeledWater->write_item(winp->getCenter());
-      assert(ae == AMI_ERROR_NO_ERROR);
-    }
-  }
-  
-  assert(pq->is_empty());
-  delete pq;
-  
-  stats->comment("done with generate watersheds", opt->verbose);
-}
-
-
-
-/* ********************************************************************** */
-
-
-class boundaryDetector {
-private:
-  const dimension_type nrows, ncols;
-  AMI_STREAM<boundaryType> *boundaryStr;
-  void processPair(labelElevType &pt, 
-		   dimension_type i, dimension_type j, labelElevType &n);
-public:
-  boundaryDetector(AMI_STREAM<boundaryType> *str, 
-				   const dimension_type gnrows, const dimension_type gncols) 
-    : nrows(gnrows), ncols(gncols), boundaryStr(str) {};
-  
-  void processWindow(dimension_type i, dimension_type j, 
-		     labelElevType &point,
-		     labelElevType *a,
-		     labelElevType *b,
-		     labelElevType *c);
-};
-
-template<class T>
-T mymax(T a, T b) {
-  return (a>b?a:b);
-}
-
-void
-boundaryDetector::processPair(labelElevType &pt, 
-			      dimension_type i, dimension_type j,
-			      labelElevType &n) {
-  if(n.getLabel() != LABEL_UNDEF && pt.getLabel() != n.getLabel()) {
-    boundaryType bt(pt, mymax(pt.getElevation(), n.getElevation()), 
-		    n.getLabel());
-    AMI_err ae = boundaryStr->write_item(bt);
-    assert(ae == AMI_ERROR_NO_ERROR);
-  } else if(IS_BOUNDARY(i,j,nrows, ncols) && pt.getLabel() != LABEL_BOUNDARY) {
-    /* this part makes sure that regions on the grid edge
-       are considered 'boundary' */
-    boundaryType bt(pt, LABEL_BOUNDARY);
-    AMI_err ae = boundaryStr->write_item(bt);
-    assert(ae == AMI_ERROR_NO_ERROR);
-  }
-}
-
-void
-boundaryDetector::processWindow(dimension_type i, dimension_type j, 
-				labelElevType &point,
-				labelElevType *a,
-				labelElevType *b,
-				labelElevType *c) {
-  if(point.getLabel() == LABEL_UNDEF) return;
-  /* NODATA_FIX */
-  /* don't use the nodata as the boundary. */
-  /* if(point.getLabel() == LABEL_NODATA) return; */
-  assert(point.getLabel() != LABEL_NODATA);
-  
-  for(int k=0; k<3; k++) {
-	processPair(point, i, j, a[k]);
-	processPair(point, i, j, b[k]);
-	processPair(point, i, j, c[k]);
-  }
-  /* processPair(point, i, j, b[0]); */
-}
-
-
-/* ********************************************************************** */
-
-void
-findBoundaries(AMI_STREAM<labelElevType> *labeledWater,
-	       const dimension_type nrows, const dimension_type ncols,	 
-	       AMI_STREAM<boundaryType> *boundaryStr) {
-  stats->comment("creating windows", opt->verbose);
-  boundaryDetector det(boundaryStr, nrows, ncols);
-  /* cerr << "WARNING: using scan3 instead of scan2" << endl; */
-  scan3(*labeledWater, nrows, ncols, labelElevType(), det);
-  
-  /*  NODATA_FIX 
-	  assert(LABEL_BOUNDARY < LABEL_NODATA);
-	  boundaryType bt(-1, -1, ELEVATION_MIN, LABEL_BOUNDARY, LABEL_NODATA);
-	  AMI_err ae = boundaryStr->write_item(bt);
-	  assert(ae == AMI_ERROR_NO_ERROR);
-  */
-}
-  
-
-/* ********************************************************************** */
-
-int
-compressedWaterWindowBaseType::computeDelta(waterWindowBaseType *center,
-					    int index,
-					    waterWindowBaseType *p) const{
-  if(center->el != p->el) {
-    assert(p->depth == 1 || center->el > p->el);
-    return 0;
-  }
-  if(index > 7) return 0;		/* we store our depth elsewhere */
-  
-  int d = p->depth - center->depth + 1;
-  assert(d >= 0);
-#ifndef NDEBUG
-  if(d>2) {
-	cerr << "whoops - assertion failure" << endl;
-	cerr << "center = " << *center << endl;
-	cerr << "p = " << *p << endl;
-	cerr << "this = " << *this << endl;
-  }
-#endif
-  assert(d <= 2);
-  return d<<(2*index);
-}
-
-compressedWaterWindowBaseType::compressedWaterWindowBaseType(dimension_type gi,
-							     dimension_type gj,
-							     waterWindowBaseType *a, 
-							     waterWindowBaseType *b, 
-							     waterWindowBaseType *c) 
-  : ijBaseType(gi, gj) {
-  
-  for(int i=0; i<3; i++) {
-    el[i] = a[i].el;
-    el[i+3] = b[i].el;
-    el[i+6] = c[i].el;
-  }
-  
-  for(int i=0; i<3; i++) {
-    const direction_type mask_a[] = {2, 4, 8};
-    const direction_type mask_b[] = {1, 0, 16};
-    const direction_type mask_c[] = {128, 64, 32};
-    points.setBit(i, a[i].dir & mask_a[i]);
-    points.setBit(norm(i+3), b[i].dir & mask_b[i]);
-    points.setBit(i+5, c[i].dir & mask_c[i]);
-  }
-  dir = b[1].dir;
-  depth = b[1].depth;
-  depth_delta = 0;
-  
-  /* nodata is not processed. */
-  if(is_nodata(b[1].el)) {
-    return;
-  }
-  
-  for(int i=0; i<3; i++) {
-    depth_delta |= computeDelta(b+1, norm(-1,i-1), a+i);
-    depth_delta |= computeDelta(b+1, norm(0,i-1), b+i);
-    depth_delta |= computeDelta(b+1, norm(1,i-1), c+i);
-  }
-}
-
-fillPriority
-compressedWaterWindowBaseType::getPriority() const {
-  return fillPriority(getElevation(), getDepth(), i, j);
-}
-
-
-bfs_depth_type
-compressedWaterWindowBaseType::getDepth(int k) const {
-  if(getElevation() != getElevation(k)) return DEPTH_INITIAL;
-  return depth + ((depth_delta >> (norm(k)*2)) & 0x3) - 1;
-}
-
-
-void 
-compressedWaterWindowBaseType::sanityCheck() {
-  assert(i >= -1);
-  assert(j >= -1);
-  assert(depth >= DEPTH_INITIAL);
-}
-  
-
-ostream&
-operator<<(ostream& s, const compressedWaterWindowBaseType &p) {
-  return s << "[compressedWaterWindowBaseType " 
-	   << p.i << "," << p.j 
-	   << " " << directionSymbol(p.getDirection())
-	   << " e=" << p.getElevation() 
-	   << " d =" << p.getDepth() << "]";
-}
-
-/* ********************************************************************** */
-
-labelElevType 
-compressedWaterWindowType::getCenter() const {
-  return labelElevType(i, j, getElevation(), label);
-}
-
-void 
-compressedWaterWindowType::sanityCheck() {
-  assert(label >= LABEL_UNDEF);
-  compressedWaterWindowBaseType::sanityCheck();
-}
-
-
-ostream&
-operator<<(ostream& s, const compressedWaterWindowType &p) {
-  return s << "[compressedWaterWindowType " 
-	   << p.i << "," <<  p.j 
-	   << "  " << directionSymbol(p.getDirection())
-	   << " e=" << p.getElevation()
-	   << " d=" << p.getDepth() 
-	   << " l=" << p.label;
-}
-
-

Copied: grass/trunk/raster/r.terraflow/water.cpp (from rev 48560, grass/trunk/raster/r.terraflow/water.cc)
===================================================================
--- grass/trunk/raster/r.terraflow/water.cpp	                        (rev 0)
+++ grass/trunk/raster/r.terraflow/water.cpp	2011-09-29 23:36:57 UTC (rev 48562)
@@ -0,0 +1,586 @@
+/****************************************************************************
+ * 
+ *  MODULE:	r.terraflow
+ *
+ *  COPYRIGHT (C) 2007 Laura Toma
+ *   
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *****************************************************************************/
+
+
+#include <assert.h>
+#include <iostream>
+using namespace std;
+
+#include <grass/iostream/ami.h>
+
+
+#include "3scan.h"
+#include "water.h"
+#include "streamutils.h"
+#include "sortutils.h"
+
+#define WATER_DEBUG if(0)
+#define XXX if(0)
+
+
+char *
+labelElevType::printLabel(const  labelElevType  &p) {
+  static char buf[8];
+  sprintf(buf, CCLABEL_FMT, p.label);
+  return buf;
+}
+
+
+
+
+
+
+/* smaller elevation, depth is smaller priority */
+int 
+fillPriority::compare(const fillPriority &a, const fillPriority &b) {
+  if(a.el < b.el) return -1;
+  if(a.el > b.el) return 1;
+  
+  if(a.depth < b.depth) return -1;
+  if(a.depth > b.depth) return 1;
+  
+  if(a.i < b.i) return -1;
+  if(a.i > b.i) return 1;
+  
+  if(a.j < b.j) return -1;
+  if(a.j > b.j) return 1;
+  
+  return 0;
+}
+
+int
+fillPriority::qscompare(const void *a, const void *b) {
+  fillPriority *x = (fillPriority*)a;
+  fillPriority *y = (fillPriority*)b;
+  return compare(*x, *y);
+}
+
+int 
+operator<(const fillPriority &a, const fillPriority &b) {
+  if(a.el < b.el) return 1;
+  if(a.el > b.el) return 0;
+  
+  if(a.depth < b.depth) return 1;
+  if(a.depth > b.depth) return 0;
+  
+  if(a.i < b.i) return 1;
+  if(a.i > b.i) return 0;
+  
+  if(a.j < b.j) return 1;
+  if(a.j > b.j) return 0;
+  
+  return 0;
+}
+
+int
+operator<=(const fillPriority &a, const fillPriority &b) {
+  if(a.el < b.el) return 1;
+  if(a.el > b.el) return 0;
+  
+  if(a.depth < b.depth) return 1;
+  if(a.depth > b.depth) return 0;
+  
+  if(a.i < b.i) return 1;
+  if(a.i > b.i) return 0;
+  
+  if(a.j < b.j) return 1;
+  if(a.j > b.j) return 0;
+  
+  return 1;
+}
+
+int 
+operator>(const fillPriority &a, const fillPriority &b) {
+  if(a.el < b.el) return 0;
+  if(a.el > b.el) return 1;
+  
+  if(a.depth < b.depth) return 0;
+  if(a.depth > b.depth) return 1;
+  
+  if(a.i < b.i) return 0;
+  if(a.i > b.i) return 1;
+  
+  if(a.j < b.j) return 0;
+  if(a.j > b.j) return 1;
+  
+  return 0;
+}
+
+
+int 
+operator==(const fillPriority &a, const fillPriority &b) {
+  return (a.el == b.el) 
+	&& (a.depth == b.depth) 
+	&& (a.i == b.i)
+	&& (a.j == b.j);
+}
+
+
+int 
+operator!=(const fillPriority &a, const fillPriority &b) {
+  return (a.el != b.el) 
+	|| (a.depth != b.depth) 
+	|| (a.i != b.i)
+	|| (a.j != b.j);	
+}
+
+
+ostream&
+operator << (ostream& s, const fillPriority &p) {
+  return s << "[fillPriority el=" << p.el 
+		   << ", d=" << p.depth << ", "
+		   << p.i  << ","
+		   << p.j << "]";
+}
+
+
+
+/* ********************************************************************** */
+
+
+ostream&
+operator << (ostream& s, const labelElevType &p) {
+  return s << (ijBaseType)p << " "
+		   << "el=" << p.el << ", "
+		   << p.label;
+}
+
+/* ********************************************************************** */
+
+char *
+waterType::printLabel(const waterType &p) {
+  static char buf[8];
+  sprintf(buf, CCLABEL_FMT, p.label);
+  return buf;
+}
+
+/* ********************************************************************** */
+
+
+char *
+boundaryType::print(const boundaryType &p) {
+  static char buf[4];
+  if(p.isValid()) {
+	buf[0] = '1';
+  } else {
+	buf[0] = '0';
+  }
+  buf[1] = '\0';
+  
+  return buf;
+}
+
+
+ostream&
+operator << (ostream& s, const boundaryType &p) {
+  return s << "[boundaryType "  
+		   << (labelElevType)p << ", "
+		   << p.label2 << "]";
+}
+
+
+
+/* ********************************************************************** */
+/* ********************************************************************** */
+
+class waterWindower {
+private:
+  AMI_STREAM<waterWindowType> *waterWindows;
+public:
+  waterWindower(AMI_STREAM<waterWindowType> *str) :
+	waterWindows(str) {};
+  void processWindow(dimension_type i, dimension_type j, 
+		     waterGridType &point,
+		     waterWindowBaseType *a,
+		     waterWindowBaseType *b,
+		     waterWindowBaseType *c);
+};
+
+void
+waterWindower::processWindow(dimension_type i, dimension_type j, 
+			     waterGridType &point,
+			     waterWindowBaseType *a,
+			     waterWindowBaseType *b,
+			     waterWindowBaseType *c) {
+  waterWindowType win = waterWindowType(i, j, point.getLabel(), a, b, c);
+  AMI_err ae = waterWindows->write_item(win);
+  assert(ae == AMI_ERROR_NO_ERROR);
+}
+
+void
+createWaterWindows(AMI_STREAM<waterGridType> *mergedWaterStr, 
+		   const dimension_type nrows, const dimension_type ncols,
+		   AMI_STREAM<waterWindowType> *waterWindows) {
+  stats->comment("creating windows", opt->verbose);
+  waterWindower winfo(waterWindows);
+  waterWindowBaseType nodata;
+  assert(mergedWaterStr->stream_len() > 0);
+  stats->comment("warning: using slower scan", opt->verbose);
+  scan3(*mergedWaterStr, nrows, ncols, nodata, winfo);
+}
+
+
+/* ********************************************************************** */
+/* ********************************************************************** */
+
+
+/*
+ * push labels to upslope neighbors 
+ */
+void
+generateWatersheds(AMI_STREAM<waterWindowType> **waterWindows,
+				   const dimension_type nrows, const dimension_type ncols,
+				   AMI_STREAM<labelElevType> *labeledWater, 
+				   AMI_STREAM<boundaryType> *boundaryStr) {
+  AMI_err ae;
+  waterWindowType *winp, prevWin;
+  assert(prevWin.getDepth() == DEPTH_INITIAL);
+  EMPQueueAdaptive<fillPLabel, fillPriority> *pq;
+
+  stats->comment("generateWatersheds", opt->verbose);
+
+  assert((*waterWindows)->stream_len() == (nrows * ncols));
+
+  WATER_DEBUG cout << "sort waterWindowsStream (by priority): ";
+  sort(waterWindows, priorityCmpWaterWindowType());
+  
+  pq = new EMPQueueAdaptive<fillPLabel, fillPriority>();
+  
+/*   if(GETOPT("alwaysUseExternalPQ")) { */
+/*      pq->makeExternal(); */
+/*    } */
+/*    if(GETOPT("useDebugPQ")) { */
+/*      pq->makeExternalDebug(); */
+/*    } */
+  
+  stats->comment("starting generate watersheds main loop", opt->verbose);
+  
+  assert((*waterWindows)->stream_len() == (nrows * ncols));
+  /* not really in a grid, so row, col are not valid (but count correct) */
+  for(dimension_type row=0; row<nrows; row++) {
+    for(dimension_type col=0; col<ncols; col++) {
+      ae = (*waterWindows)->read_item(&winp);
+      assert(ae == AMI_ERROR_NO_ERROR);
+      
+      /* make sure it's sorted; prevWin default constructor should be ok */
+      assert(winp->getPriority() > prevWin.getPriority());
+      prevWin = *winp;
+      
+      XXX winp->sanityCheck();
+      /* cout << "--- PROC: " << *winp << endl; */
+      /* get my label(s) */
+      fillPLabel plabel;		/* from the PQ */
+      fillPriority prio;
+      cclabel_type label = winp->getLabel();
+#ifndef NDEBUG
+      {
+	/* check to see if things are coming out of the pq in
+	   order. just peek at the next one */
+	fillPLabel tmp;
+	XXX winp->sanityCheck();
+	pq->min(tmp);
+	/* XXX pq->verify(); */
+	XXX winp->sanityCheck();
+	assert(pq->is_empty() || winp->getPriority() <= tmp.getPriority());
+      }
+#endif
+      while(pq->min(plabel) &&
+			((prio=plabel.getPriority()) == winp->getPriority())) {
+		/* XXX pq->verify(); */
+		XXX winp->sanityCheck();
+		pq->extract_min(plabel);
+		/* XXX pq->verify(); */
+		XXX winp->sanityCheck();
+		if(label == LABEL_UNDEF) label = plabel.getLabel();
+      } 
+      /* no label! assign a new one */
+      if((label==LABEL_UNDEF) && (!is_nodata(winp->getElevation()))) {
+#ifndef NDEBUG
+	{
+	  /* check to see if things are coming out of the pq in
+	     order. just peek at the next one */
+	  fillPLabel tmp;		
+	  XXX winp->sanityCheck();
+	  pq->min(tmp);
+	  /* XXX pq->verify(); */
+	  XXX winp->sanityCheck();
+	  assert(pq->is_empty() || winp->getPriority() <= tmp.getPriority());
+	}
+#endif
+	if(IS_BOUNDARY(winp->i,winp->j,nrows, ncols)) {  /* edge of grid */
+	  assert(!is_nodata(winp->getElevation()));
+	  label = LABEL_BOUNDARY; /* reserved for watersheds draining
+				     out of grid */
+	} else {
+	  label = labelFactory::getNewLabel();
+	}
+      }
+      winp->setLabel(label);
+      
+      /* push label to 'upslope' neighbors.  let's assume that the
+       * edges cause no problems, since they have no directions...  */
+      if(label != LABEL_UNDEF) {
+	int k=0;
+	for(int i=-1; i<2; i++) {
+	  for(int j=-1; j<2; j++) {
+	    assert(k==linear(i,j));
+	    if(!is_nodata(winp->getElevation(k))
+	       && winp->drainsFrom(i,j)) { /* points to me */
+	      assert(i || j);
+	      prio = fillPriority(winp->getElevation(k),
+				  winp->getDepth(k),
+				  winp->i + i, winp->j + j);
+#ifndef NDEBUG
+	      /* dont insert if preceeds us */
+	      if(winp->getPriority() < prio) {
+		fillPLabel plabel(prio, label);
+		pq->insert(plabel);
+	      } else {			/* trying to send a label backward */
+		cerr << "WARNING: time travel attempted" << endl; 
+		cerr << "inst priority is " << prio << endl;
+		cerr << "source is " << *winp << "; prio=" 
+		     << winp->getPriority() << endl;
+		assert(0);
+	      }
+#else
+	      fillPLabel plabel(prio, label);
+	      pq->insert(plabel);
+#endif
+	    }
+	    k++;
+	  }
+	}
+      }
+      
+      /* write myself to output */
+      ae = labeledWater->write_item(winp->getCenter());
+      assert(ae == AMI_ERROR_NO_ERROR);
+    }
+  }
+  
+  assert(pq->is_empty());
+  delete pq;
+  
+  stats->comment("done with generate watersheds", opt->verbose);
+}
+
+
+
+/* ********************************************************************** */
+
+
+class boundaryDetector {
+private:
+  const dimension_type nrows, ncols;
+  AMI_STREAM<boundaryType> *boundaryStr;
+  void processPair(labelElevType &pt, 
+		   dimension_type i, dimension_type j, labelElevType &n);
+public:
+  boundaryDetector(AMI_STREAM<boundaryType> *str, 
+				   const dimension_type gnrows, const dimension_type gncols) 
+    : nrows(gnrows), ncols(gncols), boundaryStr(str) {};
+  
+  void processWindow(dimension_type i, dimension_type j, 
+		     labelElevType &point,
+		     labelElevType *a,
+		     labelElevType *b,
+		     labelElevType *c);
+};
+
+template<class T>
+T mymax(T a, T b) {
+  return (a>b?a:b);
+}
+
+void
+boundaryDetector::processPair(labelElevType &pt, 
+			      dimension_type i, dimension_type j,
+			      labelElevType &n) {
+  if(n.getLabel() != LABEL_UNDEF && pt.getLabel() != n.getLabel()) {
+    boundaryType bt(pt, mymax(pt.getElevation(), n.getElevation()), 
+		    n.getLabel());
+    AMI_err ae = boundaryStr->write_item(bt);
+    assert(ae == AMI_ERROR_NO_ERROR);
+  } else if(IS_BOUNDARY(i,j,nrows, ncols) && pt.getLabel() != LABEL_BOUNDARY) {
+    /* this part makes sure that regions on the grid edge
+       are considered 'boundary' */
+    boundaryType bt(pt, LABEL_BOUNDARY);
+    AMI_err ae = boundaryStr->write_item(bt);
+    assert(ae == AMI_ERROR_NO_ERROR);
+  }
+}
+
+void
+boundaryDetector::processWindow(dimension_type i, dimension_type j, 
+				labelElevType &point,
+				labelElevType *a,
+				labelElevType *b,
+				labelElevType *c) {
+  if(point.getLabel() == LABEL_UNDEF) return;
+  /* NODATA_FIX */
+  /* don't use the nodata as the boundary. */
+  /* if(point.getLabel() == LABEL_NODATA) return; */
+  assert(point.getLabel() != LABEL_NODATA);
+  
+  for(int k=0; k<3; k++) {
+	processPair(point, i, j, a[k]);
+	processPair(point, i, j, b[k]);
+	processPair(point, i, j, c[k]);
+  }
+  /* processPair(point, i, j, b[0]); */
+}
+
+
+/* ********************************************************************** */
+
+void
+findBoundaries(AMI_STREAM<labelElevType> *labeledWater,
+	       const dimension_type nrows, const dimension_type ncols,	 
+	       AMI_STREAM<boundaryType> *boundaryStr) {
+  stats->comment("creating windows", opt->verbose);
+  boundaryDetector det(boundaryStr, nrows, ncols);
+  /* cerr << "WARNING: using scan3 instead of scan2" << endl; */
+  scan3(*labeledWater, nrows, ncols, labelElevType(), det);
+  
+  /*  NODATA_FIX 
+	  assert(LABEL_BOUNDARY < LABEL_NODATA);
+	  boundaryType bt(-1, -1, ELEVATION_MIN, LABEL_BOUNDARY, LABEL_NODATA);
+	  AMI_err ae = boundaryStr->write_item(bt);
+	  assert(ae == AMI_ERROR_NO_ERROR);
+  */
+}
+  
+
+/* ********************************************************************** */
+
+int
+compressedWaterWindowBaseType::computeDelta(waterWindowBaseType *center,
+					    int index,
+					    waterWindowBaseType *p) const{
+  if(center->el != p->el) {
+    assert(p->depth == 1 || center->el > p->el);
+    return 0;
+  }
+  if(index > 7) return 0;		/* we store our depth elsewhere */
+  
+  int d = p->depth - center->depth + 1;
+  assert(d >= 0);
+#ifndef NDEBUG
+  if(d>2) {
+	cerr << "whoops - assertion failure" << endl;
+	cerr << "center = " << *center << endl;
+	cerr << "p = " << *p << endl;
+	cerr << "this = " << *this << endl;
+  }
+#endif
+  assert(d <= 2);
+  return d<<(2*index);
+}
+
+compressedWaterWindowBaseType::compressedWaterWindowBaseType(dimension_type gi,
+							     dimension_type gj,
+							     waterWindowBaseType *a, 
+							     waterWindowBaseType *b, 
+							     waterWindowBaseType *c) 
+  : ijBaseType(gi, gj) {
+  
+  for(int i=0; i<3; i++) {
+    el[i] = a[i].el;
+    el[i+3] = b[i].el;
+    el[i+6] = c[i].el;
+  }
+  
+  for(int i=0; i<3; i++) {
+    const direction_type mask_a[] = {2, 4, 8};
+    const direction_type mask_b[] = {1, 0, 16};
+    const direction_type mask_c[] = {128, 64, 32};
+    points.setBit(i, a[i].dir & mask_a[i]);
+    points.setBit(norm(i+3), b[i].dir & mask_b[i]);
+    points.setBit(i+5, c[i].dir & mask_c[i]);
+  }
+  dir = b[1].dir;
+  depth = b[1].depth;
+  depth_delta = 0;
+  
+  /* nodata is not processed. */
+  if(is_nodata(b[1].el)) {
+    return;
+  }
+  
+  for(int i=0; i<3; i++) {
+    depth_delta |= computeDelta(b+1, norm(-1,i-1), a+i);
+    depth_delta |= computeDelta(b+1, norm(0,i-1), b+i);
+    depth_delta |= computeDelta(b+1, norm(1,i-1), c+i);
+  }
+}
+
+fillPriority
+compressedWaterWindowBaseType::getPriority() const {
+  return fillPriority(getElevation(), getDepth(), i, j);
+}
+
+
+bfs_depth_type
+compressedWaterWindowBaseType::getDepth(int k) const {
+  if(getElevation() != getElevation(k)) return DEPTH_INITIAL;
+  return depth + ((depth_delta >> (norm(k)*2)) & 0x3) - 1;
+}
+
+
+void 
+compressedWaterWindowBaseType::sanityCheck() {
+  assert(i >= -1);
+  assert(j >= -1);
+  assert(depth >= DEPTH_INITIAL);
+}
+  
+
+ostream&
+operator<<(ostream& s, const compressedWaterWindowBaseType &p) {
+  return s << "[compressedWaterWindowBaseType " 
+	   << p.i << "," << p.j 
+	   << " " << directionSymbol(p.getDirection())
+	   << " e=" << p.getElevation() 
+	   << " d =" << p.getDepth() << "]";
+}
+
+/* ********************************************************************** */
+
+labelElevType 
+compressedWaterWindowType::getCenter() const {
+  return labelElevType(i, j, getElevation(), label);
+}
+
+void 
+compressedWaterWindowType::sanityCheck() {
+  assert(label >= LABEL_UNDEF);
+  compressedWaterWindowBaseType::sanityCheck();
+}
+
+
+ostream&
+operator<<(ostream& s, const compressedWaterWindowType &p) {
+  return s << "[compressedWaterWindowType " 
+	   << p.i << "," <<  p.j 
+	   << "  " << directionSymbol(p.getDirection())
+	   << " e=" << p.getElevation()
+	   << " d=" << p.getDepth() 
+	   << " l=" << p.label;
+}
+
+

Deleted: grass/trunk/raster/r.terraflow/weightWindow.cc
===================================================================
--- grass/trunk/raster/r.terraflow/weightWindow.cc	2011-09-29 23:35:42 UTC (rev 48561)
+++ grass/trunk/raster/r.terraflow/weightWindow.cc	2011-09-29 23:36:57 UTC (rev 48562)
@@ -1,290 +0,0 @@
-/****************************************************************************
- * 
- *  MODULE:	r.terraflow
- *
- *  COPYRIGHT (C) 2007 Laura Toma
- *   
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *****************************************************************************/
-
-#include <stdio.h>
-#include <assert.h>
-#include <math.h>
-
-#include "weightWindow.h"
-#include "direction.h"
-
-
-/* #define CHECK_WEIGHTS   */
-/* enables printing weights as they are computed */
-
-/* 
-   Distribute flow to neighbors as in "The prediction of HIllslope
-   Flow Paths for Distributed Hydrollogical Modeling using Digital
-   Terrain Models" by Quinn, Chevallier, Planchon, in Hydrollogical
-   Processes vol. 5, 1991
-
- */
-
-
-
-/***************************************************************/
-weightWindow::weightWindow(const float dx, const float dy) :
-  cell_dx(dx), cell_dy(dy) {
-  
-  celldiag = sqrt(dx*dx + dy*dy);
-  sumweight = sumcontour = 0;
-}
-
-
-
-/***************************************************************/
-/* initialize all weights to 0 */
-void
-weightWindow::init() {
-  sumweight = sumcontour = (float)0;
-  for (int l = 0;l < 9; l++) {
-    weight.set(l,(float)0);
-  }
-}
-
-/***************************************************************/
-/* set weight of neighbor (di,dj) equal to e_diff x
-   computeContour/computeDist. This basically reduces to e_diff/2 (if
-   not on diagonal) or e_diff/4 (if on diagonal). 
-*/
-
-
-void
-weightWindow::computeWeight(const short di, const short dj, 
-			    const elevation_type elev_crt,
-			    const elevation_type elev_neighb) {
-
-  /* NOTE: it is possible that elev_neighb is EDGE_NODATA. In this
-     case, we just consider the value of EDGE_NODATA as an elevation,
-     and push flow to it. Currently the value of EDGE_NODATA is -9998,
-     and thus these cells will get most of the flow. */
-  
-  elevation_type e_diff = elev_crt - elev_neighb;
-  assert(e_diff >= 0);
-  if (di == 0 && dj == 0) {
-    return;  
-  }
-
-  double contour, flow;
-
-  if (dj==0) {
-    flow = 0.5;
-    contour = cell_dy/2;
-  } else  if (di ==0) {
-    flow = 0.5;
-    contour = cell_dx/2;
-  } else { /* on diagonal */
-    flow = 0.25;
-    contour = celldiag/4;
-  }
-  assert(contour > 0);
-
-  /* at this point, 'flow' corresponds to the relative distance to the
-   neighbor: 0.5 if horizontal/vertical, or 0.25 if diagonal. Diagonal
-   points are further away. These are somewhat arbitrary; see paper.
-   'contour' is the length perpendicular to the flow toward the
-   neighbor. */
-  
-  if (e_diff > 0) {
-    flow *= e_diff;
-  } else {
-    /* NOTE: how much flow to distribute to neighbors which are
-       at same height?? */
-    flow *=  1.0/contour; /* NOTE: this may cause overflow if contour
-                             is v small */
-  }
-  weight.set(di, dj, flow);
-  sumcontour += contour;
-  sumweight += flow;
-}
-
-
-
-/***************************************************************/
-/* computes and returns the distance corresponding to this direction */
-double
-weightWindow::computeDist(const short di, const short dj) {
-  double dist;
-  
-  if (di == 0 && dj == 0) {
-    return 0;
-  }
-  if (dj==0) {
-    dist = cell_dy;
-  } else  if (di ==0) {
-    dist = cell_dx;
-  } else { /* on diagonal */
-    dist = celldiag;
-  }
-  assert(dist > 0);
-  return dist;
-}  
-
-/***************************************************************/
-/* computes and returns the contour corresponding to this direction */
-double
-weightWindow::computeContour(const short di, const short dj) {
-  double contour;
-
-  if (di == 0 && dj == 0) {
-    return 0;
-  }
-  if (dj==0) {
-    contour = cell_dy/2;
-  } else  if (di ==0) {
-    contour = cell_dx/2;
-  } else { /* on diagonal */
-    contour = celldiag/4;
-  }
-  assert(contour > 0);
-  return contour;
-}  
-
-/***************************************************************/
-/* compute the tanB corresponding to the elevation window and neighbor
-   di,dj. */
-double 
-weightWindow::computeTanB(const short di,const short dj, 
-			  const genericWindow<elevation_type>& elevwin) {
-  
-  assert(di != 0 || dj != 0);
-  double dist = computeDist(di, dj);
-  assert(dist > 0);
-  return (elevwin.get() - elevwin.get(di, dj)) / dist;
-}
-
-
-
-
-/***************************************************************/
-void
-weightWindow::normalize() {
-  if (sumweight > 0) {
-    weight.scalarMultiply(1.0/sumweight);
-  }
-}
-
-
-/***************************************************************/
-/* compute the weights of the neighbors of a cell given an elevation
-   window and precomputed directions dir; if trustdir = 1 then trust
-   directions; otherwise push to all downslope neighbors and use dir
-   only for cells which do not have any downslope neighbors */
-/***************************************************************/
-void 
-weightWindow::compute(const dimension_type i, const dimension_type j,
-		      const genericWindow<elevation_type>& elevwin, 
-		      const direction_type dir,
-		      const int trustdir) {
-  
-  elevation_type elev_crt, elev_neighb, e_diff;
-  dimension_type i_neighb, j_neighb;
-  
-  /* initialize all weights to 0 */
-  init();
-
-  elev_crt = elevwin.get(); 
-  assert(!is_nodata(elev_crt));
-  
-  /* map direction to neighbors */
-  directionWindow dirwin(dir);  
-
-  /* compute weights of the 8 neighbours  */
-  int skipit = 0;
-  for (short di = -1; di <= 1; di++) {
-    for (short dj = -1; dj <= 1; dj++) {
-      
-      /* grid coordinates and elevation of neighbour */
-      i_neighb = i + di; 
-      j_neighb = j + dj;
-      elev_neighb = elevwin.get(di, dj);
-      e_diff = (elevation_type)(elev_crt - elev_neighb);
-
-      skipit = ((di ==0) && (dj==0));
-      skipit |= (elev_crt < elev_neighb);
-      /* skipit |= (elev_neighb == edge_nodata); ?? */
-
-      if (!trustdir) {
-	dirwin.correctDirection(di,dj,skipit, i,j, elev_crt,dir,elev_neighb);
-      }
-      
-      /* if direction points to it then compute its weight */
-      if (dirwin.get(di,dj) == true) {
-	computeWeight(di,dj, elev_crt, elev_neighb);
-      }
-    } /* for dj */
-  } /* for di */
-  normalize(); /* normalize the weights */
-  
-#ifdef CHECK_WEIGHTS 
-  cout <<"weights: [";
-  for (int l=0;l<9;l++) cout << form("%3.2f ",weight.get(l));
-  cout <<"]\n";
-#endif
-};
-
-
-
-/* Find the dominant direction. Set corresponding weight to 1, and
-   sets all other weights to 0. Set sumweight and sumcontour.*/
-void 
-weightWindow::makeD8(const dimension_type i, const dimension_type j,
-		     const genericWindow<elevation_type>& elevwin, 
-		     const direction_type dir,
-		     const bool trustdir) {
-  
-
-  elevation_type elev_crt;
-  short di,dj;
-  elev_crt = elevwin.get(); 
-  assert(!is_nodata(elev_crt));
-
-  int maxi=0, maxj=0;
-  double tanb, contour, maxtanb = -1, maxcontour = -1;
-  /* map direction to neighbors */
-  directionWindow dirwin(dir); 
-
-  /* compute biggest angle to a neighbor */
-  for (di=-1; di <=1; di++) {
-    for (dj = -1; dj <= 1; dj++) {
-      if (dirwin.get(di,dj)) {
-	
-	tanb = computeTanB(di,dj, elevwin);
-	contour = computeContour(di, dj);
-	
-	if (tanb > maxtanb) {
-	  maxtanb = tanb;
-	  maxi = di;
-	  maxj = dj;
-	  maxcontour = contour;
-	}
-      }
-    }
-  }
-  /* at this point maxi and maxj must be set */
-  assert((maxi != 0 || maxj != 0) && maxtanb >= 0);
-  
-  /* set weights corresponding to this direction */
-  init();   /* initialize all weights to 0 */
-  int maxindex = 3* (maxi + 1) + maxj+1;
-  weight.set(maxindex,1);   /* set maxweight to 1 */
-
-  sumweight = 1;
-  sumcontour = maxcontour;
-}
-

Copied: grass/trunk/raster/r.terraflow/weightWindow.cpp (from rev 48560, grass/trunk/raster/r.terraflow/weightWindow.cc)
===================================================================
--- grass/trunk/raster/r.terraflow/weightWindow.cpp	                        (rev 0)
+++ grass/trunk/raster/r.terraflow/weightWindow.cpp	2011-09-29 23:36:57 UTC (rev 48562)
@@ -0,0 +1,290 @@
+/****************************************************************************
+ * 
+ *  MODULE:	r.terraflow
+ *
+ *  COPYRIGHT (C) 2007 Laura Toma
+ *   
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *****************************************************************************/
+
+#include <stdio.h>
+#include <assert.h>
+#include <math.h>
+
+#include "weightWindow.h"
+#include "direction.h"
+
+
+/* #define CHECK_WEIGHTS   */
+/* enables printing weights as they are computed */
+
+/* 
+   Distribute flow to neighbors as in "The prediction of HIllslope
+   Flow Paths for Distributed Hydrollogical Modeling using Digital
+   Terrain Models" by Quinn, Chevallier, Planchon, in Hydrollogical
+   Processes vol. 5, 1991
+
+ */
+
+
+
+/***************************************************************/
+weightWindow::weightWindow(const float dx, const float dy) :
+  cell_dx(dx), cell_dy(dy) {
+  
+  celldiag = sqrt(dx*dx + dy*dy);
+  sumweight = sumcontour = 0;
+}
+
+
+
+/***************************************************************/
+/* initialize all weights to 0 */
+void
+weightWindow::init() {
+  sumweight = sumcontour = (float)0;
+  for (int l = 0;l < 9; l++) {
+    weight.set(l,(float)0);
+  }
+}
+
+/***************************************************************/
+/* set weight of neighbor (di,dj) equal to e_diff x
+   computeContour/computeDist. This basically reduces to e_diff/2 (if
+   not on diagonal) or e_diff/4 (if on diagonal). 
+*/
+
+
+void
+weightWindow::computeWeight(const short di, const short dj, 
+			    const elevation_type elev_crt,
+			    const elevation_type elev_neighb) {
+
+  /* NOTE: it is possible that elev_neighb is EDGE_NODATA. In this
+     case, we just consider the value of EDGE_NODATA as an elevation,
+     and push flow to it. Currently the value of EDGE_NODATA is -9998,
+     and thus these cells will get most of the flow. */
+  
+  elevation_type e_diff = elev_crt - elev_neighb;
+  assert(e_diff >= 0);
+  if (di == 0 && dj == 0) {
+    return;  
+  }
+
+  double contour, flow;
+
+  if (dj==0) {
+    flow = 0.5;
+    contour = cell_dy/2;
+  } else  if (di ==0) {
+    flow = 0.5;
+    contour = cell_dx/2;
+  } else { /* on diagonal */
+    flow = 0.25;
+    contour = celldiag/4;
+  }
+  assert(contour > 0);
+
+  /* at this point, 'flow' corresponds to the relative distance to the
+   neighbor: 0.5 if horizontal/vertical, or 0.25 if diagonal. Diagonal
+   points are further away. These are somewhat arbitrary; see paper.
+   'contour' is the length perpendicular to the flow toward the
+   neighbor. */
+  
+  if (e_diff > 0) {
+    flow *= e_diff;
+  } else {
+    /* NOTE: how much flow to distribute to neighbors which are
+       at same height?? */
+    flow *=  1.0/contour; /* NOTE: this may cause overflow if contour
+                             is v small */
+  }
+  weight.set(di, dj, flow);
+  sumcontour += contour;
+  sumweight += flow;
+}
+
+
+
+/***************************************************************/
+/* computes and returns the distance corresponding to this direction */
+double
+weightWindow::computeDist(const short di, const short dj) {
+  double dist;
+  
+  if (di == 0 && dj == 0) {
+    return 0;
+  }
+  if (dj==0) {
+    dist = cell_dy;
+  } else  if (di ==0) {
+    dist = cell_dx;
+  } else { /* on diagonal */
+    dist = celldiag;
+  }
+  assert(dist > 0);
+  return dist;
+}  
+
+/***************************************************************/
+/* computes and returns the contour corresponding to this direction */
+double
+weightWindow::computeContour(const short di, const short dj) {
+  double contour;
+
+  if (di == 0 && dj == 0) {
+    return 0;
+  }
+  if (dj==0) {
+    contour = cell_dy/2;
+  } else  if (di ==0) {
+    contour = cell_dx/2;
+  } else { /* on diagonal */
+    contour = celldiag/4;
+  }
+  assert(contour > 0);
+  return contour;
+}  
+
+/***************************************************************/
+/* compute the tanB corresponding to the elevation window and neighbor
+   di,dj. */
+double 
+weightWindow::computeTanB(const short di,const short dj, 
+			  const genericWindow<elevation_type>& elevwin) {
+  
+  assert(di != 0 || dj != 0);
+  double dist = computeDist(di, dj);
+  assert(dist > 0);
+  return (elevwin.get() - elevwin.get(di, dj)) / dist;
+}
+
+
+
+
+/***************************************************************/
+void
+weightWindow::normalize() {
+  if (sumweight > 0) {
+    weight.scalarMultiply(1.0/sumweight);
+  }
+}
+
+
+/***************************************************************/
+/* compute the weights of the neighbors of a cell given an elevation
+   window and precomputed directions dir; if trustdir = 1 then trust
+   directions; otherwise push to all downslope neighbors and use dir
+   only for cells which do not have any downslope neighbors */
+/***************************************************************/
+void 
+weightWindow::compute(const dimension_type i, const dimension_type j,
+		      const genericWindow<elevation_type>& elevwin, 
+		      const direction_type dir,
+		      const int trustdir) {
+  
+  elevation_type elev_crt, elev_neighb, e_diff;
+  dimension_type i_neighb, j_neighb;
+  
+  /* initialize all weights to 0 */
+  init();
+
+  elev_crt = elevwin.get(); 
+  assert(!is_nodata(elev_crt));
+  
+  /* map direction to neighbors */
+  directionWindow dirwin(dir);  
+
+  /* compute weights of the 8 neighbours  */
+  int skipit = 0;
+  for (short di = -1; di <= 1; di++) {
+    for (short dj = -1; dj <= 1; dj++) {
+      
+      /* grid coordinates and elevation of neighbour */
+      i_neighb = i + di; 
+      j_neighb = j + dj;
+      elev_neighb = elevwin.get(di, dj);
+      e_diff = (elevation_type)(elev_crt - elev_neighb);
+
+      skipit = ((di ==0) && (dj==0));
+      skipit |= (elev_crt < elev_neighb);
+      /* skipit |= (elev_neighb == edge_nodata); ?? */
+
+      if (!trustdir) {
+	dirwin.correctDirection(di,dj,skipit, i,j, elev_crt,dir,elev_neighb);
+      }
+      
+      /* if direction points to it then compute its weight */
+      if (dirwin.get(di,dj) == true) {
+	computeWeight(di,dj, elev_crt, elev_neighb);
+      }
+    } /* for dj */
+  } /* for di */
+  normalize(); /* normalize the weights */
+  
+#ifdef CHECK_WEIGHTS 
+  cout <<"weights: [";
+  for (int l=0;l<9;l++) cout << form("%3.2f ",weight.get(l));
+  cout <<"]\n";
+#endif
+};
+
+
+
+/* Find the dominant direction. Set corresponding weight to 1, and
+   sets all other weights to 0. Set sumweight and sumcontour.*/
+void 
+weightWindow::makeD8(const dimension_type i, const dimension_type j,
+		     const genericWindow<elevation_type>& elevwin, 
+		     const direction_type dir,
+		     const bool trustdir) {
+  
+
+  elevation_type elev_crt;
+  short di,dj;
+  elev_crt = elevwin.get(); 
+  assert(!is_nodata(elev_crt));
+
+  int maxi=0, maxj=0;
+  double tanb, contour, maxtanb = -1, maxcontour = -1;
+  /* map direction to neighbors */
+  directionWindow dirwin(dir); 
+
+  /* compute biggest angle to a neighbor */
+  for (di=-1; di <=1; di++) {
+    for (dj = -1; dj <= 1; dj++) {
+      if (dirwin.get(di,dj)) {
+	
+	tanb = computeTanB(di,dj, elevwin);
+	contour = computeContour(di, dj);
+	
+	if (tanb > maxtanb) {
+	  maxtanb = tanb;
+	  maxi = di;
+	  maxj = dj;
+	  maxcontour = contour;
+	}
+      }
+    }
+  }
+  /* at this point maxi and maxj must be set */
+  assert((maxi != 0 || maxj != 0) && maxtanb >= 0);
+  
+  /* set weights corresponding to this direction */
+  init();   /* initialize all weights to 0 */
+  int maxindex = 3* (maxi + 1) + maxj+1;
+  weight.set(maxindex,1);   /* set maxweight to 1 */
+
+  sumweight = 1;
+  sumcontour = maxcontour;
+}
+

Deleted: grass/trunk/visualization/wximgview/main.cc
===================================================================
--- grass/trunk/visualization/wximgview/main.cc	2011-09-29 23:35:42 UTC (rev 48561)
+++ grass/trunk/visualization/wximgview/main.cc	2011-09-29 23:36:57 UTC (rev 48562)
@@ -1,284 +0,0 @@
-
-/****************************************************************************
- *
- * MODULE:       wximgview
- * AUTHOR(S):    Glynn Clements
- * PURPOSE:      View BMP images from the PNG/cairo drivers
- * COPYRIGHT:    (C) 2010 Glynn Clements
- *
- *               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 <stdlib.h>
-#include <unistd.h>
-#include <string.h>
-#include <signal.h>
-#include <errno.h>
-
-#ifdef __MINGW32__
-#include <Windows.h>
-#else
-#include <sys/mman.h>
-#endif
-
-#include <unistd.h>
-#include <fcntl.h>
-#include <sys/stat.h>
-#include <sys/time.h>
-#include <sys/types.h>
-
-#include <wx/wx.h>
-
-extern "C" {
-#include <grass/gis.h>
-#include <grass/glocale.h>
-}
-
-#include "wximgview.h"
-
-#define HEADER_SIZE 64
-
-IMPLEMENT_APP_NO_MAIN(MyApp)
-
-BEGIN_EVENT_TABLE(MyFrame, wxFrame)
-EVT_ERASE_BACKGROUND(MyFrame::erase)
-EVT_PAINT(MyFrame::redraw)
-EVT_TIMER(wxID_ANY, MyFrame::tick)
-END_EVENT_TABLE()
-    ;
-const wxString MyFrame::title = wxString::FromAscii("Image Viewer");
-
-static const char *filename;
-static double fraction;
-
-void MyFrame::Create()
-{
-    timer = new wxTimer(this);
-    timer->Start(100, true);
-}
-
-void MyFrame::erase(wxEraseEvent &ev)
-{
-    ev.GetDC();
-}
-
-void MyFrame::draw()
-{
-    MyApp &app = wxGetApp();
-    wxSize size = GetSize();
-    int x0 = (size.GetWidth()  - app.i_width) / 2;
-    int y0 = (size.GetHeight() - app.i_height) / 2;
-    wxPaintDC dc(this);
-    wxImage image(app.i_width, app.i_height);
-
-    const unsigned char *p = app.imgbuf;
-    for (int y = 0; y < app.i_height; y++)
-	for (int x = 0; x < app.i_width; x++, p += 4)
-	    image.SetRGB(x, y, p[2], p[1], p[0]);
-
-    dc.DrawBitmap(wxBitmap(image), x0, y0, false);
-}
-
-void MyFrame::redraw(wxPaintEvent &ev)
-{
-    if (::fraction > 0.001) {
-	struct timeval tv0;
-	gettimeofday(&tv0, NULL);
-
-	draw();
-
-	struct timeval tv1;
-	gettimeofday(&tv1, NULL);
-
-	double last = (tv1.tv_sec - tv0.tv_sec) * 1e3 + (tv1.tv_usec - tv0.tv_usec) * 1e-3;
-	double delay = last / ::fraction;
-	timer->Start((int) delay, true);
-    }
-    else
-	draw();
-}
-
-void MyFrame::tick(wxTimerEvent &ev)
-{
-    Refresh();
-}
-
-static unsigned int get_2(const unsigned char **q)
-{
-    const unsigned char *p = *q;
-    unsigned int n = (p[0] << 0) | (p[1] << 8);
-
-    *q += 2;
-    return n;
-}
-
-static unsigned int get_4(const unsigned char **q)
-{
-    const unsigned char *p = *q;
-    unsigned int n = (p[0] << 0) | (p[1] << 8) | (p[2] << 16) | (p[3] << 24);
-
-    *q += 4;
-    return n;
-}
-
-int MyApp::read_bmp_header(const unsigned char *p)
-{
-    int size;
-
-    if (*p++ != 'B')
-	return 0;
-    if (*p++ != 'M')
-	return 0;
-
-    size = get_4(&p);
-
-    get_4(&p);
-
-    if (get_4(&p) != HEADER_SIZE)
-	return 0;
-
-    if (get_4(&p) != 40)
-	return 0;
-
-    i_width = get_4(&p);
-    i_height = -get_4(&p);
-
-    get_2(&p);
-    if (get_2(&p) != 32)
-	return 0;
-
-    if (get_4(&p) != 0)
-	return 0;
-    if (get_4(&p) != (unsigned int) i_width * i_height * 4)
-	return 0;
-
-    if (size != HEADER_SIZE + i_width * i_height * 4)
-	return 0;
-
-    get_4(&p);
-    get_4(&p);
-    get_4(&p);
-    get_4(&p);
-
-    return 1;
-}
-
-void MyApp::map_file()
-{
-    unsigned char header[HEADER_SIZE];
-    size_t size;
-    void *ptr;
-    int fd;
-
-    fd = open(::filename, O_RDONLY);
-    if (fd < 0)
-	G_fatal_error(_("Unable to open image file"));
-
-    if (read(fd, (char *) header, sizeof(header)) != sizeof(header))
-	G_fatal_error(_("Unable to read BMP header"));
-
-    if (!read_bmp_header(header))
-	G_fatal_error(_("Invalid BMP header"));
-
-    size = HEADER_SIZE + i_width * i_height * 4;
-
-#ifdef __MINGW32__
-    HANDLE handle = CreateFileMapping((HANDLE) _get_osfhandle(fd),
-				      NULL, PAGE_READONLY,
-				      0, size, NULL);
-    if (!handle)
-	return;
-    ptr = MapViewOfFile(handle, FILE_MAP_READ, 0, 0, size);
-    if (!ptr)
-	G_fatal_error(_("Unable to map image file"));
-#else
-    ptr = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, (off_t) 0);
-    if (ptr == MAP_FAILED)
-	G_fatal_error(_("Unable to map image file"));
-#endif
-
-    imgbuf = (unsigned char *)ptr + HEADER_SIZE;
-
-    close(fd);
-}
-
-static void dummy_handler(int sig)
-{
-    wxTimerEvent ev = wxTimerEvent();
-    wxPostEvent(wxGetApp().mainwin, ev);
-}
-
-static void set_handler(void)
-{
-#ifndef __MINGW32__
-    struct sigaction act;
-
-    act.sa_handler = &dummy_handler;
-    sigemptyset(&act.sa_mask);
-    act.sa_flags = 0;
-    sigaction(SIGUSR1, &act, NULL);
-#endif
-}
-
-bool MyApp::OnInit()
-{
-    map_file();
-
-    wxSize size(i_width, i_height);
-    mainwin = new MyFrame(size);
-    mainwin->Show();
-    SetTopWindow(mainwin);
-
-    set_handler();
-
-    return true;
-}
-
-int main(int argc, char **argv)
-{
-    struct GModule *module;
-    struct
-    {
-	struct Option *image, *percent;
-    } opt;
-
-    G_gisinit(argv[0]);
-
-    module = G_define_module();
-    G_add_keyword(_("display"));
-    G_add_keyword(_("raster"));
-    G_add_keyword(_("vector"));
-    G_add_keyword(_("visualization"));
-    module->description = _("View BMP images from the PNG driver.");
-
-    opt.image = G_define_option();
-    opt.image->key = "image";
-    opt.image->type = TYPE_STRING;
-    opt.image->required = YES;
-    opt.image->multiple = NO;
-    opt.image->gisprompt = "old_file,file,input";
-    opt.image->description = _("Image file");
-
-    opt.percent = G_define_option();
-    opt.percent->key = "percent";
-    opt.percent->type = TYPE_INTEGER;
-    opt.percent->required = NO;
-    opt.percent->multiple = NO;
-    opt.percent->description = _("Percentage of CPU time to use");
-    opt.percent->answer = "10";
-
-    if (G_parser(argc, argv))
-	exit(EXIT_FAILURE);
-
-    ::filename = opt.image->answer;
-    ::fraction = atoi(opt.percent->answer) / 100.0;
-
-    return wxEntry(argc, argv);
-
-    return EXIT_SUCCESS;
-}
-

Copied: grass/trunk/visualization/wximgview/main.cpp (from rev 48560, grass/trunk/visualization/wximgview/main.cc)
===================================================================
--- grass/trunk/visualization/wximgview/main.cpp	                        (rev 0)
+++ grass/trunk/visualization/wximgview/main.cpp	2011-09-29 23:36:57 UTC (rev 48562)
@@ -0,0 +1,284 @@
+
+/****************************************************************************
+ *
+ * MODULE:       wximgview
+ * AUTHOR(S):    Glynn Clements
+ * PURPOSE:      View BMP images from the PNG/cairo drivers
+ * COPYRIGHT:    (C) 2010 Glynn Clements
+ *
+ *               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 <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <signal.h>
+#include <errno.h>
+
+#ifdef __MINGW32__
+#include <Windows.h>
+#else
+#include <sys/mman.h>
+#endif
+
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/types.h>
+
+#include <wx/wx.h>
+
+extern "C" {
+#include <grass/gis.h>
+#include <grass/glocale.h>
+}
+
+#include "wximgview.h"
+
+#define HEADER_SIZE 64
+
+IMPLEMENT_APP_NO_MAIN(MyApp)
+
+BEGIN_EVENT_TABLE(MyFrame, wxFrame)
+EVT_ERASE_BACKGROUND(MyFrame::erase)
+EVT_PAINT(MyFrame::redraw)
+EVT_TIMER(wxID_ANY, MyFrame::tick)
+END_EVENT_TABLE()
+    ;
+const wxString MyFrame::title = wxString::FromAscii("Image Viewer");
+
+static const char *filename;
+static double fraction;
+
+void MyFrame::Create()
+{
+    timer = new wxTimer(this);
+    timer->Start(100, true);
+}
+
+void MyFrame::erase(wxEraseEvent &ev)
+{
+    ev.GetDC();
+}
+
+void MyFrame::draw()
+{
+    MyApp &app = wxGetApp();
+    wxSize size = GetSize();
+    int x0 = (size.GetWidth()  - app.i_width) / 2;
+    int y0 = (size.GetHeight() - app.i_height) / 2;
+    wxPaintDC dc(this);
+    wxImage image(app.i_width, app.i_height);
+
+    const unsigned char *p = app.imgbuf;
+    for (int y = 0; y < app.i_height; y++)
+	for (int x = 0; x < app.i_width; x++, p += 4)
+	    image.SetRGB(x, y, p[2], p[1], p[0]);
+
+    dc.DrawBitmap(wxBitmap(image), x0, y0, false);
+}
+
+void MyFrame::redraw(wxPaintEvent &ev)
+{
+    if (::fraction > 0.001) {
+	struct timeval tv0;
+	gettimeofday(&tv0, NULL);
+
+	draw();
+
+	struct timeval tv1;
+	gettimeofday(&tv1, NULL);
+
+	double last = (tv1.tv_sec - tv0.tv_sec) * 1e3 + (tv1.tv_usec - tv0.tv_usec) * 1e-3;
+	double delay = last / ::fraction;
+	timer->Start((int) delay, true);
+    }
+    else
+	draw();
+}
+
+void MyFrame::tick(wxTimerEvent &ev)
+{
+    Refresh();
+}
+
+static unsigned int get_2(const unsigned char **q)
+{
+    const unsigned char *p = *q;
+    unsigned int n = (p[0] << 0) | (p[1] << 8);
+
+    *q += 2;
+    return n;
+}
+
+static unsigned int get_4(const unsigned char **q)
+{
+    const unsigned char *p = *q;
+    unsigned int n = (p[0] << 0) | (p[1] << 8) | (p[2] << 16) | (p[3] << 24);
+
+    *q += 4;
+    return n;
+}
+
+int MyApp::read_bmp_header(const unsigned char *p)
+{
+    int size;
+
+    if (*p++ != 'B')
+	return 0;
+    if (*p++ != 'M')
+	return 0;
+
+    size = get_4(&p);
+
+    get_4(&p);
+
+    if (get_4(&p) != HEADER_SIZE)
+	return 0;
+
+    if (get_4(&p) != 40)
+	return 0;
+
+    i_width = get_4(&p);
+    i_height = -get_4(&p);
+
+    get_2(&p);
+    if (get_2(&p) != 32)
+	return 0;
+
+    if (get_4(&p) != 0)
+	return 0;
+    if (get_4(&p) != (unsigned int) i_width * i_height * 4)
+	return 0;
+
+    if (size != HEADER_SIZE + i_width * i_height * 4)
+	return 0;
+
+    get_4(&p);
+    get_4(&p);
+    get_4(&p);
+    get_4(&p);
+
+    return 1;
+}
+
+void MyApp::map_file()
+{
+    unsigned char header[HEADER_SIZE];
+    size_t size;
+    void *ptr;
+    int fd;
+
+    fd = open(::filename, O_RDONLY);
+    if (fd < 0)
+	G_fatal_error(_("Unable to open image file"));
+
+    if (read(fd, (char *) header, sizeof(header)) != sizeof(header))
+	G_fatal_error(_("Unable to read BMP header"));
+
+    if (!read_bmp_header(header))
+	G_fatal_error(_("Invalid BMP header"));
+
+    size = HEADER_SIZE + i_width * i_height * 4;
+
+#ifdef __MINGW32__
+    HANDLE handle = CreateFileMapping((HANDLE) _get_osfhandle(fd),
+				      NULL, PAGE_READONLY,
+				      0, size, NULL);
+    if (!handle)
+	return;
+    ptr = MapViewOfFile(handle, FILE_MAP_READ, 0, 0, size);
+    if (!ptr)
+	G_fatal_error(_("Unable to map image file"));
+#else
+    ptr = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, (off_t) 0);
+    if (ptr == MAP_FAILED)
+	G_fatal_error(_("Unable to map image file"));
+#endif
+
+    imgbuf = (unsigned char *)ptr + HEADER_SIZE;
+
+    close(fd);
+}
+
+static void dummy_handler(int sig)
+{
+    wxTimerEvent ev = wxTimerEvent();
+    wxPostEvent(wxGetApp().mainwin, ev);
+}
+
+static void set_handler(void)
+{
+#ifndef __MINGW32__
+    struct sigaction act;
+
+    act.sa_handler = &dummy_handler;
+    sigemptyset(&act.sa_mask);
+    act.sa_flags = 0;
+    sigaction(SIGUSR1, &act, NULL);
+#endif
+}
+
+bool MyApp::OnInit()
+{
+    map_file();
+
+    wxSize size(i_width, i_height);
+    mainwin = new MyFrame(size);
+    mainwin->Show();
+    SetTopWindow(mainwin);
+
+    set_handler();
+
+    return true;
+}
+
+int main(int argc, char **argv)
+{
+    struct GModule *module;
+    struct
+    {
+	struct Option *image, *percent;
+    } opt;
+
+    G_gisinit(argv[0]);
+
+    module = G_define_module();
+    G_add_keyword(_("display"));
+    G_add_keyword(_("raster"));
+    G_add_keyword(_("vector"));
+    G_add_keyword(_("visualization"));
+    module->description = _("View BMP images from the PNG driver.");
+
+    opt.image = G_define_option();
+    opt.image->key = "image";
+    opt.image->type = TYPE_STRING;
+    opt.image->required = YES;
+    opt.image->multiple = NO;
+    opt.image->gisprompt = "old_file,file,input";
+    opt.image->description = _("Image file");
+
+    opt.percent = G_define_option();
+    opt.percent->key = "percent";
+    opt.percent->type = TYPE_INTEGER;
+    opt.percent->required = NO;
+    opt.percent->multiple = NO;
+    opt.percent->description = _("Percentage of CPU time to use");
+    opt.percent->answer = "10";
+
+    if (G_parser(argc, argv))
+	exit(EXIT_FAILURE);
+
+    ::filename = opt.image->answer;
+    ::fraction = atoi(opt.percent->answer) / 100.0;
+
+    return wxEntry(argc, argv);
+
+    return EXIT_SUCCESS;
+}
+

Deleted: grass/trunk/visualization/xganim/gui.cc
===================================================================
--- grass/trunk/visualization/xganim/gui.cc	2011-09-29 23:35:42 UTC (rev 48561)
+++ grass/trunk/visualization/xganim/gui.cc	2011-09-29 23:36:57 UTC (rev 48562)
@@ -1,305 +0,0 @@
-/* Written by Bill Brown, USACERL (brown at zorro.cecer.army.mil)
- * May 2-12, 1994
- *
- * This code is in the public domain. Specifically, we give to the public
- * domain all rights for future licensing of the source code, all resale
- * rights, and all publishing rights.
- * 
- * We ask, but do not require, that the following message be included in
- * all derived works:
- *     "Portions developed at the US Army Construction Engineering 
- *     Research Laboratories, Champaign, Illinois."
- * 
- * USACERL GIVES NO WARRANTY, EXPRESSED OR IMPLIED,
- * FOR THE SOFTWARE AND/OR DOCUMENTATION PROVIDED, INCLUDING, WITHOUT
- * LIMITATION, WARRANTY OF MERCHANTABILITY AND WARRANTY OF FITNESS FOR A
- * PARTICULAR PURPOSE.
- */
-
-#include <stdlib.h>
-#include <wx/button.h>
-#include <wx/bmpbuttn.h>
-#include <wx/bitmap.h>
-#include <wx/sizer.h>
-#include <wx/strconv.h>
-#include <wx/event.h>
-#include <wx/dcclient.h>
-#include <wx/dc.h>
-#include <wx/colour.h>
-#include "gui.h"
-
-#include "bitmaps/rewind.xbm"
-#include "bitmaps/rplay.xbm"
-#include "bitmaps/stepb.xbm"
-#include "bitmaps/stop.xbm"
-#include "bitmaps/stepf.xbm"
-#include "bitmaps/play.xbm"
-#include "bitmaps/loop.xbm"
-#include "bitmaps/swing.xbm"
-#include "bitmaps/snail.xbm"
-#include "bitmaps/rabbit.xbm"
-
-enum {
-    MYID_REW,
-    MYID_RPLAY,
-    MYID_STEPB,
-    MYID_STOP,
-    MYID_STEPF,
-    MYID_PLAY,
-    MYID_LOOP,
-    MYID_SWING,
-    MYID_SLOWER,
-    MYID_FASTER,
-    MYID_SHNAMES,
-    MYID_DOEXIT,
-};
-
-BEGIN_EVENT_TABLE(MyCanvas, wxPanel)
-EVT_ERASE_BACKGROUND(MyCanvas::erase)
-END_EVENT_TABLE()
-
-MyCanvas::MyCanvas(wxWindow *parent, wxWindowID id, const wxSize &size)
-    : wxPanel(parent, id, wxDefaultPosition, size)
-{
-    SetBackgroundStyle(wxBG_STYLE_CUSTOM);
-}
-
-void MyCanvas::erase(wxEraseEvent &ev)
-{
-    ev.GetDC();
-}
-
-void MyCanvas::draw_image(wxBitmap *bmp)
-{
-    wxClientDC dc(this);
-
-    dc.DrawBitmap(*bmp, 0, 0, false);
-}
-
-void MyCanvas::draw_text(int style, int x, int y, const char *str)
-{
-    wxClientDC dc(this);
-
-    switch (style) {
-    case 1:
-	dc.SetTextBackground(*wxWHITE);
-	dc.SetTextForeground(*wxBLACK);
-	break;
-    case 2:
-	dc.SetTextBackground(*wxBLACK);
-	dc.SetTextForeground(*wxWHITE);
-	break;
-    default:
-	return;
-    }
-
-    dc.DrawText(wxString(str, wxConvISO8859_1), x, y);
-}
-
-BEGIN_EVENT_TABLE(MyFrame, wxFrame)
-EVT_BUTTON(MYID_REW,     MyFrame::rewind_callback)
-EVT_BUTTON(MYID_RPLAY,   MyFrame::rplay_callback)
-EVT_BUTTON(MYID_STEPB,   MyFrame::stepb_callback)
-EVT_BUTTON(MYID_STOP,    MyFrame::stop_callback)
-EVT_BUTTON(MYID_STEPF,   MyFrame::stepf_callback)
-EVT_BUTTON(MYID_PLAY,    MyFrame::play_callback)
-EVT_BUTTON(MYID_LOOP,    MyFrame::loop_callback)
-EVT_BUTTON(MYID_SWING,   MyFrame::swing_callback)
-EVT_BUTTON(MYID_SLOWER,  MyFrame::slower_callback)
-EVT_BUTTON(MYID_FASTER,  MyFrame::faster_callback)
-EVT_BUTTON(MYID_SHNAMES, MyFrame::names_callback)
-EVT_BUTTON(MYID_DOEXIT,  MyFrame::exit_callback)
-END_EVENT_TABLE()
-
-void MyFrame::make_buttons(wxSizer *sizer)
-{
-    sizer->Add(new wxBitmapButton(this, MYID_REW   , wxBitmap(rewind_bits, rewind_width, rewind_height)));
-    sizer->Add(new wxBitmapButton(this, MYID_RPLAY , wxBitmap(rplay_bits , rplay_width , rplay_height )));
-    sizer->Add(new wxBitmapButton(this, MYID_STEPB , wxBitmap(stepb_bits , stepb_width , stepb_height )));
-    sizer->Add(new wxBitmapButton(this, MYID_STOP  , wxBitmap(stop_bits  , stop_width  , stop_height  )));
-    sizer->Add(new wxBitmapButton(this, MYID_STEPF , wxBitmap(stepf_bits , stepf_width , stepf_height )));
-    sizer->Add(new wxBitmapButton(this, MYID_PLAY  , wxBitmap(play_bits  , play_width  , play_height  )));
-    sizer->Add(new wxBitmapButton(this, MYID_LOOP  , wxBitmap(loop_bits  , loop_width  , loop_height  )));
-    sizer->Add(new wxBitmapButton(this, MYID_SWING , wxBitmap(swing_bits , swing_width , swing_height )));
-    sizer->Add(new wxBitmapButton(this, MYID_SLOWER, wxBitmap(snail_bits , snail_width , snail_height )));
-    sizer->Add(new wxBitmapButton(this, MYID_FASTER, wxBitmap(rabbit_bits, rabbit_width, rabbit_height)));
-    sizer->Add(new wxButton(this, MYID_SHNAMES, wxString("Names", wxConvISO8859_1)));
-    sizer->Add(new wxButton(this, MYID_DOEXIT,  wxString("Exit", wxConvISO8859_1)));
-}
-
-void MyFrame::rewind_callback(wxCommandEvent &event)
-{
-    cd->step = 0;
-    cd->stop = 1;
-    cd->rewind = 1;
-}
-
-void MyFrame::rplay_callback(wxCommandEvent &event)
-{
-    cd->step = 0;
-    cd->stop = 0;
-    cd->direction = -1;
-    cd->curframe = cd->prevframe + cd->direction;
-}
-
-void MyFrame::stepb_callback(wxCommandEvent &event)
-{
-    cd->step = 1;
-    cd->direction = -1;
-    cd->curframe = cd->prevframe + cd->direction;
-}
-
-void MyFrame::stop_callback(wxCommandEvent &event)
-{
-    cd->stop = 1;
-}
-
-void MyFrame::stepf_callback(wxCommandEvent &event)
-{
-    cd->step = 1;
-    cd->direction = 1;
-    cd->curframe = cd->prevframe + cd->direction;
-}
-
-void MyFrame::play_callback(wxCommandEvent &event)
-{
-    cd->step = 0;
-    cd->stop = 0;
-    cd->direction = 1;
-    cd->curframe = cd->prevframe + cd->direction;
-}
-
-void MyFrame::loop_callback(wxCommandEvent &event)
-{
-    cd->loop = !cd->loop;
-    cd->swing = 0;
-    cd->stop = !cd->loop;
-}
-
-void MyFrame::swing_callback(wxCommandEvent &event)
-{
-    cd->swing = !cd->swing;
-    cd->loop = 0;
-    cd->stop = !cd->swing;
-}
-
-void MyFrame::slower_callback(wxCommandEvent &event)
-{
-    if (cd->speed) {
-	if (cd->speed < 200000)
-	    cd->speed *= 3;
-    }
-    else
-	cd->speed = 1;
-}
-
-void MyFrame::faster_callback(wxCommandEvent &event)
-{
-    if (cd->speed > 1)
-	cd->speed /= 3;
-}
-
-void MyFrame::names_callback(wxCommandEvent &event)
-{
-    cd->shownames = (1 + cd->shownames) % 3;
-}
-
-void MyFrame::exit_callback(wxCommandEvent &event)
-{
-    exit(0);
-}
-
-void MyFrame::change_label(const char *label)
-{
-    flabel->SetLabel(wxString(label, wxConvISO8859_1));
-}
-
-#if 0
-
-void MyFrame::init_graphics()
-{
-/* global variables */
-    Widget canvas;
-    Display *theDisplay;
-    XImage *pic_array[MAXIMAGES];
-    GC invertGC, drawGC;
-
-    int scrn;
-    Display *dpy;
-    Window grwin;
-    Colormap fixedcmap;
-    unsigned long blackPix, whitePix;
-
-    unsigned int depth;
-    Visual *use_visual;
-
-    dpy = XtDisplay(canvas);
-    grwin = XtWindow(canvas);
-    scrn = DefaultScreen(dpy);
-    use_visual = DefaultVisual(dpy, scrn);
-#if 1
-    fixedcmap = XCreateColormap(dpy, grwin, use_visual, AllocNone);
-#else
-    fixedcmap = DefaultColormap(dpy, scrn);
-#endif
-    fixedcmap = InitColorTableFixed(fixedcmap);
-
-    XtVaGetValues(canvas, XmNdepth, &depth, NULL);
-
-    XtVaSetValues(toplevel, XmNcolormap, fixedcmap, NULL);
-    XtSetWMColormapWindows(toplevel, &canvas, 1);
-
-    /**************************************************************/
-
-    blackPix = _get_lookup_for_color(0, 0, 0);
-    whitePix = _get_lookup_for_color(255, 255, 255);
-
-    drawGC =
-	XCreateGC(XtDisplay(canvas), XtWindow(canvas), (unsigned long)0,
-		  NULL);
-
-    theDisplay = XtDisplay(toplevel);
-
-    XSetFunction(theDisplay, drawGC, GXcopy);
-    XSetForeground(theDisplay, drawGC, blackPix);
-    XSetBackground(theDisplay, drawGC, whitePix);
-
-    invertGC =
-	XCreateGC(XtDisplay(canvas), XtWindow(canvas), (unsigned long)0,
-		  NULL);
-    XSetFunction(theDisplay, invertGC, GXcopy);
-    XSetForeground(theDisplay, invertGC, whitePix);
-    XSetBackground(theDisplay, invertGC, blackPix);
-
-}
-
-#endif
-
-MyFrame::MyFrame(const wxString& title, int ncols, int nrows, struct gui_data *cd)
-    : wxFrame((wxFrame *)NULL, wxID_ANY, title), cd(cd)
-{
-    canvas = new MyCanvas(this, wxID_ANY, wxSize(ncols, nrows));
-
-    wxBoxSizer *sizer, *buttons;
-
-    if (ncols > nrows) {
-	sizer = new wxBoxSizer(wxVERTICAL);
-	buttons = new wxBoxSizer(wxHORIZONTAL);
-	sizer->Add(canvas);
-	sizer->Add(buttons);
-    }
-    else {
-	sizer = new wxBoxSizer(wxHORIZONTAL);
-	buttons = new wxBoxSizer(wxVERTICAL);
-	sizer->Add(canvas);
-	sizer->Add(buttons);
-    }
-
-    make_buttons(buttons);
-
-    flabel = new wxStaticText(this, wxID_ANY, wxString("00000", wxConvISO8859_1), wxDefaultPosition, wxDefaultSize, wxALIGN_RIGHT);
-    buttons->Add(flabel);
-
-    SetSizerAndFit(sizer);
-}
-

Copied: grass/trunk/visualization/xganim/gui.cpp (from rev 48560, grass/trunk/visualization/xganim/gui.cc)
===================================================================
--- grass/trunk/visualization/xganim/gui.cpp	                        (rev 0)
+++ grass/trunk/visualization/xganim/gui.cpp	2011-09-29 23:36:57 UTC (rev 48562)
@@ -0,0 +1,305 @@
+/* Written by Bill Brown, USACERL (brown at zorro.cecer.army.mil)
+ * May 2-12, 1994
+ *
+ * This code is in the public domain. Specifically, we give to the public
+ * domain all rights for future licensing of the source code, all resale
+ * rights, and all publishing rights.
+ * 
+ * We ask, but do not require, that the following message be included in
+ * all derived works:
+ *     "Portions developed at the US Army Construction Engineering 
+ *     Research Laboratories, Champaign, Illinois."
+ * 
+ * USACERL GIVES NO WARRANTY, EXPRESSED OR IMPLIED,
+ * FOR THE SOFTWARE AND/OR DOCUMENTATION PROVIDED, INCLUDING, WITHOUT
+ * LIMITATION, WARRANTY OF MERCHANTABILITY AND WARRANTY OF FITNESS FOR A
+ * PARTICULAR PURPOSE.
+ */
+
+#include <stdlib.h>
+#include <wx/button.h>
+#include <wx/bmpbuttn.h>
+#include <wx/bitmap.h>
+#include <wx/sizer.h>
+#include <wx/strconv.h>
+#include <wx/event.h>
+#include <wx/dcclient.h>
+#include <wx/dc.h>
+#include <wx/colour.h>
+#include "gui.h"
+
+#include "bitmaps/rewind.xbm"
+#include "bitmaps/rplay.xbm"
+#include "bitmaps/stepb.xbm"
+#include "bitmaps/stop.xbm"
+#include "bitmaps/stepf.xbm"
+#include "bitmaps/play.xbm"
+#include "bitmaps/loop.xbm"
+#include "bitmaps/swing.xbm"
+#include "bitmaps/snail.xbm"
+#include "bitmaps/rabbit.xbm"
+
+enum {
+    MYID_REW,
+    MYID_RPLAY,
+    MYID_STEPB,
+    MYID_STOP,
+    MYID_STEPF,
+    MYID_PLAY,
+    MYID_LOOP,
+    MYID_SWING,
+    MYID_SLOWER,
+    MYID_FASTER,
+    MYID_SHNAMES,
+    MYID_DOEXIT,
+};
+
+BEGIN_EVENT_TABLE(MyCanvas, wxPanel)
+EVT_ERASE_BACKGROUND(MyCanvas::erase)
+END_EVENT_TABLE()
+
+MyCanvas::MyCanvas(wxWindow *parent, wxWindowID id, const wxSize &size)
+    : wxPanel(parent, id, wxDefaultPosition, size)
+{
+    SetBackgroundStyle(wxBG_STYLE_CUSTOM);
+}
+
+void MyCanvas::erase(wxEraseEvent &ev)
+{
+    ev.GetDC();
+}
+
+void MyCanvas::draw_image(wxBitmap *bmp)
+{
+    wxClientDC dc(this);
+
+    dc.DrawBitmap(*bmp, 0, 0, false);
+}
+
+void MyCanvas::draw_text(int style, int x, int y, const char *str)
+{
+    wxClientDC dc(this);
+
+    switch (style) {
+    case 1:
+	dc.SetTextBackground(*wxWHITE);
+	dc.SetTextForeground(*wxBLACK);
+	break;
+    case 2:
+	dc.SetTextBackground(*wxBLACK);
+	dc.SetTextForeground(*wxWHITE);
+	break;
+    default:
+	return;
+    }
+
+    dc.DrawText(wxString(str, wxConvISO8859_1), x, y);
+}
+
+BEGIN_EVENT_TABLE(MyFrame, wxFrame)
+EVT_BUTTON(MYID_REW,     MyFrame::rewind_callback)
+EVT_BUTTON(MYID_RPLAY,   MyFrame::rplay_callback)
+EVT_BUTTON(MYID_STEPB,   MyFrame::stepb_callback)
+EVT_BUTTON(MYID_STOP,    MyFrame::stop_callback)
+EVT_BUTTON(MYID_STEPF,   MyFrame::stepf_callback)
+EVT_BUTTON(MYID_PLAY,    MyFrame::play_callback)
+EVT_BUTTON(MYID_LOOP,    MyFrame::loop_callback)
+EVT_BUTTON(MYID_SWING,   MyFrame::swing_callback)
+EVT_BUTTON(MYID_SLOWER,  MyFrame::slower_callback)
+EVT_BUTTON(MYID_FASTER,  MyFrame::faster_callback)
+EVT_BUTTON(MYID_SHNAMES, MyFrame::names_callback)
+EVT_BUTTON(MYID_DOEXIT,  MyFrame::exit_callback)
+END_EVENT_TABLE()
+
+void MyFrame::make_buttons(wxSizer *sizer)
+{
+    sizer->Add(new wxBitmapButton(this, MYID_REW   , wxBitmap(rewind_bits, rewind_width, rewind_height)));
+    sizer->Add(new wxBitmapButton(this, MYID_RPLAY , wxBitmap(rplay_bits , rplay_width , rplay_height )));
+    sizer->Add(new wxBitmapButton(this, MYID_STEPB , wxBitmap(stepb_bits , stepb_width , stepb_height )));
+    sizer->Add(new wxBitmapButton(this, MYID_STOP  , wxBitmap(stop_bits  , stop_width  , stop_height  )));
+    sizer->Add(new wxBitmapButton(this, MYID_STEPF , wxBitmap(stepf_bits , stepf_width , stepf_height )));
+    sizer->Add(new wxBitmapButton(this, MYID_PLAY  , wxBitmap(play_bits  , play_width  , play_height  )));
+    sizer->Add(new wxBitmapButton(this, MYID_LOOP  , wxBitmap(loop_bits  , loop_width  , loop_height  )));
+    sizer->Add(new wxBitmapButton(this, MYID_SWING , wxBitmap(swing_bits , swing_width , swing_height )));
+    sizer->Add(new wxBitmapButton(this, MYID_SLOWER, wxBitmap(snail_bits , snail_width , snail_height )));
+    sizer->Add(new wxBitmapButton(this, MYID_FASTER, wxBitmap(rabbit_bits, rabbit_width, rabbit_height)));
+    sizer->Add(new wxButton(this, MYID_SHNAMES, wxString("Names", wxConvISO8859_1)));
+    sizer->Add(new wxButton(this, MYID_DOEXIT,  wxString("Exit", wxConvISO8859_1)));
+}
+
+void MyFrame::rewind_callback(wxCommandEvent &event)
+{
+    cd->step = 0;
+    cd->stop = 1;
+    cd->rewind = 1;
+}
+
+void MyFrame::rplay_callback(wxCommandEvent &event)
+{
+    cd->step = 0;
+    cd->stop = 0;
+    cd->direction = -1;
+    cd->curframe = cd->prevframe + cd->direction;
+}
+
+void MyFrame::stepb_callback(wxCommandEvent &event)
+{
+    cd->step = 1;
+    cd->direction = -1;
+    cd->curframe = cd->prevframe + cd->direction;
+}
+
+void MyFrame::stop_callback(wxCommandEvent &event)
+{
+    cd->stop = 1;
+}
+
+void MyFrame::stepf_callback(wxCommandEvent &event)
+{
+    cd->step = 1;
+    cd->direction = 1;
+    cd->curframe = cd->prevframe + cd->direction;
+}
+
+void MyFrame::play_callback(wxCommandEvent &event)
+{
+    cd->step = 0;
+    cd->stop = 0;
+    cd->direction = 1;
+    cd->curframe = cd->prevframe + cd->direction;
+}
+
+void MyFrame::loop_callback(wxCommandEvent &event)
+{
+    cd->loop = !cd->loop;
+    cd->swing = 0;
+    cd->stop = !cd->loop;
+}
+
+void MyFrame::swing_callback(wxCommandEvent &event)
+{
+    cd->swing = !cd->swing;
+    cd->loop = 0;
+    cd->stop = !cd->swing;
+}
+
+void MyFrame::slower_callback(wxCommandEvent &event)
+{
+    if (cd->speed) {
+	if (cd->speed < 200000)
+	    cd->speed *= 3;
+    }
+    else
+	cd->speed = 1;
+}
+
+void MyFrame::faster_callback(wxCommandEvent &event)
+{
+    if (cd->speed > 1)
+	cd->speed /= 3;
+}
+
+void MyFrame::names_callback(wxCommandEvent &event)
+{
+    cd->shownames = (1 + cd->shownames) % 3;
+}
+
+void MyFrame::exit_callback(wxCommandEvent &event)
+{
+    exit(0);
+}
+
+void MyFrame::change_label(const char *label)
+{
+    flabel->SetLabel(wxString(label, wxConvISO8859_1));
+}
+
+#if 0
+
+void MyFrame::init_graphics()
+{
+/* global variables */
+    Widget canvas;
+    Display *theDisplay;
+    XImage *pic_array[MAXIMAGES];
+    GC invertGC, drawGC;
+
+    int scrn;
+    Display *dpy;
+    Window grwin;
+    Colormap fixedcmap;
+    unsigned long blackPix, whitePix;
+
+    unsigned int depth;
+    Visual *use_visual;
+
+    dpy = XtDisplay(canvas);
+    grwin = XtWindow(canvas);
+    scrn = DefaultScreen(dpy);
+    use_visual = DefaultVisual(dpy, scrn);
+#if 1
+    fixedcmap = XCreateColormap(dpy, grwin, use_visual, AllocNone);
+#else
+    fixedcmap = DefaultColormap(dpy, scrn);
+#endif
+    fixedcmap = InitColorTableFixed(fixedcmap);
+
+    XtVaGetValues(canvas, XmNdepth, &depth, NULL);
+
+    XtVaSetValues(toplevel, XmNcolormap, fixedcmap, NULL);
+    XtSetWMColormapWindows(toplevel, &canvas, 1);
+
+    /**************************************************************/
+
+    blackPix = _get_lookup_for_color(0, 0, 0);
+    whitePix = _get_lookup_for_color(255, 255, 255);
+
+    drawGC =
+	XCreateGC(XtDisplay(canvas), XtWindow(canvas), (unsigned long)0,
+		  NULL);
+
+    theDisplay = XtDisplay(toplevel);
+
+    XSetFunction(theDisplay, drawGC, GXcopy);
+    XSetForeground(theDisplay, drawGC, blackPix);
+    XSetBackground(theDisplay, drawGC, whitePix);
+
+    invertGC =
+	XCreateGC(XtDisplay(canvas), XtWindow(canvas), (unsigned long)0,
+		  NULL);
+    XSetFunction(theDisplay, invertGC, GXcopy);
+    XSetForeground(theDisplay, invertGC, whitePix);
+    XSetBackground(theDisplay, invertGC, blackPix);
+
+}
+
+#endif
+
+MyFrame::MyFrame(const wxString& title, int ncols, int nrows, struct gui_data *cd)
+    : wxFrame((wxFrame *)NULL, wxID_ANY, title), cd(cd)
+{
+    canvas = new MyCanvas(this, wxID_ANY, wxSize(ncols, nrows));
+
+    wxBoxSizer *sizer, *buttons;
+
+    if (ncols > nrows) {
+	sizer = new wxBoxSizer(wxVERTICAL);
+	buttons = new wxBoxSizer(wxHORIZONTAL);
+	sizer->Add(canvas);
+	sizer->Add(buttons);
+    }
+    else {
+	sizer = new wxBoxSizer(wxHORIZONTAL);
+	buttons = new wxBoxSizer(wxVERTICAL);
+	sizer->Add(canvas);
+	sizer->Add(buttons);
+    }
+
+    make_buttons(buttons);
+
+    flabel = new wxStaticText(this, wxID_ANY, wxString("00000", wxConvISO8859_1), wxDefaultPosition, wxDefaultSize, wxALIGN_RIGHT);
+    buttons->Add(flabel);
+
+    SetSizerAndFit(sizer);
+}
+

Deleted: grass/trunk/visualization/xganim/main.cc
===================================================================
--- grass/trunk/visualization/xganim/main.cc	2011-09-29 23:35:42 UTC (rev 48561)
+++ grass/trunk/visualization/xganim/main.cc	2011-09-29 23:36:57 UTC (rev 48562)
@@ -1,474 +0,0 @@
-
-/****************************************************************************
- *
- * MODULE:       xganim
- * AUTHOR(S):    Bill Brown <brown gis.uiuc.edu> CERL (original contributor),
- *               Markus Neteler <neteler itc.it>,
- *               Roberto Flor <flor itc.it>, 
- *               Bernhard Reiter <bernhard intevation.de>, 
- *               Brad Douglas <rez touchofmadness.com>, 
- *               Glynn Clements <glynn gclements.plus.com>
- * PURPOSE:      a tool for animating a series of GRASS raster files
- * COPYRIGHT:    (C) 1999-2006 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 <string.h>
-#include <stdlib.h>
-#include <math.h>
-#include <limits.h>
-#include <unistd.h>
-
-#include <wx/image.h>
-#include <wx/bitmap.h>
-#include <wx/event.h>
-
-extern "C" {
-#include <grass/gis.h>
-#include <grass/raster.h>
-#include <grass/spawn.h>
-#include <grass/glocale.h>
-}
-
-#include "gui.h"
-
-#define DEF_MAX 900
-#define DEF_MIN 600
-#define BORDER_W    2
-
-static char **gee_wildfiles(const char *wildarg, const char *element, int *num);
-static void parse_command(
-    struct Option **viewopts,
-    char *vfiles[MAXVIEWS][MAXIMAGES],
-    int *numviews, int *numframes);
-
-struct Option *viewopts[MAXVIEWS];
-
-unsigned int nrows, ncols;
-char *vfiles[MAXVIEWS][MAXIMAGES];
-int numviews;
-int frames;
-int Top = 0, Left = 0;
-char frame[MAXIMAGES][4];
-int LabelPos[MAXVIEWS][2];
-
-float vscale, scale;		/* resampling scale factors */
-int irows, icols, vrows, vcols;
-
-BEGIN_EVENT_TABLE(MyApp, wxApp)
-EVT_IDLE(MyApp::do_run)
-END_EVENT_TABLE()
-
-int main(int argc, char **argv)
-{
-    int i;
-
-    G_gisinit(argv[0]);
-
-
-    for (i = 0; i < MAXVIEWS; i++) {
-	char buf[BUFSIZ];
-	viewopts[i] = G_define_option();
-	sprintf(buf, "view%d", i + 1);
-	viewopts[i]->key = G_store(buf);
-	viewopts[i]->type = TYPE_STRING;
-	viewopts[i]->required = (i ? NO : YES);
-	viewopts[i]->multiple = YES;
-	viewopts[i]->gisprompt = "old,cell,Raster";;
-	sprintf(buf, _("Raster file(s) for View%d"), i + 1);
-	viewopts[i]->description = G_store(buf);
-    }
-
-    if (G_parser(argc, argv))
-	exit(EXIT_FAILURE);
-
-    parse_command(viewopts, vfiles, &numviews, &frames);
-
-    return wxEntry(argc, argv);
-}
-
-bool MyApp::OnInit()
-{
-    int i, j;
-    unsigned int *sdimp;
-    int longdim;
-
-    /* debug */
-    if (G_verbose() > G_verbose_std()) {
-	for (i = 0; i < numviews; i++) {
-	    fprintf(stderr, "\nVIEW %d: ", i + 1);
-	    for (j = 0; j < frames; j++) {
-		fprintf(stderr, "%s ", vfiles[i][j]);
-	    }
-	}
-    }
-    fprintf(stderr, "\n");
-
-    vrows = Rast_window_rows();
-    vcols = Rast_window_cols();
-    nrows = vrows;
-    ncols = vcols;
-
-    /* short dimension */
-    sdimp = nrows > ncols ? &ncols : &nrows;
-
-    /* these proportions should work fine for 1 or 4 views, but for
-       2 views, want to double the narrow dim & for 3 views triple it */
-    if (numviews == 2)
-	*sdimp *= 2;
-    else if (numviews == 3)
-	*sdimp *= 3;
-
-    longdim = nrows > ncols ? nrows : ncols;
-
-    scale = 1.0;
-
-    {				/* find animation image size */
-	int max, min;
-	char *p;
-
-	max = DEF_MAX;
-	min = DEF_MIN;
-
-	if ((p = getenv("XGANIM_SIZE")))
-	    max = min = atoi(p);
-
-	if (longdim > max)	/* scale down */
-	    scale = (float)max / longdim;
-	else if (longdim < min)	/* scale up */
-	    scale = (float)min / longdim;
-    }
-
-    vscale = scale;
-    if (numviews == 4)
-	vscale = scale / 2.;
-
-    nrows = (unsigned int) (nrows * scale);
-    ncols = (unsigned int) (ncols * scale);
-    /* now nrows & ncols are the size of the combined - views image */
-    vrows = (int) (vrows * vscale);
-    vcols = (int) (vcols * vscale);
-    /* now vrows & vcols are the size for each sub-image */
-
-    /* add to nrows & ncols for borders */
-    /* irows, icols used for vert/horizontal determination in loop below */
-    irows = nrows;
-    icols = ncols;
-    nrows += (1 + (nrows / vrows)) * BORDER_W;
-    ncols += (1 + (ncols / vcols)) * BORDER_W;
-
-    gd.speed = 100;
-    gd.direction = 1;
-    gd.shownames = 1;
-
-    mainwin = new MyFrame(wxString("GRASS Animate", wxConvISO8859_1), ncols, nrows, &gd);
-    mainwin->Show();
-    SetTopWindow(mainwin);
-
-    for (j = 0; j < MAXIMAGES; j++)
-	sprintf(frame[j], "%2d", j + 1);
-
-    return true;
-}
-
-
-int MyApp::load_files(void)
-{
-    DCELL *dcell;
-    unsigned char *tr, *tg, *tb, *tset;
-    int tsiz, coff;
-    int rowoff, row, col, vxoff, vyoff;
-    int cnt, ret, fd;
-    int vnum;
-    const char *name;
-    struct Colors colors;
-
-    dcell = Rast_allocate_d_buf();
-
-    tsiz = Rast_window_cols();
-
-    /* allocate memory */
-    tr   = (unsigned char *) G_malloc(tsiz * sizeof(char));
-    tg   = (unsigned char *) G_malloc(tsiz * sizeof(char));
-    tb   = (unsigned char *) G_malloc(tsiz * sizeof(char));
-    tset = (unsigned char *) G_malloc(tsiz * sizeof(char));
-
-    wxImage img(ncols, nrows);
-
-    for (cnt = 0; cnt < frames; cnt++) {
-	if (cnt > MAXIMAGES) {
-	    cnt--;
-	    break;
-	}
-
-	for (vnum = 0; vnum < numviews; vnum++) {
-	    if (icols == vcols) {
-		vxoff = BORDER_W;
-		vyoff = (irows == vrows) ? BORDER_W :
-		    BORDER_W + vnum * (BORDER_W + vrows);
-	    }
-	    else if (irows == vrows) {
-		vxoff = (icols == vcols) ? BORDER_W :
-		    BORDER_W + vnum * (BORDER_W + vcols);
-		vyoff = BORDER_W;
-	    }
-	    else {		/* 4 views */
-		/* assumes we want :
-		   view1        view2
-
-		   view3        view4   
-		 */
-		vxoff = vnum % 2 ? BORDER_W : vcols + 2 * BORDER_W;
-		vyoff = vnum > 1 ? vrows + 2 * BORDER_W : BORDER_W;
-	    }
-	    if (!cnt) {
-		LabelPos[vnum][0] = vxoff;
-		LabelPos[vnum][1] = vyoff + vrows - 1;
-	    }
-
-	    name = vfiles[vnum][cnt];
-	    G_message(_("Reading file [%s]..."), name);
-
-	    fd = Rast_open_old(name, "");
-	    if (fd < 0)
-		G_fatal_error(_("Unable to open raster map <%s>"), name);
-	    /*
-	       strcpy(title[cnt],G_get_cell_title(name, mapset));
-	     */
-
-	    ret = Rast_read_colors(name, "", &colors);
-	    if (ret < 0)
-		G_fatal_error(_("Unable to read color file"));
-
-	    for (row = 0; row < vrows; row++) {
-		Rast_get_d_row(fd, dcell, (int)(row / vscale));
-
-		rowoff = (vyoff + row) * ncols;
-		Rast_lookup_d_colors(dcell, tr, tg, tb, tset, tsiz, &colors);
-
-		for (col = 0; col < vcols; col++) {
-		    coff = (int)(col / vscale);
-
-		    if (!tset[coff])
-			img.SetRGB(vxoff + col, vyoff + row, 255, 255, 255);
-		    else
-			img.SetRGB(vxoff + col, vyoff + row, tr[coff], tg[coff], tb[coff]);
-		}
-	    }
-
-	    Rast_close(fd);
-	}
-
-	wxBitmap *bmp = new wxBitmap(img);
-	pic_array[cnt] = bmp;
-
-	mainwin->canvas->draw_image(bmp);
-	mainwin->change_label(frame[cnt]);
-    }
-
-    G_free(dcell);
-    G_free(tr);
-    G_free(tg);
-    G_free(tb);
-    G_free(tset);
-
-    return cnt;
-}
-
-
-/* ###################################################### */
-
-void MyApp::do_run(wxIdleEvent &ev)
-{
-    static int first = 1;
-    struct gui_data *cd = &gd;
-    int i, cnt;
-
-    if (first) {
-	first = 0;
-	cnt = load_files();
-	cd->curframe = cd->direction > 0 ? 0 : cnt - 1;
-	cd->prevframe = cd->curframe;
-	cd->step = cd->stop = 0;
-	cd->loop = cd->swing = 0;
-	cd->nframes = cnt;
-
-    }
-
-    if (cd->rewind) {
-	cd->rewind = 0;
-	cd->curframe = 0;
-	cd->direction = 1;
-	cd->step = 1;
-    }
-
-    if (cd->swing) {
-	if (cd->curframe == cd->nframes || cd->curframe < 0) {
-	    cd->direction = -cd->direction;
-	    cd->curframe += cd->direction;
-	}
-    }
-    else if (cd->loop) {
-	if (cd->curframe == cd->nframes)
-	    cd->curframe = 0;
-	else if (cd->curframe < 0)
-	    cd->curframe = cd->nframes - 1;
-    }
-    else if (cd->curframe == cd->nframes || cd->curframe < 0)
-	cd->stop = 1;
-
-    if (cd->stop && !cd->step)
-	return;
-
-    if (cd->curframe < cd->nframes && cd->curframe >= 0) {
-	/* little pause */
-	{
-	    float tf;
-
-	    for (tf = 0.0; tf < cd->speed; tf += .01) ;
-	}
-
-	mainwin->canvas->draw_image(pic_array[cd->curframe]);
-
-	/* draw labels */
-	for (i = 0; i < numviews; i++) {
-	    mainwin->canvas->draw_text(
-		cd->shownames,
-		LabelPos[i][0] + 5, LabelPos[i][1] - 5,
-		vfiles[i][cd->curframe]);
-	}
-
-	mainwin->change_label(frame[cd->curframe]);
-
-	cd->prevframe = cd->curframe;
-    }
-
-    cd->curframe += cd->direction;
-
-    if (cd->step) {
-	cd->step = 0;
-	cd->stop = 1;
-    }
-}
-
-/* ###################################################### */
-
-static void mlist(const char *element, const char *wildarg, const char *outfile)
-{
-    int n;
-    const char *mapset;
-
-    for (n = 0; (mapset = G__mapset_name(n)); n++) {
-	char type_arg[GNAME_MAX];
-	char pattern_arg[GNAME_MAX];
-	char mapset_arg[GMAPSET_MAX];
-
-	if (strcmp(mapset, ".") == 0)
-	    mapset = G_mapset();
-
-	sprintf(type_arg, "type=%s", element);
-	sprintf(pattern_arg, "pattern=%s", wildarg);
-	sprintf(mapset_arg, "mapset=%s", mapset);
-
-	G_spawn_ex("g.mlist", "g.mlist",
-		   type_arg, pattern_arg, mapset_arg,
-		   SF_REDIRECT_FILE, SF_STDOUT, SF_MODE_APPEND, outfile,
-		   NULL);
-    }
-}
-
-static char **parse(const char *filename, int *num)
-{
-    char buf[GNAME_MAX];
-    char **files = NULL;
-    int max_files = 0;
-    int num_files = 0;
-    FILE *fp;
-
-    fp = fopen(filename, "r");
-    if (!fp)
-	G_fatal_error(_("Error reading wildcard"));
-
-    while (fgets(buf, sizeof(buf), fp)) {
-	char *p = strchr(buf, '\n');
-	if (p)
-	    *p = '\0';
-
-	if (!*buf)
-	    continue;
-
-	if (num_files >= max_files) {
-	    max_files += 50;
-	    files = (char **) G_realloc((void *) files,
-					max_files * sizeof(char *));
-	}
-
-	files[num_files++] = G_store(buf);
-    }
-
-    fclose(fp);
-
-    *num = num_files;
-
-    return files;
-}
-
-static char **gee_wildfiles(const char *wildarg, const char *element, int *num)
-{
-    char *tfile;
-    char **files;
-
-    tfile = G_tempfile();
-
-    mlist(element, wildarg, tfile);
-    files = parse(tfile, num);
-
-    remove(tfile);
-    G_free(tfile);
-
-    return files;
-}
-
-static void parse_command(struct Option **viewopts,
-			  char *vfiles[MAXVIEWS][MAXIMAGES],
-			  int *numviews, int *numframes)
-{
-    int i, j, k;
-
-    *numviews = *numframes = 0;
-
-    for (i = 0; i < MAXVIEWS; i++) {
-	if (viewopts[i]->answers) {
-	    int numi, wildnum;
-
-	    (*numviews)++;
-
-	    for (j = 0, numi = 0; viewopts[i]->answers[j]; j++) {
-		if ((NULL != strchr(viewopts[i]->answers[j], '*')) ||
-		    (NULL != strchr(viewopts[i]->answers[j], '?')) ||
-		    (NULL != strchr(viewopts[i]->answers[j], '['))) {
-		    char **wildfiles = gee_wildfiles(viewopts[i]->answers[j],
-						     "rast", &wildnum);
-
-		    for (k = 0; k < wildnum; k++)
-			vfiles[i][numi++] = wildfiles[k];
-		}
-		else
-		    vfiles[i][numi++] = G_store(viewopts[i]->answers[j]);
-	    }
-	    /* keep track of smallest number of frames */
-	    *numframes =
-		*numframes ? *numframes > numi ? numi : *numframes : numi;
-	}
-    }
-}
-
-/********************************************************************/
-
-IMPLEMENT_APP_NO_MAIN(MyApp)
-

Copied: grass/trunk/visualization/xganim/main.cpp (from rev 48560, grass/trunk/visualization/xganim/main.cc)
===================================================================
--- grass/trunk/visualization/xganim/main.cpp	                        (rev 0)
+++ grass/trunk/visualization/xganim/main.cpp	2011-09-29 23:36:57 UTC (rev 48562)
@@ -0,0 +1,474 @@
+
+/****************************************************************************
+ *
+ * MODULE:       xganim
+ * AUTHOR(S):    Bill Brown <brown gis.uiuc.edu> CERL (original contributor),
+ *               Markus Neteler <neteler itc.it>,
+ *               Roberto Flor <flor itc.it>, 
+ *               Bernhard Reiter <bernhard intevation.de>, 
+ *               Brad Douglas <rez touchofmadness.com>, 
+ *               Glynn Clements <glynn gclements.plus.com>
+ * PURPOSE:      a tool for animating a series of GRASS raster files
+ * COPYRIGHT:    (C) 1999-2006 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 <string.h>
+#include <stdlib.h>
+#include <math.h>
+#include <limits.h>
+#include <unistd.h>
+
+#include <wx/image.h>
+#include <wx/bitmap.h>
+#include <wx/event.h>
+
+extern "C" {
+#include <grass/gis.h>
+#include <grass/raster.h>
+#include <grass/spawn.h>
+#include <grass/glocale.h>
+}
+
+#include "gui.h"
+
+#define DEF_MAX 900
+#define DEF_MIN 600
+#define BORDER_W    2
+
+static char **gee_wildfiles(const char *wildarg, const char *element, int *num);
+static void parse_command(
+    struct Option **viewopts,
+    char *vfiles[MAXVIEWS][MAXIMAGES],
+    int *numviews, int *numframes);
+
+struct Option *viewopts[MAXVIEWS];
+
+unsigned int nrows, ncols;
+char *vfiles[MAXVIEWS][MAXIMAGES];
+int numviews;
+int frames;
+int Top = 0, Left = 0;
+char frame[MAXIMAGES][4];
+int LabelPos[MAXVIEWS][2];
+
+float vscale, scale;		/* resampling scale factors */
+int irows, icols, vrows, vcols;
+
+BEGIN_EVENT_TABLE(MyApp, wxApp)
+EVT_IDLE(MyApp::do_run)
+END_EVENT_TABLE()
+
+int main(int argc, char **argv)
+{
+    int i;
+
+    G_gisinit(argv[0]);
+
+
+    for (i = 0; i < MAXVIEWS; i++) {
+	char buf[BUFSIZ];
+	viewopts[i] = G_define_option();
+	sprintf(buf, "view%d", i + 1);
+	viewopts[i]->key = G_store(buf);
+	viewopts[i]->type = TYPE_STRING;
+	viewopts[i]->required = (i ? NO : YES);
+	viewopts[i]->multiple = YES;
+	viewopts[i]->gisprompt = "old,cell,Raster";;
+	sprintf(buf, _("Raster file(s) for View%d"), i + 1);
+	viewopts[i]->description = G_store(buf);
+    }
+
+    if (G_parser(argc, argv))
+	exit(EXIT_FAILURE);
+
+    parse_command(viewopts, vfiles, &numviews, &frames);
+
+    return wxEntry(argc, argv);
+}
+
+bool MyApp::OnInit()
+{
+    int i, j;
+    unsigned int *sdimp;
+    int longdim;
+
+    /* debug */
+    if (G_verbose() > G_verbose_std()) {
+	for (i = 0; i < numviews; i++) {
+	    fprintf(stderr, "\nVIEW %d: ", i + 1);
+	    for (j = 0; j < frames; j++) {
+		fprintf(stderr, "%s ", vfiles[i][j]);
+	    }
+	}
+    }
+    fprintf(stderr, "\n");
+
+    vrows = Rast_window_rows();
+    vcols = Rast_window_cols();
+    nrows = vrows;
+    ncols = vcols;
+
+    /* short dimension */
+    sdimp = nrows > ncols ? &ncols : &nrows;
+
+    /* these proportions should work fine for 1 or 4 views, but for
+       2 views, want to double the narrow dim & for 3 views triple it */
+    if (numviews == 2)
+	*sdimp *= 2;
+    else if (numviews == 3)
+	*sdimp *= 3;
+
+    longdim = nrows > ncols ? nrows : ncols;
+
+    scale = 1.0;
+
+    {				/* find animation image size */
+	int max, min;
+	char *p;
+
+	max = DEF_MAX;
+	min = DEF_MIN;
+
+	if ((p = getenv("XGANIM_SIZE")))
+	    max = min = atoi(p);
+
+	if (longdim > max)	/* scale down */
+	    scale = (float)max / longdim;
+	else if (longdim < min)	/* scale up */
+	    scale = (float)min / longdim;
+    }
+
+    vscale = scale;
+    if (numviews == 4)
+	vscale = scale / 2.;
+
+    nrows = (unsigned int) (nrows * scale);
+    ncols = (unsigned int) (ncols * scale);
+    /* now nrows & ncols are the size of the combined - views image */
+    vrows = (int) (vrows * vscale);
+    vcols = (int) (vcols * vscale);
+    /* now vrows & vcols are the size for each sub-image */
+
+    /* add to nrows & ncols for borders */
+    /* irows, icols used for vert/horizontal determination in loop below */
+    irows = nrows;
+    icols = ncols;
+    nrows += (1 + (nrows / vrows)) * BORDER_W;
+    ncols += (1 + (ncols / vcols)) * BORDER_W;
+
+    gd.speed = 100;
+    gd.direction = 1;
+    gd.shownames = 1;
+
+    mainwin = new MyFrame(wxString("GRASS Animate", wxConvISO8859_1), ncols, nrows, &gd);
+    mainwin->Show();
+    SetTopWindow(mainwin);
+
+    for (j = 0; j < MAXIMAGES; j++)
+	sprintf(frame[j], "%2d", j + 1);
+
+    return true;
+}
+
+
+int MyApp::load_files(void)
+{
+    DCELL *dcell;
+    unsigned char *tr, *tg, *tb, *tset;
+    int tsiz, coff;
+    int rowoff, row, col, vxoff, vyoff;
+    int cnt, ret, fd;
+    int vnum;
+    const char *name;
+    struct Colors colors;
+
+    dcell = Rast_allocate_d_buf();
+
+    tsiz = Rast_window_cols();
+
+    /* allocate memory */
+    tr   = (unsigned char *) G_malloc(tsiz * sizeof(char));
+    tg   = (unsigned char *) G_malloc(tsiz * sizeof(char));
+    tb   = (unsigned char *) G_malloc(tsiz * sizeof(char));
+    tset = (unsigned char *) G_malloc(tsiz * sizeof(char));
+
+    wxImage img(ncols, nrows);
+
+    for (cnt = 0; cnt < frames; cnt++) {
+	if (cnt > MAXIMAGES) {
+	    cnt--;
+	    break;
+	}
+
+	for (vnum = 0; vnum < numviews; vnum++) {
+	    if (icols == vcols) {
+		vxoff = BORDER_W;
+		vyoff = (irows == vrows) ? BORDER_W :
+		    BORDER_W + vnum * (BORDER_W + vrows);
+	    }
+	    else if (irows == vrows) {
+		vxoff = (icols == vcols) ? BORDER_W :
+		    BORDER_W + vnum * (BORDER_W + vcols);
+		vyoff = BORDER_W;
+	    }
+	    else {		/* 4 views */
+		/* assumes we want :
+		   view1        view2
+
+		   view3        view4   
+		 */
+		vxoff = vnum % 2 ? BORDER_W : vcols + 2 * BORDER_W;
+		vyoff = vnum > 1 ? vrows + 2 * BORDER_W : BORDER_W;
+	    }
+	    if (!cnt) {
+		LabelPos[vnum][0] = vxoff;
+		LabelPos[vnum][1] = vyoff + vrows - 1;
+	    }
+
+	    name = vfiles[vnum][cnt];
+	    G_message(_("Reading file [%s]..."), name);
+
+	    fd = Rast_open_old(name, "");
+	    if (fd < 0)
+		G_fatal_error(_("Unable to open raster map <%s>"), name);
+	    /*
+	       strcpy(title[cnt],G_get_cell_title(name, mapset));
+	     */
+
+	    ret = Rast_read_colors(name, "", &colors);
+	    if (ret < 0)
+		G_fatal_error(_("Unable to read color file"));
+
+	    for (row = 0; row < vrows; row++) {
+		Rast_get_d_row(fd, dcell, (int)(row / vscale));
+
+		rowoff = (vyoff + row) * ncols;
+		Rast_lookup_d_colors(dcell, tr, tg, tb, tset, tsiz, &colors);
+
+		for (col = 0; col < vcols; col++) {
+		    coff = (int)(col / vscale);
+
+		    if (!tset[coff])
+			img.SetRGB(vxoff + col, vyoff + row, 255, 255, 255);
+		    else
+			img.SetRGB(vxoff + col, vyoff + row, tr[coff], tg[coff], tb[coff]);
+		}
+	    }
+
+	    Rast_close(fd);
+	}
+
+	wxBitmap *bmp = new wxBitmap(img);
+	pic_array[cnt] = bmp;
+
+	mainwin->canvas->draw_image(bmp);
+	mainwin->change_label(frame[cnt]);
+    }
+
+    G_free(dcell);
+    G_free(tr);
+    G_free(tg);
+    G_free(tb);
+    G_free(tset);
+
+    return cnt;
+}
+
+
+/* ###################################################### */
+
+void MyApp::do_run(wxIdleEvent &ev)
+{
+    static int first = 1;
+    struct gui_data *cd = &gd;
+    int i, cnt;
+
+    if (first) {
+	first = 0;
+	cnt = load_files();
+	cd->curframe = cd->direction > 0 ? 0 : cnt - 1;
+	cd->prevframe = cd->curframe;
+	cd->step = cd->stop = 0;
+	cd->loop = cd->swing = 0;
+	cd->nframes = cnt;
+
+    }
+
+    if (cd->rewind) {
+	cd->rewind = 0;
+	cd->curframe = 0;
+	cd->direction = 1;
+	cd->step = 1;
+    }
+
+    if (cd->swing) {
+	if (cd->curframe == cd->nframes || cd->curframe < 0) {
+	    cd->direction = -cd->direction;
+	    cd->curframe += cd->direction;
+	}
+    }
+    else if (cd->loop) {
+	if (cd->curframe == cd->nframes)
+	    cd->curframe = 0;
+	else if (cd->curframe < 0)
+	    cd->curframe = cd->nframes - 1;
+    }
+    else if (cd->curframe == cd->nframes || cd->curframe < 0)
+	cd->stop = 1;
+
+    if (cd->stop && !cd->step)
+	return;
+
+    if (cd->curframe < cd->nframes && cd->curframe >= 0) {
+	/* little pause */
+	{
+	    float tf;
+
+	    for (tf = 0.0; tf < cd->speed; tf += .01) ;
+	}
+
+	mainwin->canvas->draw_image(pic_array[cd->curframe]);
+
+	/* draw labels */
+	for (i = 0; i < numviews; i++) {
+	    mainwin->canvas->draw_text(
+		cd->shownames,
+		LabelPos[i][0] + 5, LabelPos[i][1] - 5,
+		vfiles[i][cd->curframe]);
+	}
+
+	mainwin->change_label(frame[cd->curframe]);
+
+	cd->prevframe = cd->curframe;
+    }
+
+    cd->curframe += cd->direction;
+
+    if (cd->step) {
+	cd->step = 0;
+	cd->stop = 1;
+    }
+}
+
+/* ###################################################### */
+
+static void mlist(const char *element, const char *wildarg, const char *outfile)
+{
+    int n;
+    const char *mapset;
+
+    for (n = 0; (mapset = G__mapset_name(n)); n++) {
+	char type_arg[GNAME_MAX];
+	char pattern_arg[GNAME_MAX];
+	char mapset_arg[GMAPSET_MAX];
+
+	if (strcmp(mapset, ".") == 0)
+	    mapset = G_mapset();
+
+	sprintf(type_arg, "type=%s", element);
+	sprintf(pattern_arg, "pattern=%s", wildarg);
+	sprintf(mapset_arg, "mapset=%s", mapset);
+
+	G_spawn_ex("g.mlist", "g.mlist",
+		   type_arg, pattern_arg, mapset_arg,
+		   SF_REDIRECT_FILE, SF_STDOUT, SF_MODE_APPEND, outfile,
+		   NULL);
+    }
+}
+
+static char **parse(const char *filename, int *num)
+{
+    char buf[GNAME_MAX];
+    char **files = NULL;
+    int max_files = 0;
+    int num_files = 0;
+    FILE *fp;
+
+    fp = fopen(filename, "r");
+    if (!fp)
+	G_fatal_error(_("Error reading wildcard"));
+
+    while (fgets(buf, sizeof(buf), fp)) {
+	char *p = strchr(buf, '\n');
+	if (p)
+	    *p = '\0';
+
+	if (!*buf)
+	    continue;
+
+	if (num_files >= max_files) {
+	    max_files += 50;
+	    files = (char **) G_realloc((void *) files,
+					max_files * sizeof(char *));
+	}
+
+	files[num_files++] = G_store(buf);
+    }
+
+    fclose(fp);
+
+    *num = num_files;
+
+    return files;
+}
+
+static char **gee_wildfiles(const char *wildarg, const char *element, int *num)
+{
+    char *tfile;
+    char **files;
+
+    tfile = G_tempfile();
+
+    mlist(element, wildarg, tfile);
+    files = parse(tfile, num);
+
+    remove(tfile);
+    G_free(tfile);
+
+    return files;
+}
+
+static void parse_command(struct Option **viewopts,
+			  char *vfiles[MAXVIEWS][MAXIMAGES],
+			  int *numviews, int *numframes)
+{
+    int i, j, k;
+
+    *numviews = *numframes = 0;
+
+    for (i = 0; i < MAXVIEWS; i++) {
+	if (viewopts[i]->answers) {
+	    int numi, wildnum;
+
+	    (*numviews)++;
+
+	    for (j = 0, numi = 0; viewopts[i]->answers[j]; j++) {
+		if ((NULL != strchr(viewopts[i]->answers[j], '*')) ||
+		    (NULL != strchr(viewopts[i]->answers[j], '?')) ||
+		    (NULL != strchr(viewopts[i]->answers[j], '['))) {
+		    char **wildfiles = gee_wildfiles(viewopts[i]->answers[j],
+						     "rast", &wildnum);
+
+		    for (k = 0; k < wildnum; k++)
+			vfiles[i][numi++] = wildfiles[k];
+		}
+		else
+		    vfiles[i][numi++] = G_store(viewopts[i]->answers[j]);
+	    }
+	    /* keep track of smallest number of frames */
+	    *numframes =
+		*numframes ? *numframes > numi ? numi : *numframes : numi;
+	}
+    }
+}
+
+/********************************************************************/
+
+IMPLEMENT_APP_NO_MAIN(MyApp)
+



More information about the grass-commit mailing list