[GRASS-SVN] r68989 - grass/branches/releasebranch_6_4/raster/r.terraflow
svn_grass at osgeo.org
svn_grass at osgeo.org
Sat Jul 16 14:49:08 PDT 2016
Author: neteler
Date: 2016-07-16 14:49:07 -0700 (Sat, 16 Jul 2016)
New Revision: 68989
Added:
grass/branches/releasebranch_6_4/raster/r.terraflow/ccforest.cpp
grass/branches/releasebranch_6_4/raster/r.terraflow/common.cpp
grass/branches/releasebranch_6_4/raster/r.terraflow/direction.cpp
grass/branches/releasebranch_6_4/raster/r.terraflow/fill.cpp
grass/branches/releasebranch_6_4/raster/r.terraflow/filldepr.cpp
grass/branches/releasebranch_6_4/raster/r.terraflow/flow.cpp
grass/branches/releasebranch_6_4/raster/r.terraflow/genericWindow.cpp
grass/branches/releasebranch_6_4/raster/r.terraflow/grid.cpp
grass/branches/releasebranch_6_4/raster/r.terraflow/main.cpp
grass/branches/releasebranch_6_4/raster/r.terraflow/nodata.cpp
grass/branches/releasebranch_6_4/raster/r.terraflow/plateau.cpp
grass/branches/releasebranch_6_4/raster/r.terraflow/stats.cpp
grass/branches/releasebranch_6_4/raster/r.terraflow/sweep.cpp
grass/branches/releasebranch_6_4/raster/r.terraflow/types.cpp
grass/branches/releasebranch_6_4/raster/r.terraflow/water.cpp
grass/branches/releasebranch_6_4/raster/r.terraflow/weightWindow.cpp
Removed:
grass/branches/releasebranch_6_4/raster/r.terraflow/ccforest.cc
grass/branches/releasebranch_6_4/raster/r.terraflow/common.cc
grass/branches/releasebranch_6_4/raster/r.terraflow/direction.cc
grass/branches/releasebranch_6_4/raster/r.terraflow/fill.cc
grass/branches/releasebranch_6_4/raster/r.terraflow/filldepr.cc
grass/branches/releasebranch_6_4/raster/r.terraflow/flow.cc
grass/branches/releasebranch_6_4/raster/r.terraflow/genericWindow.cc
grass/branches/releasebranch_6_4/raster/r.terraflow/grid.cc
grass/branches/releasebranch_6_4/raster/r.terraflow/main.cc
grass/branches/releasebranch_6_4/raster/r.terraflow/nodata.cc
grass/branches/releasebranch_6_4/raster/r.terraflow/plateau.cc
grass/branches/releasebranch_6_4/raster/r.terraflow/stats.cc
grass/branches/releasebranch_6_4/raster/r.terraflow/sweep.cc
grass/branches/releasebranch_6_4/raster/r.terraflow/types.cc
grass/branches/releasebranch_6_4/raster/r.terraflow/water.cc
grass/branches/releasebranch_6_4/raster/r.terraflow/weightWindow.cc
Modified:
grass/branches/releasebranch_6_4/raster/r.terraflow/Makefile
Log:
r.terraflow: Use .cpp extension for C++ files
Modified: grass/branches/releasebranch_6_4/raster/r.terraflow/Makefile
===================================================================
--- grass/branches/releasebranch_6_4/raster/r.terraflow/Makefile 2016-07-16 18:01:34 UTC (rev 68988)
+++ grass/branches/releasebranch_6_4/raster/r.terraflow/Makefile 2016-07-16 21:49:07 UTC (rev 68989)
@@ -4,15 +4,15 @@
include $(MODULE_TOPDIR)/include/Make/Multi.make
-SOURCES = main.cc common.cc stats.cc fill.cc types.cc ccforest.cc \
- nodata.cc plateau.cc direction.cc water.cc \
- filldepr.cc grid.cc genericWindow.cc \
- flow.cc sweep.cc weightWindow.cc
+SOURCES = main.cpp common.cpp stats.cpp fill.cpp types.cpp ccforest.cpp \
+ nodata.cpp plateau.cpp direction.cpp water.cpp \
+ filldepr.cpp grid.cpp genericWindow.cpp \
+ flow.cpp sweep.cpp weightWindow.cpp
OBJARCH=OBJ.$(ARCH)
-FLOAT_OBJ := $(patsubst %.cc, $(OBJARCH)/FLOAT/%.o, $(SOURCES))
-SHORT_OBJ := $(patsubst %.cc, $(OBJARCH)/SHORT/%.o, $(SOURCES))
+FLOAT_OBJ := $(patsubst %.cpp, $(OBJARCH)/FLOAT/%.o, $(SOURCES))
+SHORT_OBJ := $(patsubst %.cpp, $(OBJARCH)/SHORT/%.o, $(SOURCES))
CXXFLAGS += -DUSER=\"$(USER)\" \
-DNODATA_FIX -D_FILE_OFFSET_BITS=64
@@ -24,16 +24,16 @@
# header files should be included as prerequisites, but does not work
# because of GRASS scripts
ifneq ($(BROKEN_MAKE),)
-$(OBJARCH)/FLOAT/%.o: %.cc $(LOCAL_HEADERS) $(OBJARCH)/FLOAT
+$(OBJARCH)/FLOAT/%.o: %.cpp $(LOCAL_HEADERS) $(OBJARCH)/FLOAT
else
-$(OBJARCH)/FLOAT/%.o: %.cc $(LOCAL_HEADERS) | $(OBJARCH)/FLOAT
+$(OBJARCH)/FLOAT/%.o: %.cpp $(LOCAL_HEADERS) | $(OBJARCH)/FLOAT
endif
$(CXX) -c $(CXXFLAGS) $(NLS_CFLAGS) -DELEV_FLOAT $< -o $@
ifneq ($(BROKEN_MAKE),)
-$(OBJARCH)/SHORT/%.o: %.cc $(LOCAL_HEADERS) $(OBJARCH)/SHORT
+$(OBJARCH)/SHORT/%.o: %.cpp $(LOCAL_HEADERS) $(OBJARCH)/SHORT
else
-$(OBJARCH)/SHORT/%.o: %.cc $(LOCAL_HEADERS) | $(OBJARCH)/SHORT
+$(OBJARCH)/SHORT/%.o: %.cpp $(LOCAL_HEADERS) | $(OBJARCH)/SHORT
endif
$(CXX) -c $(CXXFLAGS) $(NLS_CFLAGS) -DELEV_SHORT $< -o $@
Deleted: grass/branches/releasebranch_6_4/raster/r.terraflow/ccforest.cc
===================================================================
--- grass/branches/releasebranch_6_4/raster/r.terraflow/ccforest.cc 2016-07-16 18:01:34 UTC (rev 68988)
+++ grass/branches/releasebranch_6_4/raster/r.terraflow/ccforest.cc 2016-07-16 21:49:07 UTC (rev 68989)
@@ -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/branches/releasebranch_6_4/raster/r.terraflow/ccforest.cpp (from rev 68988, grass/branches/releasebranch_6_4/raster/r.terraflow/ccforest.cc)
===================================================================
--- grass/branches/releasebranch_6_4/raster/r.terraflow/ccforest.cpp (rev 0)
+++ grass/branches/releasebranch_6_4/raster/r.terraflow/ccforest.cpp 2016-07-16 21:49:07 UTC (rev 68989)
@@ -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/branches/releasebranch_6_4/raster/r.terraflow/common.cc
===================================================================
--- grass/branches/releasebranch_6_4/raster/r.terraflow/common.cc 2016-07-16 18:01:34 UTC (rev 68988)
+++ grass/branches/releasebranch_6_4/raster/r.terraflow/common.cc 2016-07-16 21:49:07 UTC (rev 68989)
@@ -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/branches/releasebranch_6_4/raster/r.terraflow/common.cpp (from rev 68988, grass/branches/releasebranch_6_4/raster/r.terraflow/common.cc)
===================================================================
--- grass/branches/releasebranch_6_4/raster/r.terraflow/common.cpp (rev 0)
+++ grass/branches/releasebranch_6_4/raster/r.terraflow/common.cpp 2016-07-16 21:49:07 UTC (rev 68989)
@@ -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/branches/releasebranch_6_4/raster/r.terraflow/direction.cc
===================================================================
--- grass/branches/releasebranch_6_4/raster/r.terraflow/direction.cc 2016-07-16 18:01:34 UTC (rev 68988)
+++ grass/branches/releasebranch_6_4/raster/r.terraflow/direction.cc 2016-07-16 21:49:07 UTC (rev 68989)
@@ -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/branches/releasebranch_6_4/raster/r.terraflow/direction.cpp (from rev 68988, grass/branches/releasebranch_6_4/raster/r.terraflow/direction.cc)
===================================================================
--- grass/branches/releasebranch_6_4/raster/r.terraflow/direction.cpp (rev 0)
+++ grass/branches/releasebranch_6_4/raster/r.terraflow/direction.cpp 2016-07-16 21:49:07 UTC (rev 68989)
@@ -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/branches/releasebranch_6_4/raster/r.terraflow/fill.cc
===================================================================
--- grass/branches/releasebranch_6_4/raster/r.terraflow/fill.cc 2016-07-16 18:01:34 UTC (rev 68988)
+++ grass/branches/releasebranch_6_4/raster/r.terraflow/fill.cc 2016-07-16 21:49:07 UTC (rev 68989)
@@ -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/branches/releasebranch_6_4/raster/r.terraflow/fill.cpp (from rev 68988, grass/branches/releasebranch_6_4/raster/r.terraflow/fill.cc)
===================================================================
--- grass/branches/releasebranch_6_4/raster/r.terraflow/fill.cpp (rev 0)
+++ grass/branches/releasebranch_6_4/raster/r.terraflow/fill.cpp 2016-07-16 21:49:07 UTC (rev 68989)
@@ -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/branches/releasebranch_6_4/raster/r.terraflow/filldepr.cc
===================================================================
--- grass/branches/releasebranch_6_4/raster/r.terraflow/filldepr.cc 2016-07-16 18:01:34 UTC (rev 68988)
+++ grass/branches/releasebranch_6_4/raster/r.terraflow/filldepr.cc 2016-07-16 21:49:07 UTC (rev 68989)
@@ -1,258 +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;
- /* no write op to boundaryStr, no need to call stream_len() each time */
- off_t nitems = boundaryStr->stream_len();
- boundaryStr->seek(0);
- for (off_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/branches/releasebranch_6_4/raster/r.terraflow/filldepr.cpp (from rev 68988, grass/branches/releasebranch_6_4/raster/r.terraflow/filldepr.cc)
===================================================================
--- grass/branches/releasebranch_6_4/raster/r.terraflow/filldepr.cpp (rev 0)
+++ grass/branches/releasebranch_6_4/raster/r.terraflow/filldepr.cpp 2016-07-16 21:49:07 UTC (rev 68989)
@@ -0,0 +1,258 @@
+/****************************************************************************
+ *
+ * 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;
+ /* no write op to boundaryStr, no need to call stream_len() each time */
+ off_t nitems = boundaryStr->stream_len();
+ boundaryStr->seek(0);
+ for (off_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/branches/releasebranch_6_4/raster/r.terraflow/flow.cc
===================================================================
--- grass/branches/releasebranch_6_4/raster/r.terraflow/flow.cc 2016-07-16 18:01:34 UTC (rev 68988)
+++ grass/branches/releasebranch_6_4/raster/r.terraflow/flow.cc 2016-07-16 21:49:07 UTC (rev 68989)
@@ -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/branches/releasebranch_6_4/raster/r.terraflow/flow.cpp (from rev 68988, grass/branches/releasebranch_6_4/raster/r.terraflow/flow.cc)
===================================================================
--- grass/branches/releasebranch_6_4/raster/r.terraflow/flow.cpp (rev 0)
+++ grass/branches/releasebranch_6_4/raster/r.terraflow/flow.cpp 2016-07-16 21:49:07 UTC (rev 68989)
@@ -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/branches/releasebranch_6_4/raster/r.terraflow/genericWindow.cc
===================================================================
--- grass/branches/releasebranch_6_4/raster/r.terraflow/genericWindow.cc 2016-07-16 18:01:34 UTC (rev 68988)
+++ grass/branches/releasebranch_6_4/raster/r.terraflow/genericWindow.cc 2016-07-16 21:49:07 UTC (rev 68989)
@@ -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/branches/releasebranch_6_4/raster/r.terraflow/genericWindow.cpp (from rev 68988, grass/branches/releasebranch_6_4/raster/r.terraflow/genericWindow.cc)
===================================================================
--- grass/branches/releasebranch_6_4/raster/r.terraflow/genericWindow.cpp (rev 0)
+++ grass/branches/releasebranch_6_4/raster/r.terraflow/genericWindow.cpp 2016-07-16 21:49:07 UTC (rev 68989)
@@ -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/branches/releasebranch_6_4/raster/r.terraflow/grid.cc
===================================================================
--- grass/branches/releasebranch_6_4/raster/r.terraflow/grid.cc 2016-07-16 18:01:34 UTC (rev 68988)
+++ grass/branches/releasebranch_6_4/raster/r.terraflow/grid.cc 2016-07-16 21:49:07 UTC (rev 68989)
@@ -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/branches/releasebranch_6_4/raster/r.terraflow/grid.cpp (from rev 68988, grass/branches/releasebranch_6_4/raster/r.terraflow/grid.cc)
===================================================================
--- grass/branches/releasebranch_6_4/raster/r.terraflow/grid.cpp (rev 0)
+++ grass/branches/releasebranch_6_4/raster/r.terraflow/grid.cpp 2016-07-16 21:49:07 UTC (rev 68989)
@@ -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/branches/releasebranch_6_4/raster/r.terraflow/main.cc
===================================================================
--- grass/branches/releasebranch_6_4/raster/r.terraflow/main.cc 2016-07-16 18:01:34 UTC (rev 68988)
+++ grass/branches/releasebranch_6_4/raster/r.terraflow/main.cc 2016-07-16 21:49:07 UTC (rev 68989)
@@ -1,630 +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.
- *
- * TODO before GRASS 7 released: change param 'STREAM_DIR' -> 'stream_dir'
- *****************************************************************************/
-
-#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/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;
- streamdir->description=
- _("Directory to hold temporary files (they can be large)");
-
- /* verbose flag */
- /* please, remove before GRASS 7 released */
- struct Flag *quiet;
- quiet = G_define_flag() ;
- quiet->key = 'q' ;
- quiet->description = _("Quiet");
-
- /* 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);
- if (!streamdir->answer) {
- const char *tmpdir = G_tempfile();
-
- if (G_mkdir(tmpdir) == -1)
- G_fatal_error(_("Unable to create temp dir"));
- opt->streamdir = G_store(tmpdir);
- }
- else
- opt->streamdir = streamdir->answer;
-
- opt->verbose = FALSE;
-
-/* please, remove before GRASS 7 released */
- if(quiet->answer) {
- G_warning(_("The '-q' flag is superseded and will be removed "
- "in future. Please use '--quiet' instead."));
- G_putenv("GRASS_VERBOSE","0");
- opt->verbose = FALSE;
- }
- else {
- if(G_verbose() == G_verbose_max())
- opt->verbose = TRUE;
- }
-
-
- opt->stats = stats_opt->answer;
-
- /* somebody should delete the options */
-}
-
-
-/* ---------------------------------------------------------------------- */
-/* check compatibility of map header and region header */
-void check_header(char* cellname) {
-
- char *mapset;
- mapset = G_find_cell(cellname, "");
- if (mapset == NULL) {
- G_fatal_error(_("Raster map <%s> not found"), cellname);
- }
- /* read cell header */
- struct Cell_head cell_hd;
- if (G_get_cellhd (cellname, mapset, &cell_hd) < 0)
- G_fatal_error(_("Cannot read header of [%s]"), cellname);
-
- /* 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 = G_raster_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;
- char *mapset;
- struct Range r;
-
- mapset = G_find_cell(cellname, "");
- if (mapset == NULL) {
- G_fatal_error (_("Raster map <%s> not found"), cellname);
- }
- if (G_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;
-
-
- G_init_colors(&colors);
-
- G_add_color_rule(v[0], 255,255,255, v[1], 255,255,0, &colors);
- G_add_color_rule(v[1], 255,255,0, v[2], 0,255,255, &colors);
- G_add_color_rule(v[2], 0,255,255, v[3], 0,127,255, &colors);
- G_add_color_rule(v[3], 0,127,255, v[4], 0,0,255, &colors);
- G_add_color_rule(v[4], 0,0,255, (CELL)v[5], 0,0,0, &colors);
-
-
- if (G_write_colors(cellname, mapset, &colors) == -1) {
- G_fatal_error(_("cannot write colors"));
- }
- G_free_colors(&colors);
-}
-
-
-/* ---------------------------------------------------------------------- */
-void
-setSinkWatershedColorTable(char* cellname) {
- struct Colors colors;
- char *mapset;
- struct Range r;
-
- mapset = G_find_cell(cellname, "");
- if (mapset == NULL) {
- G_fatal_error (_("Raster map <%s> not found"), cellname);
- }
- if (G_read_range(cellname, mapset, &r) == -1) {
- G_fatal_error(_("cannot read range"));
- }
-
- G_init_colors(&colors);
- G_make_random_colors(&colors, 1, r.max);
-
- if (G_write_colors(cellname, mapset, &colors) == -1) {
- G_fatal_error(_("cannot write colors"));
- }
- G_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
- module->keywords = _("raster, 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 */
- if (G_get_set_window(region) == -1) {
- G_fatal_error("r.terraflow: error getting current region");
- }
- check_args();
-
- int nr = G_window_rows();
- int nc = G_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/branches/releasebranch_6_4/raster/r.terraflow/main.cpp (from rev 68988, grass/branches/releasebranch_6_4/raster/r.terraflow/main.cc)
===================================================================
--- grass/branches/releasebranch_6_4/raster/r.terraflow/main.cpp (rev 0)
+++ grass/branches/releasebranch_6_4/raster/r.terraflow/main.cpp 2016-07-16 21:49:07 UTC (rev 68989)
@@ -0,0 +1,630 @@
+/****************************************************************************
+ *
+ * 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.
+ *
+ * TODO before GRASS 7 released: change param 'STREAM_DIR' -> 'stream_dir'
+ *****************************************************************************/
+
+#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/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;
+ streamdir->description=
+ _("Directory to hold temporary files (they can be large)");
+
+ /* verbose flag */
+ /* please, remove before GRASS 7 released */
+ struct Flag *quiet;
+ quiet = G_define_flag() ;
+ quiet->key = 'q' ;
+ quiet->description = _("Quiet");
+
+ /* 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);
+ if (!streamdir->answer) {
+ const char *tmpdir = G_tempfile();
+
+ if (G_mkdir(tmpdir) == -1)
+ G_fatal_error(_("Unable to create temp dir"));
+ opt->streamdir = G_store(tmpdir);
+ }
+ else
+ opt->streamdir = streamdir->answer;
+
+ opt->verbose = FALSE;
+
+/* please, remove before GRASS 7 released */
+ if(quiet->answer) {
+ G_warning(_("The '-q' flag is superseded and will be removed "
+ "in future. Please use '--quiet' instead."));
+ G_putenv("GRASS_VERBOSE","0");
+ opt->verbose = FALSE;
+ }
+ else {
+ if(G_verbose() == G_verbose_max())
+ opt->verbose = TRUE;
+ }
+
+
+ opt->stats = stats_opt->answer;
+
+ /* somebody should delete the options */
+}
+
+
+/* ---------------------------------------------------------------------- */
+/* check compatibility of map header and region header */
+void check_header(char* cellname) {
+
+ char *mapset;
+ mapset = G_find_cell(cellname, "");
+ if (mapset == NULL) {
+ G_fatal_error(_("Raster map <%s> not found"), cellname);
+ }
+ /* read cell header */
+ struct Cell_head cell_hd;
+ if (G_get_cellhd (cellname, mapset, &cell_hd) < 0)
+ G_fatal_error(_("Cannot read header of [%s]"), cellname);
+
+ /* 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 = G_raster_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;
+ char *mapset;
+ struct Range r;
+
+ mapset = G_find_cell(cellname, "");
+ if (mapset == NULL) {
+ G_fatal_error (_("Raster map <%s> not found"), cellname);
+ }
+ if (G_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;
+
+
+ G_init_colors(&colors);
+
+ G_add_color_rule(v[0], 255,255,255, v[1], 255,255,0, &colors);
+ G_add_color_rule(v[1], 255,255,0, v[2], 0,255,255, &colors);
+ G_add_color_rule(v[2], 0,255,255, v[3], 0,127,255, &colors);
+ G_add_color_rule(v[3], 0,127,255, v[4], 0,0,255, &colors);
+ G_add_color_rule(v[4], 0,0,255, (CELL)v[5], 0,0,0, &colors);
+
+
+ if (G_write_colors(cellname, mapset, &colors) == -1) {
+ G_fatal_error(_("cannot write colors"));
+ }
+ G_free_colors(&colors);
+}
+
+
+/* ---------------------------------------------------------------------- */
+void
+setSinkWatershedColorTable(char* cellname) {
+ struct Colors colors;
+ char *mapset;
+ struct Range r;
+
+ mapset = G_find_cell(cellname, "");
+ if (mapset == NULL) {
+ G_fatal_error (_("Raster map <%s> not found"), cellname);
+ }
+ if (G_read_range(cellname, mapset, &r) == -1) {
+ G_fatal_error(_("cannot read range"));
+ }
+
+ G_init_colors(&colors);
+ G_make_random_colors(&colors, 1, r.max);
+
+ if (G_write_colors(cellname, mapset, &colors) == -1) {
+ G_fatal_error(_("cannot write colors"));
+ }
+ G_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
+ module->keywords = _("raster, 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 */
+ if (G_get_set_window(region) == -1) {
+ G_fatal_error("r.terraflow: error getting current region");
+ }
+ check_args();
+
+ int nr = G_window_rows();
+ int nc = G_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/branches/releasebranch_6_4/raster/r.terraflow/nodata.cc
===================================================================
--- grass/branches/releasebranch_6_4/raster/r.terraflow/nodata.cc 2016-07-16 18:01:34 UTC (rev 68988)
+++ grass/branches/releasebranch_6_4/raster/r.terraflow/nodata.cc 2016-07-16 21:49:07 UTC (rev 68989)
@@ -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/branches/releasebranch_6_4/raster/r.terraflow/nodata.cpp (from rev 68988, grass/branches/releasebranch_6_4/raster/r.terraflow/nodata.cc)
===================================================================
--- grass/branches/releasebranch_6_4/raster/r.terraflow/nodata.cpp (rev 0)
+++ grass/branches/releasebranch_6_4/raster/r.terraflow/nodata.cpp 2016-07-16 21:49:07 UTC (rev 68989)
@@ -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/branches/releasebranch_6_4/raster/r.terraflow/plateau.cc
===================================================================
--- grass/branches/releasebranch_6_4/raster/r.terraflow/plateau.cc 2016-07-16 18:01:34 UTC (rev 68988)
+++ grass/branches/releasebranch_6_4/raster/r.terraflow/plateau.cc 2016-07-16 21:49:07 UTC (rev 68989)
@@ -1,469 +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/branches/releasebranch_6_4/raster/r.terraflow/plateau.cpp (from rev 68988, grass/branches/releasebranch_6_4/raster/r.terraflow/plateau.cc)
===================================================================
--- grass/branches/releasebranch_6_4/raster/r.terraflow/plateau.cpp (rev 0)
+++ grass/branches/releasebranch_6_4/raster/r.terraflow/plateau.cpp 2016-07-16 21:49:07 UTC (rev 68989)
@@ -0,0 +1,469 @@
+/****************************************************************************
+ *
+ * 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/branches/releasebranch_6_4/raster/r.terraflow/stats.cc
===================================================================
--- grass/branches/releasebranch_6_4/raster/r.terraflow/stats.cc 2016-07-16 18:01:34 UTC (rev 68988)
+++ grass/branches/releasebranch_6_4/raster/r.terraflow/stats.cc 2016-07-16 21:49:07 UTC (rev 68989)
@@ -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/branches/releasebranch_6_4/raster/r.terraflow/stats.cpp (from rev 68988, grass/branches/releasebranch_6_4/raster/r.terraflow/stats.cc)
===================================================================
--- grass/branches/releasebranch_6_4/raster/r.terraflow/stats.cpp (rev 0)
+++ grass/branches/releasebranch_6_4/raster/r.terraflow/stats.cpp 2016-07-16 21:49:07 UTC (rev 68989)
@@ -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/branches/releasebranch_6_4/raster/r.terraflow/sweep.cc
===================================================================
--- grass/branches/releasebranch_6_4/raster/r.terraflow/sweep.cc 2016-07-16 18:01:34 UTC (rev 68988)
+++ grass/branches/releasebranch_6_4/raster/r.terraflow/sweep.cc 2016-07-16 21:49:07 UTC (rev 68989)
@@ -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/branches/releasebranch_6_4/raster/r.terraflow/sweep.cpp (from rev 68988, grass/branches/releasebranch_6_4/raster/r.terraflow/sweep.cc)
===================================================================
--- grass/branches/releasebranch_6_4/raster/r.terraflow/sweep.cpp (rev 0)
+++ grass/branches/releasebranch_6_4/raster/r.terraflow/sweep.cpp 2016-07-16 21:49:07 UTC (rev 68989)
@@ -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/branches/releasebranch_6_4/raster/r.terraflow/types.cc
===================================================================
--- grass/branches/releasebranch_6_4/raster/r.terraflow/types.cc 2016-07-16 18:01:34 UTC (rev 68988)
+++ grass/branches/releasebranch_6_4/raster/r.terraflow/types.cc 2016-07-16 21:49:07 UTC (rev 68989)
@@ -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/branches/releasebranch_6_4/raster/r.terraflow/types.cpp (from rev 68988, grass/branches/releasebranch_6_4/raster/r.terraflow/types.cc)
===================================================================
--- grass/branches/releasebranch_6_4/raster/r.terraflow/types.cpp (rev 0)
+++ grass/branches/releasebranch_6_4/raster/r.terraflow/types.cpp 2016-07-16 21:49:07 UTC (rev 68989)
@@ -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/branches/releasebranch_6_4/raster/r.terraflow/water.cc
===================================================================
--- grass/branches/releasebranch_6_4/raster/r.terraflow/water.cc 2016-07-16 18:01:34 UTC (rev 68988)
+++ grass/branches/releasebranch_6_4/raster/r.terraflow/water.cc 2016-07-16 21:49:07 UTC (rev 68989)
@@ -1,587 +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/branches/releasebranch_6_4/raster/r.terraflow/water.cpp (from rev 68988, grass/branches/releasebranch_6_4/raster/r.terraflow/water.cc)
===================================================================
--- grass/branches/releasebranch_6_4/raster/r.terraflow/water.cpp (rev 0)
+++ grass/branches/releasebranch_6_4/raster/r.terraflow/water.cpp 2016-07-16 21:49:07 UTC (rev 68989)
@@ -0,0 +1,587 @@
+/****************************************************************************
+ *
+ * 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/branches/releasebranch_6_4/raster/r.terraflow/weightWindow.cc
===================================================================
--- grass/branches/releasebranch_6_4/raster/r.terraflow/weightWindow.cc 2016-07-16 18:01:34 UTC (rev 68988)
+++ grass/branches/releasebranch_6_4/raster/r.terraflow/weightWindow.cc 2016-07-16 21:49:07 UTC (rev 68989)
@@ -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/branches/releasebranch_6_4/raster/r.terraflow/weightWindow.cpp (from rev 68988, grass/branches/releasebranch_6_4/raster/r.terraflow/weightWindow.cc)
===================================================================
--- grass/branches/releasebranch_6_4/raster/r.terraflow/weightWindow.cpp (rev 0)
+++ grass/branches/releasebranch_6_4/raster/r.terraflow/weightWindow.cpp 2016-07-16 21:49:07 UTC (rev 68989)
@@ -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;
+}
+
More information about the grass-commit
mailing list