[GRASS-SVN] r53410 - in grass-addons/grass7: . grass7 grass7/raster grass7/raster/r.agent grass7/raster/r.agent/libagent grass7/raster/r.agent/libold grass7/raster/r.area grass7/raster/r.clump2 grass7/raster/r.convergence grass7/raster/r.convert grass7/raster/r.fuzzy grass7/raster/r.fuzzy/r.fuzzy.logic grass7/raster/r.fuzzy/r.fuzzy.set grass7/raster/r.fuzzy/r.fuzzy.system grass7/raster/r.gdd grass7/raster/r.houghtransform grass7/raster/r.hydrodem grass7/raster/r.in.srtm.region grass7/raster/r.in.wms2 grass7/raster/r.massmov grass7/raster/r.mess grass7/raster/r.modis grass7/raster/r.modis/libmodis grass7/raster/r.modis/r.modis.download grass7/raster/r.modis/r.modis.import grass7/raster/r.regression.multi grass7/raster/r.regression.series grass7/raster/r.stream.basins grass7/raster/r.stream.channel grass7/raster/r.stream.distance grass7/raster/r.stream.extract grass7/raster/r.stream.order grass7/raster/r.stream.segment grass7/raster/r.stream.slope grass7/raster/r.stream.snap grass 7/raster/r.stream.stats grass7/raster/r.sun.angle grass7/raster/r.threshold grass7/raster/r.vol.dem

svn_grass at osgeo.org svn_grass at osgeo.org
Mon Oct 15 11:25:44 PDT 2012


Author: pvanbosgeo
Date: 2012-10-15 11:25:43 -0700 (Mon, 15 Oct 2012)
New Revision: 53410

Added:
   grass-addons/grass7/grass7.txt
   grass-addons/grass7/grass7/
   grass-addons/grass7/grass7/raster.txt
   grass-addons/grass7/grass7/raster/
   grass-addons/grass7/grass7/raster/Makefile
   grass-addons/grass7/grass7/raster/r.agent/
   grass-addons/grass7/grass7/raster/r.agent/libagent/
   grass-addons/grass7/grass7/raster/r.agent/libagent/__init__.py
   grass-addons/grass7/grass7/raster/r.agent/libagent/aco.py
   grass-addons/grass7/grass7/raster/r.agent/libagent/agent.py
   grass-addons/grass7/grass7/raster/r.agent/libagent/ant.py
   grass-addons/grass7/grass7/raster/r.agent/libagent/error.py
   grass-addons/grass7/grass7/raster/r.agent/libagent/playground.py
   grass-addons/grass7/grass7/raster/r.agent/libagent/world.py
   grass-addons/grass7/grass7/raster/r.agent/libold/
   grass-addons/grass7/grass7/raster/r.agent/libold/__init__.py
   grass-addons/grass7/grass7/raster/r.agent/libold/aco.py
   grass-addons/grass7/grass7/raster/r.agent/libold/agent.py
   grass-addons/grass7/grass7/raster/r.agent/libold/alltests.py
   grass-addons/grass7/grass7/raster/r.agent/libold/ant.py
   grass-addons/grass7/grass7/raster/r.agent/libold/error.py
   grass-addons/grass7/grass7/raster/r.agent/libold/layer.py
   grass-addons/grass7/grass7/raster/r.agent/libold/overview.html
   grass-addons/grass7/grass7/raster/r.agent/libold/playground.py
   grass-addons/grass7/grass7/raster/r.agent/libold/rasterlayer.py
   grass-addons/grass7/grass7/raster/r.agent/libold/vectorlayer.py
   grass-addons/grass7/grass7/raster/r.agent/libold/world.py
   grass-addons/grass7/grass7/raster/r.agent/r.agent.aco
   grass-addons/grass7/grass7/raster/r.agent/r.agent.html
   grass-addons/grass7/grass7/raster/r.agent/r.agent.tests.py
   grass-addons/grass7/grass7/raster/r.area/
   grass-addons/grass7/grass7/raster/r.area/Makefile
   grass-addons/grass7/grass7/raster/r.area/main.c
   grass-addons/grass7/grass7/raster/r.area/r.area.html
   grass-addons/grass7/grass7/raster/r.clump2/
   grass-addons/grass7/grass7/raster/r.clump2/Makefile
   grass-addons/grass7/grass7/raster/r.clump2/flag.c
   grass-addons/grass7/grass7/raster/r.clump2/flag.h
   grass-addons/grass7/grass7/raster/r.clump2/local_proto.h
   grass-addons/grass7/grass7/raster/r.clump2/main.c
   grass-addons/grass7/grass7/raster/r.clump2/pq.c
   grass-addons/grass7/grass7/raster/r.clump2/r.clump2.html
   grass-addons/grass7/grass7/raster/r.clump2/ramseg.c
   grass-addons/grass7/grass7/raster/r.clump2/ramseg.h
   grass-addons/grass7/grass7/raster/r.convergence/
   grass-addons/grass7/grass7/raster/r.convergence/Makefile
   grass-addons/grass7/grass7/raster/r.convergence/conv.png
   grass-addons/grass7/grass7/raster/r.convergence/local_proto.h
   grass-addons/grass7/grass7/raster/r.convergence/main.c
   grass-addons/grass7/grass7/raster/r.convergence/memory.c
   grass-addons/grass7/grass7/raster/r.convergence/r.convergence.html
   grass-addons/grass7/grass7/raster/r.convergence/slope_aspect.c
   grass-addons/grass7/grass7/raster/r.convert/
   grass-addons/grass7/grass7/raster/r.convert/r.convert
   grass-addons/grass7/grass7/raster/r.convert/r.convert.all
   grass-addons/grass7/grass7/raster/r.fuzzy/
   grass-addons/grass7/grass7/raster/r.fuzzy/Makefile
   grass-addons/grass7/grass7/raster/r.fuzzy/r.fuzzy.logic/
   grass-addons/grass7/grass7/raster/r.fuzzy/r.fuzzy.logic/Makefile
   grass-addons/grass7/grass7/raster/r.fuzzy/r.fuzzy.logic/local_proto.h
   grass-addons/grass7/grass7/raster/r.fuzzy/r.fuzzy.logic/logic.c
   grass-addons/grass7/grass7/raster/r.fuzzy/r.fuzzy.logic/main.c
   grass-addons/grass7/grass7/raster/r.fuzzy/r.fuzzy.logic/r.fuzzy.logic.html
   grass-addons/grass7/grass7/raster/r.fuzzy/r.fuzzy.set/
   grass-addons/grass7/grass7/raster/r.fuzzy/r.fuzzy.set/Makefile
   grass-addons/grass7/grass7/raster/r.fuzzy/r.fuzzy.set/boundary.png
   grass-addons/grass7/grass7/raster/r.fuzzy/r.fuzzy.set/fuzzy.c
   grass-addons/grass7/grass7/raster/r.fuzzy/r.fuzzy.set/local_proto.h
   grass-addons/grass7/grass7/raster/r.fuzzy/r.fuzzy.set/main.c
   grass-addons/grass7/grass7/raster/r.fuzzy/r.fuzzy.set/r.fuzzy.set.html
   grass-addons/grass7/grass7/raster/r.fuzzy/r.fuzzy.set/set.png
   grass-addons/grass7/grass7/raster/r.fuzzy/r.fuzzy.set/shape.png
   grass-addons/grass7/grass7/raster/r.fuzzy/r.fuzzy.system/
   grass-addons/grass7/grass7/raster/r.fuzzy/r.fuzzy.system/Makefile
   grass-addons/grass7/grass7/raster/r.fuzzy/r.fuzzy.system/f_result.png
   grass-addons/grass7/grass7/raster/r.fuzzy/r.fuzzy.system/flood.map
   grass-addons/grass7/grass7/raster/r.fuzzy/r.fuzzy.system/flood.rul
   grass-addons/grass7/grass7/raster/r.fuzzy/r.fuzzy.system/fuzzylogic.c
   grass-addons/grass7/grass7/raster/r.fuzzy/r.fuzzy.system/helpers.c
   grass-addons/grass7/grass7/raster/r.fuzzy/r.fuzzy.system/io.c
   grass-addons/grass7/grass7/raster/r.fuzzy/r.fuzzy.system/local_proto.h
   grass-addons/grass7/grass7/raster/r.fuzzy/r.fuzzy.system/main.c
   grass-addons/grass7/grass7/raster/r.fuzzy/r.fuzzy.system/map_parser.c
   grass-addons/grass7/grass7/raster/r.fuzzy/r.fuzzy.system/r.fuzzy.system.html
   grass-addons/grass7/grass7/raster/r.fuzzy/r.fuzzy.system/rule_parser.c
   grass-addons/grass7/grass7/raster/r.fuzzy/r.fuzzy.system/system.c
   grass-addons/grass7/grass7/raster/r.gdd/
   grass-addons/grass7/grass7/raster/r.gdd/Makefile
   grass-addons/grass7/grass7/raster/r.gdd/main.c
   grass-addons/grass7/grass7/raster/r.gdd/r.gdd.html
   grass-addons/grass7/grass7/raster/r.houghtransform/
   grass-addons/grass7/grass7/raster/r.houghtransform/Makefile
   grass-addons/grass7/grass7/raster/r.houghtransform/hough.cpp
   grass-addons/grass7/grass7/raster/r.houghtransform/hough.h
   grass-addons/grass7/grass7/raster/r.houghtransform/houghparameters.h
   grass-addons/grass7/grass7/raster/r.houghtransform/houghtransform.cpp
   grass-addons/grass7/grass7/raster/r.houghtransform/houghtransform.h
   grass-addons/grass7/grass7/raster/r.houghtransform/linesegmentsextractor.cpp
   grass-addons/grass7/grass7/raster/r.houghtransform/linesegmentsextractor.h
   grass-addons/grass7/grass7/raster/r.houghtransform/main.cpp
   grass-addons/grass7/grass7/raster/r.houghtransform/matrix.h
   grass-addons/grass7/grass7/raster/r.houghtransform/r.houghtransform.html
   grass-addons/grass7/grass7/raster/r.hydrodem/
   grass-addons/grass7/grass7/raster/r.hydrodem/Makefile
   grass-addons/grass7/grass7/raster/r.hydrodem/bseg.c
   grass-addons/grass7/grass7/raster/r.hydrodem/close.c
   grass-addons/grass7/grass7/raster/r.hydrodem/cseg.c
   grass-addons/grass7/grass7/raster/r.hydrodem/do_astar.c
   grass-addons/grass7/grass7/raster/r.hydrodem/dseg.c
   grass-addons/grass7/grass7/raster/r.hydrodem/flag.h
   grass-addons/grass7/grass7/raster/r.hydrodem/hydro_con.c
   grass-addons/grass7/grass7/raster/r.hydrodem/init_search.c
   grass-addons/grass7/grass7/raster/r.hydrodem/load.c
   grass-addons/grass7/grass7/raster/r.hydrodem/local_proto.h
   grass-addons/grass7/grass7/raster/r.hydrodem/main.c
   grass-addons/grass7/grass7/raster/r.hydrodem/r.hydrodem.html
   grass-addons/grass7/grass7/raster/r.hydrodem/seg.c
   grass-addons/grass7/grass7/raster/r.hydrodem/seg.h
   grass-addons/grass7/grass7/raster/r.in.srtm.region/
   grass-addons/grass7/grass7/raster/r.in.srtm.region/Makefile
   grass-addons/grass7/grass7/raster/r.in.srtm.region/r.in.srtm.region.html
   grass-addons/grass7/grass7/raster/r.in.srtm.region/r.in.srtm.region.py
   grass-addons/grass7/grass7/raster/r.in.wms2/
   grass-addons/grass7/grass7/raster/r.in.wms2/Makefile
   grass-addons/grass7/grass7/raster/r.in.wms2/r.in.wms2.html
   grass-addons/grass7/grass7/raster/r.in.wms2/r.in.wms2.py
   grass-addons/grass7/grass7/raster/r.in.wms2/wms_base.py
   grass-addons/grass7/grass7/raster/r.in.wms2/wms_drv.py
   grass-addons/grass7/grass7/raster/r.in.wms2/wms_gdal_drv.py
   grass-addons/grass7/grass7/raster/r.massmov/
   grass-addons/grass7/grass7/raster/r.massmov/Makefile
   grass-addons/grass7/grass7/raster/r.massmov/filters.c
   grass-addons/grass7/grass7/raster/r.massmov/filters.h
   grass-addons/grass7/grass7/raster/r.massmov/general_f.c
   grass-addons/grass7/grass7/raster/r.massmov/general_f.h
   grass-addons/grass7/grass7/raster/r.massmov/main.c
   grass-addons/grass7/grass7/raster/r.massmov/r.massmov.html
   grass-addons/grass7/grass7/raster/r.mess/
   grass-addons/grass7/grass7/raster/r.mess/Makefile
   grass-addons/grass7/grass7/raster/r.mess/r.mess
   grass-addons/grass7/grass7/raster/r.mess/r.mess.html
   grass-addons/grass7/grass7/raster/r.modis/
   grass-addons/grass7/grass7/raster/r.modis/Makefile
   grass-addons/grass7/grass7/raster/r.modis/libmodis/
   grass-addons/grass7/grass7/raster/r.modis/libmodis/Makefile
   grass-addons/grass7/grass7/raster/r.modis/libmodis/convertmodis.py
   grass-addons/grass7/grass7/raster/r.modis/libmodis/downmodis.py
   grass-addons/grass7/grass7/raster/r.modis/libmodis/parsemodis.py
   grass-addons/grass7/grass7/raster/r.modis/libmodis/rmodislib.py
   grass-addons/grass7/grass7/raster/r.modis/r.modis.download/
   grass-addons/grass7/grass7/raster/r.modis/r.modis.download/Makefile
   grass-addons/grass7/grass7/raster/r.modis/r.modis.download/r.modis.download.html
   grass-addons/grass7/grass7/raster/r.modis/r.modis.download/r.modis.download.py
   grass-addons/grass7/grass7/raster/r.modis/r.modis.html
   grass-addons/grass7/grass7/raster/r.modis/r.modis.import/
   grass-addons/grass7/grass7/raster/r.modis/r.modis.import/Makefile
   grass-addons/grass7/grass7/raster/r.modis/r.modis.import/r.modis.import.html
   grass-addons/grass7/grass7/raster/r.modis/r.modis.import/r.modis.import.py
   grass-addons/grass7/grass7/raster/r.regression.multi/
   grass-addons/grass7/grass7/raster/r.regression.multi/Makefile
   grass-addons/grass7/grass7/raster/r.regression.multi/main.c
   grass-addons/grass7/grass7/raster/r.regression.multi/r.regression.multi.html
   grass-addons/grass7/grass7/raster/r.regression.series/
   grass-addons/grass7/grass7/raster/r.regression.series/Makefile
   grass-addons/grass7/grass7/raster/r.regression.series/main.c
   grass-addons/grass7/grass7/raster/r.regression.series/r.regression.series.html
   grass-addons/grass7/grass7/raster/r.stream.basins/
   grass-addons/grass7/grass7/raster/r.stream.basins/Makefile
   grass-addons/grass7/grass7/raster/r.stream.basins/basins_fill.c
   grass-addons/grass7/grass7/raster/r.stream.basins/basins_inputs.c
   grass-addons/grass7/grass7/raster/r.stream.basins/io.c
   grass-addons/grass7/grass7/raster/r.stream.basins/io.h
   grass-addons/grass7/grass7/raster/r.stream.basins/local_proto.h
   grass-addons/grass7/grass7/raster/r.stream.basins/local_vars.h
   grass-addons/grass7/grass7/raster/r.stream.basins/main.c
   grass-addons/grass7/grass7/raster/r.stream.basins/r.stream.basins.html
   grass-addons/grass7/grass7/raster/r.stream.channel/
   grass-addons/grass7/grass7/raster/r.stream.channel/Makefile
   grass-addons/grass7/grass7/raster/r.stream.channel/io.c
   grass-addons/grass7/grass7/raster/r.stream.channel/io.h
   grass-addons/grass7/grass7/raster/r.stream.channel/local_proto.h
   grass-addons/grass7/grass7/raster/r.stream.channel/local_vars.h
   grass-addons/grass7/grass7/raster/r.stream.channel/main.c
   grass-addons/grass7/grass7/raster/r.stream.channel/r.stream.channel.html
   grass-addons/grass7/grass7/raster/r.stream.channel/stream_topology.c
   grass-addons/grass7/grass7/raster/r.stream.channel/stream_write.c
   grass-addons/grass7/grass7/raster/r.stream.distance/
   grass-addons/grass7/grass7/raster/r.stream.distance/Makefile
   grass-addons/grass7/grass7/raster/r.stream.distance/distance_calc.c
   grass-addons/grass7/grass7/raster/r.stream.distance/distance_init.c
   grass-addons/grass7/grass7/raster/r.stream.distance/io.c
   grass-addons/grass7/grass7/raster/r.stream.distance/io.h
   grass-addons/grass7/grass7/raster/r.stream.distance/local_proto.h
   grass-addons/grass7/grass7/raster/r.stream.distance/local_vars.h
   grass-addons/grass7/grass7/raster/r.stream.distance/main.c
   grass-addons/grass7/grass7/raster/r.stream.distance/r.stream.distance.html
   grass-addons/grass7/grass7/raster/r.stream.extract/
   grass-addons/grass7/grass7/raster/r.stream.extract/Makefile
   grass-addons/grass7/grass7/raster/r.stream.extract/bseg.c
   grass-addons/grass7/grass7/raster/r.stream.extract/close.c
   grass-addons/grass7/grass7/raster/r.stream.extract/cseg.c
   grass-addons/grass7/grass7/raster/r.stream.extract/del_streams.c
   grass-addons/grass7/grass7/raster/r.stream.extract/do_astar.c
   grass-addons/grass7/grass7/raster/r.stream.extract/dseg.c
   grass-addons/grass7/grass7/raster/r.stream.extract/flag.h
   grass-addons/grass7/grass7/raster/r.stream.extract/init_search.c
   grass-addons/grass7/grass7/raster/r.stream.extract/load.c
   grass-addons/grass7/grass7/raster/r.stream.extract/local_proto.h
   grass-addons/grass7/grass7/raster/r.stream.extract/main.c
   grass-addons/grass7/grass7/raster/r.stream.extract/r.stream.extract.html
   grass-addons/grass7/grass7/raster/r.stream.extract/seg.c
   grass-addons/grass7/grass7/raster/r.stream.extract/seg.h
   grass-addons/grass7/grass7/raster/r.stream.extract/streams.c
   grass-addons/grass7/grass7/raster/r.stream.extract/thin.c
   grass-addons/grass7/grass7/raster/r.stream.order/
   grass-addons/grass7/grass7/raster/r.stream.order/Makefile
   grass-addons/grass7/grass7/raster/r.stream.order/io.c
   grass-addons/grass7/grass7/raster/r.stream.order/io.h
   grass-addons/grass7/grass7/raster/r.stream.order/local_proto.h
   grass-addons/grass7/grass7/raster/r.stream.order/local_vars.h
   grass-addons/grass7/grass7/raster/r.stream.order/main.c
   grass-addons/grass7/grass7/raster/r.stream.order/orders.png
   grass-addons/grass7/grass7/raster/r.stream.order/r.stream.order.html
   grass-addons/grass7/grass7/raster/r.stream.order/stream_init.c
   grass-addons/grass7/grass7/raster/r.stream.order/stream_order.c
   grass-addons/grass7/grass7/raster/r.stream.order/stream_raster_close.c
   grass-addons/grass7/grass7/raster/r.stream.order/stream_topology.c
   grass-addons/grass7/grass7/raster/r.stream.order/stream_vector.c
   grass-addons/grass7/grass7/raster/r.stream.segment/
   grass-addons/grass7/grass7/raster/r.stream.segment/Makefile
   grass-addons/grass7/grass7/raster/r.stream.segment/dirs.png
   grass-addons/grass7/grass7/raster/r.stream.segment/io.c
   grass-addons/grass7/grass7/raster/r.stream.segment/io.h
   grass-addons/grass7/grass7/raster/r.stream.segment/local_proto.h
   grass-addons/grass7/grass7/raster/r.stream.segment/local_vars.h
   grass-addons/grass7/grass7/raster/r.stream.segment/main.c
   grass-addons/grass7/grass7/raster/r.stream.segment/r.stream.segment.html
   grass-addons/grass7/grass7/raster/r.stream.segment/sectors.png
   grass-addons/grass7/grass7/raster/r.stream.segment/stream_segment.c
   grass-addons/grass7/grass7/raster/r.stream.segment/stream_topology.c
   grass-addons/grass7/grass7/raster/r.stream.segment/stream_vector.c
   grass-addons/grass7/grass7/raster/r.stream.slope/
   grass-addons/grass7/grass7/raster/r.stream.slope/Makefile
   grass-addons/grass7/grass7/raster/r.stream.slope/main.c
   grass-addons/grass7/grass7/raster/r.stream.slope/r.stream.slope.html
   grass-addons/grass7/grass7/raster/r.stream.snap/
   grass-addons/grass7/grass7/raster/r.stream.snap/Makefile
   grass-addons/grass7/grass7/raster/r.stream.snap/io.c
   grass-addons/grass7/grass7/raster/r.stream.snap/io.h
   grass-addons/grass7/grass7/raster/r.stream.snap/local_proto.h
   grass-addons/grass7/grass7/raster/r.stream.snap/local_vars.h
   grass-addons/grass7/grass7/raster/r.stream.snap/main.c
   grass-addons/grass7/grass7/raster/r.stream.snap/points_io.c
   grass-addons/grass7/grass7/raster/r.stream.snap/r.stream.snap.html
   grass-addons/grass7/grass7/raster/r.stream.snap/snap.c
   grass-addons/grass7/grass7/raster/r.stream.stats/
   grass-addons/grass7/grass7/raster/r.stream.stats/Makefile
   grass-addons/grass7/grass7/raster/r.stream.stats/io.c
   grass-addons/grass7/grass7/raster/r.stream.stats/io.h
   grass-addons/grass7/grass7/raster/r.stream.stats/local_proto.h
   grass-addons/grass7/grass7/raster/r.stream.stats/local_vars.h
   grass-addons/grass7/grass7/raster/r.stream.stats/main.c
   grass-addons/grass7/grass7/raster/r.stream.stats/r.stream.stats.html
   grass-addons/grass7/grass7/raster/r.stream.stats/stats_calculate.c
   grass-addons/grass7/grass7/raster/r.stream.stats/stats_prepare.c
   grass-addons/grass7/grass7/raster/r.stream.stats/stats_print.c
   grass-addons/grass7/grass7/raster/r.sun.angle/
   grass-addons/grass7/grass7/raster/r.sun.angle/Makefile
   grass-addons/grass7/grass7/raster/r.sun.angle/main.c
   grass-addons/grass7/grass7/raster/r.sun.angle/r.sun.angle.html
   grass-addons/grass7/grass7/raster/r.sun.angle/solpos00.c
   grass-addons/grass7/grass7/raster/r.sun.angle/solpos00.h
   grass-addons/grass7/grass7/raster/r.threshold/
   grass-addons/grass7/grass7/raster/r.threshold/Makefile
   grass-addons/grass7/grass7/raster/r.threshold/r.threshold.html
   grass-addons/grass7/grass7/raster/r.threshold/r.threshold.py
   grass-addons/grass7/grass7/raster/r.vol.dem/
   grass-addons/grass7/grass7/raster/r.vol.dem/Makefile
   grass-addons/grass7/grass7/raster/r.vol.dem/chull.c
   grass-addons/grass7/grass7/raster/r.vol.dem/chull.h
   grass-addons/grass7/grass7/raster/r.vol.dem/globals.h
   grass-addons/grass7/grass7/raster/r.vol.dem/macros.h
   grass-addons/grass7/grass7/raster/r.vol.dem/main.c
   grass-addons/grass7/grass7/raster/r.vol.dem/r.vol.dem.html
   grass-addons/grass7/grass7/raster/r.vol.dem/r_vol_dem_layerdown.jpg
   grass-addons/grass7/grass7/raster/r.vol.dem/r_vol_dem_layerup.jpg
Log:


Added: grass-addons/grass7/grass7/raster/Makefile
===================================================================
--- grass-addons/grass7/grass7/raster/Makefile	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/Makefile	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,28 @@
+MODULE_TOPDIR = ..
+
+SUBDIRS = \
+	r.area \
+	r.clump2 \
+	r.convergence \
+	r.fuzzy \
+	r.hydrodem \
+	r.in.srtm.region \
+	r.in.wms2 \
+	r.modis \
+	r.regression.multi \
+	r.regression.series \
+	r.stream.basins \
+	r.stream.channel \
+	r.stream.distance \
+	r.stream.extract \
+	r.stream.order \
+	r.stream.segment \
+	r.stream.slope \
+	r.stream.snap \
+	r.stream.stats \
+	r.threshold
+
+include $(MODULE_TOPDIR)/include/Make/Dir.make
+
+default: subdirs
+

Added: grass-addons/grass7/grass7/raster/r.agent/libagent/__init__.py
===================================================================
Added: grass-addons/grass7/grass7/raster/r.agent/libagent/aco.py
===================================================================
--- grass-addons/grass7/grass7/raster/r.agent/libagent/aco.py	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.agent/libagent/aco.py	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,27 @@
+############################################################################
+#
+# MODULE:       r.agent.*
+# AUTHOR(S):    michael lustenberger inofix.ch
+# PURPOSE:      library file for the r.agent.* suite
+# COPYRIGHT:    (C) 2011 by Michael Lustenberger and the GRASS Development Team
+#
+#               This program is free software under the GNU General Public
+#               License (>=v2). Read the file COPYING that comes with GRASS
+#               for details.
+#
+#############################################################################
+
+import error
+import world
+import ant
+
+from math import sqrt
+from math import exp
+from random import randint
+
+class ACO(world.World):
+    """World class for using the Ant Colony Optimization Algorithm for
+       modelling Agent Based worlds."""
+    def __init__(self):
+        world.World.__init__(self, ant.Ant)
+

Added: grass-addons/grass7/grass7/raster/r.agent/libagent/agent.py
===================================================================
--- grass-addons/grass7/grass7/raster/r.agent/libagent/agent.py	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.agent/libagent/agent.py	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,41 @@
+############################################################################
+#
+# MODULE:       r.agent.*
+# AUTHOR(S):    michael lustenberger inofix.ch
+# PURPOSE:      library file for the r.agent.* suite
+# COPYRIGHT:    (C) 2011 by Michael Lustenberger and the GRASS Development Team
+#
+#               This program is free software under the GNU General Public
+#               License (>=v2). Read the file COPYING that comes with GRASS
+#               for details.
+#
+#############################################################################
+
+class Agent(object):
+    """Generic Agent class with limited capabilities, as a basis for
+       child classes."""
+    def __init__(self, timetolive, world, position=[]):
+        self.ttl = timetolive
+        self.world = world
+        self.position = position
+        self.knowscompass = False
+        self.freedom = 0
+    def setposition(self, position):
+        if position and position != []:
+            self.position[0] = position[0]
+            self.position[1] = position[1]
+    def getposition(self):
+        return self.position
+    def move(self, nrofsteps, direction):
+        pass
+    def age(self):
+        if self.ttl > 0:
+            self.ttl -= 1
+            return True
+        else:
+            self.snuffit()
+            return False
+    def snuffit(self):
+        """to die peacefully and without pain."""
+        self.world.kill(self)
+

Added: grass-addons/grass7/grass7/raster/r.agent/libagent/ant.py
===================================================================
--- grass-addons/grass7/grass7/raster/r.agent/libagent/ant.py	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.agent/libagent/ant.py	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,32 @@
+############################################################################
+#
+# MODULE:       r.agent.*
+# AUTHOR(S):    michael lustenberger inofix.ch
+# PURPOSE:      library file for the r.agent.* suite
+# COPYRIGHT:    (C) 2011 by Michael Lustenberger and the GRASS Development Team
+#
+#               This program is free software under the GNU General Public
+#               License (>=v2). Read the file COPYING that comes with GRASS
+#               for details.
+#
+#############################################################################
+
+from random import choice, randint
+import agent
+import error
+
+class Ant(agent.Agent):
+    """Implementation of an Ant Agent for an ACO kind of World."""
+    def __init__(self, timetolive, world, position):
+        agent.Agent.__init__(self, timetolive, world, position)
+        self.position.extend([None,None,0,0])
+        self.home = self.position[:]
+        self.laststeps = [self.position[:]]
+        self.visitedsteps = []
+        self.done = False
+        self.nextstep = [None,None,0,0,0,0]
+        self.goal = []
+        self.penalty = 0.0
+#
+
+

Added: grass-addons/grass7/grass7/raster/r.agent/libagent/error.py
===================================================================
--- grass-addons/grass7/grass7/raster/r.agent/libagent/error.py	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.agent/libagent/error.py	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,43 @@
+############################################################################
+#
+# MODULE:       r.agent.*
+# AUTHOR(S):    michael lustenberger inofix.ch
+# PURPOSE:      library file for the r.agent.* suite
+# COPYRIGHT:    (C) 2011 by Michael Lustenberger and the GRASS Development Team
+#
+#               This program is free software under the GNU General Public
+#               License (>=v2). Read the file COPYING that comes with GRASS
+#               for details.
+#
+#############################################################################
+
+class Error(Exception):
+    """Base class for exceptions in this module.
+
+    Attributes:
+        expr -- Context expression in which the error occurred
+        msg  -- explanation of the error
+    """
+    def __init__(self, expr, msg):
+        self.expr = expr
+        self.msg = msg
+    def __str__(self):
+        return self.expr + " '" + self.msg + "'"
+
+class EnvError(Error):
+    """Exception raised for missing GRASS environement.
+
+    Attributes:
+        expr -- Context expression in which the error occurred
+        msg  -- explanation of the error
+    """
+
+class DataError(Error):
+    """Exception raised for errors in the input.
+
+    Attributes:
+        expr -- Context expression in which the error occurred
+        msg  -- explanation of the error
+    """
+
+

Added: grass-addons/grass7/grass7/raster/r.agent/libagent/playground.py
===================================================================
--- grass-addons/grass7/grass7/raster/r.agent/libagent/playground.py	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.agent/libagent/playground.py	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,40 @@
+#!/usr/bin/env python
+############################################################################
+#
+# MODULE:       r.agent.*
+# AUTHOR(S):    michael lustenberger inofix.ch
+# PURPOSE:      very basic test collection for the r.agent.* suite
+# COPYRIGHT:    (C) 2011 by Michael Lustenberger and the GRASS Development Team
+#
+#               This program is free software under the GNU General Public
+#               License (>=v2). Read the file COPYING that comes with GRASS
+#               for details.
+#
+#############################################################################
+
+import grass.script as grass
+
+class Playground(object):
+    """A Playground is a major component of a World, defining
+       and organizing space, and the interface to GRASS."""
+    def __init__(self):
+        self.layers = dict()
+        self.region = grass.region()
+        if self.region['ewres'] != self.region['nsres']:
+            raise error.DataError("r.agent::libagent.playground.Playground()",
+                                    "Only square raster cells make sense.")
+    def getregion(self):
+        return self.region
+    def getbound(self, bound):
+        return self.region[bound]
+    def setlayer(self, layername, layer, force=False):
+        pass
+    def createlayer(self, layername, grassmap=False):
+        pass
+    def getlayer(self, layername):
+        return []
+    def removelayer(self, layername):
+        pass
+    def writelayer(self, layername):
+        pass
+

Added: grass-addons/grass7/grass7/raster/r.agent/libagent/world.py
===================================================================
--- grass-addons/grass7/grass7/raster/r.agent/libagent/world.py	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.agent/libagent/world.py	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,55 @@
+############################################################################
+#
+# MODULE:       r.agent.*
+# AUTHOR(S):    michael lustenberger inofix.ch
+# PURPOSE:      library file for the r.agent.* suite
+# COPYRIGHT:    (C) 2011 by Michael Lustenberger and the GRASS Development Team
+#
+#               This program is free software under the GNU General Public
+#               License (>=v2). Read the file COPYING that comes with GRASS
+#               for details.
+#
+#############################################################################
+
+import error
+import playground
+import agent
+
+class World(object):
+    """Generic World class as basis for more complex worlds."""
+    def __init__(self, agenttype=None, pg=None):
+        if pg == None:
+            self.playground = playground.Playground()
+        else:
+            self.playground = pg
+        self.agentclass = agent.Agent
+        if agenttype == None:
+            self.agenttype = self.agentclass
+        else:
+            self.setagenttype(agenttype)
+        self.agents = []
+        self.artefacts = []
+    def addlayertopg(self, layername, layertype):
+        pass
+    def getlayer(self, layername):
+        pass
+#       return layer
+    def rmlayer(self, layername):
+        pass
+    def setagenttype(self, agentype):
+        pass
+    def getagenttype(self):
+        pass
+#       return agenttype
+    def bear(self, timetolive, position, agenttype):
+        pass
+#       return agent
+    def getnextagent():
+        return next(self, agents)
+    def move(self, agent, position):
+        pass
+    def getposition(self, agent):
+        pass
+    def kill(self, agent):
+        pass
+

Added: grass-addons/grass7/grass7/raster/r.agent/libold/__init__.py
===================================================================
Added: grass-addons/grass7/grass7/raster/r.agent/libold/aco.py
===================================================================
--- grass-addons/grass7/grass7/raster/r.agent/libold/aco.py	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.agent/libold/aco.py	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,228 @@
+############################################################################
+#
+# MODULE:       r.agent.*
+# AUTHOR(S):    michael lustenberger inofix.ch
+# PURPOSE:      library file for the r.agent.* suite
+# COPYRIGHT:    (C) 2011 by  Michael Lustenberger and the GRASS Development Team
+#
+#               This program is free software under the GNU General Public
+#               License (>=v2). Read the file COPYING that comes with GRASS
+#               for details.
+#
+#############################################################################
+
+from math import sqrt
+from math import exp
+from random import randint
+import world
+import error
+import ant
+
+class ACO(world.World):
+    """Ant Colony Optimization Algorithm for Modelling an Agent Based World"""
+    def __init__(self):
+        world.World.__init__(self, ant.Ant)
+        ### auto/constant
+        self.agentclass = ant.Ant
+        self.ants = self.agents
+        self.artefacts.append([])
+        self.holes = self.artefacts[0]
+        self.artefacts.append([])
+        self.sugar = self.artefacts[1]
+        self.surfaceslope = None
+        self.costsurface = None
+        self.pherovapour = None
+        self.bounds = None
+        self.straight = 0
+        self.diagonal = sqrt(2)-1
+        # count paths
+        self.nrop = 0
+        ### user parameter
+        self.globalfreedom = 8
+        self.rounds = 0
+        self.outrounds = 0
+        self.outfilename = ""
+        self.maxpheromone = 2147483647
+        self.minpheromone = 10
+#        self.maxpenalty = 999
+        self.volatilizationtime = 1
+        self.stepintensity = 10
+        self.pathintensity = 10000
+        self.decisionbase = "standard"
+        self.pheroweight = 1
+        self.randomweight = 1
+        self.validposition = "specials"
+# use fibonacci?
+        self.maxants = 100
+        self.antslife = 0
+    def checkvalues(self):
+        if self.costsurface == None:
+            raise error.DataError("aco.ACO.checkvalues()",
+                    "main input missing: costraster")
+        self.playground.setboundsfromlayer("costs")
+        self.playground.forcelayerbounds()
+        self.bounds = self.playground.getrelativebounds()
+        if self.costsurface == None:
+            raise error.DataError("aco.ACO.checkvalues()",
+                    "input layer missing: costsurface")
+        elif self.costsurface == []:
+            if self.surfaceslope == None:
+                raise error.DataError("aco.ACO.checkvalues()",
+                    "input layer missing: please provide cost or slope layer")
+            else:
+                self.calccostsurface()
+        if self.pherovapour == None:
+            raise error.DataError("aco.ACO.checkvalues()",
+                    "output layer missing: pheromoneraster")
+        if self.holes == None:
+            raise error.DataError("aco.ACO.checkvalues()",
+                    "input layer missing: vectorholes")
+        if self.rounds <= 0:
+            raise error.DataError("aco.ACO.checkvalues()",
+                    "number of rounds is zero or not set.")
+        if self.outrounds <= 0:
+            self.outrounds = self.rounds
+        if self.antslife == 0:
+            self.antslife = (self.bounds[4]+self.bounds[5])
+        if self.volatilizationtime > self.rounds:
+            self.volatilizationtime = self.rounds
+        elif self.volatilizationtime < 0:
+            self.volatilizationtime = 0
+        for hole in self.holes[:]:
+            if self.costsurface[hole[0]][hole[1]] < 0:
+                self.holes.remove(hole)
+            else:
+# TODO if two holes are close, choose outermost.. or so.
+                self.pherovapour[hole[0]][hole[1]] = -1
+    def addneighbour(self, positions, position):
+        position[2] = self.costsurface[position[0]][position[1]]
+# TODO > or >=
+#        if position[2] > self.maxpenalty:
+#            return
+        if position[2] >= 0:
+            position[3] = self.pherovapour[position[0]][position[1]]
+            positions.append(position)
+    def calccostsurface(self):
+        for x in range(self.bounds[2]):
+            for y in range(self.bounds[0]):
+                val = self.surfaceslope[x][y]
+                if self.surfaceslope > 0:
+                    self.costsurface[x][y] = (1/exp(-0.035*abs(val+5)))-1
+    def getneighbourpositions(self, position, freedom=None):
+        # position = [ x, y, surfacecost, special/phero, timecost, direction ]
+        if freedom == None:
+            freedom = self.globalfreedom
+        positions = []
+        if freedom >= 4:
+            #north = 1
+#TODO improve with not creating position in any case..
+            p = [position[0], position[1]+1, 0, 0, self.straight, 1]
+            if p[1] <= self.bounds[0]:
+                self.addneighbour(positions, p)
+            #south = 2
+            p = [position[0], position[1]-1, 0, 0, self.straight, 2]
+            if p[1] >= self.bounds[1]:
+                self.addneighbour(positions, p)
+            #east = 3
+            p = [position[0]+1, position[1], 0, 0, self.straight, 3]
+            if p[0] <= self.bounds[2]:
+                self.addneighbour(positions, p)
+            #west = 4
+            p = [position[0]-1, position[1], 0, 0, self.straight, 4]
+            if p[0] >= self.bounds[3]:
+                self.addneighbour(positions, p)
+        if freedom >= 8:
+            #northeast = 5
+            p = [position[0]+1, position[1]+1, 0, 0, self.diagonal, 5]
+            if p[1] <= self.bounds[0] and p[0] <= self.bounds[2]:
+                self.addneighbour(positions, p)
+            #northwest = 6
+            p = [position[0]-1, position[1]+1, 0, 0, self.diagonal, 6]
+            if p[1] <= self.bounds[0] and p[0] >= self.bounds[3]:
+                self.addneighbour(positions, p)
+            #southeast = 7
+            p = [position[0]+1, position[1]-1, 0, 0, self.diagonal, 7]
+            if p[1] >= self.bounds[1] and p[0] <= self.bounds[2]:
+                self.addneighbour(positions, p)
+            #southwest = 8
+            p = [position[0]-1, position[1]-1, 0, 0, self.diagonal, 8]
+            if p[1] >= self.bounds[1] and p[0] >= self.bounds[3]:
+                self.addneighbour(positions, p)
+        return positions
+    def letantsdance(self):
+        if 0 < self.outrounds < self.rounds:
+            mainloops = self.rounds/self.outrounds
+            loops = self.outrounds
+        else:
+            mainloops = 1
+            loops = self.rounds
+        nrofrounds = mainloops*loops
+        remember = loops
+        while mainloops > 0:
+            loops = remember
+            while loops > 0:
+                if len(self.ants) < self.maxants:
+                    position = self.holes[randint(0, len(self.holes)-1)][0:2]
+                    self.bear(None, self.antslife, position)
+                for ant in self.ants:
+                    ant.walk()
+                self.volatilize()
+                loops -= 1
+            self.export(str(mainloops))
+            print "nrofpaths:", self.nrop
+            mainloops -= 1
+        print "nrofrounds", nrofrounds
+    def volatilize(self):
+        if self.volatilizationtime > 0:
+            limit = self.minpheromone
+            halflife = self.volatilizationtime
+            for x in range(self.bounds[2]):
+                for y in range(self.bounds[0]):
+                    if self.pherovapour[x][y] > limit:
+                        val = int(self.pherovapour[x][y]*0.5**(1.0/halflife))
+                        if val > limit:
+                            self.pherovapour[x][y] = val
+    def export(self, suffix=""):
+        layer = self.playground.getlayer("phero")
+        if self.outfilename == "":
+            self.outfilename = layer.outfilename
+        layer.setoutfilename(self.outfilename+suffix)
+        layer.exportfile()
+
+def test(inraster=False, outraster=False, invector=False, slope=False):
+    """Test suite for ACO Class"""
+    print "creating a new ants world.."
+    w = ACO()
+    if inraster:
+        layer = w.importlayer("costs", "raster", inraster)
+        w.costsurface = layer.raster
+    elif slope:
+        layer = w.importlayer("slope", "raster", slope)
+        w.surfaceslope = layer.raster
+        w.playground.setboundsfromlayer("slope")
+        layer = w.createlayer("costs", "raster", None, None)
+        w.costsurface = layer.raster
+        w.calccostsurface()
+    print "start playing with it.."
+    if outraster and invector:
+        layer = w.createlayer("phero", "raster", None, outraster)
+        w.pherovapour = layer.raster
+        layer = w.importlayer("holes", "vector", invector)
+        w.holes = layer.objects
+        w.rounds = 1
+        w.checkvalues()
+        print "set, within:", w.playground.getbounds()
+        print "this translates to:", w.bounds
+        print " this are the holes:"
+        for hole in w.holes:
+            print str(hole)
+        print "neighbourpositions of [9,9]:", w.getneighbourpositions([9,9])
+        print "setting [9,9] to pheromone 999"
+        w.pherovapour[9][9] = 999
+        w.volatilize()
+        print " after some volatilization:",w.pherovapour[9][9]
+        print "playing with some ants"
+        w.letantsdance()
+        print "rock n' roll"
+        w.export()
+

Added: grass-addons/grass7/grass7/raster/r.agent/libold/agent.py
===================================================================
--- grass-addons/grass7/grass7/raster/r.agent/libold/agent.py	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.agent/libold/agent.py	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,63 @@
+############################################################################
+#
+# MODULE:       r.agent.*
+# AUTHOR(S):    michael lustenberger inofix.ch
+# PURPOSE:      library file for the r.agent.* suite
+# COPYRIGHT:    (C) 2011 by Michael Lustenberger and the GRASS Development Team
+#
+#               This program is free software under the GNU General Public
+#               License (>=v2). Read the file COPYING that comes with GRASS
+#               for details.
+#
+#############################################################################
+
+import world
+
+class Agent(object):
+    """standard agent"""
+    def __init__(self, timetolive, world, position=[]):
+        self.ttl = timetolive
+        self.world = world
+        self.position = position
+        self.knowscompass = False
+        self.freedom = 0
+    def setposition(self, position):
+        if position and position != []:
+            self.position[0] = position[0]
+            self.position[1] = position[1]
+    def getposition(self):
+        return self.position
+    def move(self, nrofsteps, direction):
+        pass
+    def age(self):
+        if self.ttl > 0:
+            self.ttl -= 1
+            return True
+        else:
+            self.snuffit()
+            return False
+    def snuffit(self):
+        """to die peacefully and without pain."""
+        self.world.kill(self)
+
+def test():
+    """Test suite for Agent Class"""
+    print "create a world with an agent in."
+    w = world.World(Agent)
+    w.bear(Agent,1,[0,0])
+    print "agent seems fine (for now). time to live:", str(w.agents[0].ttl)
+    print "fake-placing it somewhere ([0,1]).."
+    w.agents[0].setposition([0,1])
+    print "getting its position:", w.agents[0].getposition()
+    print "'cause this takes some time.."
+    w.agents[0].age()
+    print "agent should have grown older by now. time to live:", \
+         str(w.agents[0].ttl)
+    print "and now let agent die.."
+    w.agents[0].age()
+    try:
+        print "should be dead by now. time to live:", str(w.agents[0].ttl)
+    except IndexError:
+        print "IndexError catched: ant was not found in the world anymore."
+    print "all done."
+

Added: grass-addons/grass7/grass7/raster/r.agent/libold/alltests.py
===================================================================
--- grass-addons/grass7/grass7/raster/r.agent/libold/alltests.py	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.agent/libold/alltests.py	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,61 @@
+#!/usr/bin/env python
+############################################################################
+#
+# MODULE:       r.agent.*
+# AUTHOR(S):    michael lustenberger inofix.ch
+# PURPOSE:      very basic test collection for the r.agent.* suite
+# COPYRIGHT:    (C) 2011 by Michael Lustenberger and the GRASS Development Team
+#
+#               This program is free software under the GNU General Public
+#               License (>=v2). Read the file COPYING that comes with GRASS
+#               for details.
+#
+#############################################################################
+
+import sys
+
+import error
+import agent
+import ant
+import layer
+import rasterlayer
+import vectorlayer
+import world
+import aco
+import playground
+
+def dotest(function, argv):
+    while True:
+        n = function.func_doc
+        o = str(argv)
+        if not n:
+            n = str(function)
+        t = str(raw_input("execute this now: '"+n+" - "+o+"'? [y/n/abort] "))
+        if t == "y":
+            if argv != None:
+                function(*argv)
+            else:
+                function()
+            break
+        elif t == "n":
+            break
+        elif t == "abort":
+            exit()
+
+files = ["elev.grid", "elev.grid.out", "arch.vect"]
+
+alltests = [[error.test, None],
+            [agent.test, None],
+            [ant.test, None],
+            [layer.test, [files[2]]],
+            [layer.test, [files[0]]],
+            [rasterlayer.test, [files[0]]],
+            [vectorlayer.test, [files[2]]],
+            [world.test, None],
+            [world.test, files],
+            [aco.test, files],
+            [playground.test, ["raster", files[0], "vector", files[2]]]]
+
+for test in alltests:
+    dotest(test[0], test[1])
+


Property changes on: grass-addons/grass7/grass7/raster/r.agent/libold/alltests.py
___________________________________________________________________
Added: svn:executable
   + 

Added: grass-addons/grass7/grass7/raster/r.agent/libold/ant.py
===================================================================
--- grass-addons/grass7/grass7/raster/r.agent/libold/ant.py	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.agent/libold/ant.py	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,335 @@
+############################################################################
+#
+# MODULE:       r.agent.*
+# AUTHOR(S):    michael lustenberger inofix.ch
+# PURPOSE:      library file for the r.agent.* suite
+# COPYRIGHT:    (C) 2011 by Michael Lustenberger and the GRASS Development Team
+#
+#               This program is free software under the GNU General Public
+#               License (>=v2). Read the file COPYING that comes with GRASS
+#               for details.
+#
+#############################################################################
+
+from random import choice, randint
+import agent
+import error
+
+class Ant(agent.Agent):
+    """custom"""
+    def __init__(self, timetolive, world, position):
+        agent.Agent.__init__(self, timetolive, world, position)
+        self.position.extend([None,None,0,0])
+        self.home = self.position[:]
+        self.laststeps = [self.position[:]]
+        self.visitedsteps = []
+        self.done = False
+        self.nextstep = [None,None,0,0,0,0]
+        self.goal = []
+        self.penalty = 0.0
+        self.steppaint = world.stepintensity
+        self.pathpaint = world.pathintensity
+        if world.decisionbase == "standard":
+            self.pickaposition = self.smellposition
+            self.pheroweight = self.world.pheroweight * 2
+            self.randomweight = self.world.randomweight * 2
+        elif world.decisionbase == "random":
+            self.pickaposition = self.randomposition
+        elif world.decisionbase == "test":
+            self.pickaposition = self.testposition
+            self.pheroweight = self.world.pheroweight * 2
+            self.randomweight = self.world.randomweight * 2
+        if world.validposition == "avoidloop":
+            self.haspositions = self.avoidloop
+        elif world.validposition == "forgetloop":
+            self.haspositions = self.forgetloop
+        elif world.validposition == "avoidorforgetloop":
+            self.haspositions = self.avoidorforgetloop
+        elif world.validposition == "specials":
+            self.haspositions = self.searchspecials
+    def paint(self, position, value):
+#TODO mv to tests:
+        if self.world.pherovapour[position[0]][position[1]] < 0:
+            print "home:", self.home, "paint:", position, ":", value
+            raise error.Error("Ant.paint()", "Not painting over specials.")
+        if self.world.maxpheromone-value > \
+         self.world.pherovapour[position[0]][position[1]]:
+            self.world.pherovapour[position[0]][position[1]] += value
+    def randomposition(self, positions):
+        self.nextstep = positions[randint(0, len(positions)-1)]
+    def testposition(self, positions):
+        i = 0
+        l = []
+        for pos in positions:
+            l.append([pos[3]/self.randomweight+randint(0,\
+                self.world.maxpheromone)/self.pheroweight, i])
+            i += 1
+        l.sort()
+        self.nextstep = positions[l[0][1]]
+#TODO add some position search alg that avoids high penalties..
+    def smellposition(self, positions):
+        self.nextstep = positions[0]
+        self.nextstep[3] = self.nextstep[3]/self.randomweight+ \
+                    randint(0,self.world.maxpheromone)/self.pheroweight
+        for pos in positions[1:]:
+            pos[3] = pos[3]/self.randomweight+ \
+                    randint(0,self.world.maxpheromone)/self.pheroweight
+            if self.nextstep[3] < pos[3]:
+                self.nextstep = pos
+    def avoidloop(self, positions):
+        ''' This method tries to avoid stepping on already passed
+            nodes. That it is basically. '''
+        # remember all positions for worst case..
+        temppositions = positions[:]
+        for last in self.laststeps[:]:
+            for pos in positions[:]:
+                if last[0] == pos[0] and last[1] == pos[1]:
+                    # position already visited once..
+                    try:
+                        positions.remove(pos)
+                    except ValueError:
+                        pass
+        if len(positions) == 0:
+            # can not be special value, because it would already be visited
+            # make sure it is not home
+            pos = choice(temppositions)
+            if pos[0] == self.home[0] and pos[1] == self.home[1]:
+                temppositions.remove(pos)
+                pos = choice(temppositions)
+            # if none was left: choose another one by chance
+            # no need to proceed with choosing from only one position
+            self.nextstep = pos
+            return True
+        else:
+            for pos in positions[:]:
+                if pos[3] < 0:
+                    # home is already handled because visited
+                    # goal node found. add one to the counter
+                    self.world.nrop += 1
+                    self.done = True
+                    # now, head back home..
+                    self.nextstep = self.laststeps.pop()
+                    return True
+        return False       
+    def avoidorforgetloop(self, positions):
+        ''' This method tries to avoid stepping on already passed
+            nodes. If this is not possible or if a path is coming
+            close to such nodes in the grid, it will grant not to
+            produce loops by deleting all intermediate steps.'''
+        # remember all positions for worst case..
+        temppositions = positions[:]
+        # initially start with no loop found
+        hasposition = False
+        # search for loops, but exclude last step from process (keep it)
+        for last in self.laststeps[:]:
+            if hasposition == True:
+                # remove loop, but remember visited steps
+                self.visitedsteps.append(last)
+                self.laststeps.remove(last)
+            else:
+                # search for loop in positions
+                for pos in positions[:]:
+                    if last[0] == pos[0] and last[1] == pos[1]:
+                        # shortcut found, so remove loop
+                        hasposition = True
+                        # remove that position from possible next ones
+                        positions.remove(pos)
+                        # change direction penalty to new shortcut
+                        self.laststeps[-1][4] = pos[4]
+        # remove all yet visited nodes from possible next positions
+        for visited in self.visitedsteps:
+            for pos in positions[:]:
+                if visited[0] == pos[0] and visited[1] == pos[1]:
+                    # do not step on visited nodes again
+                    positions.remove(pos)
+        if len(positions) == 0:
+            # can not be special value, because it would already be visited
+            # make sure it is not home
+            pos = choice(temppositions)
+            if pos[0] == self.home[0] and pos[1] == self.home[1]:
+                temppositions.remove(pos)
+                pos = choice(temppositions)
+            # if none was left: choose another one by chance
+            # no need to proceed with choosing from only one position
+            self.nextstep = pos
+            return True
+        else:
+            for pos in positions[:]:
+                if pos[3] < 0:
+                    # home is already handled because visited
+                    # goal node found. add one to the counter
+                    self.world.nrop += 1
+                    self.done = True
+                    # now, head back home..
+                    self.nextstep = self.laststeps.pop()
+                    return True
+        return False
+    def forgetloop(self, positions):
+        ''' This method deletes all positions that form a loop in the
+            path. It also prohibits to walk back one step both to the
+            true former position, and to the assumed last step on the
+            newly created shortcut.'''
+        # initially start with no loop found
+        hasposition = False
+        # search for loops, but exclude last step from process (keep it)
+        for last in self.laststeps[:-1]:
+            if hasposition == True:
+                # remove loop
+                self.laststeps.remove(last)
+            else:
+                # search for loop in positions
+                for pos in positions[:]:
+                    if last[0] == pos[0] and last[1] == pos[1]:
+                        # shortcut found, so remove loop
+                        hasposition = True
+                        # remove that position from possible next ones
+                        positions.remove(pos)
+                        # change direction penalty for laststep to new shortcut
+                        self.laststeps[-1][4] = pos[4]
+        for pos in positions[:]:
+            if pos[3] < 0:
+                # promissing, but home is not excluded (only loops are..)
+                if pos[0] == self.home[0] and pos[1] == self.home[1]:
+                    # so, make sure it is not home..
+                    positions.remove(pos)
+                else:
+                    # goal node found. add one to the counter
+                    self.world.nrop += 1
+                    self.done = True
+                    # now, head back home..
+                    self.nextstep = self.laststeps.pop()
+                    return True
+        return False
+    def searchspecials(self, positions):
+        for pos in positions[:]:
+            if pos[3] < 0:
+                # nice value found, goal might be reached
+                if pos[0] == self.home[0] and pos[1] == self.home[1]:
+                    # make sure it is not home..
+                    positions.remove(pos)
+                else:
+                    # this is it! add one to the counter
+                    self.world.nrop += 1
+                    self.done = True
+                    self.nextstep = self.laststeps.pop()
+                    return True
+        return False
+    def choose(self):
+        positions = self.world.getneighbourpositions(self.position)
+        # remove last step from possible neighbourpositions
+        try:
+            positions.remove(self.laststeps[len(self.laststeps)-1])
+        except ValueError:
+            pass
+        if not self.haspositions(positions):
+            self.pickaposition(positions)
+    def walk(self):
+        # we are all only getting older..
+        if self.age() == False:
+            return False
+        # if we do not have decided yet where to go to..
+        if self.nextstep[0] == None:
+            self.choose()
+        # if penalty is positive, wait one round
+        if self.penalty > 0:
+            self.penalty -= 1
+        else:
+            # add penalty from direction or underground
+# TODO: think about adding 1 to each and then multiplicate them ;)
+            self.penalty += self.nextstep[4] + self.nextstep[2]
+            # are we luckily walking home?
+            if self.done == True:
+                # walk back home one step
+                self.position = [self.nextstep[0],self.nextstep[1]]
+                # mark current position as a good choice
+                self.paint(self.position, self.pathpaint)
+                if len(self.laststeps) > 1:
+                    # next step towards back home
+                    self.nextstep = self.laststeps.pop()
+                else:
+                    # retire after work
+                    self.snuffit()
+            else:
+                # make a step
+                self.position = self.nextstep
+                # remember it
+                self.laststeps.append(self.position)
+                # clear nextstep for next round
+                self.nextstep = [None,None,0,0,0,0]
+                # mark current position
+                self.paint(self.position, self.steppaint)
+
+def test():
+    """Test suite for Ant Class"""
+    import aco
+    print "creating a new world"
+    w = aco.ACO()
+    w.bounds = [5,0,5,0,6,6]
+    w.playground.setbounds(5,0,5,0,6,6)
+    print " limits set:",w.playground.getbounds()
+    w.playground.setnewlayer("cost", "raster", True)
+    w.costsurface = w.playground.getlayer("cost").raster
+    w.playground.setnewlayer("phero", "raster", True)
+    w.pherovapour = w.playground.getlayer("phero").raster
+    print " playground looks like (cost+phero)"
+    print " #c#",w.costsurface
+    print " #p#",w.pherovapour
+    w.holes = [[0,0,1]]
+    print ""
+    print "let's put some life in it.."
+    w.bear(Ant,5,[0,0])
+    a = w.agents[0]
+    print " agent seems fine (for now). time to live:",str(a.ttl),\
+        ". location:",a.position
+    a.paint([0,0],500)
+    a.paint([1,1],800)
+    a.paint([1,2],900)
+    print " playground(phero) after some painting:"
+    print " ", w.pherovapour
+    print "look around on positions.."
+    positions = w.getneighbourpositions(a.position)
+    print " tmp positions: ", positions
+    print "- any special cells in raster? ",\
+        a.searchspecials(positions)
+    positions[1][3] = -1
+    print "- any special cells in raster (marking one)? ",\
+        a.searchspecials(positions)
+    print "now die."
+    a.snuffit()
+    print ""
+    print "new ant.."
+    w.bear(Ant,5,[0,0])
+    a = w.agents[0]
+    print " agent seems fine (for now). time to live:",str(a.ttl),\
+        ". location:",a.position
+    print "let's do some positioning..."
+    positions = w.getneighbourpositions(a.position)
+    print "- now pickaposition:"
+    a.randomposition(positions)
+    print " a random choice: ", a.nextstep
+    a.smellposition(positions)
+    print " in smell-mode we would choose: ", a.nextstep
+    a.testposition(positions)
+    print " alternative test:", a.nextstep
+    print "- hasposition alternatives"
+    print " avoid walking in loops:"
+    ps = positions[:]
+    a.avoidloop(ps)
+    print " ",ps
+    ps = positions[:]
+    print " forget loops:"
+    a.forgetloop(ps)
+    print " ",ps
+    ps = positions[:]
+    print " avoid or forget loops:"
+    a.avoidorforgetloop(ps)
+    print " ",ps
+    print "- regularly choose a position now.. based on .. why not: smell."
+    print positions
+    a.choose()
+    print " ant: I'd go there,", a.position
+    print "- make a step forward then.."
+    a.walk()
+    print " ant: I am here now,", a.position
+    print "all done."
+

Added: grass-addons/grass7/grass7/raster/r.agent/libold/error.py
===================================================================
--- grass-addons/grass7/grass7/raster/r.agent/libold/error.py	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.agent/libold/error.py	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,48 @@
+############################################################################
+#
+# MODULE:       r.agent.*
+# AUTHOR(S):    michael lustenberger inofix.ch
+# PURPOSE:      library file for the r.agent.* suite
+# COPYRIGHT:    (C) 2011 by Michael Lustenberger and the GRASS Development Team
+#
+#               This program is free software under the GNU General Public
+#               License (>=v2). Read the file COPYING that comes with GRASS
+#               for details.
+#
+#############################################################################
+
+class Error(Exception):
+    """Base class for exceptions in this module."""
+    pass
+
+class DataError(Error):
+    """Exception raised for errors in the input.
+
+    Attributes:
+        expr -- Context expression in which the error occurred
+        msg  -- explanation of the error
+    """
+    def __init__(self, expr, msg):
+        self.expr = expr
+        self.msg = msg
+        print "DataError: " + expr + " " + msg
+
+class InputError(Error):
+    """Exception raised for errors in the input.
+
+    Attributes:
+        expr -- input expression in which the error occurred
+        msg  -- explanation of the error
+    """
+    def __init__(self, expr, msg):
+        self.expr = expr
+        self.msg = msg
+        print "InputError: " + expr + " " +msg
+
+def test():
+    """Test suite for Error Class"""
+    try:
+        raise InputError("Error Test Suite", "(no problem with this error)")
+    except InputError:
+        print "catched! all fine."
+

Added: grass-addons/grass7/grass7/raster/r.agent/libold/layer.py
===================================================================
--- grass-addons/grass7/grass7/raster/r.agent/libold/layer.py	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.agent/libold/layer.py	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,140 @@
+############################################################################
+#
+# MODULE:       r.agent.*
+# AUTHOR(S):    michael lustenberger inofix.ch
+# PURPOSE:      library file for the r.agent.* suite
+# COPYRIGHT:    (C) 2011 by Michael Lustenberger and the GRASS Development Team
+#
+#               This program is free software under the GNU General Public
+#               License (>=v2). Read the file COPYING that comes with GRASS
+#               for details.
+#
+#############################################################################
+
+import error
+
+class Layer():
+    """More like a meta/stub Class (or Interface).
+        To be inherited by children."""
+    def __init__(self):
+        self.infilename = None
+        self.outfilename = None
+        self.offset = [None,None]
+        self.limit = [None,None]
+        self.steps = []
+        self.resolution = [1,1]
+        self.fbuffer = None
+    def setinfilename(self, filename):
+        self.infilename = filename
+    def setoutfilename(self, filename):
+        self.outfilename = filename
+    def clearlayer(self):
+        self.offset = [None, None]
+        self.limit = [None, None]
+        if self.steps != []:
+            self.steps = [None, None]
+    def setbounds(self, north, south, east, west, rows=None, cols=None):
+        self.offset = [west,south]
+        self.limit = [east,north]
+        # here layer decides if steps shall be set (see Playground)
+        if self.steps != []:
+            self.steps = [cols,rows]
+            self.resolution[0] = (self.limit[0]-self.offset[0])/self.steps[0]
+            self.resolution[1] = (self.limit[1]-self.offset[1])/self.steps[1]
+    def getbounds(self):
+        if self.steps != []:
+            rows = self.steps[1]
+            cols = self.steps[0]
+        else:
+            rows = None
+            cols = None
+        return [self.limit[1], self.offset[1], self.limit[0],
+                 self.offset[0], rows, cols]
+    def shiftbound(self, direction, delta):
+        if delta < 0:
+            pass
+        elif delta > 0:
+            pass
+    def comparebounds(self, north, south, east, west, rows=None, cols=None):
+        if [west,south] == self.offset and [east,north] == self.limit:
+            if self.steps == []:
+                return True
+            elif [cols,rows] == self.steps:
+                return True
+        return False
+    def forcebounds(self, north, south, east, west, rows=None, cols=None):
+        if not self.comparebounds(north, south, east, west, rows, cols):
+            if self.resolution[0] and self.resolution[1]:
+                xres = self.resolution[0]
+                yres = self.resolution[1]
+            else:
+                xres = 1
+                yres = 1
+            self.shiftbound('north', (north-self.limit[1])/yres)
+            self.shiftbound('south', (south-self.offset[1])/yres)
+            self.shiftbound('east', (east-self.limit[0])/xres)
+            self.shiftbound('west', (west-self.offset[0])/xres)
+            self.setbounds(north, south, east, west, rows, cols)
+    def parsefile(self, fileh):
+        self.fbuffer = fileh.read()
+    def createfile(self, fileh):
+        if self.fbuffer:
+            fileh.write(self.fbuffer)
+    def importfile(self):
+        try:
+            with open(self.infilename, 'r') as fileh:
+                self.parsefile(fileh)
+        except IOError:
+            print "Error: Can not read " + self.infilename
+        except error.InputError:
+            print "Error: " + self.infilename + \
+                    " is not a valid ascii file"
+    def exportfile(self):
+        try:
+            with open(self.outfilename, "w") as fileh:
+                self.createfile(fileh)
+        except IOError:
+            print "Error: Can not write", self.infilename
+
+def test(infile, export=True, remove=True):
+    """Test suite for Layer Class"""
+    outfile = "out-" + infile
+    import os
+    if os.path.isfile(infile) and not os.path.isfile(outfile):
+        l = Layer()
+        print "setting files.."
+        l.setinfilename(infile)
+        l.setoutfilename(outfile)
+        print " import"
+        l.importfile()
+        if export == True:
+            print " export"
+            l.exportfile()
+            import filecmp
+            if filecmp.cmp(infile, outfile):
+                print "import/export seem ok"
+            else:
+                print "import/export failed"
+            if remove == True:
+                os.remove(outfile)
+        print "setting bounds"
+        l.setbounds(9,0,10,1)
+        print " bounds:", str(l.getbounds())
+        print " offset/limit:", str(l.offset), str(l.limit)
+        print "comparing bounds: "
+        print " True:",str(l.comparebounds(*l.getbounds()))
+        print " False:",str(l.comparebounds(l.offset[0]+1,l.offset[1],*l.limit))
+        print "clear all"
+        print "all again with steps:"
+        l.setbounds(9,0,10,1,1,1)
+        print " bounds:", str(l.getbounds())
+        print " offset/limit:", str(l.offset), str(l.limit)
+        print "comparing bounds: "
+        print " True:",str(l.comparebounds(*l.getbounds()))
+        print " False:",str(l.comparebounds(l.offset[0]+1,l.offset[1],*l.limit))
+        print "clear all"
+        l.clearlayer()
+        print " noting: "+str(l.offset)+str(l.limit)
+    else:
+        print "Error: no " + infile + " or " + outfile + " exists."
+

Added: grass-addons/grass7/grass7/raster/r.agent/libold/overview.html
===================================================================
--- grass-addons/grass7/grass7/raster/r.agent/libold/overview.html	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.agent/libold/overview.html	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,85 @@
+<h2>general oversimplified abstract overview</h2>
+
+<ul><li>world
+<ul><li>e.g. an anthill, or a planet..
+</li><li>organizes how things work together
+</li><li>has:
+<ul><li>playground
+</li><li>list of agents
+<ul><li>killagent(agent)
+</li></ul></li><li>list of artefacts
+</li></ul></li></ul></li><li>aco - world
+<ul><li>is a:
+<ul><li>world
+</li></ul></li><li>for ants as agents with Ant Colony Optimization Algorithm as interaction rule
+</li><li>has:
+<ul><li>playground with
+<ul><li>penalty raster layer
+</li><li>pheromone raster layer
+</li><li>vector layer with holes/anthills
+</li></ul></li><li>list of ants
+</li><li>list of attractors..
+</li><li>list of holes/anthills..
+</li><li>several values that control the behaviour..
+</li></ul></li></ul></li><li>playground
+<ul><li>e.g. dirt, dead wood/leaves/needles, pheromone, etc.
+</li><li>manages layers => coordinates or graph(?)
+</li><li>has:
+<ul><li>layers
+<ul><li>knows its borders
+<ul><li>start/end coordinates
+</li><li>graph ...
+</li></ul></li><li>calcgraph(raster, degreeoffreedom, sizeofstep)
+</li><li>neighbours(node)->listofedges
+</li><li>neighbours(coordinates)->mapofcoordinate=>value's
+</li></ul></li></ul></li></ul></li><li>layer (meta)
+<ul><li>one aspect from playground (one layer therefore..)
+</li></ul></li><li>rasterlayer - layer
+<ul><li>is a:
+<ul><li>layer
+</li></ul></li><li>e.g. pheromone "smell"
+</li><li>represents gis-rasterlayer
+</li><li>has:
+<ul><li>borders
+</li><li>matrix
+</li></ul></li></ul></li><li>vectorlayer - layer
+<ul><li>is a:
+<ul><li>layer
+</li></ul></li><li>e.g. holes in the ground
+</li><li>represents gis-vectorlayer
+</li><li>has:
+<ul><li>borders
+</li><li>list of vector objects/points/..
+</li></ul></li></ul></li><li>graph - layer (not yet available...)
+<ul><li>is a:
+<ul><li>layer
+</li></ul></li><li>made from raster-/vectorlayer
+</li><li>has:
+<ul><li>map of nodes
+<ul><li>node
+<ul><li>id
+</li><li>n:edges list
+</li></ul></li></ul></li><li>list of edges
+<ul><li>edge
+<ul><li>2:nodes
+</li><li>mapof'attribute=value's
+</li></ul></li></ul></li></ul></li></ul></li><li>agent
+<ul><li>e.g. a passenger or an ant
+</li><li>"lives" sort of in the world and on the playground
+</li><li>has:
+<ul><li>ttl
+</li><li>knowscompass
+</li><li>degreeoffreedom - (might be different from playground)
+</li><li>walk()
+</li></ul></li></ul></li><li>ant - agent
+<ul><li>is a:
+<ul><li>agent
+</li></ul></li><li>actor in an aco world
+</li><li>has:
+<ul><li>home position / position of origin / birthplace
+</li><li>list of its positions visited
+</li><li>pheromone intensity to use on certain circumstances
+</li><li>penalty value for its moving velocity
+</li><li>decisionbase for knowing how to find new positions
+</li><li>decisionbase for remembering visited positions
+</li></ul></li></ul></li></ul>

Added: grass-addons/grass7/grass7/raster/r.agent/libold/playground.py
===================================================================
--- grass-addons/grass7/grass7/raster/r.agent/libold/playground.py	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.agent/libold/playground.py	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,120 @@
+############################################################################
+#
+# MODULE:       r.agent.*
+# AUTHOR(S):    michael lustenberger inofix.ch
+# PURPOSE:      library file for the r.agent.* suite
+# COPYRIGHT:    (C) 2011 by Michael Lustenberger and the GRASS Development Team
+#
+#               This program is free software under the GNU General Public
+#               License (>=v2). Read the file COPYING that comes with GRASS
+#               for details.
+#
+#############################################################################
+
+import rasterlayer
+import vectorlayer
+
+class Playground(object):
+    """..."""
+    def __init__(self):
+        self.layers = dict()
+        self.offset = [None,None]
+        self.limit = [None,None]
+        self.steps = []
+    def setbounds(self, north=None, south=None, east=None, west=None,
+                     rows=None, cols=None):
+        self.offset = [west,south]
+        self.limit = [east,north]
+        # here always try to set steps (see Layer)
+        if rows:
+            self.steps = [cols,rows]
+    def setboundsfromlayer(self, layername):
+        self.setbounds(*self.layers[layername].getbounds())
+    def getbounds(self):
+        if self.steps:
+            rows = self.steps[1]
+            cols = self.steps[0]
+        else:
+            rows = None
+            cols = None
+        return [self.limit[1], self.offset[1], self.limit[0],
+                self.offset[0], rows, cols]
+    def getrelativebounds(self):
+        b = self.getbounds()
+        b = [b[4]-1,0,b[5]-1,0,b[4],b[5]]
+        return b
+    def setlayeralias(self, layername, layer):
+        self.layers[layername] = layer
+    def removelayer(self, layername):
+        del self.layers[layername]
+    def getlayer(self, layername):
+        return self.layers[layername]
+    def setlayer(self, layername, layer, force=False):
+        self.layers[layername] = layer
+        if force and self.offset[0] != None:
+            self.layers[layername].forcebounds(*self.getbounds())
+    def setnewlayer(self, layername, typename, force=False):
+        if typename == "raster":
+            layer = rasterlayer.RasterLayer()
+        elif typename == "vector":
+            layer = vectorlayer.VectorLayer()
+#        elif typename == "graph":
+#            self.layers[layername] = layer.Layer()
+        else:
+            print "layertype not supported (yet)."
+        self.setlayer(layername, layer, force)
+    def setlayerfromfile(self, layername, typename, filename):
+        self.setnewlayer(layername, typename)
+        self.layers[layername].setinfilename(filename)
+        self.layers[layername].importfile()
+        if self.offset[0] != None:
+            self.layers[layername].forcebounds(*self.getbounds())
+    def forcelayerbounds(self):
+        if self.offset[0] != None:
+            for layer in self.layers.itervalues():
+                layer.forcebounds(*self.getbounds())
+
+def test(layer0type=None, layer0=None, layer1type=None, layer1=None):
+    """Test suite for Playground Class"""
+    def testhelper(north=None, south=None, east=None, west=None,
+                     rows=None, cols=None):
+        print " It has this boundaries: "
+        print "  south: " + str(south)
+        print "  west: " + str(west)
+        print "  north: " + str(north)
+        print "  east: " + str(east)
+        print "  rows: " + str(rows)
+        print "  cols: " + str(cols)
+    print "creating new Playground.."
+    pg = Playground()
+    print "start filling it up.."
+    if layer0:
+        pg.setlayerfromfile("l0", layer0type, layer0)
+    else:
+        pg.setbounds(20, 0, 20, 0, 20, 20)
+        pg.setnewlayer("l0", "raster", True)
+        layer0type="raster"
+    print "Layer: "+"l0"+" ("+layer0type+")"
+    testhelper(*pg.layers["l0"].getbounds())
+    if layer1:
+        pg.setlayerfromfile("l1", layer1type, layer1)
+    else:
+        pg.setnewlayer("l1", "vector", True)
+        layer1type="vector"
+    print "Layer: "+"l1"+" ("+layer1type+")"
+    testhelper(*pg.layers["l1"].getbounds())
+    print "Setting global boundaries from layer l0"
+    pg.setboundsfromlayer("l0")
+    testhelper(*pg.getbounds())
+    print "adding new name/alias for l0"
+    pg.setlayeralias("newname", pg.getlayer("l0"))
+    print " " + str(pg.layers.keys())
+    testhelper(*pg.layers["newname"].getbounds())
+    print "remove new name"
+    pg.removelayer("newname")
+    print str(pg.layers.keys())
+    print "force global boundaries on layers"
+    pg.forcelayerbounds()
+    print " l1"
+    testhelper(*pg.layers["l1"].getbounds())
+

Added: grass-addons/grass7/grass7/raster/r.agent/libold/rasterlayer.py
===================================================================
--- grass-addons/grass7/grass7/raster/r.agent/libold/rasterlayer.py	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.agent/libold/rasterlayer.py	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,254 @@
+############################################################################
+#
+# MODULE:       r.agent.*
+# AUTHOR(S):    michael lustenberger inofix.ch
+# PURPOSE:      library file for the r.agent.* suite
+# COPYRIGHT:    (C) 2011 by Michael Lustenberger and the GRASS Development Team
+#
+#               This program is free software under the GNU General Public
+#               License (>=v2). Read the file COPYING that comes with GRASS
+#               for details.
+#
+#############################################################################
+
+import layer
+import error
+
+class RasterLayer(layer.Layer):
+    """..."""
+    def __init__(self):
+        layer.Layer.__init__(self)
+        self.bkeys = ["north", "south", "east", "west", "rows", "cols"]
+        self.steps = [None,None]
+        self.resolution = [None,None]
+        self.raster = []
+        self.gisempty = "*"
+        self.emptyvalue = -1
+    def clearlayer(self):
+        layer.Layer.clearlayer(self)
+        self.raster = []
+    def xyflipmatrix(self, matrix):
+        newmatrix = []
+        for i in range(len(matrix[0])):
+            newrow = []
+            for j in range(len(matrix)):
+                newrow.append(matrix[j][i])
+            newmatrix.append(newrow)
+        return newmatrix
+    def xflipmatrix(self, matrix):
+        raster = []
+        for i in range(len(matrix)-1, -1, -1):
+            raster.append(matrix[i])
+        return raster
+    def shiftbound(self, direction, delta):
+        if delta < 0:
+            if direction == "east":
+                for i in range(delta, 0):
+                    del self.raster[-1]
+            elif direction == "west":
+                for i in range(delta, 0):
+                    self.raster.insert(0,
+                        [0 for i in range(len(self.raster[0]))])
+            elif direction == "north":
+                for i in range(delta, 0):
+                    for j in range(len(self.raster)):
+                        del self.raster[j][-1]
+            elif direction == "south":
+                for i in range(delta, 0):
+                    for j in range(len(self.raster)):
+                        self.raster[j].insert(0, 0)
+        if delta > 0:
+            if direction == "east":
+                for i in range(delta):
+                    self.raster.append([0 for i in range(len(self.raster[0]))])
+            elif direction == "west":
+                for i in range(delta):
+                    del self.raster[0]
+            elif direction == "north":
+                for i in range(delta):
+                    for j in range(len(self.raster)):
+                        self.raster[j].append(0)
+            elif direction == "south":
+                for i in range(delta):
+                    for j in range(len(self.raster)):
+                        del self.raster[j][0]
+    def testresolution(self, north, south, east, west, rows, cols):
+        if rows > 0 < cols:
+            xres = ( east - west ) / cols
+            yres = ( north - south ) / rows
+            if self.resolution[0] == xres and self.resolution[1] == yres:
+                return True
+        return False
+    def forcebounds(self, north, south, east, west, rows, cols):
+        if self.steps[0] == None and self.raster == []:
+            self.setbounds(north, south, east, west, rows, cols)
+            for i in range(cols):
+                self.raster.append([0 for j in range(rows)])
+        elif not self.testresolution(north, south, east, west, rows, cols):
+            raise error.DataError("raster.forcebounds", "wrong resolution")
+        else:
+            layer.Layer.forcebounds(self, north, south, east, west, rows, cols)
+    def parsefile(self, fileh):
+        self.clearlayer()
+        bounds = []
+        for key in self.bkeys:
+            keylength = len(key)
+            line = fileh.readline()
+            if line[0:keylength] in key:
+                bounds.append(int(line[keylength+2:-1]))
+            else:
+                raise error.InputError(self.infilename, "no valid raster")
+        self.setbounds(*bounds)
+        raster = []
+        for line in fileh:
+            rasterline = []
+            for word in line.split(" "):
+                if word.find(".") > 0:
+                    rasterline.append(float(word))
+                elif word.isdigit():
+                    rasterline.append(int(word))
+                elif word in '\r' '\n' '\r\n':
+                    pass
+                else:
+                    rasterline.append(self.emptyvalue)
+            raster.append(rasterline[:])
+        if not (len(raster) == self.steps[1] and
+                        len(raster[0]) == self.steps[0]):
+            raise error.InputError(self.infilename, "wrong # rows/cols")
+        self.raster = self.xyflipmatrix(self.xflipmatrix(raster))
+    def createfile(self, fileh):
+        if self.limit[0]:
+            raster = self.xflipmatrix(self.xyflipmatrix(self.raster))
+            bounds = self.getbounds()
+            bounds.reverse()
+            for key in self.bkeys:
+                line = key + ": " + str(bounds.pop()) + "\n"
+                fileh.writelines(line)
+            for line in raster:
+                for word in line:
+                    if word == self.emptyvalue:
+                        fileh.write(self.gisempty + " ")
+                    else:
+                        fileh.write(str(word) + " ")
+                fileh.write("\n")
+
+def test(infile, export=True, remove=True):
+    """Test suite for RasterLayer Class"""
+    outfile = "out-" + infile
+    import os
+    if os.path.isfile(infile) and not os.path.isfile(outfile):
+        print "create raster layer"
+        r = RasterLayer()
+        r.setinfilename(infile)
+        r.setoutfilename(outfile)
+        print "importing file.."
+        r.importfile()
+        print "file says:"
+        print " r:", str(r.steps[0])+"; c:", str(r.steps[1])
+        print "matrix:"
+        print " x:", str(len(r.raster))+"; y:", str(len(r.raster[0]))
+        if export == True:
+            r.exportfile()
+            import filecmp
+            if filecmp.cmp(infile, outfile):
+                print "import/export seem ok"
+            else:
+                print "import/export failed"
+            if remove == True:
+                os.remove(outfile)
+        print "properties are still:"
+        print " r:", str(r.steps[0])+"; c:", str(r.steps[1])
+        print "flipping raster on x:"
+        b = r.xflipmatrix(r.raster)               
+        print " x:", str(len(b))+"; y:", str(len(b[0]))
+        print "flipping raster on x/y:"
+        b = r.xyflipmatrix(r.raster)
+        print " x:", str(len(b))+"; y:", str(len(b[0]))
+        print "a little resolution test first (to be True):", \
+                str(r.testresolution(*r.getbounds()))
+        print "now force bounds on raster: "
+        print " the same as now"
+        r.forcebounds(*r.getbounds())
+        print "  n/w:", str(r.offset), "s/e:", str(r.limit), "r/c:", \
+                    str(r.steps)
+        print "  at position [0,0] we have now:", str(r.raster[0][0])
+        print " setting new values now: 100,0,100,0,1,1"
+        r.clearlayer()
+        r.forcebounds(100,0,100,0,1,1)
+        print "  n/w:", str(r.offset), "s/e:", str(r.limit), "r/c:", \
+                    str(r.steps)
+        print "  testing wheter they are set now (True):", \
+                str(r.testresolution(100,0,100,0,1,1))
+        print "  at position [0,0] we have now: ", str(r.raster[0][0])
+        print " momentary raster:"
+        print str(r.raster)
+        print " now reforcing these (correct) values: 200,100,200,100,1,1"
+        r.forcebounds(200,100,200,100,1,1)
+        print "  n/w:", str(r.offset), "s/e:", str(r.limit), "r/c:", \
+                    str(r.steps)
+        print " momentary raster:"
+        print str(r.raster)
+        print " now some wrong values, should throw Error.."
+        try:
+            r.forcebounds(0,0,1,1,1,10000)
+        except error.DataError:
+            print "expected Error received.."
+        print " momentary raster:"
+        print str(r.raster)
+        print " changeing value r[0][0] to 1"
+        r.raster[0][0] = 1
+        print " momentary raster:"
+        print str(r.raster)
+        print "adding some space in the north"
+        print " setting new values now: 400,100,200,100,3,1"
+        r.forcebounds(400,100,200,100,3,1)
+        print "  n/w:", str(r.offset), "s/e:", str(r.limit), "r/c:", \
+                str(r.steps), "::", str(len(r.raster[0]))+":"+str(len(r.raster))
+        print " momentary raster:"
+        print str(r.raster)
+        print "removing some space in the north"
+        print " setting new values now: 300,100,200,100,2,1"
+        r.forcebounds(300,100,200,100,2,1)
+        print "  n/w:", str(r.offset), "s/e:", str(r.limit), "r/c:", \
+                str(r.steps), "::", str(len(r.raster[0]))+":"+str(len(r.raster))
+        print " momentary raster:"
+        print str(r.raster)
+        print "adding some space in the east"
+        r.forcebounds(300,100,400,100,2,3)
+        print " momentary raster:"
+        print "  n/w:", str(r.offset), "s/e:", str(r.limit), "r/c:", \
+                str(r.steps), "::", str(len(r.raster[0]))+":"+str(len(r.raster))
+        print str(r.raster)
+        print "removing some space in the east"
+        r.forcebounds(300,100,300,100,2,2)
+        print "  n/w:", str(r.offset), "s/e:", str(r.limit), "r/c:", \
+                str(r.steps), "::", str(len(r.raster[0]))+":"+str(len(r.raster))
+        print " momentary raster:"
+        print str(r.raster)
+        print "adding some space in the south"
+        r.forcebounds(300,0,300,100,3,2)
+        print " momentary raster:"
+        print "  n/w:", str(r.offset), "s/e:", str(r.limit), "r/c:", \
+                str(r.steps), "::", str(len(r.raster[0]))+":"+str(len(r.raster))
+        print str(r.raster)
+        print "removing some space in the south"
+        r.forcebounds(300,100,300,100,2,2)
+        print "  n/w:", str(r.offset), "s/e:", str(r.limit), "r/c:", \
+                str(r.steps), "::", str(len(r.raster[0]))+":"+str(len(r.raster))
+        print " momentary raster:"
+        print str(r.raster)
+        print "adding some space in the west"
+        r.forcebounds(300,100,300,0,2,3)
+        print " momentary raster:"
+        print "  n/w:", str(r.offset), "s/e:", str(r.limit), "r/c:", \
+                str(r.steps), "::", str(len(r.raster[0]))+":"+str(len(r.raster))
+        print str(r.raster)
+        print "removing some space in the west"
+        r.forcebounds(300,100,300,100,2,2)
+        print "  n/w:", str(r.offset), "s/e:", str(r.limit), "r/c:", \
+                str(r.steps), "::", str(len(r.raster[0]))+":"+str(len(r.raster))
+        print " momentary raster:"
+        print str(r.raster)
+    else:
+        print "Failed: no", infile, "or", outfile, "exists."
+

Added: grass-addons/grass7/grass7/raster/r.agent/libold/vectorlayer.py
===================================================================
--- grass-addons/grass7/grass7/raster/r.agent/libold/vectorlayer.py	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.agent/libold/vectorlayer.py	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,161 @@
+############################################################################
+#
+# MODULE:       r.agent.*
+# AUTHOR(S):    michael lustenberger inofix.ch
+# PURPOSE:      library file for the r.agent.* suite
+# COPYRIGHT:    (C) 2011 by Michael Lustenberger and the GRASS Development Team
+#
+#               This program is free software under the GNU General Public
+#               License (>=v2). Read the file COPYING that comes with GRASS
+#               for details.
+#
+#############################################################################
+
+import layer
+import error
+
+class VectorLayer(layer.Layer):
+    """..."""
+    def __init__(self):
+        layer.Layer.__init__(self)
+        self.objects = []
+        self.gissplit = "|"
+    def clearlayer(self):
+        layer.Layer.clearlayer(self)
+        self.objects = []
+    def shiftbound(self, direction, delta):
+# TODO off by one?
+        for obj in self.objects[:]:
+            if direction == "north":
+                if obj[1] > self.limit[1]+delta:
+                    self.objects.remove(obj)
+            elif direction == "east":
+                if obj[0] > self.limit[0]+delta:
+                    self.objects.remove(obj)
+            elif direction == "south":
+                if obj[1] < self.offset[1]+delta:
+                    self.objects.remove(obj)
+                else:
+                    obj[1] = obj[1]-delta
+            elif direction == "west":
+                if obj[0] < self.offset[0]+delta:
+                    self.objects.remove(obj)
+                else:
+                    obj[0] = obj[0]-delta
+    def reclassify(self, oldres, newres):
+# TODO if nothing changes..?
+# TODO goes to world??
+        dx = (newres[0] + 0.0) / oldres[0]
+        dy = (newres[1] + 0.0) / oldres[1]
+        for obj in self.objects:
+            obj[0] = int(round(obj[0] / dx))
+            obj[1] = int(round(obj[1] / dy))
+    def forcebounds(self, north, south, east, west, norows=None, nocols=None):
+        if self.offset[0] == None or self.offset[0] == self.limit[0]:
+            self.setbounds(north, south, east, west)
+        else:
+            layer.Layer.forcebounds(self, north, south, east, west)
+            if norows != None:
+                newres = [((east-west)/nocols),((north-south)/norows)]
+                self.reclassify(self.resolution, newres)
+                self.resolution = newres
+    def parsefile(self, fileh):
+        self.clearlayer()
+        vectorlist = []
+        self.offset = [0,0]
+        self.limit = [0,0]
+        for line in fileh:
+            if line[-1] in '\r' '\n' '\r\n':
+                line = line[:-1]
+            line = line.split(self.gissplit)
+            avector = []
+            for e in line:
+                avector.append(int(e))
+            vectorlist.append(avector)
+            if avector[0] > int(self.limit[0]):
+                self.limit[0] = avector[0]
+            if avector[1] > int(self.limit[1]):
+                self.limit[1] = avector[1]
+        self.objects = vectorlist
+    def createfile(self, fileh):
+        if self.limit[0] != None:
+            for obj in self.objects:
+                text = ""
+                for element in obj:
+                    if text:
+                        text = text + self.gissplit + str(element)
+                    else:
+                        text = str(element)
+                fileh.write(text + "\n")
+
+def test(infile, export=True, remove=True):
+    """Test suite for VectorLayer Class"""
+    outfile = "out-" + infile
+    import os
+    if os.path.isfile(infile) and not os.path.isfile(outfile):
+        print "create vector layer"
+        v = VectorLayer()
+        v.setinfilename(infile)
+        v.setoutfilename(outfile)
+        print "importing file"
+        v.importfile()
+        print "entries # " + str(len(v.objects))
+        for o in v.objects:
+            print " obj is: x=" + str(o[0]) + " y=" + str(o[1]) + \
+                " cat=" + str(o[2])
+        print "all between:"
+        print " south: " + str(v.offset[1])
+        print " west: " + str(v.offset[0])
+        print " north: " + str(v.limit[1])
+        print " east: " + str(v.limit[0])
+        if export == True:
+            v.exportfile()
+            import filecmp
+            if filecmp.cmp(infile, outfile):
+                print "import/export seem ok"
+            else:
+                print "import/export failed"
+            if remove == True:
+                os.remove(outfile)
+
+        print "creating new example:"
+        print " clear all"
+        v.clearlayer()
+        print " set new values"        
+        print "  setting new boundaries: n9, s0, e9, w0"
+        v.forcebounds( 9, 0, 9, 0 )
+        print "  setting new vectors: 0:5, 5:0, 9:5, 5:9, 5:5"
+        v.objects.append([0, 5, 0])
+        v.objects.append([5, 0, 1])
+        v.objects.append([9, 5, 2])
+        v.objects.append([5, 9, 3])
+        v.objects.append([5, 5, 4])
+        print " set:"
+        print "  south: " + str(v.offset[1])
+        print "  west: " + str(v.offset[0])
+        print "  north: " + str(v.limit[1])
+        print "  east: " + str(v.limit[0])
+        print " entries # " + str(len(v.objects))
+        for o in v.objects:
+            print "  obj is: x=" + str(o[0]) + " y=" + str(o[1]) + " cat=" + \
+                str(o[2])
+        print " set new values"
+        print "  setting new boundaries: n6, s4, e6, w4"
+        v.forcebounds( 6, 4, 6, 4 )
+        print " set:"
+        print "  south: " + str(v.offset[1])
+        print "  west: " + str(v.offset[0])
+        print "  north: " + str(v.limit[1])
+        print "  east: " + str(v.limit[0])
+        print " remaining entries # " + str(len(v.objects))
+        for o in v.objects:             
+            print "  obj is: x=" + str(o[0]) + " y=" + str(o[1]) + " cat=" + \
+                str(o[2])
+        print " again with the old boundaries: n9, s0, e9, w0"
+        v.forcebounds( 9, 0, 9, 0 )
+        for o in v.objects:
+            print "  obj is: x=" + str(o[0]) + " y=" + str(o[1]) + " cat=" + \
+                str(o[2])
+    else:
+        print "Error: no " + infile + " or " + outfile + " exists."
+

Added: grass-addons/grass7/grass7/raster/r.agent/libold/world.py
===================================================================
--- grass-addons/grass7/grass7/raster/r.agent/libold/world.py	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.agent/libold/world.py	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,128 @@
+############################################################################
+#
+# MODULE:       r.agent.*
+# AUTHOR(S):    michael lustenberger inofix.ch
+# PURPOSE:      library file for the r.agent.* suite
+# COPYRIGHT:    (C) 2011 by Michael Lustenberger and the GRASS Development Team
+#
+#               This program is free software under the GNU General Public
+#               License (>=v2). Read the file COPYING that comes with GRASS
+#               for details.
+#
+#############################################################################
+
+import error
+import agent
+import playground
+
+class World(object):
+    """meta class"""
+    def __init__(self, agenttype=None, pg=None):
+        if pg == None:
+            self.playground = playground.Playground()
+        else:
+            self.playground = pg
+        self.agentclass = agent.Agent
+        if agenttype == None:
+            self.agenttype = self.agentclass
+        else:
+            self.setagenttype(agenttype)
+        self.agents = []
+        self.artefacts = []
+    def importlayer(self, name, typename=None, filename=None):
+        if typename != None:
+            self.playground.setlayerfromfile(name, typename, filename)
+        elif filename != None:
+            self.playground.getlayer(name).setinfilename(filename)
+            self.playground.getlayer(name).importfile()
+        else:
+            self.playground.getlayer(name).importfile()
+        return self.playground.getlayer(name)
+    def createlayer(self, name, typename, infile=None, outfile=None):
+        self.playground.setnewlayer(name, typename, False)
+        if infile:
+            self.playground.getlayer(name).setinfilename(infile)
+        if outfile:
+            self.playground.getlayer(name).setoutfilename(outfile)
+        return self.playground.getlayer(name)
+    def exportlayer(self, name, typename=None, filename=None):
+        if filename == None:
+            self.playground.getlayer(name).exportfile()
+        elif typename == None:
+            self.playground.getlayer(name).setoutfilename(filename)
+        else:
+            if not self.playground.getlayer(name):
+                self.playground.setnewlayer(name, typename)
+            self.playground.getlayer(name).setoutfilename(filename)
+            self.playground.getlayer(name).exportfile()
+    def setagenttype(self, agenttype):
+        if issubclass(agenttype, self.agentclass):
+            self.agenttype = agenttype
+    def getagenttype(self):
+        return self.agenttype
+    def bear(self, agenttype=None, timetolife=0, position=[]):
+        if agenttype == None:
+            agenttype = self.agenttype
+        if issubclass(agenttype, self.agentclass):
+            self.agents.append(agenttype(timetolife, self, position))
+    def moveto(self, agent, position):
+        pass
+    def move(self, agent, nrofsteps, direction="random"):
+        pass
+#        print "moving " + self.agent + self.nrofsteps + \
+#            " steps towards " + self.direction
+#    def letwalk(self, agent, nrofsteps=1, direction="random"):
+#        position = agent.getposition()
+#        npositions = self.playground.getneighbourpositions("costs", position)
+        #agent.move()
+    def kill(self, agent):
+        self.agents.remove(agent)
+#    def build(self, artefact):
+#        self.artefacts.add(artefact)
+#    def place(self, artefact, position):
+#        pass
+#    def destroy(self, artefact):
+#        self.artefacts.remove(artefact)
+
+def test(inraster=None, outraster=None, invector=None):
+    """Test suite for World Class"""
+    print "creating world"
+    w = World()
+    print "playing with agents"
+    print " nothing changed.."
+    print "  Agenttype is:", w.getagenttype()
+    print " illegaly overwriting agent.."
+    w.agenttype = ""
+    print "  Agenttype is:", w.getagenttype()
+    print " set new agenttype.."
+    w.setagenttype(agent.Agent)
+    print "  Agenttype is:", w.getagenttype()
+    print "giving birth to some agents"
+    w.bear()
+    w.bear(agent.Agent)
+    print " Agentlist:", w.agents
+    print "killing an agent"
+    w.kill(w.agents[0])
+    print " Agentlist:", w.agents
+#??    w.build()..
+#??    w.moveto()..
+#??    w.move()..
+#??    w.place()..
+#??    w.letwalk()..
+#??    w.destroy()..
+    print "adding layers?"
+    if inraster:
+        print "  adding raster"
+        w.importlayer("raster", "raster", inraster)
+        print "  re-adding again in diffrent way"
+        w.createlayer("raster", "raster", inraster, inraster)
+        w.importlayer("raster")
+        print "  is set."
+        if outraster:
+            w.exportlayer("raster", "raster", outraster)
+            print "  exported to:", str(outraster), "- check and remove.."
+        if invector:
+            print "  adding vectors"
+            w.importlayer("vector", "vector", invector)
+            print "  is set."
+

Added: grass-addons/grass7/grass7/raster/r.agent/r.agent.aco
===================================================================
--- grass-addons/grass7/grass7/raster/r.agent/r.agent.aco	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.agent/r.agent.aco	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,269 @@
+#!/usr/bin/env python
+############################################################################
+#
+# MODULE:       r.agent.aco
+# AUTHOR(S):    michael lustenberger inofix.ch
+# PURPOSE:      r.agent.aco is used to organize ant-like agents in a raster
+#               based playground. As decribed by the Ant Colony Optimization
+#               algorithm, the ants wander around looking for attractors,
+#               marking their paths if they find any.
+# COPYRIGHT:    (C) 2011 by Michael Lustenberger and the GRASS Development Team
+#
+#               This program is free software under the GNU General Public
+#               License (>=v2). Read the file COPYING that comes with GRASS
+#               for details.
+#
+#############################################################################
+
+#%Module
+#% description: Creates a special kind of world, that follows the rules of ACO - with ant-like agents in it.
+#%End
+#%option
+#% key: outputmap
+#% type: string
+#% gisprompt: old,cell,raster
+#% description: Name of pheromone output map
+#% required : yes
+#%end
+#%option
+#% key: inputmap
+#% type: string
+#% gisprompt: old,cell,raster
+#% description: Name of input pheromone raster map (e.g. from prior run)
+#% required : no
+#%end
+#%flag
+#% key: overwrite
+#% description: Allow overwriting existing pheromone maps (e.g. if in == out)
+#%end
+#%flag
+#% key: overwritecosts
+#% description: Overwrite existing cost map (only used with penalty conversion)
+#%end
+#%option
+#% key: costmap
+#% type: string
+#% gisprompt: old,cell,raster
+#% description: Name of penalty resp. cost raster map (note conversion checkbox)
+#% required : yes
+#%end
+#%flag
+#% key: convert
+#% description: Convert cost (slope..) to penalty map (using "tobler", see docu)
+#%end
+#%option
+#% key: sitesmap
+#% type: string
+#% gisprompt: vector
+#% description: Name of sites map, vector data with possible points of origin
+#% required : yes
+#%end
+#%option
+#% key: rounds
+#% type: integer
+#% gisprompt: number
+#% description: Number of iterations/rounds to run
+#% answer: 999
+#% options: 0-999999
+#% required : yes
+#%end
+#%option
+#% key: outrounds
+#% type: integer
+#% gisprompt: number
+#% description: Produce output after running this number of iterations/rounds
+#% options: 0-999999
+#% required : no
+#%end
+#%option
+#% key: highcostlimit
+#% type: integer
+#% gisprompt: number
+#% description: Penalty values above this point an ant considers as illegal
+#% options: 0-<max integer on system would make sense>
+#% required : no
+#%end
+#%option                                                       
+#% key: lowcostlimit
+#% type: integer
+#% gisprompt: number
+#% description: Penalty values below this point an ant considers as illegal
+#% options: <min integer on system would make sense>-0
+#% required : no
+#%end
+#%option
+#% key: maxpheromone
+#% type: integer
+#% gisprompt: number
+#% description: Absolute maximum of pheromone intensity a position may have
+#% options: <minpheromone>-<max integer on system would make sense>
+#% required : no
+#%end
+#%option
+#% key: minpheromone
+#% type: integer
+#% gisprompt: number
+#% description: Absolute minimum of pheromone intensity to leave on playground
+#% options: 0-<maxpheromone>
+#% required : no
+#%end
+#%option
+#% key: volatilizationtime
+#% type: integer
+#% gisprompt: number
+#% description: Half-life for pheromone to volatize (e.g. =rounds)
+#% options: 0-<max integer on system would make sense>
+#% required : no
+#%end
+#%option
+#% key: stepintensity
+#% type: integer
+#% gisprompt: number
+#% description: Pheromone intensity to leave on each step
+#% options: 0-<max integer on system would make sense>
+#% required : no
+#%end
+#%option
+#% key: pathintensity
+#% type: integer
+#% gisprompt: number
+#% description: Pheromone intensity to leave on found paths
+#% options: 0-<max integer on system would make sense>
+#% required : no
+#%end
+#%option
+#% key: maxants
+#% type: integer
+#% gisprompt: number
+#% description: Maximum amount of ants that may live concurrently (x*y)
+#% options: 0-<the bigger the playground, the more space they have>
+#% required : no
+#%end
+#%option
+#% key: antslife
+#% type: integer
+#% gisprompt: number
+#% description: Time to live for an ant (e.g. four times points distance)
+#% options: 0-<max integer on system would make sense>
+#% required : no
+#%end
+#%option
+#% key: decisionalgorithm
+#% type: string
+#% gisprompt: algorithm
+#% description: Algorithm used for walking step
+#% answer: standard
+#% options: standard,random,test
+#% required : yes
+#%end
+#%option
+#% key: validposition
+#% type: string
+#% gisprompt: algorithm
+#% description: Algorithm used for finding and remembering paths
+#% answer: avoidorforgetloop
+#% options: specials,avoidloop,forgetloop,avoidorforgetloop
+#% required : yes
+#%end
+#%option
+#% key: agentfreedom
+#% type: integer
+#% gisprompt: number
+#% description: Number of possible directions the ant can take (4 or 8)
+#% options: 4,8
+#% required : no
+#%end
+#%option
+#% key: pheromoneweight
+#% type: integer
+#% gisprompt: number
+#% description: How is the pheromone value (P) weighted when walking (p*P:r*R:c*C)
+#% answer: 1
+#% options: 0-999
+#% required : yes
+#%end
+#%option
+#% key: randomnessweight
+#% type: integer
+#% gisprompt: number
+#% description: How is the random value (R) weighted when walking (p*P:r*R:c*C)
+#% answer: 1
+#% options: 0-999
+#% required : yes
+#%end
+#%option
+#% key: costweight
+#% type: integer
+#% gisprompt: number
+#% description: How is the penalty value (C) weighted when walking (p*P:r*R:c*C)
+#% answer: 0
+#% options: 0-999
+#% required : yes
+#%end
+
+import sys
+from grass.script import core as grass
+
+from libagent import error, aco
+
+def main():
+    world = aco.ACO()
+
+    layer = world.importlayer("costs", "raster", options['penaltymap'])
+    world.costsurface = layer.raster
+    world.playground.setboundsfromlayer("costs")
+
+    if options['inputmap']:
+        layer = world.importlayer("phero", "raster", options['inputmap'])
+        world.outfilename = options['outputmap']
+    else:
+        layer = world.createlayer("phero", "raster", None, options['outputmap'])
+        world.pherovapour = layer.raster
+
+    layer = world.importlayer("holes", "vector", options['sitesmap'])
+    world.holes = layer.objects
+
+    world.rounds = int(options['rounds'])
+    if options['outrounds']:
+        world.outrounds = int(options['outrounds'])
+    if options['maxpheromone']:
+        world.maxpheromone = int(options['maxpheromone'])
+    if options['minpheromone']:
+        world.minpheromone = int(options['minpheromone'])
+    if options['volatilizationtime']:
+        world.volatilizationtime = int(options['volatilizationtime'])
+    if options['stepintensity']:
+        world.stepintensity = int(options['stepintensity'])
+    if options['pathintensity']:
+        world.pathintensity = int(options['pathintensity'])
+    if options['maxants']:
+        world.maxants = int(options['maxants'])
+    if options['antslife']:
+        world.antslife = int(options['antslife'])
+    if options['decisionalgorithm']:
+        world.decisionbase = str(options['decisionalgorithm'])
+    if options['validposition']:
+        world.validposition = str(options['validposition'])
+    if options['agentfreedom']:
+        world.globalfreedom = int(options['agentfreedom'])
+    if options['pheromoneweight']:
+        world.pheroweight = int(options['pheromoneweight'])
+    if options['randomnessweight']:
+        world.randomweight = int(options['randomnessweight'])
+    if options['costweight']:
+        world.costweight = int(options['costweight'])
+    #if arglist[0] == "stability":
+        #TODO ask silvia..
+    try:
+        world.checkvalues()
+        world.letantsdance()
+        print "FINISH"
+    except error.DataError:
+        print "Failed to parse args.."
+        sys.exit(1)
+
+
+if __name__ == "__main__":
+    options, flags = grass.parser()
+    main()
+


Property changes on: grass-addons/grass7/grass7/raster/r.agent/r.agent.aco
___________________________________________________________________
Added: svn:executable
   + 

Added: grass-addons/grass7/grass7/raster/r.agent/r.agent.html
===================================================================
--- grass-addons/grass7/grass7/raster/r.agent/r.agent.html	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.agent/r.agent.html	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,98 @@
+<h2>DESCRIPTION</h2>
+
+<em>r.agent</em> shall provide an inital base for organizing worlds
+with raster playgrounds and agents in.
+<p>
+As this is only a first implementation the encapsulation that grants
+a modular usage is still suffering..
+<p>
+<em>r.agent</em> is written in python for more transparency and
+better extendability.
+<p>
+As a first world example there is an ACO-based environment
+(see <a href="http://en.wikipedia.org/wiki/Ant_colony_optimization_algorithms">Ant Colony Optimization</a>)
+available (in <em>libold</em> see below..).
+<p>
+The basic concept of such an ACO world, is to take some cost surface
+and transform it to a penalty layer - where for human ants for example
+this penalty layer may be expressed by the walking velocity, e.g. calculated
+with the algorithm proposed by
+<a href="http://www.geodyssey.com/papers/tobler93.html">Tobler1993</a>.
+The actors on the playground will wander around on the playground
+using the time for their paths that correspond with the values in the penalty
+grid.
+If they find some attractor, they walk home to the position they
+originated, marking their way with pheromones. While this
+pheromone vanishes over time, the following agents are more likely
+to choose their next steps to a position that smells most.
+<p>
+This first toolset was mainly developed for
+<a href="http://www.topoi.org/group/a-iii-4/">Topoi Project A-III-4</a>,
+with some
+inspirations from previous work conducted at the
+<a href="http://www.unibe.ch/">Uni Bern</a> in 2008.
+
+
+<h2>NOTES</h2>
+
+The state of this software is: "first do it".
+This is work in progress and its structure will probably change quite a lot
+in the future due to a better integration in GRASS and other refactoring.
+<p>
+The refactoring causes <em>r.agent</em> to not work for the moment. The general
+behaviour can be seen by changeing the imports in <em>r.agent.aco</em>
+to the old library <em>libold</em> -- <em>libagent</em> is coming soon.
+<p>
+Unfortunately the colletion is not very well included in GRASS yet.
+At the moment <em>libold</em> only handles ASCII grid and vector in- and
+output data. With a better GRASS integration (arrays) not only will the code
+get lighter but also these drawbacks shall vanish.
+<p>
+ACO works best on dynamic maps -- it constantly tries to improve paths...
+
+
+<h2>EXAMPLE</h2>
+
+A fictive usecase could look something like this
+(note: at the moment the
+in- and output variables with <em>libold</em>, are still ascii-files):
+<p>
+<div class="code"><pre>
+r.agent.aco outputmap=out.map penaltymap=testpenalty.grid \
+  sitesmap=sites.vect rounds=100 outrounds=100 volatilizationtime=5000 \
+  antslife=2000 maxants=400 pathintensity=1000000
+</pre></div>
+<p>
+For running the total test suite on the libraries,
+i.e. to run all the tests that are at the end
+of each python file, use this test collection
+(for certain tests, the following files must exist though:
+ "elev.grid", and "arch.vect"):
+<p>
+<div class="code"><pre>
+user at host:~$ cd /<pathtoaddons>/r.agent/libagent
+
+user at host:libold$ ./alltests.py
+</pre></div>
+
+<h2>TODO</h2>
+
+Integrate it directly within grass.
+<p>
+Improve encapsulation of classes.
+<p>
+Find good parameters, or parameter finding strategies for the ACO part.
+Try to avoid high penalty fields.
+Think about heuristics too.
+<p>
+Implement other ABM scenarios.
+
+<h2>SEE ALSO</h2>
+
+<h2>AUTHORS</h2>
+
+Michael Lustenberger inofix.ch
+
+<p><i>Last changed: $Date: 2011-11-13 16:47:34 +0100 (Sun, 13 Nov 2011) $</i>
+
+

Added: grass-addons/grass7/grass7/raster/r.agent/r.agent.tests.py
===================================================================
--- grass-addons/grass7/grass7/raster/r.agent/r.agent.tests.py	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.agent/r.agent.tests.py	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,103 @@
+#!/usr/bin/env python
+############################################################################
+#
+# MODULE:       r.agent.aco
+# AUTHOR(S):    michael lustenberger inofix.ch
+# PURPOSE:      r.agent.aco is used to organize ant-like agents in a raster
+#               based playground. As decribed by the Ant Colony Optimization
+#               algorithm, the ants wander around looking for attractors,
+#               marking their paths if they find any.
+# COPYRIGHT:    (C) 2011 by Michael Lustenberger and the GRASS Development Team
+#
+#               This program is free software under the GNU General Public
+#               License (>=v2). Read the file COPYING that comes with GRASS
+#               for details.
+#
+#############################################################################
+
+def dotest(function, argv):
+    """Global wrapper for the individual test suits."""
+    while True:
+        n = function.func_doc
+        o = str(argv)
+        if not n:
+            n = str(function)
+        t = str(raw_input("execute this now: '"+n+" - "+o+"'? [y/n/abort] "))
+        if t == "y":
+            if argv != None:
+                function(*argv)
+            else:
+                function()
+            break
+        elif t == "n":
+            break
+        elif t == "abort":
+            exit()
+
+def testError(expr, msg):
+    """Test suite for Class: Error"""
+    try:
+        raise error.DataError(expr, msg)
+    except error.DataError:
+        print "catched! all fine."
+
+def testPlayground():
+    """Test suite for Class: Playground"""
+    pg = playground.Playground()
+    
+    print(pg.region)
+
+def testWorld():
+    """Test suite for Class: World"""
+    w = world.World()
+
+def testACO():
+    """Test suite for World-Class: ACO"""
+    w = aco.ACO()
+
+def testAgent(ttl):
+    """Test suite for Class: Agent"""
+    w = world.World()
+    w = agent.Agent(ttl, w)
+
+def testAnt(ttl, position):
+    """Test suite for Agent-Class: Ant"""
+    w = world.World()
+    w = ant.Ant(ttl, w, position)
+
+if __name__ == "__main__":
+    """Main method for testing when run as a script."""
+    import sys
+    import os
+
+    from libagent import error
+
+    if os.environ.get("GISBASE") == None:
+        raise error.EnvError("r.agent::TestSuite", "Please run inside GRASS.")
+
+    from libagent import playground
+    from libagent import world
+    from libagent import aco
+    from libagent import agent
+    from libagent import ant
+
+    alltests = {"error":[testError, ["Error Test Suite",
+                     "(this error is good)"]],
+                "playground":[testPlayground, []],
+                "world":[testWorld, []],
+                "aco":[testACO, []],
+                "Agent":[testAgent, [1]],
+                "Ant":[testAnt, [1, []]]}
+
+    if len(sys.argv) == 1:
+        for test,details in alltests.iteritems():
+            dotest(details[0], details[1])
+    else:
+        sys.argv.pop(0)
+        for t in sys.argv:
+            if t in alltests:
+                dotest(*alltests[t])
+            else:
+                print("Test does not exist: ", t)
+
+


Property changes on: grass-addons/grass7/grass7/raster/r.agent/r.agent.tests.py
___________________________________________________________________
Added: svn:executable
   + 

Added: grass-addons/grass7/grass7/raster/r.area/Makefile
===================================================================
--- grass-addons/grass7/grass7/raster/r.area/Makefile	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.area/Makefile	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,12 @@
+# fix this relative to include/
+# or use absolute path to the GRASS source code
+MODULE_TOPDIR = ../..
+
+PGM = r.area
+
+LIBES = $(RASTERLIB) $(GISLIB) $(MATHLIB)
+DEPENDENCIES = $(RASTERDEP) $(GISDEP)
+
+include $(MODULE_TOPDIR)/include/Make/Module.make
+
+default: cmd

Added: grass-addons/grass7/grass7/raster/r.area/main.c
===================================================================
--- grass-addons/grass7/grass7/raster/r.area/main.c	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.area/main.c	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,154 @@
+/* ***************************************************************************
+ *
+ * MODULE:       r.area
+ * AUTHOR(S):    Jarek Jasiewicz <jarekj amu.edu.pl>
+ * PURPOSE:      Calculate area of clumped areas. Remove areas smaller than
+ * 							 given treshold.
+ * 
+ * COPYRIGHT:    (C) 1999-2010 by the GRASS Development Team
+ *
+ *               This program is free software under the GNU General Public
+ *               License (>=v2). Read the file COPYING that comes with GRASS
+ *               for details.
+ *
+ ****************************************************************************
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <grass/gis.h>
+#include <grass/raster.h>
+#include <grass/glocale.h>
+
+int main(int argc, char *argv[])
+{
+
+	struct GModule *module;
+	struct Option *input,
+								*output,
+								*par_treshold;
+	struct Flag *flag_binary;							
+									
+	struct Cell_head cellhd;
+	struct Range range;
+  struct History history;
+
+	char *mapset;
+	int nrows, ncols;
+	int binary, treshold;
+	int row, col;
+	int infd, outfd;
+	CELL *in_buf;
+	CELL *out_buf;
+	CELL c_min, c_max;
+	int *ncells;
+	int i;
+	
+	G_gisinit(argv[0]);
+	
+	input = G_define_standard_option(G_OPT_R_INPUT);
+  input->description = _("Map created with r.clump");
+  
+  output = G_define_standard_option(G_OPT_R_OUTPUT);
+	output->description = _("Map with area size (in cells)");
+	
+	par_treshold = G_define_option();	/* input stream mask file - optional */
+  par_treshold->key = "treshold";
+  par_treshold->type = TYPE_INTEGER;
+  par_treshold->answer = "0";
+  par_treshold->description = _("Remove areas lower than (0 for none):");
+	
+	flag_binary=G_define_flag();
+	flag_binary->key = 'b';
+  flag_binary->description = _("Binary output");
+	
+
+	 	if (G_parser(argc, argv))
+	exit(EXIT_FAILURE);
+	
+	
+	treshold = atof(par_treshold->answer);
+	binary = (flag_binary->answer != 0);
+	mapset = (char*)G_find_raster2(input->answer, "");
+	
+	  if (mapset == NULL)
+	G_fatal_error(_("Raster map <%s> not found"), input->answer);
+	
+	infd = Rast_open_old(input->answer, mapset);
+	Rast_get_cellhd(input->answer, mapset, &cellhd);
+
+	
+		if (Rast_map_type(input->answer, mapset) != CELL_TYPE)
+	 G_fatal_error(_("<%s> is not of type CELL, probably not crated with r.clump"), input->answer);
+	 
+	Rast_init_range(&range);
+	Rast_read_range(input->answer,mapset,&range);
+	Rast_get_range_min_max(&range, &c_min, &c_max);
+	
+	in_buf = Rast_allocate_c_buf();
+	
+	nrows = Rast_window_rows();
+	ncols = Rast_window_cols();
+
+	ncells=G_calloc(c_max+1,sizeof(int));
+
+	G_message(_("Reading..."));
+	for (row = 0; row < nrows; row++) {
+		G_percent(row, nrows, 2);
+		Rast_get_row(infd, in_buf, row, CELL_TYPE);
+
+		for (col = 0; col < ncols; col++) {
+				if(!Rast_is_c_null_value(&in_buf[col])) {
+						if(in_buf[col]<c_min || in_buf[col] > c_max)
+					G_fatal_error(_("Value at row %d, col %d out of range: %d"),row,col,in_buf[col]);
+					ncells[in_buf[col]]++;
+				}
+		}
+	} /* end for row */
+	
+		if(treshold) {
+				for (i=1;i<c_max;++i)
+			if(ncells[i]<treshold)
+    ncells[i]=-1;
+		}
+		
+		if(binary) {
+				for (i=1;i<c_max;++i)
+			ncells[i]= ncells[i]<treshold ? -1 : 1;
+		}
+    
+	outfd = Rast_open_new(output->answer, CELL_TYPE);
+	out_buf = Rast_allocate_c_buf();
+
+  G_message(_("Writing..."));
+	for (row = 0; row < nrows; row++) {
+		G_percent(row, nrows, 2);
+				
+	Rast_get_row(infd, in_buf, row, CELL_TYPE);
+		
+		for (col = 0; col < ncols; col++) {
+				if(Rast_is_c_null_value(&in_buf[col]) || ncells[in_buf[col]]==-1)
+						if(binary)
+					out_buf[col]=0;
+						else
+					Rast_set_c_null_value(&out_buf[col],1);
+				else
+			out_buf[col] = ncells[in_buf[col]];
+		}
+		Rast_put_row(outfd, out_buf, CELL_TYPE);
+	} /* end for row */
+  
+  G_free(ncells);
+  G_free(in_buf);
+	Rast_close(infd);
+	G_free(out_buf);
+	Rast_close(outfd);
+
+	Rast_short_history(output->answer, "raster", &history);
+	Rast_command_history(&history);
+	Rast_write_history(output->answer, &history);
+	
+	G_message(_("Done!"));
+	exit(EXIT_SUCCESS);
+}

Added: grass-addons/grass7/grass7/raster/r.area/r.area.html
===================================================================
--- grass-addons/grass7/grass7/raster/r.area/r.area.html	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.area/r.area.html	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,26 @@
+<h2>OPTIONS</h2>
+<dl>
+<dt><b>input</b></dt>
+<dd>Name of input created with r.clump or another cell category map.</dd>
+<dt><b>treshold</b></dt>
+<dd>Remove areas smaller than treshold, set null for removing areas</dd>
+<dt><b>binary</b></dt>
+<dd>Output map has only 0 and 1 values. If treshold is applied small areas are emoved and replaced by 0</dd>
+<dt><b>output</b></dt>
+<dd>Original categories replaced with number of cells for each category. If areas belonging to category are not continuous every area belonging to the same category has the same area value.</dd>
+</dl>
+<h2>DESCRIPTION</h2>
+<p>module can be used to remove, areas smaller than treshold, reclass according areas (similar to r.reclass area, but work in cells, not hectares and allow create more classes)</p>
+
+<h2>SEE ALSO</h2>
+<em>
+<a href="r.clump.html">r.clump</a>,
+<a href="r.mapcalc.html">r.mapcalc</a>,
+<a href="r.reclass.area.html">r.reclass.area</a>
+</em>
+
+
+<h2>AUTHOR</h2>
+Jarek  Jasiewicz
+
+

Added: grass-addons/grass7/grass7/raster/r.clump2/Makefile
===================================================================
--- grass-addons/grass7/grass7/raster/r.clump2/Makefile	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.clump2/Makefile	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,10 @@
+MODULE_TOPDIR = ../..
+
+PGM = r.clump2
+
+LIBES = $(RASTERLIB) $(GISLIB)
+DEPENDENCIES = $(RASTERDEP) $(GISDEP)
+
+include $(MODULE_TOPDIR)/include/Make/Module.make
+
+default: cmd

Added: grass-addons/grass7/grass7/raster/r.clump2/flag.c
===================================================================
--- grass-addons/grass7/grass7/raster/r.clump2/flag.c	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.clump2/flag.c	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,68 @@
+#include <grass/gis.h>
+#include "flag.h"
+
+FLAG *flag_create(int nrows, int ncols)
+{
+    unsigned char *temp;
+    FLAG *new_flag;
+    register int i;
+
+    new_flag = (FLAG *) G_malloc(sizeof(FLAG));
+    new_flag->nrows = nrows;
+    new_flag->ncols = ncols;
+    new_flag->leng = (ncols + 7) / 8;
+    new_flag->array =
+	(unsigned char **)G_malloc(nrows * sizeof(unsigned char *));
+
+    temp =
+	(unsigned char *)G_malloc(nrows * new_flag->leng *
+				  sizeof(unsigned char));
+
+    for (i = 0; i < nrows; i++) {
+	new_flag->array[i] = temp;
+	temp += new_flag->leng;
+    }
+
+    return (new_flag);
+}
+
+int flag_destroy(FLAG * flags)
+{
+    G_free(flags->array[0]);
+    G_free(flags->array);
+    G_free(flags);
+
+    return 0;
+}
+
+int flag_set(FLAG * flags, int row, int col)
+{
+    flags->array[row][col >> 3] |= (1 << (col & 7));
+
+    return 0;
+}
+
+int flag_unset(FLAG * flags, int row, int col)
+{
+    flags->array[row][col >> 3] &= ~(1 << (col & 7));
+
+    return 0;
+}
+
+int flag_get(FLAG * flags, int row, int col)
+{
+    return (flags->array[row][col >> 3] & (1 << (col & 7)));
+}
+
+int flag_clear_all(FLAG * flags)
+{
+    register int r, c;
+
+    for (r = 0; r < flags->nrows; r++) {
+	for (c = 0; c < flags->leng; c++) {
+	    flags->array[r][c] = 0;
+	}
+    }
+
+    return 0;
+}

Added: grass-addons/grass7/grass7/raster/r.clump2/flag.h
===================================================================
--- grass-addons/grass7/grass7/raster/r.clump2/flag.h	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.clump2/flag.h	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,66 @@
+#ifndef __FLAG_H__
+#define __FLAG_H__
+
+/* flag.[ch] is a set of routines which will set up an array of bits
+ ** that allow the programmer to "flag" cells in a raster map.
+ **
+ ** FLAG *
+ ** flag_create(nrows,ncols)
+ ** int nrows, ncols;
+ **     opens the structure flag.  
+ **     The flag structure will be a two dimensional array of bits the
+ **     size of nrows by ncols.  Will initalize flags to zero (unset).
+ **
+ ** flag_destroy(flags)
+ ** FLAG *flags;
+ **     closes flags and gives the memory back to the system.
+ **
+ ** flag_clear_all(flags)
+ ** FLAG *flags;
+ **     sets all values in flags to zero.
+ **
+ ** flag_unset(flags, row, col)
+ ** FLAG *flags;
+ ** int row, col;
+ **     sets the value of (row, col) in flags to zero.
+ **
+ ** flag_set(flags, row, col)
+ ** FLAG *flags;
+ ** int row, col;
+ **     will set the value of (row, col) in flags to one.
+ **
+ ** int
+ ** flag_get(flags, row, col)
+ ** FLAG *flags;
+ ** int row, col;
+ **     returns the value in flags that is at (row, col).
+ **
+ ** idea by Michael Shapiro
+ ** code by Chuck Ehlschlaeger
+ ** April 03, 1989
+ */
+
+#define FLAG struct _flagsss_
+FLAG {
+    int nrows, ncols, leng;
+    unsigned char **array;
+};
+
+#define FLAG_UNSET(flags,row,col) \
+	(flags)->array[(row)][(col)>>3] &= ~(1<<((col) & 7))
+
+#define FLAG_SET(flags,row,col) \
+	(flags)->array[(row)][(col)>>3] |= (1<<((col) & 7))
+
+#define FLAG_GET(flags,row,col) \
+	(flags)->array[(row)][(col)>>3] & (1<<((col) & 7))
+
+/* flag.c */
+int flag_clear_all(FLAG *);
+FLAG *flag_create(int, int);
+int flag_destroy(FLAG *);
+int flag_get(FLAG *, int, int);
+int flag_set(FLAG *, int, int);
+int flag_unset(FLAG *, int, int);
+
+#endif /* __FLAG_H__ */

Added: grass-addons/grass7/grass7/raster/r.clump2/local_proto.h
===================================================================
--- grass-addons/grass7/grass7/raster/r.clump2/local_proto.h	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.clump2/local_proto.h	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,37 @@
+
+/****************************************************************************
+ *
+ * MODULE:       r.clump
+ *
+ * AUTHOR(S):    Michael Shapiro - CERL
+ *
+ * PURPOSE:      Recategorizes data in a raster map layer by grouping cells
+ *               that form physically discrete areas into unique categories.
+ *
+ * COPYRIGHT:    (C) 2006 by the GRASS Development Team
+ *
+ *               This program is free software under the GNU General Public
+ *               License (>=v2). Read the file COPYING that comes with GRASS
+ *               for details.
+ *
+ ***************************************************************************/
+
+#ifndef __LOCAL_PROTO_H__
+#define __LOCAL_PROTO_H__
+
+#include <grass/gis.h>
+#include <grass/raster.h>
+#include "flag.h"
+#include "ramseg.h"
+
+extern long pqsize;
+extern CELL *clump_id;
+
+/* pq.c */
+int init_pq(long);
+int free_pq(void);
+int add_pnt(long);
+long drop_pnt(void);
+
+
+#endif /* __LOCAL_PROTO_H__ */

Added: grass-addons/grass7/grass7/raster/r.clump2/main.c
===================================================================
--- grass-addons/grass7/grass7/raster/r.clump2/main.c	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.clump2/main.c	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,373 @@
+
+/****************************************************************************
+ *
+ * MODULE:       r.clump2
+ *
+ * AUTHOR(S):    Markus Metz
+ *
+ * PURPOSE:      Recategorizes data in a raster map layer by grouping cells
+ *		 that form physically discrete areas into unique categories.
+ *
+ * COPYRIGHT:    (C) 2009 by the GRASS Development Team
+ *
+ *               This program is free software under the GNU General Public
+ *               License (>=v2). Read the file COPYING that comes with GRASS
+ *               for details.
+ *
+ ***************************************************************************/
+
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+#include <math.h>
+#include "local_proto.h"
+#include <grass/glocale.h>
+
+CELL *clump_id;
+long pqsize;
+
+int main(int argc, char *argv[])
+{
+    struct Colors colr;
+    struct Range range;
+    CELL min, max;
+    int in_fd, out_fd;
+    char title[512];
+    char name[GNAME_MAX];
+    struct GModule *module;
+    struct Option *opt_in;
+    struct Option *opt_out;
+    struct Option *opt_title;
+    struct Option *opt_coord;
+    struct Flag *flag_sides;
+    CELL clump_no, *out_buf;
+    struct Cell_head window, cellhd;
+    int nrows, ncols, r, c;
+    long ncells, counter;
+    void *in_ptr, *in_buf;
+    int map_type, in_size;
+    FLAG *inlist;
+    long ramseg;
+    long index, index_nbr;
+    int sides, s, r_nbr, c_nbr, have_seeds = 0, *id_map = NULL;
+    int nextdr[8] = { 1, -1, 0, 0, -1, 1, 1, -1 };
+    int nextdc[8] = { 0, 0, -1, 1, 1, -1, 1, -1 };
+
+    G_gisinit(argv[0]);
+
+    /* Define the different options */
+
+    module = G_define_module();
+    G_add_keyword(_("raster"));
+    G_add_keyword(_("statistics"));
+    G_add_keyword(_("reclass"));
+    module->description =
+	_("Recategorizes data in a raster map by grouping cells "
+	  "that form physically discrete areas into unique categories.");
+
+    opt_in = G_define_standard_option(G_OPT_R_INPUT);
+
+    opt_out = G_define_standard_option(G_OPT_R_OUTPUT);
+
+    opt_title = G_define_option();
+    opt_title->key = "title";
+    opt_title->type = TYPE_STRING;
+    opt_title->required = NO;
+    opt_title->description = _("Title");
+    
+    opt_coord = G_define_option();
+    opt_coord->key = "coordinate";
+    opt_coord->type = TYPE_STRING;
+    opt_coord->key_desc = "x,y";
+    opt_coord->multiple = YES;
+    opt_coord->description =
+	_("Map grid coordinates of starting points (E,N)");
+
+    flag_sides = G_define_flag();
+    flag_sides->key = 'e';
+    flag_sides->description = _("Ignore diagonal cells");
+
+    /* parse options */
+    if (G_parser(argc, argv))
+	exit(EXIT_FAILURE);
+
+    in_fd = Rast_open_old(opt_in->answer, "");
+    if (in_fd < 0)
+	G_fatal_error(_("Unable to open raster map <%s>"), opt_in->answer);
+
+    out_fd = Rast_open_c_new(opt_out->answer);
+    if (out_fd < 0)
+	G_fatal_error(_("Unable to create raster map <%s>"), opt_out->answer);
+
+    if (flag_sides->answer)
+	sides = 4;
+    else
+	sides = 8;
+
+    /* some checks */
+    G_get_set_window(&window);
+    Rast_get_cellhd(opt_in->answer, "", &cellhd);
+
+    if (fabs(window.ew_res - cellhd.ew_res) > GRASS_EPSILON ||
+	fabs(window.ns_res - cellhd.ns_res) > GRASS_EPSILON) {
+	G_warning(_("Current region resolution and raster map resolution mismatch!"));
+	G_warning(_("Real clumps may not be presented"));
+	G_warning("ew diff %e", window.ew_res - cellhd.ew_res);
+	G_warning("ns diff %e", window.ns_res - cellhd.ns_res);
+    }
+
+    nrows = window.rows;
+    ncols = window.cols;
+    
+    {
+	long mem;
+	
+	mem = (long) nrows * ncols * sizeof(CELL) + nrows * ((ncols + 7) / 8) * sizeof(unsigned char);
+	
+	if (mem < 1024)
+	    G_verbose_message(_("Will need %ld bytes of memory"), mem);
+	else {
+	    if (mem / 1024 < 1024)
+		G_verbose_message(_("Will need %.2f KB of memory"), (double) mem / 1024);
+	    else {
+		mem /= 1024;
+		if (mem / 1024 < 1024)
+		    G_verbose_message(_("Will need %.2f MB of memory"), (double) mem / 1024);
+		else {
+		    mem /= 1024;
+		    G_verbose_message(_("Will need %.2f GB of memory"), (double) mem / 1024);
+		}
+	    }
+	}
+    }
+
+    if ((double)nrows * ncols > LONG_MAX)
+	G_fatal_error(_("Current region is too large, can't process raster map <%s>"),
+		      opt_in->answer);
+
+    /* allocate space */
+    clump_id =
+	(CELL *) G_malloc(size_array(&ramseg, nrows, ncols) * sizeof(CELL));
+
+    /* read input */
+    map_type = Rast_get_map_type(in_fd);
+    in_size = Rast_cell_size(map_type);
+    in_buf = Rast_allocate_buf(map_type);
+
+    inlist = flag_create(nrows, ncols);
+
+    G_message(_("Loading input map ..."));
+    for (r = 0; r < nrows; r++) {
+	Rast_get_row(in_fd, in_buf, r, map_type);
+	in_ptr = in_buf;
+	G_percent(r, nrows, 2);
+	for (c = 0; c < ncols; c++) {
+	    index = SEG_INDEX(ramseg, r, c);
+	    if (Rast_is_null_value(in_ptr, map_type))
+		clump_id[index] = 0;
+	    else
+		clump_id[index] = 1;
+
+	    FLAG_UNSET(inlist, r, c);
+
+	    in_ptr = G_incr_void_ptr(in_ptr, in_size);
+	}
+    }
+    G_percent(nrows, nrows, 2);
+
+    Rast_close(in_fd);
+    G_free(in_buf);
+
+    ncells = nrows * ncols;
+    counter = 1;
+
+    /* initialize priority queue */
+    init_pq(nrows * ncols * 0.02);
+
+    clump_no = 1;
+    if (opt_coord->answers) {
+	int col, row, i;
+	double east, north;
+	char **answers = opt_coord->answers;
+	struct Cell_head window;
+	
+	/* get start point coordinates */
+	G_message(_("Get start point coordinates ..."));
+
+	G_get_window(&window);
+	
+	for (; *answers != NULL; answers += 2) {
+	    if (!G_scan_easting(*answers, &east, G_projection()))
+		G_fatal_error(_("Illegal x coordinate <%s>"), *answers);
+	    if (*(answers + 1) == NULL)
+		G_fatal_error(_("Missing y corrdinate"));
+	    if (!G_scan_northing(*(answers + 1), &north, G_projection()))
+		G_fatal_error(_("Illegal y coordinate <%s>"), *(answers + 1));
+
+	    if (east < window.west || east > window.east ||
+		north < window.south || north > window.north) {
+		G_warning(_("Warning, ignoring point outside window: %.4f,%.4f"),
+			  east, north);
+		continue;
+	    }
+	    row = (window.north - north) / window.ns_res;
+	    col = (east - window.west) / window.ew_res;
+	    
+	    index = SEG_INDEX(ramseg, row, col);
+	    if (clump_id[index] != 0) {
+		/* add seed points with decreasing clump ID: first point will seed first clump */
+		clump_id[index] = clump_no++;
+		add_pnt(index);
+		FLAG_SET(inlist, row, col);
+		have_seeds = 1;
+	    }
+	}
+
+	id_map = G_malloc(clump_no * sizeof(int));
+	for (i = 0; i < clump_no; i++)
+	    id_map[i] = i;
+
+	if (!have_seeds)
+	    G_fatal_error(_("All start coordinates fall into NULL (nodata) areas"));
+    }
+    else {
+	index = SEG_INDEX(ramseg, 0, 0);
+	if (clump_id[index] != 0)
+	    clump_id[index] = clump_no++;
+	add_pnt(index);
+	FLAG_SET(inlist, 0, 0);
+    }
+
+    /* determine clumps */
+    G_message(_("Determine clumps ..."));
+
+    int perc = -1, lastperc;
+    while (pqsize > 0) {
+	int start_new = 1;
+
+	lastperc = perc;
+	perc = (double) (counter++ / (double)ncells) * 1000000;
+	if (perc > lastperc && perc < 1000000)
+	    G_percent(perc, 1000000, 2);
+
+	index = drop_pnt();
+	seg_index_rc(ramseg, index, &r, &c);
+
+	for (s = 0; s < sides; s++) {
+	    r_nbr = r + nextdr[s];
+	    c_nbr = c + nextdc[s];
+	    if (r_nbr >= 0 && r_nbr < nrows && c_nbr >= 0 && c_nbr < ncols) {
+
+		if ((FLAG_GET(inlist, r_nbr, c_nbr)) == 0) {
+
+		    index_nbr = SEG_INDEX(ramseg, r_nbr, c_nbr);
+
+		    /* not in clump, start new clump */
+		    if (clump_id[index] == 0 && clump_id[index_nbr] != 0) {
+			/* skip other neighbors of same or other clump */
+			if (start_new) {
+			    clump_id[index_nbr] = clump_no++;
+			    add_pnt(index_nbr);
+			    FLAG_SET(inlist, r_nbr, c_nbr);
+			    start_new = 0;
+			}
+		    }
+		    else if (clump_id[index] == 0 && clump_id[index_nbr] == 0) {
+			if (!have_seeds) {
+			    add_pnt(index_nbr);
+			    FLAG_SET(inlist, r_nbr, c_nbr);
+			}
+		    }
+		    else if (clump_id[index] != 0) {
+			if (clump_id[index_nbr] != 0)
+			    clump_id[index_nbr] = clump_id[index];
+
+			if (!have_seeds ||
+			    (have_seeds && clump_id[index_nbr] != 0)) {
+			    add_pnt(index_nbr);
+			    FLAG_SET(inlist, r_nbr, c_nbr);
+			}
+		    }
+		}
+		else if (have_seeds) {
+		    /* safety check */
+		    index_nbr = SEG_INDEX(ramseg, r_nbr, c_nbr);
+		    if (clump_id[index] != clump_id[index_nbr]) {
+			G_warning(_("%d. and %d. start point are in the same clump, ignoring %d. start point"),
+			          clump_id[index], clump_id[index_nbr], clump_id[index_nbr]);
+			id_map[clump_id[index_nbr]] = clump_id[index];
+			clump_id[index_nbr] = clump_id[index];
+		    }
+		}
+	    }
+	}
+    }
+    free_pq();
+
+    if (counter < ncells) {
+	if (!have_seeds)
+	    G_warning("Missed some cells!");
+	else
+	    G_percent(1, 1, 1);
+    }
+    else if ((double) ((double)counter++ / ncells) * 1000000 < 1000000)
+	G_percent(1, 1, 1);
+    
+    if (have_seeds && clump_no > 1) {
+	int i;
+	
+	for (i = 1; i < clump_no; i++) {
+	    if (id_map[i] - id_map[i - 1] > 1)
+		id_map[i] = id_map[i - 1] + 1;
+	}
+    }
+    
+    /* write output */
+    G_message(_("Write output map ..."));
+    out_buf = Rast_allocate_buf(CELL_TYPE);
+    for (r = 0; r < nrows; r++) {
+	G_percent(r, nrows, 2);
+	for (c = 0; c < ncols; c++) {
+	    index = SEG_INDEX(ramseg, r, c);
+	    if (have_seeds) {
+		if ((FLAG_GET(inlist, r, c)) == 0) {
+		    clump_id[index] = 0;
+		}
+		else
+		    clump_id[index] = id_map[clump_id[index]];
+	    }
+	    if (clump_id[index] == 0)
+		Rast_set_c_null_value(&out_buf[c], 1);
+	    else
+		out_buf[c] = clump_id[index];
+
+	}
+	Rast_put_row(out_fd, out_buf, CELL_TYPE);
+    }
+    G_percent(nrows, nrows, 2);
+    G_free(out_buf);
+    Rast_close(out_fd);
+    G_free(clump_id);
+    flag_destroy(inlist);
+    if (id_map)
+	G_free(id_map);
+
+
+    G_debug(1, "Creating support files...");
+
+    /* build title */
+    if (opt_title->answer != NULL)
+	strcpy(title, opt_title->answer);
+    else
+	sprintf(title, "clump of <%s@%s>", name, G_mapset());
+
+    Rast_put_cell_title(opt_out->answer, title);
+    Rast_read_range(opt_out->answer, G_mapset(), &range);
+    Rast_get_range_min_max(&range, &min, &max);
+    Rast_make_random_colors(&colr, min, max);
+    Rast_write_colors(opt_out->answer, G_mapset(), &colr);
+
+    G_done_msg(_("%d clumps."), range.max);
+
+    exit(EXIT_SUCCESS);
+}

Added: grass-addons/grass7/grass7/raster/r.clump2/pq.c
===================================================================
--- grass-addons/grass7/grass7/raster/r.clump2/pq.c	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.clump2/pq.c	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,157 @@
+
+/****************************************************************************
+ *
+ * MODULE:       r.clump2
+ *
+ * AUTHOR(S):    Markus Metz
+ *
+ * PURPOSE:      Recategorizes data in a raster map layer by grouping cells
+ *		 that form physically discrete areas into unique categories.
+ *
+ * COPYRIGHT:    (C) 2009 by the GRASS Development Team
+ *
+ *               This program is free software under the GNU General Public
+ *               License (>=v2). Read the file COPYING that comes with GRASS
+ *               for details.
+ *
+ ***************************************************************************/
+
+#include <stdlib.h>
+#include <grass/glocale.h>
+#include "local_proto.h"
+
+#define GET_PARENT(c) (int) (((c) - 2) / 3 + 1)
+#define GET_CHILD(p) (int) (((p) * 3) - 1)
+
+static int heap_alloced = 0;
+static long heap_step;
+static long *heap_index;
+
+int cmp_clump(long cid1, long cid2)
+{
+    if (!cid1)
+	return 0;
+    if (!cid2)
+	return 1;
+    return (cid1 < cid2);
+}
+
+int init_pq(long step)
+{
+    pqsize = 0;
+    if (step < 100)
+	step = 100;
+
+    heap_alloced = heap_step = step;
+    heap_index = (long *)G_malloc(heap_alloced * sizeof(long));
+
+    return 0;
+}
+
+int free_pq(void)
+{
+    if (heap_alloced)
+	G_free(heap_index);
+
+    return 0;
+}
+
+long sift_up(long start, long child_pnt)
+{
+    register long parent, child;
+
+    child = start;
+
+    while (child > 1) {
+	parent = GET_PARENT(child);
+
+	/* child is larger */
+	if (cmp_clump(clump_id[child_pnt], clump_id[heap_index[parent]])) {
+	    /* push parent point down */
+	    heap_index[child] = heap_index[parent];
+	    child = parent;
+	}
+	else
+	    /* no more sifting up, found new slot for child */
+	    break;
+    }
+
+    /* put point in new slot */
+    if (child < start) {
+	heap_index[child] = child_pnt;
+    }
+
+    return child;
+}
+
+int add_pnt(long index)
+{
+    pqsize++;
+    if (pqsize >= heap_alloced) {
+	heap_alloced += heap_step;
+	heap_index =
+	    (long *)G_realloc((void *)heap_index,
+			      heap_alloced * sizeof(long));
+    }
+
+    heap_index[pqsize] = index;
+    sift_up(pqsize, index);
+
+    return 0;
+}
+
+long drop_pnt(void)
+{
+    register long parent, child, childr, i;
+    long next_index;
+
+    if (pqsize == 0)
+	return -1;
+
+    next_index = heap_index[1];
+
+    if (pqsize == 1) {
+	pqsize--;
+
+	heap_index[1] = -1;
+
+	return next_index;
+    }
+
+    /* start with root */
+    parent = 1;
+
+    /* sift down: move hole back towards bottom of heap */
+
+    while ((child = GET_CHILD(parent)) <= pqsize) {
+	if (child < pqsize) {
+	    childr = child + 1;
+	    i = child + 3;
+	    /* get largest child */
+	    while (childr < i && childr <= pqsize) {
+		if (cmp_clump(clump_id[heap_index[childr]], 
+		    clump_id[heap_index[child]])) {
+		    child = childr;
+		}
+		childr++;
+	    }
+	}
+
+	/* move hole down */
+	heap_index[parent] = heap_index[child];
+	parent = child;
+    }
+
+    /* hole is in lowest layer, move to heap end */
+    if (parent < pqsize) {
+	heap_index[parent] = heap_index[pqsize];
+
+	/* sift up last swapped point, only necessary if hole moved to heap end */
+	sift_up(parent, heap_index[parent]);
+    }
+
+    /* the actual drop */
+    pqsize--;
+
+    return next_index;
+}

Added: grass-addons/grass7/grass7/raster/r.clump2/r.clump2.html
===================================================================
--- grass-addons/grass7/grass7/raster/r.clump2/r.clump2.html	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.clump2/r.clump2.html	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,49 @@
+<h2>DESCRIPTION</h2>
+
+<em>r.clump2</em> finds all areas of contiguous cell category values in the
+input raster map layer <em>name.</em> It assigns a unique category value
+to each such area ("clump") in the resulting output raster map layer
+<em>name.</em> Optionally <em>r.clump2</em> uses start points and finds
+only those clumps where the start points are falling into.
+
+<h4>Differences to r.clump</h4>
+
+Category distinctions in the input raster map layer are NOT preserved.
+This means that if distinct category values are adjacent, they will be
+clumped together if possible.
+<p>
+Contrary to r.clump, NULL cells are ignored and not clumped.
+<p>
+<em>r.clump2</em> also consideres diagonal cells. <em>r.clump2</em> can
+be forced to consider only edge cells with the <em>e</em> flag, diagonal
+cells are now ignored.
+<p>
+Linear elements (lines that are a single cell wide) are without the
+<em>e</em> flag always clumped together.
+<p> 
+
+
+<h2>NOTES</h2>
+
+A random color table and other support files are
+generated for the <em>output</em> raster map layer.
+
+<h2>SEE ALSO</h2>
+
+<em><a href="r.clump.html">r.clump</a></em><br>
+<em><a href="r.average.html">r.average</a></em><br>
+<em><a href="r.buffer.html">r.buffer</a></em><br>
+<em><a href="r.grow.html">r.grow</a></em><br>
+<em><a href="r.mapcalc.html">r.mapcalc</a></em><br>
+<em><a href="r.mfilter.html">r.mfilter</a></em><br>
+<em><a href="r.neighbors.html">r.neighbors</a></em><br>
+<em><a href="r.to.vect.html">r.to.vect</a></em><br>
+<em><a href="r.reclass.html">r.reclass</a></em><br>
+<em><a href="r.statistics.html">r.statistics</a></em><br>
+<em><a href="r.support.html">r.support</a></em>
+
+<h2>AUTHOR</h2>
+
+Markus Metz
+
+<p><i>Last changed: $Date: 2011-05-09 14:44:59 +0200 (Mon, 09 May 2011) $</i>

Added: grass-addons/grass7/grass7/raster/r.clump2/ramseg.c
===================================================================
--- grass-addons/grass7/grass7/raster/r.clump2/ramseg.c	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.clump2/ramseg.c	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,50 @@
+#include <stdio.h>
+#include "ramseg.h"
+
+#ifdef LARGE_MAPS
+
+long size_array(long *ramseg, int nrows, int ncols)
+{
+    *ramseg = (long)ncols;
+    
+    return ((long) nrows * ncols);
+}
+
+/* get r, c from seg_index */
+long seg_index_rc(long ramseg, long seg_index, int *r, int *c)
+{
+    *r = seg_index / ramseg;
+    *c = seg_index - *r * ramseg;
+    
+    return 0;
+}
+
+#else
+
+long size_array(long *ramseg, int nrows, int ncols)
+{
+    long size, segs_in_col;
+
+    segs_in_col = ((nrows - 1) >> RAMSEGBITS) + 1;
+    *ramseg = ((ncols - 1) >> RAMSEGBITS) + 1;
+    size = ((((nrows - 1) >> RAMSEGBITS) + 1) << RAMSEGBITS) *
+	((((ncols - 1) >> RAMSEGBITS) + 1) << RAMSEGBITS);
+    size -= ((segs_in_col << RAMSEGBITS) - nrows) << RAMSEGBITS;
+    size -= (*ram_seg << RAMSEGBITS) - ncols;
+    return (size);
+}
+
+/* get r, c from seg_index */
+long seg_index_rc(long ramseg, long seg_index, int *r, int *c)
+{
+    long seg_no, seg_remainder;
+
+    seg_no = seg_index >> DOUBLEBITS;
+    seg_remainder = seg_index - (seg_no << DOUBLEBITS);
+    *r = ((seg_no / ramseg) << RAMSEGBITS) + (seg_remainder >> RAMSEGBITS);
+    *c = ((seg_no - ((*r) >> RAMSEGBITS) * ramseg) << RAMSEGBITS) +
+	seg_remainder - (((*r) & SEGLENLESS) << RAMSEGBITS);
+    return seg_no;
+}
+
+#endif

Added: grass-addons/grass7/grass7/raster/r.clump2/ramseg.h
===================================================================
--- grass-addons/grass7/grass7/raster/r.clump2/ramseg.h	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.clump2/ramseg.h	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,27 @@
+#ifndef __RAMSEG_H__
+#define __RAMSEG_H__
+
+
+#define RAMSEG		long
+#define RAMSEGBITS 	4
+#define DOUBLEBITS 	8	/* 2 * ramsegbits       */
+#define SEGLENLESS 	15	/* 2 ^ ramsegbits - 1   */
+
+#define LARGE_MAPS 1
+
+#ifdef LARGE_MAPS
+
+#define SEG_INDEX(s,r,c) (long) ((r) * (s) + (c))
+
+#else
+
+#define SEG_INDEX(s,r,c) (long) \
+   (((((r) >> RAMSEGBITS) * (s) + ((c) >> RAMSEGBITS)) << DOUBLEBITS) \
+    + (((r) & SEGLENLESS) << RAMSEGBITS) + ((c) & SEGLENLESS))
+    
+#endif
+
+long size_array(long *, int, int);
+long seg_index_rc(long, long, int *, int *);
+
+#endif /* __RAMSEG_H__ */

Added: grass-addons/grass7/grass7/raster/r.convergence/Makefile
===================================================================
--- grass-addons/grass7/grass7/raster/r.convergence/Makefile	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.convergence/Makefile	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,10 @@
+MODULE_TOPDIR = ../..
+
+PGM = r.convergence
+
+LIBES = $(RASTERLIB) $(GISLIB) $(MATHLIB)
+DEPENDENCIES = $(RASTERDEP) $(GISDEP)
+
+include $(MODULE_TOPDIR)/include/Make/Module.make
+
+default: cmd

Added: grass-addons/grass7/grass7/raster/r.convergence/conv.png
===================================================================
(Binary files differ)


Property changes on: grass-addons/grass7/grass7/raster/r.convergence/conv.png
___________________________________________________________________
Added: svn:mime-type
   + application/octet-stream

Added: grass-addons/grass7/grass7/raster/r.convergence/local_proto.h
===================================================================
--- grass-addons/grass7/grass7/raster/r.convergence/local_proto.h	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.convergence/local_proto.h	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,87 @@
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include <grass/glocale.h>
+#include <grass/gis.h>
+#include <grass/raster.h>
+
+#ifdef MAIN
+#define GLOBAL
+#else
+#define GLOBAL extern
+#endif
+
+/*
+   PI2= PI/2
+   PI4= PI/4
+   M2PI=2*PI
+ */
+#ifndef PI2
+#define PI2 (2*atan(1))
+#endif
+
+#ifndef PI4
+#define PI4 (atan(1))
+#endif
+
+#ifndef PI
+#define PI (4*atan(1))
+#endif
+
+#ifndef M2PI
+#define M2PI (8*atan(1))
+#endif
+
+#ifndef PI2PERCENT
+#define PI2PERCENT (50/atan(1))
+#endif
+
+
+#define MAX(a,b) ((a) > (b) ? (a) : (b))
+#define MIN(a,b) ((a) < (b) ? (a) : (b))
+#define DEGREE2RAD(a) ((a)/(180/PI))
+#define RAD2DEGREE(a) ((a)*(180/PI))
+
+
+typedef char *STRING;
+typedef enum
+{
+    m_STANDARD,
+    m_INVERSE,
+    m_POWER,
+    m_SQUARE,
+    m_GENTLE
+} methods;
+
+typedef struct
+{
+    char elevname[150];
+    RASTER_MAP_TYPE raster_type;
+    FCELL **elev;
+    int fd;			/* file descriptor */
+} MAPS;
+
+typedef struct
+{
+    double cat;
+int r, g, b} FCOLORS;
+
+GLOBAL int gradient, f_circular, f_slope, f_method, window_size, radius;
+GLOBAL float *aspect_matrix, *distance_matrix;
+GLOBAL MAPS elevation;
+GLOBAL FCELL **slope;
+GLOBAL FCELL **aspect;
+
+GLOBAL int nrows, ncols;
+GLOBAL double H, V;
+GLOBAL struct Cell_head window;
+
+int open_map(MAPS * rast);
+int create_maps(void);
+int shift_buffers(int row);
+int get_cell(int col, float *buf_row, void *buf, RASTER_MAP_TYPE raster_type);
+int get_slope_aspect(int row);
+int get_distance(int once, int row);
+int create_distance_aspect_matrix(int row);
+float calculate_convergence(int row, int cur_row, int col);
+int free_map(FCELL ** map, int n);

Added: grass-addons/grass7/grass7/raster/r.convergence/main.c
===================================================================
--- grass-addons/grass7/grass7/raster/r.convergence/main.c	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.convergence/main.c	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,197 @@
+
+/****************************************************************************
+ *
+ * MODULE:			 r.convergence
+ * AUTHOR(S):		Jarek Jasiewicz jarekj amu.edu.pl
+ * 							Original convergence index in SAGA GIS sofware: Olaf Conrad
+ *							 
+ * PURPOSE:			Calculate convergence index (parameter defining the local convergence of the relief)
+*								
+*
+* COPYRIGHT:		 (C) 2002,2010 by the GRASS Development Team
+*
+*								 This program is free software under the GNU General Public
+*								 License (>=v2). Read the file COPYING that comes with GRASS
+*								 for details.
+*
+ *****************************************************************************/
+
+#define MAIN
+#include "local_proto.h"
+
+int main(int argc, char **argv)
+{
+    struct Option *map_dem,
+	*map_slope,
+	*map_aspect, *par_window, *par_method, *par_differnce, *map_output;
+
+    struct History history;
+    struct Colors colors;
+    struct Flag *flag_slope, *flag_circular;
+
+    int out_fd;
+    float tmp;
+    FCELL *out_buf;
+
+    int i, j, n;
+
+    G_gisinit(argv[0]);
+
+    map_dem = G_define_standard_option(G_OPT_R_INPUT);
+    map_dem->description = _("Digital elevation model map");
+
+    map_output = G_define_standard_option(G_OPT_R_OUTPUT);
+    map_output->description = _("Output convergence index map");
+
+    par_window = G_define_option();
+    par_window->key = "window";
+    par_window->type = TYPE_INTEGER;
+    par_window->answer = "3";
+    par_window->required = YES;
+    par_window->description = _("Window size");
+
+    par_method = G_define_option();
+    par_method->key = "weights";
+    par_method->type = TYPE_STRING;
+    par_method->options = "standard,inverse,power,square,gentle";
+    par_method->answer = "standard";
+    par_method->required = YES;
+    par_method->description =
+	_("Method for reducing the impact of the cell due to distance");
+
+    flag_circular = G_define_flag();
+    flag_circular->key = 'c';
+    flag_circular->description = _("Use circular window (default: square)");
+
+    flag_slope = G_define_flag();
+    flag_slope->key = 's';
+    flag_slope->description =
+	_("Add slope convergence (radically slow down calculation time)");
+
+    if (G_parser(argc, argv))
+	exit(EXIT_FAILURE);
+
+    window_size = atoi(par_window->answer);
+    if (window_size < 3 || window_size % 2 == 0)
+	G_fatal_error(_("Window size must be odd and at least 3"));
+
+    if (!strcmp(par_method->answer, "standard"))
+	f_method = m_STANDARD;
+    else if (!strcmp(par_method->answer, "inverse"))
+	f_method = m_INVERSE;
+    else if (!strcmp(par_method->answer, "power"))
+	f_method = m_POWER;
+    else if (!strcmp(par_method->answer, "square"))
+	f_method = m_SQUARE;
+    else if (!strcmp(par_method->answer, "gentle"))
+	f_method = m_GENTLE;
+
+    f_circular = (flag_circular->answer != 0);
+    f_slope = (flag_slope->answer != 0);
+
+    /* align window */
+    G_check_input_output_name(map_dem->answer, map_output->answer,
+			      G_FATAL_EXIT);
+    nrows = Rast_window_rows();
+    ncols = Rast_window_cols();
+    Rast_get_window(&window);
+    radius = window_size / 2;
+
+
+    {
+	int row, col;
+	int cur_row;
+	int i_row, i_col, j_row, j_col;
+	float contr_aspect;
+	float dir;
+	int n = 0;
+	float *local_aspect;
+	float convergence;
+
+	out_fd = Rast_open_new(map_output->answer, FCELL_TYPE);
+	out_buf = Rast_allocate_buf(FCELL_TYPE);
+
+	strcpy(elevation.elevname, map_dem->answer);
+	open_map(&elevation);
+	create_maps();
+
+	/* create aspect matrix and distance_matrix */
+	create_distance_aspect_matrix(0);
+
+	/* cur_row: current to row in the buffer */
+	/* open_map and create_maps create data for first pass */
+
+
+	for (row = 0; row < nrows; ++row) {
+	    G_percent(row, nrows, 2);
+	    cur_row = (row < radius) ? row :
+		((row >=
+		  nrows - radius) ? window_size - (nrows - row) : radius);
+
+	    if (row < radius || row > nrows - radius) {
+		Rast_set_f_null_value(out_buf, ncols);
+		Rast_put_row(out_fd, out_buf, FCELL_TYPE);
+		continue;
+	    }
+
+	    for (col = 0; col < ncols; ++col) {
+		if (col < radius || col > ncols - radius) {
+		    Rast_set_f_null_value(&out_buf[col], 1);
+		    continue;
+		}
+		out_buf[col] =
+		    PI2PERCENT * calculate_convergence(row, cur_row, col);
+	    }
+
+	    if (row > radius && row < nrows - (radius + 1))
+		shift_buffers(row);
+
+	    Rast_put_row(out_fd, out_buf, FCELL_TYPE);
+
+	}			/* end for row */
+	G_percent(row, nrows, 2);
+    }				/* end block */
+
+    {
+	FCOLORS fcolr[7] = {
+	    {-100, 56, 0, 0}
+	    ,
+	    {-70, 128, 0, 0}
+	    ,
+	    {-50, 255, 0, 0}
+	    ,
+	    {0, 255, 255, 255}
+	    ,
+	    {50, 0, 0, 255}
+	    ,
+	    {70, 0, 0, 128}
+	    ,
+	    {100, 0, 0, 56}
+	};
+
+	Rast_init_colors(&colors);
+	for (i = 0; i < 6; ++i)
+	    Rast_add_d_color_rule(&fcolr[i].cat, fcolr[i].r, fcolr[i].g,
+				  fcolr[i].b, &fcolr[i + 1].cat,
+				  fcolr[i + 1].r, fcolr[i + 1].g,
+				  fcolr[i + 1].b, &colors);
+	Rast_write_colors(map_output->answer, G_mapset(), &colors);
+    }
+
+    free_map(slope, window_size);
+    free_map(aspect, window_size);
+    free_map(elevation.elev, window_size + 1);
+    G_free(distance_matrix);
+    G_free(aspect_matrix);
+    G_free(out_buf);
+    Rast_close(out_fd);
+
+    Rast_short_history(map_output->answer, "raster", &history);
+    Rast_command_history(&history);
+    Rast_write_history(map_output->answer, &history);
+
+
+    G_message("Done!");
+    exit(EXIT_SUCCESS);
+
+}

Added: grass-addons/grass7/grass7/raster/r.convergence/memory.c
===================================================================
--- grass-addons/grass7/grass7/raster/r.convergence/memory.c	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.convergence/memory.c	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,143 @@
+#include "local_proto.h"
+
+int open_map(MAPS * rast)
+{
+
+    int row, col;
+    int fd;
+    char *mapset;
+    struct Cell_head cellhd;
+    int bufsize;
+    void *tmp_buf;
+
+    mapset = (char *)G_find_raster2(rast->elevname, "");
+
+    if (mapset == NULL)
+	G_fatal_error(_("Raster map <%s> not found"), rast->elevname);
+
+    rast->fd = Rast_open_old(rast->elevname, mapset);
+    Rast_get_cellhd(rast->elevname, mapset, &cellhd);
+    rast->raster_type = Rast_map_type(rast->elevname, mapset);
+
+    if (window.ew_res < cellhd.ew_res || window.ns_res < cellhd.ns_res)
+	G_fatal_error(_("Region resolution shoudn't be lesser than map %s resolution. Run g.region rast=%s to set proper resolution"),
+		      rast->elevname, rast->elevname);
+
+    tmp_buf = Rast_allocate_buf(rast->raster_type);
+    rast->elev = (FCELL **) G_malloc((window_size + 1) * sizeof(FCELL *));
+
+    for (row = 0; row < window_size + 1; ++row) {
+	rast->elev[row] = Rast_allocate_buf(FCELL_TYPE);
+	Rast_get_row(rast->fd, tmp_buf, row, rast->raster_type);
+	for (col = 0; col < ncols; ++col)
+	    get_cell(col, rast->elev[row], tmp_buf, rast->raster_type);
+    }				/* end elev */
+
+    G_free(tmp_buf);
+    return 0;
+}
+
+int get_cell(int col, float *buf_row, void *buf, RASTER_MAP_TYPE raster_type)
+{
+
+    switch (raster_type) {
+
+    case CELL_TYPE:
+	if (Rast_is_null_value(&((CELL *) buf)[col], CELL_TYPE))
+	    Rast_set_f_null_value(&buf_row[col], 1);
+	else
+	    buf_row[col] = (FCELL) ((CELL *) buf)[col];
+	break;
+
+    case FCELL_TYPE:
+	if (Rast_is_null_value(&((FCELL *) buf)[col], FCELL_TYPE))
+	    Rast_set_f_null_value(&buf_row[col], 1);
+	else
+	    buf_row[col] = (FCELL) ((FCELL *) buf)[col];
+	break;
+
+    case DCELL_TYPE:
+	if (Rast_is_null_value(&((DCELL *) buf)[col], DCELL_TYPE))
+	    Rast_set_f_null_value(&buf_row[col], 1);
+	else
+	    buf_row[col] = (FCELL) ((DCELL *) buf)[col];
+    }
+}
+
+int create_maps(void)
+{
+    int row, col;
+
+    G_begin_distance_calculations();
+    if (G_projection() != PROJECTION_LL)
+	get_distance(1, 0);
+
+    slope = (FCELL **) G_malloc(window_size * sizeof(FCELL *));
+    aspect = (FCELL **) G_malloc(window_size * sizeof(FCELL *));
+    for (row = 0; row < window_size; ++row) {
+
+	if (G_projection() == PROJECTION_LL) {
+	    get_distance(0, row);
+	    create_distance_aspect_matrix(row);
+	}
+
+	slope[row] = Rast_allocate_buf(FCELL_TYPE);
+	aspect[row] = Rast_allocate_buf(FCELL_TYPE);
+	get_slope_aspect(row);
+    }
+}
+
+int shift_buffers(int row)
+{
+    int i;
+    int col;
+    void *tmp_buf;
+    FCELL *tmp_elev_buf, *slope_tmp, *aspect_tmp;
+
+    tmp_buf = Rast_allocate_buf(elevation.raster_type);
+
+    tmp_elev_buf = elevation.elev[0];
+
+    for (i = 1; i < window_size + 1; ++i)
+	elevation.elev[i - 1] = elevation.elev[i];
+
+    elevation.elev[window_size] = tmp_elev_buf;
+    Rast_get_row(elevation.fd, tmp_buf, row + radius + 1,
+		 elevation.raster_type);
+
+    for (col = 0; col < ncols; ++col)
+	get_cell(col, elevation.elev[window_size], tmp_buf,
+		 elevation.raster_type);
+
+    G_free(tmp_buf);
+
+    slope_tmp = slope[0];
+    aspect_tmp = aspect[0];
+
+    for (i = 1; i < window_size; ++i) {
+	slope[i - 1] = slope[i];
+	aspect[i - 1] = aspect[i];
+    }
+
+    slope[window_size - 1] = slope_tmp;
+    aspect[window_size - 1] = aspect_tmp;
+
+    if (G_projection() == PROJECTION_LL) {
+	get_distance(0, row);
+	create_distance_aspect_matrix(row);
+    }
+
+    get_slope_aspect(window_size - 1);
+
+    return 0;
+}
+
+int free_map(FCELL ** map, int n)
+{
+    int i;
+
+    for (i = 0; i < n; ++i)
+	G_free(map[i]);
+    G_free(map);
+    return 0;
+}

Added: grass-addons/grass7/grass7/raster/r.convergence/r.convergence.html
===================================================================
--- grass-addons/grass7/grass7/raster/r.convergence/r.convergence.html	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.convergence/r.convergence.html	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,59 @@
+<h2>OPTIONS</h2>
+<dl>
+<dt><b>-s</b></dt>
+<dd>Increase convergence if slope value is high. Slope parameter radically slow down computation time, especially if window parameter is high. If slope is used addational modifier is used according to formula: sin(current)*sin(target) + cos(current)*cos(target). if slope of current and target cells are equal. The modifier is 1. If not, the modifier is applied with formula: acos(cos(convergence) * modifier)  </dd>
+<dt><b>-c</b></dt>
+<dd>use circular window instead of suqare (default)</dd>
+
+<dt><b>input</b></dt>
+<dd>Digital elevation model. Data can be of any type and any projection. To calculate relief convergnece, r.convergence uses real distance which is recalculated into cell distance, according formula: <br><code>distance_between_current_cell_and_traget_cell/distance_between_current_cell_and_nearest_neighbour_cell.</code> It is important if convergence is calculated for large areas in LatLong projecton.
+</dd>
+
+<dt><b>weights</b></dt>
+<dd>Parameter describing the reduction of the impact of the cell due to its distance, where distance in cells:
+<ul>
+<li><b>standard:</b>no decay
+<li><b>inverse:</b>distance modifier is calculated as 1/x
+<li><b>power:</b>distance modifier is calculated as 1/(x*x)
+<li><b>power:</b>distance modifier is calculated as 1/(x*x)
+<li><b>gentle:</b>distance modifier is calculated as 1/((1-x)/(1+x))
+</ul>
+
+<dt><b>window</b></dt>
+<dd>window size. Must be odd. For now there is no limits in window size. r.convergence uses window size instead of classical radius for compatibility with other GRASS programs.</dd>
+
+
+<dt><b>output</b></dt>
+<dd>Map of convergence index. The values ranges from -100 (max divergent, real peaks and ridges) by 0 (planar areas) to 100 (max convergent, real pits and channels). Classical convergence index presented with degrees (-90 to 90)</dd>
+
+
+<h2>DESCRIPTION</h2>
+<center>
+<h3>How convergence index is calculated (3 x 3 window):<h3>
+<img src=conv.png border=1><br>
+</center>
+Convergence index is a terrain parameter which show the structure od the relief as a set of convergent areas (channels) and divergent areas (ridges). It represents the agreement of aspect direction of surrounding cells with the teoretical matrix direction. Convergence index is mean (or weighted mean if weights are used) aspect difference between real aspect and teoretical maximum divergent direction matrix representing ideal peak (see figure) minus 90 degres. So if there is maximum agreement with divergent matrix the convergence index is (0 - 90) * 10/9 = -100. If there is ideal sink (maximum convergence) the convergence index is (180 -90) * 10/9 = 100.
+Slope and aspect ere calculated internaly with the same formula as in r.slope.aspect
+Convergence index is very useful for analysis of lineamets especially represented by rigdes or chanell systems as well as valley recognition tool.
+
+
+<h2>SEE ALSO</h2>
+
+<em>
+<a href="r.slope.aspect.html">r.slope.aspect</a>,
+<a href="r.param.scale.html">r.param.scale</a>,
+<a href="r.neighbour.html">r.neighbour</a>,
+</em>
+
+
+<h2>REFERENCES</h2>
+<p>
+Claps, P., Fiorentino, M., Oliveto, G., (1994), <i>Informational entropy of fractal river networks</i>,
+Journal of Hydrology, 187(1-2), 145-156 .</p>
+<p>
+Bauer J., Rohdenburg H., Bork H.-R., (1985), Ein Digitales Reliefmodell als Vorraussetzung fuer ein deterministisches Modell der Wasser- und Stoff-Fluesse, <i>IN: Bork, H.-R., Rohdenburg, H., Landschaftsgenese und Landschaftsoekologie, Parameteraufbereitung fuer deterministische Gebiets-Wassermodelle, Grundlagenarbeiten zu Analyse von Agrar-Oekosystemen</i>, 1-15.
+<p>
+Böhner J., Blaschke T., Montanarella, L. (eds.) (2008). SAGA Seconds Out. Hamburger Beiträge zur Physischen Geographie und Landschaftsökologie, 19: 113 s.</p>
+
+<h2>AUTHOR</h2>
+Jarek  Jasiewicz

Added: grass-addons/grass7/grass7/raster/r.convergence/slope_aspect.c
===================================================================
--- grass-addons/grass7/grass7/raster/r.convergence/slope_aspect.c	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.convergence/slope_aspect.c	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,256 @@
+#include "local_proto.h"
+int get_distance(int once, int row)
+{
+
+    double north, south, east, west, middle;
+    double zfactor = 1;
+
+    if (once) {
+
+	north = Rast_row_to_northing(0.5, &window);
+	middle = Rast_row_to_northing(1.5, &window);
+	south = Rast_row_to_northing(2.5, &window);
+	east = Rast_col_to_easting(2.5, &window);
+	west = Rast_col_to_easting(0.5, &window);
+
+    }
+    else {
+
+	north = Rast_row_to_northing(row + 0.5, &window);
+	middle = Rast_row_to_northing(row + 1.5, &window);
+	south = Rast_row_to_northing(row + 2.5, &window);
+	east = Rast_col_to_easting(2.5, &window);
+	west = Rast_col_to_easting(0.5, &window);
+
+    }
+
+    V = G_distance(east, north, east, south) / zfactor;
+    H = G_distance(east, middle, west, middle) / zfactor;
+    return 0;
+
+}
+
+int create_distance_aspect_matrix(int row)
+{
+
+    int i;
+    int mx, x, my, y;
+    int dx, dy;
+    float distance;
+    int set_to_zero = 0;
+    float cur_northing, cur_easting, target_northing, target_easting;
+    float ns_dist, ew_dist;
+    float min_cell_size;
+
+    aspect_matrix = G_calloc(window_size * window_size, sizeof(float));
+    distance_matrix = G_calloc(window_size * window_size, sizeof(float));
+
+    cur_northing = Rast_row_to_northing(row + 0.5, &window);
+    cur_easting = Rast_col_to_easting(0.5, &window);
+    target_northing = Rast_row_to_northing(row + 1.5, &window);
+    target_easting = Rast_col_to_easting(1.5, &window);
+
+    ns_dist =
+	G_distance(cur_easting, cur_northing, cur_easting, target_northing);
+    ew_dist =
+	G_distance(cur_easting, cur_northing, target_easting, cur_northing);
+
+    min_cell_size = MIN(ns_dist, ew_dist);
+
+    for (my = 0, y = -radius; my < window_size; ++my, ++y)
+	for (mx = 0, x = radius; mx < window_size; ++mx, --x) {
+
+	    cur_northing = Rast_row_to_northing(row + 0.5, &window);
+	    cur_easting = Rast_col_to_easting(0.5, &window);
+	    target_northing = Rast_row_to_northing(row + y + 0.5, &window);
+	    target_easting = Rast_col_to_easting(x + 0.5, &window);
+
+	    distance =
+		G_distance(cur_easting, cur_northing, target_easting,
+			   target_northing);
+	    distance /= min_cell_size;
+
+	    set_to_zero = 0;
+	    if (distance < 1)
+		set_to_zero = 1;
+	    if (f_circular && distance > radius)
+		set_to_zero = 1;
+
+
+	    if (set_to_zero) {
+		distance_matrix[my * window_size + mx] = 0;
+		aspect_matrix[my * window_size + mx] = -1;
+	    }
+	    else {
+		distance_matrix[my * window_size + mx] = distance;
+		ns_dist =
+		    G_distance(cur_easting, cur_northing, cur_easting,
+			       target_northing);
+		ns_dist =
+		    (cur_northing > target_northing) ? ns_dist : -ns_dist;
+		ew_dist =
+		    G_distance(cur_easting, cur_northing, target_easting,
+			       cur_northing);
+		ew_dist = (cur_easting > target_easting) ? -ew_dist : ew_dist;
+
+		aspect_matrix[my * window_size + mx] =
+		    (y != 0.) ? PI + atan2(ew_dist, ns_dist) :
+		    (x > 0. ? PI2 + PI : PI2);
+	    }
+	}
+
+    return 0;
+
+}
+
+int get_slope_aspect(int row)
+{
+
+    int col, i;
+    FCELL c[10];
+    FCELL dx, dy;
+    FCELL *uprow, *thisrow, *downrow;
+    int d_row[] = { -1, -1, -1, 0, 0, 0, 1, 1, 1 };
+    int d_col[] = { -1, 0, 1, -1, 0, 1, -1, 0, 1 };
+
+    if (row < 1 || row > nrows - 2) {
+	Rast_set_f_null_value(slope[row], ncols);
+	Rast_set_f_null_value(aspect[row], ncols);
+	return 1;
+    }
+
+    Rast_set_f_null_value(&slope[row][0], 1);
+    Rast_set_f_null_value(&aspect[row][0], 1);
+    Rast_set_f_null_value(&slope[row][ncols - 1], 1);
+    Rast_set_f_null_value(&aspect[row][ncols - 1], 1);
+
+    uprow = elevation.elev[row - 1];
+    thisrow = elevation.elev[row];
+    downrow = elevation.elev[row + 1];
+
+    for (col = 1; col < ncols - 1; ++col) {
+
+	for (i = 0; i < 9; ++i)
+	    if (Rast_is_f_null_value
+		(&elevation.elev[row + d_row[i]][col + d_col[i]])) {
+		Rast_set_f_null_value(&slope[row][col], 1);
+		Rast_set_f_null_value(&aspect[row][col], 1);
+		continue;
+	    }
+
+	dx = ((elevation.elev[row - 1][col - 1] +
+	       2 * elevation.elev[row][col - 1] + elevation.elev[row +
+								 1][col -
+								    1]) -
+	      (elevation.elev[row - 1][col + 1] +
+	       2 * elevation.elev[row][col + 1] + elevation.elev[row +
+								 1][col +
+								    1])) /
+	    (H * 4);
+
+	dy = ((elevation.elev[row + 1][col - 1] +
+	       2 * elevation.elev[row + 1][col] + elevation.elev[row +
+								 1][col +
+								    1]) -
+	      (elevation.elev[row - 1][col - 1] +
+	       2 * elevation.elev[row - 1][col] + elevation.elev[row -
+								 1][col +
+								    1])) /
+	    (V * 4);
+
+	slope[row][col] = atan(sqrt(dx * dx + dy * dy));
+	if (dy == 0.)
+	    aspect[row][col] = dx < 0 ? PI + PI2 : PI2;
+	else
+	    aspect[row][col] =
+		atan2(dx, dy) < 0 ? atan2(dx, dy) + M2PI : atan2(dx, dy);
+
+    }
+    return 0;
+}
+
+float calculate_convergence(int row, int cur_row, int col)
+{
+    int i, j, k = 0;
+    float i_distance;
+    float conv, sum = 0, div = 0;
+    float x;
+    float cur_slope;
+    float slope_modifier;
+    float distance_modifier;
+    float cur_northing, cur_easting, target_northing, target_easting,
+	cur_distance;
+
+    if (f_slope) {
+	cur_northing = Rast_row_to_northing(row + 0.5, &window);
+	cur_easting = Rast_col_to_easting(col + 0.5, &window);
+    }
+
+
+    for (i = -radius; i < radius + 1; ++i)
+	for (j = -radius; j < radius + 1; ++j, ++k) {
+
+	    if (cur_row + i < 0 || cur_row + i > window_size - 1 ||
+		col + j < 1 || col + j > ncols - 2)
+		continue;
+	    x = distance_matrix[k];
+
+	    if (x < 1)
+		continue;
+
+	    if (f_slope) {
+		target_northing =
+		    Rast_row_to_northing(row + i + 0.5, &window);
+		target_easting = Rast_col_to_easting(col + j + 0.5, &window);
+
+		cur_distance =
+		    G_distance(cur_easting, cur_northing, target_easting,
+			       target_northing);
+		cur_slope =
+		    (atan
+		     ((elevation.elev[cur_row + i][col + j] -
+		       elevation.elev[cur_row][col]) / cur_distance));
+		slope_modifier =
+		    sin(slope[cur_row][col]) * sin(cur_slope) +
+		    cos(slope[cur_row][col]) * cos(cur_slope);
+	    }
+
+	    conv = aspect[cur_row + i][col + j] - aspect_matrix[k];
+
+	    if (f_slope)
+		conv = acos(slope_modifier * cos(conv));
+
+	    if (conv < -PI)
+		conv += M2PI;
+	    else if (conv > PI)
+		conv -= M2PI;
+
+	    switch (f_method) {
+	    case 0:
+		distance_modifier = 1;
+		break;
+	    case 1:		/* inverse */
+		distance_modifier = x;
+		break;
+	    case 2:		/* power */
+		distance_modifier = x * x;
+		break;
+	    case 3:		/* square */
+		distance_modifier = sqrt(x);
+		break;
+	    case 4:		/* gentle */
+		distance_modifier = 1 + ((1 - x) * (1 + x));
+		break;
+	    default:
+		G_fatal_error(_("Decay: wrong option"));
+	    }
+
+	    sum += fabs(conv) * (1 / distance_modifier);
+	    div += 1 / distance_modifier;
+
+	}			/* end for i, j */
+
+    sum /= div;
+    sum -= PI2;
+    return sum;
+}

Added: grass-addons/grass7/grass7/raster/r.convert/r.convert
===================================================================
--- grass-addons/grass7/grass7/raster/r.convert/r.convert	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.convert/r.convert	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,178 @@
+#!/bin/sh
+############################################################################
+#
+# MODULE:       r.convert
+# AUTHOR:       M. Hamish Bowman, Dunedin, New Zealand
+#
+# PURPOSE:      Converts a GRASS 4-6 raster map to a GRASS 7 raster map
+#		  *** EXPERIMENTAL GRASS 7 RASTER DIR FILE LAYOUT ***
+#
+# COPYRIGHT:    (c) 2007 Hamish Bowman, and the GRASS Development Team
+#               This program is free software under the GNU General Public
+#               License (>=v2). Read the file COPYING that comes with GRASS
+#               for details.
+#
+#############################################################################
+
+#%Module
+#% description: Converts a GRASS 4-6 raster map to a GRASS 7 raster map format
+#% keywords: raster, import, conversion
+#%end
+#%option
+#% key: map
+#% type: string
+#% gisprompt: old,cell,raster
+#% key_desc: name
+#% description: Name of input raster map
+#% required: yes
+#%end
+#%flag
+#%  key: m
+#%  description: Move map instead of copying it
+#%end
+#%flag
+#%  key: r
+#%  description: Reverse action: Convert from GRASS 7 to GRASS 4-6 format
+#%end
+
+if  [ -z "$GISBASE" ] ; then
+    echo "You must be in GRASS GIS to run this program." 1>&2
+    exit 1
+fi
+
+if [ "$1" != "@ARGS_PARSED@" ] ; then
+    exec g.parser "$0" "$@"
+fi
+
+
+eval `g.gisenv`
+: ${GISBASE?} ${GISDBASE?} ${LOCATION_NAME?} ${MAPSET?}
+LOCATION="$GISDBASE"/"$LOCATION_NAME"/"$MAPSET"
+
+cd "$LOCATION"
+
+
+# to copy or move?
+if [ $GIS_FLAG_M -eq 0 ] ; then
+   MVCMD="cp"
+else
+   MVCMD="mv"
+fi
+
+
+if [ $GIS_FLAG_R -eq 0 ] ; then
+
+    # make new $MAPSET/raster/ dir if needed
+    if [ ! -e raster ] ; then
+	mkdir raster
+    fi
+    if [ ! -d raster ] ; then
+	echo "ERROR: Could not convert map." 1>&2
+	exit 1
+    fi
+
+    g.findfile element=cell mapset=. file="$GIS_OPT_MAP" > /dev/null
+    if [ $? -ne 0 ] ; then
+	echo "Raster map <$GIS_OPT_MAP> not found in current mapset." 1>&2
+	exit 1
+    fi
+
+    # make new $MAPSET/raster/$MAPNAME dir
+    if [ ! -e "raster/$GIS_OPT_MAP" ] ; then
+	mkdir "raster/$GIS_OPT_MAP"
+    fi
+    if [ ! -d "raster/$GIS_OPT_MAP" ] ; then
+	echo "ERROR: Could not convert map." 1>&2
+	exit 1
+    fi
+
+    for ELEMENT in cats cell cellhd colr fcell grid3 hist ; do
+	if [ -e "$ELEMENT/$GIS_OPT_MAP" ] ; then
+	    $MVCMD "$ELEMENT/$GIS_OPT_MAP" "raster/$GIS_OPT_MAP/$ELEMENT"
+	    if  [ $? -ne 0 ] ; then
+		echo "ERROR converting map. (element: $ELEMENT)" 1>&2
+		exit 1
+	    fi
+	fi
+    done
+
+    if [ -d "cell_misc/$GIS_OPT_MAP/" ] ; then
+	$MVCMD "cell_misc/$GIS_OPT_MAP"/* "raster/$GIS_OPT_MAP/"
+	if  [ $? -ne 0 ] ; then
+	    echo "ERROR converting map. (element: cell_misc/)" 1>&2
+	    exit 1
+	fi
+
+	if [ $GIS_FLAG_M -eq 1 ] ; then
+	    rmdir "cell_misc/$GIS_OPT_MAP/"
+	    if  [ $? -ne 0 ] ; then
+		echo "WARNING: problem removing old map. (element: cell_misc/)" 1>&2
+	    fi
+	fi
+    fi
+
+else
+    # reverse: make a GRASS 6 map from a GRASS 7 map
+    if [ ! -d "raster/$GIS_OPT_MAP/" ] ; then
+	echo "Raster map <$GIS_OPT_MAP> not found in current mapset." 1>&2
+	exit 1
+    fi
+
+
+    for ELEMENT in cats cell cellhd colr fcell grid3 hist ; do
+	# make new $MAPSET/raster/ dir if needed
+	if [ ! -e $ELEMENT ] ; then
+	    mkdir $ELEMENT
+	fi
+	if [ ! -d $ELEMENT ] ; then
+	    echo "ERROR: Could not convert map." 1>&2
+	    exit 1
+	fi
+
+
+	if [ -e "raster/$GIS_OPT_MAP/$ELEMENT" ] ; then
+	    $MVCMD "raster/$GIS_OPT_MAP/$ELEMENT" "$ELEMENT/$GIS_OPT_MAP"
+	    if  [ $? -ne 0 ] ; then
+		echo "ERROR converting map. (element: $ELEMENT)" 1>&2
+		exit 1
+	    fi
+	fi
+    done
+
+    for ELEMENT in f_format f_quant f_range null range reclassed_to ; do
+	if [ -e "raster/$GIS_OPT_MAP/$ELEMENT" ] ; then
+	    if [ ! -e cell_misc ] ; then
+		mkdir cell_misc
+	    fi
+	    if [ ! -d cell_misc ] ; then
+		echo "ERROR: Could not convert map." 1>&2
+		exit 1
+	    fi
+
+	    if [ ! -e "cell_misc/$GIS_OPT_MAP" ] ; then
+		mkdir "cell_misc/$GIS_OPT_MAP"
+	    fi
+	    if [ ! -d "cell_misc/$GIS_OPT_MAP" ] ; then
+		echo "ERROR: Could not convert map." 1>&2
+		exit 1
+	    fi
+
+
+	    $MVCMD "raster/$GIS_OPT_MAP/$ELEMENT" "cell_misc/$GIS_OPT_MAP"
+	    if  [ $? -ne 0 ] ; then
+		echo "ERROR converting map. (element: $ELEMENT)" 1>&2
+		exit 1
+	    fi
+	fi
+    done
+
+    if [ $GIS_FLAG_M -eq 1 ] ; then
+	rmdir "raster/$GIS_OPT_MAP/"
+	if  [ $? -ne 0 ] ; then
+	    echo "WARNING: problem removing old map. Left over files:" 1>&2
+	    ls "raster/$GIS_OPT_MAP/"
+	fi
+    fi
+
+fi
+


Property changes on: grass-addons/grass7/grass7/raster/r.convert/r.convert
___________________________________________________________________
Added: svn:executable
   + 

Added: grass-addons/grass7/grass7/raster/r.convert/r.convert.all
===================================================================
--- grass-addons/grass7/grass7/raster/r.convert/r.convert.all	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.convert/r.convert.all	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,55 @@
+#!/bin/sh
+############################################################################
+#
+# MODULE:       r.convert.all
+# AUTHOR:       M. Hamish Bowman, Dunedin, New Zealand
+# PURPOSE:      Converts all GRASS 4-6 raster maps in current mapset to
+#		 GRASS 7 raster map format
+# COPYRIGHT:    (c) 2007 Hamish Bowman, and the GRASS Development Team
+#               This program is free software under the GNU General Public
+#               License (>=v2). Read the file COPYING that comes with GRASS
+#               for details.
+#
+#############################################################################
+
+#%Module
+#% description: Converts all GRASS 4-6 raster maps in current mapset to GRASS 7 raster map format
+#% keywords: raster, import, conversion, bulk
+#%end
+#%flag
+#%  key: m
+#%  description: Move maps instead of copying then
+#%end
+#%flag
+#%  key: r
+#%  description: Reverse action: Convert from GRASS 7 to GRASS 4-6 format
+#%end
+
+if  [ -z "$GISBASE" ] ; then
+    echo "You must be in GRASS GIS to run this program." 1>&2
+    exit 1
+fi
+
+if [ "$1" != "@ARGS_PARSED@" ] ; then
+    exec g.parser "$0" "$@"
+fi
+
+if [ $GIS_FLAG_M -eq 1 ] ; then
+    MV_FLAG="-m"
+else
+    MV_FLAG=""
+fi
+
+if [ $GIS_FLAG_R -eq 1 ] ; then
+    REV_FLAG="-r"
+else
+    REV_FLAG=""
+fi
+
+
+for MAP in `g.mlist type=rast mapset=.` ; do
+    r.convert map="$MAP" $MV_FLAG $REV_FLAG
+    if [ $? -ne 0 ] ; then
+	echo "Error converting <$MAP>" 1>&2
+    fi
+done


Property changes on: grass-addons/grass7/grass7/raster/r.convert/r.convert.all
___________________________________________________________________
Added: svn:executable
   + 

Added: grass-addons/grass7/grass7/raster/r.fuzzy/Makefile
===================================================================
--- grass-addons/grass7/grass7/raster/r.fuzzy/Makefile	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.fuzzy/Makefile	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,10 @@
+MODULE_TOPDIR = ../..
+
+SUBDIRS = \
+	r.fuzzy.set \
+	r.fuzzy.logic \
+	r.fuzzy.system \
+
+include $(MODULE_TOPDIR)/include/Make/Dir.make
+
+default: parsubdirs

Added: grass-addons/grass7/grass7/raster/r.fuzzy/r.fuzzy.logic/Makefile
===================================================================
--- grass-addons/grass7/grass7/raster/r.fuzzy/r.fuzzy.logic/Makefile	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.fuzzy/r.fuzzy.logic/Makefile	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,10 @@
+MODULE_TOPDIR = ../../..
+
+PGM = r.fuzzy.logic
+
+LIBES = $(RASTERLIB) $(GISLIB) $(MATHLIB)
+DEPENDENCIES = $(RASTERDEP) $(GISDEP)
+
+include $(MODULE_TOPDIR)/include/Make/Module.make
+
+default: cmd

Added: grass-addons/grass7/grass7/raster/r.fuzzy/r.fuzzy.logic/local_proto.h
===================================================================
--- grass-addons/grass7/grass7/raster/r.fuzzy/r.fuzzy.logic/local_proto.h	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.fuzzy/r.fuzzy.logic/local_proto.h	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,29 @@
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <math.h>
+#include <grass/gis.h>
+#include <grass/raster.h>
+#include <grass/glocale.h>
+
+#define _AND	1
+#define _OR		2
+#define _NOT	3
+#define _IMP	4
+
+#define ZADEH 			1
+#define PRODUCT			2	
+#define DRASTIC			3
+#define LUKASIEWICZ	4
+#define FODOR				5
+#define HAMACHER		6
+
+#define MAX(a,b) ((a) > (b) ? (a) : (b))
+#define MIN(a,b) ((a) < (b) ? (a) : (b))
+
+
+float f_and(float cellx, float celly, int family);
+float f_or(float cellx, float celly, int family);
+float f_imp(float cellx, float celly, int family);
+float f_not(float cellx, int family);
+

Added: grass-addons/grass7/grass7/raster/r.fuzzy/r.fuzzy.logic/logic.c
===================================================================
--- grass-addons/grass7/grass7/raster/r.fuzzy/r.fuzzy.logic/logic.c	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.fuzzy/r.fuzzy.logic/logic.c	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,105 @@
+#include <grass/gis.h>
+#include <grass/glocale.h>
+#include "local_proto.h"
+
+float f_and(float x, float y, int family) {
+
+	switch (family) {
+		
+			case ZADEH:
+		return MIN(x,y);
+			break;
+		
+			case PRODUCT:
+		return x*y;
+			break;	
+		
+			case DRASTIC:
+		return MAX(x, y) == 1 ? MIN(x, y) : 0;
+			break;	
+		
+			case LUKASIEWICZ:
+		return MAX((x+y-1),0);
+			break;
+		
+			case FODOR:
+		return (x+y)>1 ? MIN(x,y) : 0;	
+			break;
+			
+			case HAMACHER:
+		return (x==y==0) ? 0 : (x*y)/((x+y)-x*y);	
+			break;
+			
+
+				
+	}
+	return -1; /* error */
+}
+
+float f_or(float x, float y, int family) {
+			float b;
+	switch (family) {
+		
+			case ZADEH:
+		return MAX(x,y);
+			break;
+		
+			case PRODUCT:
+		return x + y -x * y;
+			break;	
+		
+			case DRASTIC:
+		return (MIN(x, y) == 0) ? MAX(x, y) : 1;
+			break;	
+		
+			case LUKASIEWICZ:
+		return MIN((x+y),1);
+			break;
+	
+			case FODOR:
+		return (x+y<1) ? MAX(x,y) : 1;		
+			break;
+			
+			case HAMACHER:
+		return (x+y)/(1+x*y);
+			break;
+	}
+	return -1; /* error */
+}
+
+float f_imp(float x, float y, int family) {
+		
+	switch (family) {
+			
+			case ZADEH:
+		return (x <= y) ? 1 : y;
+			break;
+
+			case PRODUCT:
+		return MIN(y/x,1);
+			break;	
+		
+			case DRASTIC:
+		return -1; /* not avaialble */	
+			break;	
+			
+			case LUKASIEWICZ:
+		return MIN((1-x+y),1);	
+			break;
+			
+			case FODOR:
+		return (x<=y) ? 1 : MAX(1-x,y);		
+			break;
+	}
+	return -1; /* error */	
+}
+
+float f_not(float x, int family) {
+	
+		if (family==HAMACHER)
+	return (1-x)/(1+x);
+		else
+	return ((1-x)<0 || (1-x)>1) ? -1 : 1-x;
+}
+
+

Added: grass-addons/grass7/grass7/raster/r.fuzzy/r.fuzzy.logic/main.c
===================================================================
--- grass-addons/grass7/grass7/raster/r.fuzzy/r.fuzzy.logic/main.c	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.fuzzy/r.fuzzy.logic/main.c	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,240 @@
+/* ***************************************************************************
+ *
+ * MODULE:       r.fuzzy.logic
+ * AUTHOR(S):    Jarek Jasiewicz <jarekj amu.edu.pl>
+ * PURPOSE:      Performs logical operations on membership images created with 
+ *                   r.fuzzy or different method. Use families for fuzzy logic
+ * COPYRIGHT:    (C) 1999-2010 by the GRASS Development Team
+ *
+ *               This program is free software under the GNU General Public
+ *               License (>=v2). Read the file COPYING that comes with GRASS
+ *               for details.
+ *
+ ****************************************************************************
+ */
+
+#include <grass/gis.h>
+#include <grass/glocale.h>
+#include "local_proto.h"
+
+int main(int argc, char *argv[])
+{
+
+	struct GModule *module;
+	struct Option *par_inputx,
+								*par_inputy,
+								*par_output,
+								*par_operation,
+								*par_family;
+	
+	struct Cell_head cellhdx;
+	struct Cell_head cellhdy;  
+  struct FPRange membership_range;
+  struct History history;
+
+	char *mapsetx, *mapsety;
+	char *inputx, *inputy;
+	char *output;
+	int nrows, ncols;
+	int row, col;
+	int infdx, infdy, outfd;
+	void *in_bufx, *in_bufy;
+	unsigned char *out_buf;
+	float tmp;
+	DCELL c_min, c_max;
+	int family, operator;
+	
+	G_gisinit(argv[0]);
+	
+    module = G_define_module();
+    module->keywords = _("raster, fuzzy logic");
+    module->description =
+        _("xxxx");
+
+	par_inputx = G_define_standard_option(G_OPT_R_INPUT);
+    par_inputx->description = _("x operand (membership map)");
+    par_inputx->key = "xmap";
+  
+    par_inputy = G_define_standard_option(G_OPT_R_INPUT);
+    par_inputy->description = _("y operand (membership map)");
+    par_inputy->key = "ymap";
+    par_inputy->required = NO;
+  
+    par_output = G_define_standard_option(G_OPT_R_OUTPUT);
+	par_output->description = _("Resulting map");
+
+	par_operation=G_define_option();
+	par_operation->key = "operator";
+	par_operation->type = TYPE_STRING;
+	par_operation->options = "AND,OR,NOT,IMP";
+	par_operation->answer = "AND";
+	par_operation->multiple = NO;
+	par_operation->required = YES;
+	par_operation->description = _("Fuzzy logic operation");
+	
+	par_family=G_define_option();
+	par_family->key = "family";
+	par_family->type = TYPE_STRING;
+	par_family->options = "Zadeh,product,drastic,Lukasiewicz,Fodor,Hamacher";
+	par_family->answer = "Zadeh";
+	par_family->multiple = NO;
+	par_family->required = YES;
+	par_family->description = _("Fuzzy logic family");
+	
+  	if (G_parser(argc, argv))
+	exit(EXIT_FAILURE);
+	
+	inputx=par_inputx->answer;
+	inputy=par_inputy->answer;
+	output=par_output->answer;
+	
+			if (!strcmp(par_operation->answer, "AND"))
+	operator=_AND;
+		else if (!strcmp(par_operation->answer, "OR"))
+	operator=_OR;
+		else if (!strcmp(par_operation->answer, "NOT"))
+	operator=_NOT;
+		else if (!strcmp(par_operation->answer, "IMP"))
+	operator=_IMP;
+	  
+  		if (!strcmp(par_family->answer, "Zadeh"))
+	family=ZADEH;
+		else if (!strcmp(par_family->answer, "product"))
+	family=PRODUCT;
+		else if (!strcmp(par_family->answer, "drastic"))
+	family=DRASTIC;
+		else if (!strcmp(par_family->answer, "Lukasiewicz"))
+	family=LUKASIEWICZ;
+		else if (!strcmp(par_family->answer, "Fodor"))
+	family=FODOR;
+			else if (!strcmp(par_family->answer, "Hamacher"))
+	family=HAMACHER;
+	
+		if(operator == _NOT && inputy)
+	G_warning("Negation is unary operaton ymap is ignored");
+	
+		if(operator != _NOT && !inputy)
+	G_fatal_error("For binary operation (AND, OR, IMP) ymap is required");
+	
+		if(family == DRASTIC && operator == _IMP)
+  G_fatal_error("implication is not available for <drastic> family");
+	
+	/* end of interface */
+	
+	mapsetx = (char *)G_find_raster2(inputx, "");
+	
+	  if (mapsetx == NULL)
+	G_fatal_error(_("Raster map <%s> not found"), inputx);
+	
+	infdx = Rast_open_old(inputx, mapsetx);
+	Rast_get_cellhd(inputx, mapsetx, &cellhdx);
+	
+		if (Rast_map_type(inputx, mapsetx) != FCELL_TYPE)
+	 G_fatal_error(_("<%s> is not of type CELL"), inputx);
+	 
+	Rast_init_fp_range(&membership_range);
+	Rast_read_fp_range(inputx,mapsetx,&membership_range);
+	Rast_get_fp_range_min_max(&membership_range, &c_min, &c_max);
+		if(c_min<0 || c_max>1)
+	G_fatal_error("Membership out of range");
+	
+	in_bufx = Rast_allocate_buf(FCELL_TYPE);
+	
+		if(inputy) {
+	
+	mapsety = (char *)G_find_raster2(inputy, "");
+	
+	  if (mapsety == NULL)
+	G_fatal_error(_("Raster map <%s> not found"), inputy);
+	
+	infdy = Rast_open_old(inputy, mapsety);
+	Rast_get_cellhd(inputy, mapsety, &cellhdy);
+
+		if (Rast_map_type(inputy, mapsety) != FCELL_TYPE);
+	G_fatal_error(_("<%s> is not of type CELL"), inputy);
+	
+	Rast_init_fp_range(&membership_range);
+	Rast_read_fp_range(inputy,mapsety,&membership_range);
+	Rast_get_fp_range_min_max(&membership_range, &c_min, &c_max);
+		if(c_min<0 || c_max>1)
+	G_fatal_error("Membership out of range");
+	
+	
+	in_bufy = Rast_allocate_buf(FCELL_TYPE);
+		
+		} /* end if inputy */
+	
+	nrows = Rast_window_rows();
+	ncols = Rast_window_cols();
+
+	outfd = Rast_open_new(output, FCELL_TYPE);
+	out_buf = Rast_allocate_buf(FCELL_TYPE);
+	
+	
+	/* binary processing */
+	for (row = 0; row < nrows; row++) {
+		G_percent(row, nrows, 2);
+		
+		FCELL fx, fy=0;
+		
+		Rast_get_row(infdx, in_bufx, row, FCELL_TYPE);
+		
+			if(inputy)
+		Rast_get_row(infdy, in_bufy, row, FCELL_TYPE);
+		
+		for (col = 0; col < ncols; col++) {
+				
+				fx = ((FCELL *) in_bufx)[col];
+					if(inputy)
+				fy = ((FCELL *) in_bufy)[col];
+
+				 if (Rast_is_f_null_value(&fx) || Rast_is_f_null_value(&fy))
+			Rast_set_f_null_value(&tmp, 1); 
+				 
+				 else
+			
+			switch (operator) {
+				case _AND:
+					//if((row+col)%100==0)
+						if(0>(tmp = f_and(fx,fy,family)))
+					G_warning("Cannot determine result at row %d, col %d", row,col);
+					break;
+				
+				case _OR:
+						if(0>(tmp=f_or(fx,fy,family)))
+					G_warning("Cannot determine result at row %d, col %d", row,col);
+					break;
+					
+				case _IMP:
+						if((tmp=f_imp(fx,fy,family))<0)
+					G_warning("Cannot determine result at row %d, col %d", row,col);
+					break;	
+				
+				case _NOT:
+						if((tmp=f_not(fx, family))<0)
+					G_warning("Cannot determine result at row %d, col %d", row,col);
+					break;
+			} /* end switch */
+			
+			((FCELL *) out_buf)[col] = tmp;
+		}
+		Rast_put_row(outfd, out_buf, FCELL_TYPE);
+	} /* end for row */
+	
+  G_free(in_bufx);
+	Rast_close(infdx);
+	
+		if(inputy) {
+  G_free(in_bufy);
+  Rast_close(infdy);
+	}
+	
+	G_free(out_buf);
+	Rast_close(outfd);
+
+	Rast_short_history(output, "raster", &history);
+	Rast_command_history(&history);
+	Rast_write_history(output, &history);
+	
+	exit(EXIT_SUCCESS);
+}

Added: grass-addons/grass7/grass7/raster/r.fuzzy/r.fuzzy.logic/r.fuzzy.logic.html
===================================================================
--- grass-addons/grass7/grass7/raster/r.fuzzy/r.fuzzy.logic/r.fuzzy.logic.html	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.fuzzy/r.fuzzy.logic/r.fuzzy.logic.html	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,86 @@
+<h2>OPTIONS</h2>
+<dl>
+<dt><b>xmap</b></dt>
+<dd>Name of input x membership operand. This map must be of type FCELL with
+range 0 :1 and may require null values. Otherwise program will print error
+message and stops.
+</dd>
+<dt><b>xmap</b></dt>
+<dd>Name of input y membership operand. This map must be of type FCELL with
+range 0 :1 and may require null values. Otherwise program will print error
+message and stops. This map is optional bit is required for all operation except
+NOT
+</dd>
+<dt><b>operator</b></dt>
+<dd>A fuzzy set operators are generalization of crisp operators. There is more
+than one possible generalization of every opeartor. There are three operations:
+fuzzy complements, fuzzy intersections, and fuzzy unions. Addational implication
+operator is also provided.
+<ul>
+<li>fuzzy intersection (<b>AND</b>) use T-norm of given family for calculation;
+<li>fuzzy union (<b>OR</b>) use T-conorm of given family for calculation;
+<li>fuzzy complement (<b>NOT</b>) fuzzy negation ussualy 1-x;
+<li>fuzzy implication (<b>IMP</b>) use residuum of given family if available;
+</ul>
+</dd>
+<dt><b>family</b></dt>
+<dd>T-norms, T-conorms and residuals are a generalization of the two-valued
+logical conjunction,  disjunction and implication used by boolean logic, for
+fuzzy logics. Because there is more than one possible generalisation of logial
+operations, r.fuzzy.logic provides 6 most popular families for fuzzy operations:
+<ul>
+<li><b>Zadeh</b> with minimum (Godel) t-norm and maximum T-conorm;
+<li><b>product</b> with product T-norm and probabilistic sum as T-conorm;
+<li><b>drastic</b> with drastic T-norm and drastic T-conorm;
+<li><b>Łukasiewicz</b> with Łukasiewicz T-norm and bounded sum as a T-conorm;
+<li><b>Fodor</b> with nilpotent minimum as T-norm and nilpotent maximum as
+T-conorm;
+<li><b>Hamacher</b> (simplified) with Hamacher product as T-norm and Einstein
+sum as T-conorm;
+</ul>
+There is no residuum for drastic and Hamacher families.
+For more details see <a href="http://www.jstatsoft.org/v31/i02">Meyer D, Hornik
+K (2009)</a>; <a href="http://en.wikipedia.org/wiki/T-norm">T-norms</a>; 
+</dd>
+</dl>
+<h2>OUTPUTS</h2>
+<dl>
+<dt><b>output</b></dt>
+<dd>Map containing result of two-values operations. Multivalued operations will
+be avaialbel in the future. Map is always of type FCELLS and contains values
+from 0 (no membership) to 1 (full membership). Values between 0 and 1 indicate
+partial membership</dd>
+</dl>
+<h2>SEE ALSO</h2>
+<em>
+<a href="r.fuzzy.html">r.fuzzy</a>,
+<a href="r.mapcalc.html">r.mapcalc</a>,
+</em>
+
+
+<h2>REFERENCES</h2>
+
+Zadeh, L.A. (1965). "Fuzzy sets". Information and Control 8 (3): 338–353.
+doi:10.1016/S0019-9958(65)90241-X. ISSN 0019-9958.<p>
+
+Novák, Vilém (1989). Fuzzy Sets and Their Applications. Bristol: Adam Hilger.
+ISBN 0-85274-583-4.<p>
+
+Klir, George J.; Yuan, Bo (1995). Fuzzy sets and fuzzy logic: theory and
+applications. Upper Saddle River, NJ: Prentice Hall PTR. ISBN 0-13-101171-5.<p>
+
+Klir, George J.; St Clair, Ute H.; Yuan, Bo (1997). Fuzzy set theory:
+foundations and applications. Englewood Cliffs, NJ: Prentice Hall. ISBN
+0133410587.<p>
+
+Meyer D, Hornik K (2009a). \Generalized and Customizable Sets in R." Journal of
+Statistical Software, 31(2), 1{27. URL http://www.jstatsoft.org/v31/i02/.<p>
+
+Meyer D, Hornik K (2009b). sets: Sets, Generalized Sets, and Customizable Sets.
+R~package version~1.0, URL http://CRAN.R-project.org/package=sets.<p>
+
+<h2>AUTHOR</h2>
+Jarek  Jasiewicz
+
+<p><i>Last changed: $Date: 2011-11-08 22:56:45 +0100 (Tue, 08 Nov 2011) $</i>
+

Added: grass-addons/grass7/grass7/raster/r.fuzzy/r.fuzzy.set/Makefile
===================================================================
--- grass-addons/grass7/grass7/raster/r.fuzzy/r.fuzzy.set/Makefile	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.fuzzy/r.fuzzy.set/Makefile	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,11 @@
+MODULE_TOPDIR = ../../..
+
+PGM = r.fuzzy.set
+
+LIBES = $(RASTERLIB) $(GISLIB) $(MATHLIB)
+DEPENDENCIES = $(RASTERDEP) $(GISDEP)
+
+include $(MODULE_TOPDIR)/include/Make/Module.make
+
+default: cmd
+

Added: grass-addons/grass7/grass7/raster/r.fuzzy/r.fuzzy.set/boundary.png
===================================================================
(Binary files differ)


Property changes on: grass-addons/grass7/grass7/raster/r.fuzzy/r.fuzzy.set/boundary.png
___________________________________________________________________
Added: svn:mime-type
   + application/octet-stream

Added: grass-addons/grass7/grass7/raster/r.fuzzy/r.fuzzy.set/fuzzy.c
===================================================================
--- grass-addons/grass7/grass7/raster/r.fuzzy/r.fuzzy.set/fuzzy.c	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.fuzzy/r.fuzzy.set/fuzzy.c	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,52 @@
+#include <grass/glocale.h>
+#include "local_proto.h"
+
+float fuzzy (FCELL cell) {
+
+	float x, m;
+	
+	if (!side) { /* both left and right */
+	
+			if (cell <= p[0] || cell >= p[3])
+		return 0.;
+			if (cell >= p[1] && cell <= p[2])
+		return 1.;	
+
+		x = (cell<p[1]) ? (cell-p[0])/(p[1]-p[0])
+				: (p[3]-cell)/(p[3]-p[2]);
+	}
+	
+	if (side) { /* left: 1 OR right: 2 */
+
+			if (cell <= p[0])
+		return (side == 1) ? 0. : 1.;
+			if (cell >= p[1])
+		return (side == 1) ? 1. : 0.;
+	
+		x = (side == 1) ? (cell-p[0])/(p[1]-p[0])
+				: (p[1]-cell)/(p[1]-p[0]);
+	}
+
+		if (type == LINEAR)
+	return x;
+		
+		if (type == JSHAPE) {
+	m = (shape < 0) ? pow(2,1+shape) 
+			: pow(2,exp(2*shape));	
+	return pow(tan(x * PI4),m);
+		}
+		
+		if (type == GSHAPE) {
+	m = (shape > 0) ? pow(2,1-shape) 
+			: pow(2,exp(-2*shape));	
+	return pow(tan(x * PI4),1/m);	
+		}
+	
+			if(type==SSHAPE) {
+		m =  pow(2,exp(2*abs(shape)));
+		return (shape < 0) ? pow(1-cos(x*PI2),m)
+			: pow(sin(x*PI2),m);
+	}
+
+return -1; /* error */
+}

Added: grass-addons/grass7/grass7/raster/r.fuzzy/r.fuzzy.set/local_proto.h
===================================================================
--- grass-addons/grass7/grass7/raster/r.fuzzy/r.fuzzy.set/local_proto.h	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.fuzzy/r.fuzzy.set/local_proto.h	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,36 @@
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <math.h>
+#include <grass/raster.h>
+#include <grass/gis.h>
+#include <grass/glocale.h>
+/*
+PI2= PI/2
+PI4= PI/4
+*/
+#ifndef PI2
+	#define PI2 (2*atan(1))
+#endif
+
+#ifndef PI4
+	#define PI4 (atan(1))
+#endif
+	
+
+#define LINEAR 0
+#define SSHAPE 1
+#define JSHAPE 2
+#define GSHAPE 3
+
+#define BOTH 0
+#define LEFT 1
+#define RIGHT 2
+
+extern char *input, *output;
+extern float shape, height;
+extern int type, side;
+extern double p[4]; /* inflection points */
+extern int num_points;
+
+float fuzzy (FCELL cell);

Added: grass-addons/grass7/grass7/raster/r.fuzzy/r.fuzzy.set/main.c
===================================================================
--- grass-addons/grass7/grass7/raster/r.fuzzy/r.fuzzy.set/main.c	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.fuzzy/r.fuzzy.set/main.c	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,239 @@
+/* ***************************************************************************
+ *
+ * MODULE:       r.fuzzy.set
+ * AUTHOR(S):    Jarek Jasiewicz <jarekj amu.edu.pl>
+ * PURPOSE:      Calculate membership value of any raster map according user's rules
+ * COPYRIGHT:    (C) 1999-2010 by the GRASS Development Team
+ *
+ *               This program is free software under the GNU General Public
+ *               License (>=v2). Read the file COPYING that comes with GRASS
+ *               for details.
+ *
+ ****************************************************************************
+ */
+
+#define MAIN
+#include <grass/gis.h>
+#include <grass/glocale.h>
+#include "local_proto.h"
+
+char *input, *output;
+float shape, height;
+int type, side;
+double p[4]; /* inflection points */
+int num_points;
+
+int main(int argc, char *argv[])
+{
+	struct GModule *module;
+	struct Option *par_input,
+								*par_output,
+								*par_points,
+								*par_side,
+								*par_type,
+								*par_height,
+								*par_shape;
+	
+	struct Cell_head cellhd; 
+  struct History history;
+	
+	
+	char *mapset;
+	int nrows, ncols;
+  int row, col;
+  int infd, outfd;
+  void *in_buf;
+	unsigned char *out_buf;
+  RASTER_MAP_TYPE raster_type;
+  FCELL tmp=0;
+	
+	G_gisinit(argv[0]);	
+	
+	par_input = G_define_standard_option(G_OPT_R_INPUT);
+  par_input->description = _("Raster map to be fuzzified");
+  
+  par_output = G_define_standard_option(G_OPT_R_OUTPUT);
+	par_output->description = _("Membership map");
+	
+	par_points=G_define_option();
+	par_points->key = "points";
+	par_points->type = TYPE_STRING;
+	par_points->answer = "a,b[,c,d]";
+	par_points->multiple = YES;
+	par_points->required = YES;
+	par_points->description = _("Inflection points: a,b[,c,d]");
+	
+	par_side=G_define_option();
+	par_side->key = "side";
+	par_side->type = TYPE_STRING;
+	par_side->options = "both,left,right";
+	par_side->answer = "both";
+	par_side->multiple = NO;
+	par_side->required = YES;
+	par_side->description = _("Fuzzy range");
+	
+	par_type=G_define_option();
+	par_type->key = "boundary";
+	par_type->type = TYPE_STRING;
+	par_type->options = "Linear,S-shaped,J-shaped,G-shaped";
+	par_type->answer = "S-shaped";
+	par_type->multiple = NO;
+	par_type->required = YES;
+	par_type->description = _("Type of fuzzy boundaries");
+	par_type->guisection = _("Default options");
+	
+	par_shape=G_define_option();
+	par_shape->key = "shape";
+	par_shape->type = TYPE_DOUBLE;
+	par_shape->options = "-1,1";
+	par_shape->answer = "0.";
+	par_shape->multiple = NO;
+	par_shape->required = YES;
+	par_shape->description = _("Shape modifier: -1 to 1");
+	par_shape->guisection = _("Default options");
+	
+	par_height=G_define_option();
+	par_height->key = "height";
+	par_height->type = TYPE_DOUBLE;
+	par_height->options = "0,1";
+	par_height->answer = "1.";
+	par_height->multiple = NO;
+	par_height->required = YES;
+	par_height->description = _("Membership height: 0 to 1");
+	par_height->guisection = _("Default options");
+	
+	    if (G_parser(argc, argv))
+	exit(EXIT_FAILURE);
+	
+	input=par_input->answer;
+	output=par_output->answer;
+		
+		if (!strcmp(par_type->answer, "Linear"))
+	type=LINEAR;
+		else if (!strcmp(par_type->answer, "S-shaped"))
+	type=SSHAPE;
+		else if (!strcmp(par_type->answer, "J-shaped"))
+	type=JSHAPE;
+		else if (!strcmp(par_type->answer, "G-shaped"))
+	type=GSHAPE;
+	
+			if (!strcmp(par_side->answer, "both"))
+	side=BOTH;
+		else if (!strcmp(par_side->answer, "left"))
+	side=LEFT;
+		else if (!strcmp(par_side->answer, "right"))
+	side=RIGHT;
+	
+	shape = atof(par_shape->answer);
+		if(shape<-1. || shape>1.)
+	G_fatal_error(_("Shape modifier must be between -1 and 1 but is %f"),shape);
+	
+	height = atof(par_height->answer);
+		if(height>1 || height<0)
+	G_fatal_error(_("Heght modifier must be between 0 and 1 but is %f"),height);
+		
+	num_points=sscanf(par_points->answer,
+			"%lf,%lf,%lf,%lf", 
+			&p[0], &p[1], &p[2], &p[3]);
+	
+		if(!side && num_points != 4)
+	G_fatal_error(_("Wrong number of values: got %d but need 4"),
+		      num_points);
+	
+			if(side && num_points != 2)
+	G_fatal_error(_("Wrong number of values: got %d but need 2"),
+		      num_points);
+	
+	if (num_points==2) {
+			if(	p[0]>p[1])
+		G_fatal_error(_("Point sequence must be: a <= b"));
+	} else {
+			if(	p[0]>p[1]||p[1]>p[2]||p[2]>p[3])
+		G_fatal_error(_("Point sequence must be: a <= b; b <= c; c <= d;"));	
+	}
+
+	/* end of interface */
+
+	mapset = (char *)G_find_raster2(input, "");
+	
+	    if (mapset == NULL)
+	G_fatal_error(_("Raster map <%s> not found"), input);
+	
+	infd = Rast_open_old(input, mapset);
+	Rast_get_cellhd(input, mapset, &cellhd);
+	
+	nrows = Rast_window_rows();
+	ncols = Rast_window_cols();
+	raster_type = Rast_map_type(input,mapset);
+	
+	outfd = Rast_open_new(output, FCELL_TYPE);
+	
+	in_buf = Rast_allocate_buf(raster_type);
+	out_buf = Rast_allocate_buf(FCELL_TYPE);
+	
+	/* processing */
+	for (row = 0; row < nrows; row++) {
+		G_percent(row, nrows, 2);
+		CELL c;
+		FCELL f;
+		DCELL d;
+		
+	Rast_get_row(infd, in_buf, row, raster_type);
+
+		for (col = 0; col < ncols; col++) {
+				 
+			switch (raster_type) {
+
+				case CELL_TYPE:
+			c = ((CELL *) in_buf)[col];
+				if(Rast_is_null_value(&c,CELL_TYPE))
+			Rast_set_f_null_value(&tmp, 1);
+				else {
+					if(0>(tmp = fuzzy((FCELL) c)))
+			G_warning("Cannot determine memebership at row %d, col %d", row,col);
+			((FCELL *) out_buf)[col] = tmp;
+				}
+			break;
+
+				case FCELL_TYPE:
+			f = ((FCELL *) in_buf)[col];
+				if(Rast_is_null_value(&f,FCELL_TYPE))
+			Rast_set_f_null_value(&tmp, 1);
+				else {			
+				tmp = fuzzy((FCELL) f);
+				if(0>(tmp = fuzzy((FCELL) f)))
+			G_warning("Cannot determine memebership at row %d, col %d", row,col);
+			((FCELL *) out_buf)[col] = tmp;
+				}
+			break;
+
+				case DCELL_TYPE:
+			d = ((DCELL *) in_buf)[col];
+				if(Rast_is_null_value(&d,DCELL_TYPE))
+			Rast_set_f_null_value(&tmp, 1);
+				else {
+				if(0>(tmp = fuzzy ((FCELL) d)))
+			G_warning("Cannot determine memebership at row %d, col %d", row,col);
+			((FCELL *) out_buf)[col] = tmp;
+				}
+			break;
+	    }
+		}
+		Rast_put_row(outfd, out_buf, FCELL_TYPE);
+	} /* end for */
+	
+  G_free(in_buf);
+  G_free(out_buf);
+
+	Rast_close(infd);
+	Rast_close(outfd);
+
+	Rast_short_history(output, "raster", &history);
+	Rast_command_history(&history);
+	Rast_write_history(output, &history);
+	
+	exit(EXIT_SUCCESS);
+}
+
+	
+	

Added: grass-addons/grass7/grass7/raster/r.fuzzy/r.fuzzy.set/r.fuzzy.set.html
===================================================================
--- grass-addons/grass7/grass7/raster/r.fuzzy/r.fuzzy.set/r.fuzzy.set.html	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.fuzzy/r.fuzzy.set/r.fuzzy.set.html	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,148 @@
+<h2>OPTIONS</h2>
+<dl>
+<dt><b>input</b></dt>
+<dd>Name of input raster map to be fuzified. This map may be of any type and may
+require null values. 
+</dd>
+<dt><b>points</b></dt>
+<dd>A list containing 4 (A,B,C,D) or 2 A,B) points defining set boundaries.
+Points must not to be in map range, but it may lead to only 0 o 1 membership for
+the whole map. For "both" side parameters range between A and D defines base,
+but range between B and C core of the fuzzy set. Between A and B and C and D are
+set's boundaries. If side is "both" it require 4 points, else 2 points.
+<center>
+<h3>Fuzzy set definition:</h3>
+<img src="set.png" border=1>
+</center>
+</dd>
+<dt><b>side</b></dt>
+<dd>Option indicate if set is fuzzified of both sides (both), left or right
+side. See description for details.
+<center>
+<h3>Boundary definition:</h3>
+<img src=boundary.png border=1><br>
+</center>
+</dd>
+</dl>
+
+<h2>OUTPUTS</h2>
+<dl>
+<dt><b>output</b></dt>
+<dd>Map containing membership value of original map. Map is alvays of type
+FCELLS and contains values from 0 (no membership) to 1 (full membership). Values
+between 0 and 1 indicate partial membership</dd>
+</dl>
+<h2>FUZZY SET PARAMETERS</h2>
+<dl>
+<dt><b>boundary</b></dt>
+<dd>Parameter definied the shape of the fuzzy boundary. The default and most
+popular is S-shaped, linear, J-shaped and G-shaped boundaries are also
+available. The same boundaires are appled to the both sides.</dd>
+
+<dt><b>shape</b></dt>
+<dd>Optional shape modifier. Range from -1 to 1. The default value is 0 and
+shoud  not be changed in most of the time. The negative values indicate more
+dilatant set, the positive values more concentrate set. See description for
+details.
+<center>
+<h3>Impact of shape parameter on shape boundary:</h3>
+<img src=shape.png border=1>
+</center>
+</dd>
+<dt><b>height</b></dt>
+<dd>Optional height modifier. Range from 0 to 1. The default value is 1 and
+indicate full membership beteen points B and C. If height is lesser than one the
+maximum memebrship is equal to height. See image: Fuzzy set definition.</dd>
+</dl>
+
+<h2>DESCRIPTION</h2>
+
+<h4>Definition of fuzzy set</h4>
+Fuzzy sets are sets whose elements have degrees of membership. Zadeh (1965)
+introduced Fuzzy sets as an extension of the classical notion of set. Classical 
+membership of elements in a set are binary terms: an element either belongs or
+does not belong to the set. Fuzzy set theory use the gradual assessment of the
+membership of elements in a set. A membership function valued in the real unit
+interval [0, 1]. Classical sets, are special cases of the membership functions
+of fuzzy sets, if the latter only take values 0 or 1. Classical sets are in
+fuzzy set theory usually called crisp sets. The fuzzy set theory can be used in
+a wide range of domains in which information is  imprecise, such as most of the
+GIS operations.
+
+
+<h2>NOTES</h2>
+<h4>Calculation of boundary shape</h4>
+Depending on type of the boundary different equation are used to determine its
+shape:
+<p>
+<b>Linear:</b> the membership is calculated according following equation:<br>
+<pre><code>
+value  <=  A -> x = 0
+A< value > B -> x = (value-A)/(B-A)
+B <= value >= C -> x = 1
+C< value > D -> x = (D-value)/(D-C)
+value  >=  D -> x = 0
+
+where x: membership
+</code></pre>
+<p>
+<b>S-shaped:</b> it use following equation:
+<pre><code>
+sin(x * Pi/2)^m (for positive shape parameter)
+1-cos(x * Pi/2)^m (for nagative shape parameter)
+
+where x: membership, and 
+m = 2^exp(2,shape) (for positive shape parameter)
+m = 2^(1+shape) (for negative shape parameter)
+where m: shape parameter.
+</code></pre>
+
+For default shape parameter = 0 m is = 2 whcich is most common parameter for
+that equation.
+
+<p>
+<b>G-shaped and J shaped:</b> it use following equations: 
+<pre><code>
+tan(x * Pi/4)^m (for J-shaped)
+tan(x * Pi/4)^1/m (for G-shaped)
+
+where x: membership, and 
+m = 2^exp(2,shape) (for positive shape parameter)
+m = 2^(1+shape) (for negative shape parameter)
+where m: shape parameter.
+</code></pre>
+ 
+
+<h2>SEE ALSO</h2>
+
+<em>
+<a href="r.fuzzy.logic.html">r.fuzzy.logic</a>,
+<a href="r.mapcalc.html">r.mapcalc</a>,
+</em>
+
+
+<h2>REFERENCES</h2>
+
+<p>Zadeh, L.A. (1965). "Fuzzy sets". Information and Control 8 (3): 338–353.
+doi:10.1016/S0019-9958(65)90241-X. ISSN 0019-9958.</P>
+
+<p>Novák, Vilém (1989). Fuzzy Sets and Their Applications. Bristol: Adam Hilger.
+ISBN 0-85274-583-4.</P>
+
+<p>Klir, George J.; Yuan, Bo (1995). Fuzzy sets and fuzzy logic: theory and
+applications. Upper Saddle River, NJ: Prentice Hall PTR. ISBN 0-13-101171-5.</P>
+
+<p>Klir, George J.; St Clair, Ute H.; Yuan, Bo (1997). Fuzzy set theory:
+foundations and applications. Englewood Cliffs, NJ: Prentice Hall. ISBN
+0133410587.</P>
+
+<p>Meyer D, Hornik K (2009a). \Generalized and Customizable Sets in R." Journal
+of Statistical Software, 31(2), 1{27. URL http://www.jstatsoft.org/v31/i02/.</P>
+
+Meyer D, Hornik K (2009b). sets: Sets, Generalized Sets, and Customizable Sets.
+R~package version~1.0, URL http://CRAN.R-project.org/package=sets.<p>
+
+<h2>AUTHOR</h2>
+Jarek  Jasiewicz
+
+<p><i>Last changed: $Date: 2011-11-08 22:56:45 +0100 (Tue, 08 Nov 2011) $</i>

Added: grass-addons/grass7/grass7/raster/r.fuzzy/r.fuzzy.set/set.png
===================================================================
(Binary files differ)


Property changes on: grass-addons/grass7/grass7/raster/r.fuzzy/r.fuzzy.set/set.png
___________________________________________________________________
Added: svn:mime-type
   + application/octet-stream

Added: grass-addons/grass7/grass7/raster/r.fuzzy/r.fuzzy.set/shape.png
===================================================================
(Binary files differ)


Property changes on: grass-addons/grass7/grass7/raster/r.fuzzy/r.fuzzy.set/shape.png
___________________________________________________________________
Added: svn:mime-type
   + application/octet-stream

Added: grass-addons/grass7/grass7/raster/r.fuzzy/r.fuzzy.system/Makefile
===================================================================
--- grass-addons/grass7/grass7/raster/r.fuzzy/r.fuzzy.system/Makefile	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.fuzzy/r.fuzzy.system/Makefile	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,10 @@
+MODULE_TOPDIR = ../../..
+
+PGM = r.fuzzy.system
+
+LIBES = $(RASTERLIB) $(GISLIB) $(MATHLIB)
+DEPENDENCIES = $(RASTERDEP) $(GISDEP)
+
+include $(MODULE_TOPDIR)/include/Make/Module.make
+
+default: cmd

Added: grass-addons/grass7/grass7/raster/r.fuzzy/r.fuzzy.system/f_result.png
===================================================================
(Binary files differ)


Property changes on: grass-addons/grass7/grass7/raster/r.fuzzy/r.fuzzy.system/f_result.png
___________________________________________________________________
Added: svn:mime-type
   + application/octet-stream

Added: grass-addons/grass7/grass7/raster/r.fuzzy/r.fuzzy.system/flood.map
===================================================================
--- grass-addons/grass7/grass7/raster/r.fuzzy/r.fuzzy.system/flood.map	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.fuzzy/r.fuzzy.system/flood.map	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,25 @@
+#flood.map
+
+	%elevation
+$ low {right; 2,4; sshaped; 0; 1}
+$ moderate {both; 2,4,5,10; sshaped; 0; 1}
+$ high {left; 5,10; sshaped; 0; 1}
+
+	%distance
+$ near {right; 30,70; sshaped; 0; 1}
+$ medium {both; 30,70,100,150; sshaped; 0; 1}
+$ far {both; 100,150,200,300; sshaped; 0; 1}
+$ veryfar {left; 200,300; sshaped; 0; 1}
+	
+	%accum_abs
+$ low {right; 500,5000; sshaped; 0; 1}
+$ $ high {left; 500,5000; sshaped; 0; 1}
+
+#output map
+
+	%_OUTPUT_
+$ none {both; 0,20,20,40; linear; 0;1}
+$ small {both; 20,40,40,60; linear; 0;1}
+$ moderate {both; 40,60,60,80; linear; 0;1}
+$ high {both; 60,80,80,100; linear; 0;1}
+$ veryhigh {both; 80,100,100,120; linear; 0;1}

Added: grass-addons/grass7/grass7/raster/r.fuzzy/r.fuzzy.system/flood.rul
===================================================================
--- grass-addons/grass7/grass7/raster/r.fuzzy/r.fuzzy.system/flood.rul	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.fuzzy/r.fuzzy.system/flood.rul	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,6 @@
+#flood.rul
+$ none {distance = veryfar | elevation = high}
+$ small {distance ~ near & accum_abs = high}
+$ moderate {(distance = medium | distance = far) & (elevation = low | elevation = moderate)}
+$ high {(distance = medium & elevation = low)|(distance = near & elevation = moderate)}
+$ veryhigh {distance = near & elevation = low}

Added: grass-addons/grass7/grass7/raster/r.fuzzy/r.fuzzy.system/fuzzylogic.c
===================================================================
--- grass-addons/grass7/grass7/raster/r.fuzzy/r.fuzzy.system/fuzzylogic.c	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.fuzzy/r.fuzzy.system/fuzzylogic.c	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,134 @@
+#include "local_proto.h"
+
+float fuzzy(FCELL cell, SETS * set)
+{
+
+    float x;
+
+    if (!set->side) {		/* both left and right */
+
+	if (cell <= set->points[0] || cell >= set->points[3])
+	    return 0.;
+	if (cell >= set->points[1] && cell <= set->points[2])
+	    return 1.;
+
+	x = (cell <
+	     set->points[1]) ? (cell - set->points[0]) / (set->points[1] -
+							  set->points[0])
+	    : (set->points[3] - cell) / (set->points[3] - set->points[2]);
+    }
+
+    if (set->side) {		/* left: 1 OR right: 2 */
+
+	if (cell <= set->points[0])
+	    return (set->side == 1) ? 0. : 1.;
+	if (cell >= set->points[1])
+	    return (set->side == 1) ? 1. : 0.;
+
+	x = (set->side ==
+	     s_LEFT) ? (cell - set->points[0]) / (set->points[1] -
+						  set->points[0])
+	    : (set->points[1] - cell) / (set->points[1] - set->points[0]);
+    }
+
+    switch (set->shape) {
+    case s_LINEAR:
+	break;
+    case s_SSHAPE:
+	x = pow(sin(x * PI2), 2);
+	break;
+    case s_JSHAPE:
+	x = pow(tan(x * PI4), 2);
+	break;
+    case s_GSHAPE:
+	x = pow(tan(x * PI4), 1 / 2.);
+	break;
+    }
+
+    if (set->hedge)
+	x = (set->hedge > 0) ? pow(x, pow(2, set->hedge)) : pow(x,
+								pow(0.5,
+								    (-set->
+								     hedge)));
+
+    if (set->height < 1)
+	x = x * set->height;
+
+    return (x >= 0 && x <= 1) ? x : -1;
+}
+
+float f_and(float x, float y, logics family)
+{
+    switch (family) {
+
+    case l_ZADEH:
+	return MIN(x, y);
+	break;
+
+    case l_PRODUCT:
+	return x * y;
+	break;
+
+    case l_DRASTIC:
+	return MAX(x, y) == 1 ? MIN(x, y) : 0;
+	break;
+
+    case l_LUKASIEWICZ:
+	return MAX((x + y - 1), 0);
+	break;
+
+    case l_FODOR:
+	return (x + y) > 1 ? MIN(x, y) : 0;
+	break;
+
+    case l_HAMACHER:
+	return (x == 0||y == 0) ? 0 : (x * y) / ((x + y) - x * y);
+	break;
+
+
+
+    }
+    return -1;			/* error */
+}
+
+float f_or(float x, float y, logics family)
+{
+
+    switch (family) {
+
+    case l_ZADEH:
+	return MAX(x, y);
+	break;
+
+    case l_PRODUCT:
+	return x + y - x * y;
+	break;
+
+    case l_DRASTIC:
+	return (MIN(x, y) == 0) ? MAX(x, y) : 1;
+	break;
+
+    case l_LUKASIEWICZ:
+	return MIN((x + y), 1);
+	break;
+
+    case l_FODOR:
+	return (x + y < 1) ? MAX(x, y) : 1;
+	break;
+
+    case l_HAMACHER:
+	return (x + y) / (1 + x * y);
+	break;
+    }
+    return -1;			/* error */
+}
+
+
+float f_not(float x, logics family)
+{
+
+    if (family == l_HAMACHER)
+	return (1 - x) / (1 + x);
+    else
+	return ((1 - x) < 0 || (1 - x) > 1) ? -1 : 1 - x;
+}

Added: grass-addons/grass7/grass7/raster/r.fuzzy/r.fuzzy.system/helpers.c
===================================================================
--- grass-addons/grass7/grass7/raster/r.fuzzy/r.fuzzy.system/helpers.c	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.fuzzy/r.fuzzy.system/helpers.c	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,270 @@
+#include "local_proto.h"
+
+int get_nsets(FILE * fd, fpos_t position)
+/* get number of maps (setd) used in analysis */
+{
+
+    int nsets = 0;
+
+    fsetpos(fd, &position);
+    char buf[500];
+
+    fgetpos(fd, &position);
+
+
+    while (fgets(buf, sizeof buf, fd)) {
+	G_strip(buf);
+
+	if (*buf == '#' || *buf == 0 || *buf == '\n')
+	    continue;
+
+	if (*buf == '$')
+	    nsets++;
+
+	if (*buf == '%')
+	    break;
+    }
+    fsetpos(fd, &position);
+    return nsets;
+}
+
+
+int char_strip(char *buf, char rem)
+/* remove spaces, tabs and one addational character */
+{
+    register char *a, *b;
+
+    for (a = b = buf; *a == rem || *a == ' ' || *a == '\t'; a++);
+    if (a != b)
+	while ((*b++ = *a++));
+
+    return 0;
+}
+
+int char_copy(const char *buf, char *res, int start, int stop)
+/* copy part of the string to another string */
+{
+    register int i, j;
+
+    for (i = start, j = 0; i < stop; res[j++] = buf[i++]) ;
+    res[j] = '\0';
+
+    return 0;
+}
+
+
+int get_universe(void)
+{
+    int i, j;
+    float min = 100000000., max = 0;
+
+    resolution += 1;
+
+    for (i = 0; i < nmaps; ++i) {
+	if (s_maps[i].output)
+	    break;
+    }
+    output_index = i;
+
+    for (j = 0; j < s_maps[i].nsets; ++j) {
+
+	min = (s_maps[i].sets[j].points[0] < min) ?
+	    s_maps[i].sets[j].points[0] : min;
+
+	if (s_maps[i].sets[j].side)
+	    max = (s_maps[i].sets[j].points[1] > max) ?
+		s_maps[i].sets[j].points[1] : max;
+	else
+	    max = (s_maps[i].sets[j].points[3] > max) ?
+		s_maps[i].sets[j].points[3] : max;
+    }
+
+
+    universe = (float *)G_calloc(resolution, sizeof(float));
+    for (i = 0; i < resolution; ++i)
+	universe[i] = min + ((max - min) / resolution) * i;
+
+/* visual output */
+
+    return 0;
+}
+
+void process_coors(char *answer)
+{
+
+    struct Cell_head window;
+    double x, y;
+    int i, j;
+    int r, c;
+    int num_points;
+    float result;
+
+		visual_output = (float **)G_malloc(resolution * sizeof(float *));
+
+				for (j = 0; j < nrules; ++j) 
+		for (i = 0; i < resolution; ++i) {
+	    visual_output[i] = (float *)G_calloc(nrules + 2, sizeof(float));
+	    visual_output[i][0] = universe[i];
+		}
+			
+    Rast_get_window(&window);
+    num_points = sscanf(answer, "%lf,%lf", &x, &y);
+
+    c = (int)Rast_easting_to_col(x, &window);
+    r = (int)Rast_northing_to_row(y, &window);
+    
+		get_rows(r);
+    get_cells(c);
+    
+    result = implicate(); /* jump to different function */
+
+    for (i = 0; i < nrules; ++i)
+	fprintf(stdout, "ANTECEDENT %s: %5.3f\n", s_rules[i].outname,
+		antecedents[i]);
+
+  fprintf(stdout, "RESULT (deffuzified):  %5.3f\n", result);
+  
+  fprintf(stdout, "UNIVERSE,");
+    for (i = 0; i < nrules; ++i)
+	fprintf(stdout, "%s,", s_rules[i].outname);
+    fprintf(stdout, "AGREGATE \n");
+
+    for (i = 0; i < resolution; ++i)
+	for (j = 0; j < nrules + 2; ++j) {
+	    fprintf(stdout, "%5.3f", visual_output[i][j]);
+	    if (j < nrules + 1)
+		fprintf(stdout, ",");
+	    else
+		fprintf(stdout, "\n");
+	}
+
+			for (i = 0; i < nmaps; ++i) {
+	G_free(s_maps[i].sets);
+	if (s_maps[i].output)
+	    continue;
+		G_free(s_maps[i].in_buf);
+	Rast_close(s_maps[i].cfd);
+    }
+
+			for (j = 0; j < nrules; ++j)
+				G_free(visual_output[j]);
+    G_free(visual_output);
+    
+    G_free(antecedents);
+    G_free(s_maps);
+    G_free(s_rules);
+   
+    exit(EXIT_SUCCESS);
+}
+
+
+void show_membership(void) {
+	int i,j,k;
+	STRING cur_mapset;
+	struct FPRange map_range;
+	DCELL min, max;
+	float* map_universe;
+	
+	resolution=resolution+1;
+	map_universe = (float *)G_calloc(resolution, sizeof(float));
+
+	for(i=0;i<nmaps;++i) {
+		
+		if(s_maps[i].output)
+			continue;
+		Rast_init_fp_range(&map_range);
+		cur_mapset = (STRING)G_find_raster2(s_maps[i].name, "");
+		Rast_read_fp_range(s_maps[i].name,cur_mapset,&map_range);
+		Rast_get_fp_range_min_max(&map_range,&min, &max);
+		
+			for (k = 0; k < resolution; ++k)
+		map_universe[k] = min + ((max - min) / resolution) * k;
+		
+		fprintf(stdout,"#MAP: %s \n",s_maps[i].name);
+		
+		fprintf(stdout,"value,");
+			for(j=0;j<s_maps[i].nsets;++j) {
+		fprintf(stdout,"%s",s_maps[i].sets[j].setname);
+				if (j < s_maps[i].nsets-1)
+			fprintf(stdout, ",");
+				else
+			fprintf(stdout, "\n");
+			}
+			
+			for(k=0;k<resolution;++k) { 
+				fprintf(stdout,"%5.3f,",map_universe[k]);
+				for(j=0;j<s_maps[i].nsets;++j) {
+					fprintf(stdout,"%5.3f",
+					fuzzy(map_universe[k],&s_maps[i].sets[j]));
+						if (j < s_maps[i].nsets-1)
+							fprintf(stdout, ",");
+						else
+							fprintf(stdout, "\n");
+				}
+			}
+	}
+
+	G_free(map_universe);
+
+    for (i = 0; i < nmaps; ++i)
+	G_free(s_maps[i].sets);
+
+    G_free(s_maps);
+    G_free(s_rules);
+
+		exit(EXIT_SUCCESS);
+	
+}
+
+int set_cats(void)
+{
+struct Categories cats;
+float fmin, fmax;
+int cmin, cmax;
+int i, j;
+
+fmin=universe[0];
+fmax=universe[resolution];
+cmin=(int)universe[0];
+cmax=(int)universe[resolution];
+double tmp1, tmp2;
+float fuzzy_val=0;
+char buf[200];
+float rang;
+
+rang=(universe[0]+universe[1])/2.;
+Rast_read_cats(output, G_mapset(), &cats);
+Rast_set_cats_title("Result membership", &cats);
+
+	for (i=0;i<resolution;++i) {
+		strcpy(buf,"");
+		for (j=0; j<s_maps[output_index].nsets; ++j) { 
+			fuzzy_val=fuzzy(universe[i],&s_maps[output_index].sets[j]);
+				
+				if(universe[i]<s_maps[output_index].sets[1].points[0] ||
+					universe[i]>s_maps[output_index].sets[s_maps[output_index].nsets-2].points[3])
+			fuzzy_val=1;	
+				if (fuzzy_val>0.)
+			sprintf(buf,"%s %s=%2.2f", buf, s_maps[output_index].sets[j].setname,fuzzy_val);	
+		}
+
+		tmp1=(double)universe[i]-rang;
+		tmp2=(double)universe[i]+rang;
+		if(i==0) tmp1=(double)universe[i];
+		if(i==resolution) tmp2=(double)universe[i];
+		Rast_set_d_cat(&tmp1, &tmp2, buf, &cats);
+	}	
+Rast_write_cats(output, &cats);
+Rast_free_cats(&cats);
+return 0;
+}
+
+
+/* not in use yet
+void set_colors(void) {
+struct Colors colors;
+Rast_init_colors(&colors);
+Rast_add_d_color_rule(&val1, 255, 255, 255, &val2, 255, 255, 0, &colors);
+Rast_write_colors(output, G_mapset(), &colors);
+}
+*/

Added: grass-addons/grass7/grass7/raster/r.fuzzy/r.fuzzy.system/io.c
===================================================================
--- grass-addons/grass7/grass7/raster/r.fuzzy/r.fuzzy.system/io.c	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.fuzzy/r.fuzzy.system/io.c	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,108 @@
+#include "local_proto.h"
+
+int open_maps(void)
+{
+
+    int i;
+    char *mapset;
+    struct Cell_head cellhd;
+
+			for (i = 0; i < nmaps; ++i) {
+		if (s_maps[i].output) {
+	s_maps[i].in_buf = NULL;
+	continue;
+		}
+	mapset = (char *)G_find_raster2(s_maps[i].name, "");
+
+	if (mapset == NULL)
+	    G_fatal_error(_("Raster map <%s> not found"), s_maps[i].name);
+
+	s_maps[i].cfd = Rast_open_old(s_maps[i].name, mapset);
+	Rast_get_cellhd(s_maps[i].name, mapset, &cellhd);
+
+	s_maps[i].raster_type = Rast_map_type(s_maps[i].name,mapset);
+	s_maps[i].in_buf = Rast_allocate_buf(s_maps[i].raster_type);
+			}
+	return 0;
+}
+
+int get_rows(int row)
+{
+	int i;
+
+    for (i = 0; i < nmaps; ++i) {
+			if (s_maps[i].output)
+		continue;
+	Rast_get_row(s_maps[i].cfd, s_maps[i].in_buf, row,
+	     s_maps[i].raster_type);
+		}
+  return 0;
+}
+
+int get_cells(int col)
+{
+    int i;
+    CELL c;
+    FCELL f;
+    DCELL d;
+
+    for (i = 0; i < nmaps; ++i) {
+
+	if (s_maps[i].output)
+	    continue;
+
+	switch (s_maps[i].raster_type) {
+
+	case CELL_TYPE:
+	    c = ((CELL *) s_maps[i].in_buf)[col];
+	    if (Rast_is_null_value(&c, CELL_TYPE))
+		return 1;
+	    else
+		s_maps[i].cell = (DCELL) c;
+	    break;
+
+	case FCELL_TYPE:
+	    f = ((FCELL *) s_maps[i].in_buf)[col];
+	    if (Rast_is_null_value(&f, FCELL_TYPE))
+		return 1;
+	    else
+		s_maps[i].cell = (DCELL) f;
+	    break;
+
+	case DCELL_TYPE:
+	    d = ((DCELL *) s_maps[i].in_buf)[col];
+	    if (Rast_is_null_value(&d, DCELL_TYPE))
+		return 1;
+	    else
+		s_maps[i].cell = (DCELL) d;
+	    break;
+	}
+    }				/* end for */
+
+    return 0;
+}
+
+int create_output_maps(void)
+{
+
+    STRING connector = "_";
+    int i;
+
+    m_outputs = (OUTPUTS *) G_malloc(nrules * sizeof(OUTPUTS));
+
+    for (i = 0; i < nrules; ++i) {
+	strcpy(m_outputs[i].output_name, output);
+	strcat(m_outputs[i].output_name, connector);
+	strcat(m_outputs[i].output_name, s_rules[i].outname);
+
+	if ((m_outputs[i].ofd =
+	     Rast_open_new(m_outputs[i].output_name, FCELL_TYPE)) < 0)
+	    G_fatal_error(_("Unable to create raster map <%s>"),
+			  m_outputs[i].output_name);
+
+	m_outputs[i].out_buf = Rast_allocate_f_buf();
+
+    }
+return 0;
+}
+

Added: grass-addons/grass7/grass7/raster/r.fuzzy/r.fuzzy.system/local_proto.h
===================================================================
--- grass-addons/grass7/grass7/raster/r.fuzzy/r.fuzzy.system/local_proto.h	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.fuzzy/r.fuzzy.system/local_proto.h	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,190 @@
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <math.h>
+#include <grass/gis.h>
+#include <grass/raster.h>
+#include <grass/glocale.h>
+
+/*
+   PI2= PI/2
+   PI4= PI/4
+ */
+#ifndef PI2
+#define PI2 (2*atan(1))
+#endif
+
+#ifndef PI4
+#define PI4 (atan(1))
+#endif
+
+#define STACKMAX 50
+#define VARMAX 31
+
+#define MAX(a,b) ((a) > (b) ? (a) : (b))
+#define MIN(a,b) ((a) < (b) ? (a) : (b))
+
+
+typedef char *STRING;
+
+typedef enum
+{
+    l_ZADEH,
+    l_PRODUCT,
+    l_DRASTIC,
+    l_LUKASIEWICZ,
+    l_FODOR,
+    l_HAMACHER
+} logics;
+
+typedef enum
+{
+    s_LINEAR,
+    s_SSHAPE,
+    s_JSHAPE,
+    s_GSHAPE
+} shapes;
+
+typedef enum
+{
+    s_BOTH,
+    s_LEFT,
+    s_RIGHT
+} sides;
+
+typedef enum
+{
+    i_MIN,
+    i_PROD
+} implications;
+
+typedef enum
+{
+    d_CENTEROID,
+    d_BISECTOR,
+    d_MINOFHIGHEST,
+    d_MAXOFHIGHEST,
+    d_MEANOFHIGHEST
+} defuzz;
+
+typedef enum
+{
+    E,				/* ERROR */
+    S,				/* SHIFT */
+    R,				/* REDUCE */
+    A				/* ACCEPT */
+} actions;
+
+typedef enum
+{
+    t_START,			/* { */
+    t_AND,			/* & */
+    t_OR,			/* | */
+    t_IS_NOT,			/* ~ */
+    t_IS,			/* = */
+    t_LBRC,			/* ( */
+    t_RBRC,			/* ) */
+    t_STOP,			/* } */
+    t_size,			/* number of tokens */
+    t_VAL			/* value a product of MAP and VARIABLE */
+} tokens;
+
+typedef struct
+{				/* membership definition */
+    char setname[21];
+    sides side;
+    float points[4];
+    shapes shape;
+    int hedge;
+    float height;
+} SETS;
+
+typedef struct
+{
+    char name[30];
+    int nsets;
+    int output;			/* is output map? */
+    RASTER_MAP_TYPE raster_type;
+    fpos_t position;
+    void *in_buf;
+    DCELL cell;
+    int cfd;			/* file descriptor */
+    SETS *sets;
+} MAPS;
+
+typedef struct
+{
+    DCELL *value;
+    SETS *set;
+    char oper;
+} VALUES;
+
+
+typedef struct /* stores queues with rules */
+{
+    char outname[20];
+    int output_set_index;
+    char parse_queue[STACKMAX][VARMAX]; /* original rule */
+    int work_queue[STACKMAX]; /* symbols of values and operators */
+    VALUES value_queue[STACKMAX]; /* pointers to values, operators and sets */
+    float weight;
+} RULES;
+
+typedef struct _outs
+{
+    char output_name[52];
+    int ofd;			/* output file descriptor */
+    FCELL *out_buf;
+} OUTPUTS;
+
+
+extern STRING var_name_file;
+extern STRING rule_name_file;
+extern STRING output;
+extern MAPS *s_maps;
+extern RULES *s_rules;
+extern OUTPUTS *m_outputs;
+extern float **visual_output;
+extern float *universe;
+extern float *antecedents;
+extern float *agregate;
+extern int nmaps, nrules, output_index, multiple, membership_only, coor_proc;
+extern int resolution;
+extern implications implication;
+extern defuzz defuzzyfication;
+extern logics family;
+
+extern char **rules;
+extern int HERE;
+
+int char_strip(char *buf, char rem);
+int char_copy(const char *buf, char *res, int start, int stop);
+int get_nsets(FILE * fd, fpos_t position);
+int get_universe(void);
+int set_cats(void);
+
+int parse_map_file(STRING file);
+int parse_rule_file(STRING file);
+int parser(void);
+int open_maps(void);
+int create_output_maps(void);
+int get_rows(int row);
+int get_cells(int col);
+
+int parse_sets(SETS * set, char buf[], const char mapname[]);
+int parse_rules(int rule_num, int n, char buf[]);
+void process_coors(char *answer);
+void show_membership(void);
+
+float implicate(void);
+float parse_expression(int n);
+float defuzzify(int defuzzification, float max_agregate);
+
+float f_and(float cellx, float celly, logics family);
+float f_or(float cellx, float celly, logics family);
+float f_not(float cellx, logics family);
+float fuzzy(FCELL cell, SETS * set);
+
+int parse(void);
+void display(void);
+

Added: grass-addons/grass7/grass7/raster/r.fuzzy/r.fuzzy.system/main.c
===================================================================
--- grass-addons/grass7/grass7/raster/r.fuzzy/r.fuzzy.system/main.c	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.fuzzy/r.fuzzy.system/main.c	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,276 @@
+/* ***************************************************************************
+ *
+ * MODULE:       r.fuzzy.system
+ * AUTHOR(S):    Jarek Jasiewicz <jarekj amu.edu.pl>
+ * PURPOSE:      Full fuzzy logic standalone classification system with few fuzzy logic families 
+ *                                                       implication and defuzzification and methods.
+ * COPYRIGHT:    (C) 1999-2010 by the GRASS Development Team
+ *
+ *               This program is free software under the GNU General Public
+ *               License (>=v2). Read the file COPYING that comes with GRASS
+ *               for details.
+ *
+ *************************************************************************** */
+
+#include <grass/gis.h>
+#include <grass/glocale.h>
+#include "local_proto.h"
+
+STRING var_name_file;
+STRING rule_name_file;
+STRING output;
+MAPS *s_maps;
+RULES *s_rules;
+OUTPUTS *m_outputs;
+float **visual_output;
+float *universe;
+float *antecedents;
+float *agregate;
+int nmaps, nrules, output_index, multiple, membership_only, coor_proc;
+int resolution;
+implications implication;
+defuzz defuzzyfication;
+logics family;
+
+char **rules;
+int HERE;
+
+int main(int argc, char **argv)
+{
+    struct Option *file_vars,
+	*file_rules,
+	*par_family,
+	*par_resolution,
+	*par_defuzzify, *par_implication, *in_coor_opt, *opt_output;
+
+    struct History history;
+
+    struct GModule *module;
+    struct Flag *out_multiple, *out_membership;
+
+    int nrows, ncols;
+    int row, col;
+    int outfd;
+    float tmp;
+    FCELL *out_buf;
+
+    int i, j, n;
+
+    G_gisinit(argv[0]);
+
+    module = G_define_module();
+    module->keywords = _("raster, fuzzy logic");
+    module->description =
+        _("xxxx");
+
+    file_vars = G_define_standard_option(G_OPT_F_INPUT);
+    file_vars->key = "maps";
+    file_vars->required = YES;
+    file_vars->description = _("Name of fuzzy variable file");
+
+    file_rules = G_define_standard_option(G_OPT_F_INPUT);
+    file_rules->key = "rules";
+    file_rules->required = NO;
+    file_rules->description = _("Name of rules file");
+
+    par_family = G_define_option();
+    par_family->key = "family";
+    par_family->type = TYPE_STRING;
+    par_family->options = "Zadeh,product,drastic,Lukasiewicz,Fodor,Hamacher";
+    par_family->answer = "Zadeh";
+    par_family->required = YES;
+    par_family->description = _("Fuzzy logic family");
+    par_family->guisection = _("Advanced options");
+
+    par_defuzzify = G_define_option();
+    par_defuzzify->key = "defuz";
+    par_defuzzify->type = TYPE_STRING;
+    par_defuzzify->options = "centroid,bisector,min_of_highest,max_of_highest,mean_of_highest";
+    par_defuzzify->answer = "bisector";
+    par_defuzzify->required = YES;
+    par_defuzzify->description = _("Defuzzyfication method");
+    par_defuzzify->guisection = _("Advanced options");
+
+    par_implication = G_define_option();
+    par_implication->key = "imp";
+    par_implication->type = TYPE_STRING;
+    par_implication->options = "minimum,product";
+    par_implication->answer = "minimum";
+    par_implication->required = YES;
+    par_implication->description = _("Implication method");
+    par_implication->guisection = _("Advanced options");
+
+    par_resolution = G_define_option();
+    par_resolution->key = "res";
+    par_resolution->type = TYPE_INTEGER;
+    par_resolution->answer = "100";
+    par_resolution->required = YES;
+    par_resolution->description = _("Universe resolution");
+    par_resolution->guisection = _("Advanced options");
+
+    in_coor_opt = G_define_option();	/* input coordinates de outlet */
+    in_coor_opt->key = "coors";
+    in_coor_opt->type = TYPE_STRING;
+    in_coor_opt->key_desc = "x,y";
+    in_coor_opt->answer = NULL;
+    in_coor_opt->required = NO;
+    in_coor_opt->multiple = NO;
+    in_coor_opt->description =
+	"Coordinate of cell for detail data (print end exit)";
+    in_coor_opt->guisection = _("Visual Output");
+
+    out_membership = G_define_flag();
+    out_membership->key = 'o';
+    out_membership->description =
+	_("Print only membership values and exit");
+		out_membership->guisection = _("Visual Output");
+
+    out_multiple = G_define_flag();
+    out_multiple->key = 'm';
+    out_multiple->description =
+	_("Create addational fuzzy output maps for every rule");
+
+
+    opt_output = G_define_standard_option(G_OPT_R_OUTPUT);
+    opt_output->description = _("Name of output file");
+		opt_output->required = NO;
+
+    if (G_parser(argc, argv))
+	exit(EXIT_FAILURE);
+
+    var_name_file = file_vars->answer;
+    rule_name_file = file_rules->answer;
+    output = opt_output->answer;
+    multiple = (out_multiple->answer != 0);
+    membership_only = (out_membership->answer != 0);
+    coor_proc = (in_coor_opt->answer) ? 1 : 0;
+
+			if(!membership_only & (!output | !rule_name_file))
+		G_fatal_error(_("for standard analysis both output and rule file are required"));
+
+    resolution = atoi(par_resolution->answer);
+    if (resolution < 10)
+	G_fatal_error(_("Universe resolution too small, choose greater value"));
+    if (resolution > 500)
+	G_warning(_("Universe resolution is very high, computation may take a long time"));
+
+    if (!strcmp(par_family->answer, "Zadeh"))
+	family = l_ZADEH;
+    else if (!strcmp(par_family->answer, "product"))
+	family = l_PRODUCT;
+    else if (!strcmp(par_family->answer, "drastic"))
+	family = l_DRASTIC;
+    else if (!strcmp(par_family->answer, "Lukasiewicz"))
+	family = l_LUKASIEWICZ;
+    else if (!strcmp(par_family->answer, "Fodor"))
+	family = l_FODOR;
+    else if (!strcmp(par_family->answer, "Hamacher"))
+	family = l_HAMACHER;
+
+    if (!strcmp(par_implication->answer, "minimum"))
+	implication = i_MIN;
+    else if (!strcmp(par_implication->answer, "product"))
+	implication = i_PROD;
+
+    if (!strcmp(par_defuzzify->answer, "centroid"))
+	defuzzyfication = d_CENTEROID;
+    else if (!strcmp(par_defuzzify->answer, "bisector"))
+	defuzzyfication = d_BISECTOR;
+    else if (!strcmp(par_defuzzify->answer, "min_of_highest"))
+	defuzzyfication = d_MINOFHIGHEST;
+    else if (!strcmp(par_defuzzify->answer, "max_of_highest"))
+	defuzzyfication = d_MAXOFHIGHEST;
+    else if (!strcmp(par_defuzzify->answer, "mean_of_highest"))
+	defuzzyfication = d_MEANOFHIGHEST;
+
+    nrows = Rast_window_rows();
+    ncols = Rast_window_cols();
+		
+		parse_map_file(var_name_file);
+			if (membership_only)
+    show_membership();
+    
+		parse_rule_file(rule_name_file);
+    get_universe();
+    open_maps();
+	
+		antecedents = (float *)G_malloc(nrules * sizeof(float));
+		agregate = (float *)G_calloc(resolution, sizeof(float));
+			if (coor_proc)
+		process_coors(in_coor_opt->answer);
+
+   outfd = Rast_open_new(output, FCELL_TYPE);
+   out_buf = Rast_allocate_f_buf();
+
+    if (multiple)
+	create_output_maps();
+  
+		G_message("Calculate...");
+
+	for (row = 0; row < nrows; ++row) {
+		G_percent(row, nrows, 2);
+		get_rows(row);
+		for (col = 0; col < ncols; ++col) {
+	    if (get_cells(col)) {
+		Rast_set_f_null_value(&out_buf[col], 1);
+
+		if (multiple) {
+		    for (i = 0; i < nrules; ++i)
+			Rast_set_f_null_value(&m_outputs[i].out_buf[col], 1);
+		}
+	    }
+	    else {
+		out_buf[col] = implicate();
+			if (out_buf[col] == -9999)
+		Rast_set_f_null_value(&out_buf[col], 1);
+
+		if (multiple) {
+		    for (i = 0; i < nrules; ++i)
+			m_outputs[i].out_buf[col] = antecedents[i];
+		}
+	    }
+	}
+	Rast_put_row(outfd, out_buf, FCELL_TYPE);
+
+			if (multiple) 
+	  for (i = 0; i < nrules; ++i)
+	Rast_put_row(m_outputs[i].ofd, m_outputs[i].out_buf, FCELL_TYPE);
+    }
+  G_percent(row, nrows, 2);
+		
+  G_message("Close...");
+
+		
+
+  Rast_close(outfd);
+  Rast_short_history(output, "raster", &history);
+  Rast_command_history(&history);
+  Rast_write_history(output, &history);
+	set_cats();
+		/* free */
+			for (i = 0; i < nmaps; ++i) {
+		G_free(s_maps[i].sets);
+				if (s_maps[i].output)
+	    continue;
+		G_free(s_maps[i].in_buf);
+		Rast_close(s_maps[i].cfd);
+			}
+  G_free(antecedents);
+  G_free(agregate);
+  G_free(out_buf);
+  G_free(s_maps);
+  G_free(s_rules);
+   
+    if (multiple)
+	for (i = 0; i < nrules; ++i) {
+	  G_free(m_outputs[i].out_buf);
+	  Rast_close(m_outputs[i].ofd);
+	  Rast_short_history(m_outputs[i].output_name, "raster", &history);
+	  Rast_command_history(&history);
+	  Rast_write_history(m_outputs[i].output_name, &history);
+	}
+
+   G_message("Done!");
+    exit(EXIT_SUCCESS);
+
+}

Added: grass-addons/grass7/grass7/raster/r.fuzzy/r.fuzzy.system/map_parser.c
===================================================================
--- grass-addons/grass7/grass7/raster/r.fuzzy/r.fuzzy.system/map_parser.c	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.fuzzy/r.fuzzy.system/map_parser.c	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,222 @@
+#include "local_proto.h"
+
+int parse_map_file(STRING file)
+{
+    FILE *fd;
+    int line = 0;
+    char buf[500];
+    STRING mapset;
+    char map[30];
+    int nmaps2 = 0, nsets = 0;
+    fpos_t init;
+    fpos_t position;
+    int set_num;
+
+    int i;
+
+    fd = fopen(file, "r");
+    if (!fd)
+	G_fatal_error(_("Cannot open map file '%s'"), file);
+
+    fgetpos(fd, &init);
+
+    nmaps = 0;
+    /* number of maps */
+    while (fgets(buf, sizeof buf, fd)) {
+	G_strip(buf);
+	if (*buf != '%')
+	    continue;
+	nmaps++;
+    }
+    s_maps = (MAPS *) G_malloc(nmaps * sizeof(MAPS));
+    fsetpos(fd, &init);		/* reset position */
+
+    while (fgets(buf, sizeof buf, fd)) {
+	line++;
+
+	G_strip(buf);
+	if (*buf == '#' || *buf == 0 || *buf == '\n')
+	    continue;
+
+	if (*buf != '%' && *buf != '$')
+	    G_fatal_error(_("Wrong syntax at line %d: line must start with <#>, <%> or <$> or be empty line"),
+			  line);
+
+	if (*buf == '%') {
+
+	    fgetpos(fd, &position);
+
+	    sscanf(buf, "%[^\n]", map);
+	    char_strip(map, '%');
+	    G_strip(map);
+	    mapset = (STRING)G_find_raster2(map, "");
+
+	    if (mapset == NULL && strcmp(map, "_OUTPUT_"))
+		G_fatal_error(_("Raster map <%s> not found"), map);
+
+				if (!strcmp(map, "_OUTPUT_")) {
+			strcpy(s_maps[nmaps2].name, output);
+			s_maps[nmaps2].output=1;
+				} else {
+	    strcpy(s_maps[nmaps2].name, map);
+	    s_maps[nmaps2].output=0;
+				}
+	    s_maps[nmaps2].position = position;
+	    s_maps[nmaps2].nsets = get_nsets(fd, position);
+	    
+
+	    if (!s_maps[nmaps2].nsets)
+		G_warning(_("map <%s> has no rules"), s_maps[nmaps2].name);
+
+	    if (s_maps[nmaps2].nsets)
+		s_maps[nmaps2].sets =
+		    (SETS *) G_malloc(s_maps[nmaps2].nsets * sizeof(SETS));
+
+	    set_num = 0;
+	    while (fgets(buf, sizeof buf, fd)) {
+		G_strip(buf);
+
+		if (*buf == '#' || *buf == 0 || *buf == '\n')
+		    continue;
+		if (*buf == '%')
+		    break;
+
+		parse_sets(&s_maps[nmaps2].sets[set_num++], buf,
+			   s_maps[nmaps2].name);
+
+	    }
+	    fsetpos(fd, &position);
+
+	    if (nmaps2++ > nmaps)
+		G_fatal_error(_("number of maps do not match"));
+
+	}
+
+    }				/* end while */
+
+    fclose(fd);
+    return 0;
+}
+
+
+int parse_sets(SETS * set, char buf[], const char mapname[])
+{
+
+    char tmp[20];
+    int i;
+
+    char_strip(buf, '$');
+
+    {				/* check length of fuzzy value (cannot be longer than 20) */
+	sscanf(buf, "%[^{] %[^\n]", tmp, buf);
+	G_strip(tmp);
+
+	if (strlen(tmp) < 21)
+	    strcpy(set->setname, tmp);
+	else
+	    G_fatal_error(_("Map: <%s>, Membership: <%s>: Value name cannot be longer than 20 chars, but has %d chars"),
+			  mapname, tmp, (int)strlen(tmp));
+    }				/* check length of fuzzy value */
+
+    {				/* check if side is valid (both,left,right) */
+	int done = 1;
+	STRING sides[] = { "both", "left", "right" };
+
+	char_strip(buf, '{');
+	sscanf(buf, "%[^;] %[^\n]", tmp, buf);
+
+	done = 0;
+	for (i = 0; i < 3; ++i)
+	    if (strcmp(tmp, sides[i]) == 0) {
+		done = 1;
+		break;
+	    }
+
+	if (done)
+	    set->side = i;
+	else
+	    G_fatal_error(_(" Map: <%s>, Membership: <%s>:  <side> parameter must be:  <left,right,both> but is: <%s>"),
+			  mapname, set->setname, tmp);
+    }				/* end check if side is valid */
+
+
+    {				/* check number of points and order.  Point number limited to 10 chars including coma */
+	char p[11];
+	int npoints;
+
+	char_strip(buf, ';');
+	sscanf(buf, "%[^;] %[^\n]", tmp, buf);
+	char_strip(tmp, ';');
+
+	npoints = set->side ? 2 : 4;
+
+	for (i = 0; i < npoints; ++i) {
+	    sscanf(tmp, "%[^,] %[^\n]", p, tmp);
+
+	    if (tmp[0] != ',' && i < (npoints - 1))
+		G_fatal_error(_("Map: <%s>, Variable: <%s>: Require %d points but has %d"),
+			      mapname, set->setname, npoints, i + 1);
+
+	    if (sscanf(p, "%f", &set->points[i]) != 1)
+		G_fatal_error(_("Map: <%s>, Variable: <%s>: Points must be numeric  but is: %s or space between '-' and digit"),
+			      mapname, set->setname, p);
+
+	    char_strip(tmp, ',');
+
+	    if (i > 0 && (set->points[i] < set->points[i - 1]))
+		G_fatal_error(_("Map: <%s>, Membership: <%s>: Points sequence must be non-declining"),
+			      mapname, set->setname);
+	}
+
+    }				/* check number of points and order */
+
+
+    {				/* check if shape is valid (linear,sshaped,jshaped,gshaped) */
+	int done = 1;
+	STRING shapes[] = { "linear", "sshaped", "jshaped", "gshaped" };
+
+	char_strip(buf, ';');
+	sscanf(buf, "%[^;] %[^\n]", tmp, buf);
+
+	done = 0;
+	for (i = 0; i < 4; ++i)
+	    if (strcmp(tmp, shapes[i]) == 0) {
+		done = 1;
+		break;
+	    }
+
+	if (done)
+	    set->shape = i;
+	else
+	    G_fatal_error(_(" Map: <%s>, Variable: <%s>:  <shape> parameter must be: <linear,sshaped,jshaped,gshaped> but is: <%s>"),
+			  mapname, set->setname, tmp);
+    }				/* end check if shape is valid */
+
+
+    {				/* check if hedge is valid  (integer) */
+	char_strip(buf, ';');
+	sscanf(buf, "%[^;] %[^\n]", tmp, buf);
+
+	if (sscanf(tmp, "%d", &set->hedge) != 1)
+	    G_fatal_error(_("Map: <%s>, variable: <%s>: Hedge must be numeric  but is: %s or space between '-' and digit"),
+			  mapname, set->setname, tmp);
+
+    }				/* end check if hedge is valid */
+
+
+    {				/* check if height is valid  (float 0-1) */
+	char_strip(buf, ';');
+	sscanf(buf, "%[^}] %[^\n]", tmp, buf);
+
+	if (sscanf(tmp, "%f", &set->height) != 1)
+	    G_fatal_error(_("Map: <%s>, Variable: <%s>: Height must be  non-negative numeric lesser than 1 but is: %s"),
+			  mapname, set->setname, tmp);
+
+	if (set->height <= 0 || set->height > 1)
+	    G_fatal_error(_("Map: <%s>, Variable: <%s>: Height must be  non-negative numeric lesser than 1 but is: %f"),
+			  mapname, set->setname, set->height);
+
+    }				/* end check if height is valid */
+
+    return 0;
+}

Added: grass-addons/grass7/grass7/raster/r.fuzzy/r.fuzzy.system/r.fuzzy.system.html
===================================================================
--- grass-addons/grass7/grass7/raster/r.fuzzy/r.fuzzy.system/r.fuzzy.system.html	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.fuzzy/r.fuzzy.system/r.fuzzy.system.html	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,320 @@
+<h2>OPTIONS</h2>
+
+<dl>
+<dt><b>maps</b></dt>
+<dd>A text file containing maps name and  fuzzy sets connected with map
+definition. Maps in text file must exist on a search path, except the output
+map. The name of output map name is the output name parameter. In map file
+outmput map is marked by special name <b>_OUTPUT_</b>  If maps are in different
+mapsets the name require @. Map names in database cannot contain following
+symbols: <b> %,$ and #</b>. Every map name must start with map name
+identifier:<b> %</b>. Every set definition connected with cetrain map must
+follow the map name and must start with set identifier :<b> $</b>. The set
+definition must be in braces { } and requires parameters separated by semicolon.
+Any whitespaces like spaces, tabs, empty lines are allowed and may used to
+visual format of rule file.
+
+<pre>$ set_name {side; points; boundary_shape; hedge; height }</pre>
+<ul>
+<li><b>set_name</b>: Any name of the fuzzy set. Must not contain symbols: <i>
+%,$ and #</i>
+<li><b>side</b>: Option indicate if set is fuzzified of both sides (both), left
+or right side. Available: <i>both, left, right</i>. 
+<li><b>points</b>: A list containing 4 (A,B,C,D) or 2 A,B) points separated by
+comma. Points definine  location of sets of boundaries. Points may not to be in
+map range, but it may lead to only 0 o 1 membership for the whole map. For
+"both" side parameters range between A and D defines base, but range between B
+and C core of the fuzzy set. Between A and B and C and D are set's boundaries.
+If side is "both" it require 4 points, else 2 points. Points values must be
+not-decreasing.
+<li><b>shape</b>: Parameter definied the shape of the fuzzy boundary. Available:
+<i>sshaped, linear, jshaped, gshaped</i>. The same boundaires are appled to 
+both sides of fuzzy set.
+<li><b>hedge</b>: Shape modifier the positive number means dilatation (power the
+fuzzy set by 2) the negative means concetration (square root of fuzzy set). The
+number means number of dilatation/concetration applied on fuzzy set.
+<li><b>height</b>: Height modifier. Range from 0 to 1. The  value 1 and indicate
+full membership beteen points B and C. If height is lesser than one the maximum
+memebrship is equal to height.
+</ul>
+<p>An example of fuzzy sets definiton:
+<pre>$ moderate {both; 90,100,120,130; sshaped; 0; 1}</pre>
+
+<b>Special notes about sets definition for output map:</b><br>
+These sets shall be created as triangular (both sides) sets with linear
+boundaries, without hedge and height modifiers:
+<pre>$ moderate {both; 0,20,20,40; linear; 0; 1}</pre>
+</dd>
+
+<dt><b>rules</b></dt>
+<dd>A text file containing rules for classification.Th typical fuzzy rule
+consists of one or more antecedents and one consequent:
+
+<pre>IF elev IS high AND distance IS low THEN probability IS small
+
+where:
+antecetends: elev IS high; distance IS low
+consequent: probability IS small
+</pre>
+
+The rule file has his own syntax. Because module creates only one result map,
+the map name is ommited. Every rule starts with $ and consist of consequent name
+and antecedents in braces { }. All maps and sets used in atecednets must be
+included in the maps file. At the begining of the calculation program checks if
+all names and sets are included in maps file. Names of the rules must be same as
+sets names of the output map. The rules file use following symbols:
+<ul>
+<li>IS is symbolised by <b>=</b>
+<li>IS NOT is symbolised by <b>~</b>
+<li>AND is symbolised by <b>&</b>
+<li>OR is symbolised by <b>|</b>
+<li>To  specify the order of operators must use parentheses <b>()</b>.
+</ul>
+
+
+<p>An example of fuzzy rules definiton:
+<pre>
+$ small {distance = high & elev = high}
+</pre>
+
+</dd>
+</dl>
+<h2>ADVANCED OPTIONS</h2>
+In most cases default options shoud not be changed.
+<dl>
+<dt><b>family</b></dt>
+<dd>AND and OR operations in fuzzy logic are made with T-norms, T-conorms.
+T-norms, T-conorms are a generalization of the two-valued logical conjunction
+and  disjunction  used by boolean logic, for fuzzy logics. Because there is more
+than one possible generalisation of logial operations, r.fuzzy.system provides 6
+most popular families for fuzzy operations:
+<ul>
+<li><b>Zadeh</b> with minimum (Godel) t-norm and maximum T-conorm;
+<li><b>product</b> with product T-norm and probabilistic sum as T-conorm;
+<li><b>drastic</b> with drastic T-norm and drastic T-conorm;
+<li><b>Lukasiewicz</b> with Lukasiewicz T-norm and bounded sum as a T-conorm;
+<li><b>Fodor</b> with nilpotent minimum as T-norm and nilpotent maximum as
+T-conorm;
+<li><b>Hamacher</b> (simplified) with Hamacher product as T-norm and Einstein
+sum as T-conorm;
+</ul>
+<p>
+<TABLE cellspacing=4>
+<TR><TH>Family</TH><TH> T-NORM (AND) </TH><TH>T CONORM (OR) </TH></TR>
+<TR><TD>ZADEH</TD><TD> MIN(x,y)</TD><TD>MAX(x,y)</TD></TR>
+<TR><TD>PRODUCT</TD><TD>	x*y	</TD><TD>x + y -x * y</TD></TR>
+<TR><TD>DRASTIC	</TD><TD>IF MAX(x, y) == 1 THEN MIN(x, y) ELSE 0
+</TD><TD>IF (MIN(x, y) == 0) THEN MAX(x, y) ELSE 1</TD></TR>
+<TR><TD>LUKASIEWICZ</TD><TD>	MAX((x+y-1),0)</TD><TD>	MIN((x+y),1)</TD></TR>
+<TR><TD>FODOR	</TD><TD>IF (x+y)>1 THEN MIN(x,y) ELSE 0	</TD><TD>IF
+(x+y<1) THEN MAX(x,y) ELSE 1</TD></TR>
+<TR><TD>HAMACHER</TD><TD>	IF (x==y==0) THEN 0 ELSE
+(x*y)/((x+y)-x*y)</TD><TD>	(x+y)/(1+x*y)</TD></TR>
+</TABLE>
+</dd>
+<dt><b>imp: implication </b></dt>
+<dd>Imlication determines the method of reshapening of consequents (fuzzy set)
+by antecedents (single value) : 
+<ul>
+<li><b>minimum</b> means the lowest value of the antecedtents and output set
+definition. It usually creates trapezoidal consequent set definition.
+<li><b>product</b> means the multiplication of the antecedtents and output set
+definition. It usually creates triangular consequent set definition.
+</ul>
+</dd>
+<dt><b>defuzz: deffuzyfication method</b></dt>
+<dd>Before deffuzification all consequents are agregated into one fuzzy set.
+Defuzzification is the process of conversion of aggregated fuzzy set into one
+crisp value. The r.fuzzy.system provides 5 methods of deffuzyfication:
+<ul>
+<li><b>centroid</b> center of mass of the fuzzy set (in practise weighted mean);
+<li><b>bisector</b> a value which divide fuzzy set on two parts of equal area;
+<li><b>min</b> min (right limit) of highest part of the set;
+<li><b>mean</b> mean (center) of highest part of the set;
+<li><b>max</b> max (left limit) of highest part of the set;
+</ul>
+</dd>
+<dt><b>res: universe resolution</b></dt>
+<dd>The universe is an interval between the lowest and highest values of
+consequent and agregated fuzzy sets. The resolution provides number of elements
+of these fuzzy sets. The minimum and maximum for univese is taken from the
+minimal and maximal values of fuzzy set definition of output map Because it has
+strong impact on computation time and precision of deffuzification, values lower
+than 30 may impact on precision of final result, but values above 200 may slow
+down computation time.
+</dd>
+</dl>
+<h2>VISUAL OUTPUT</h2>
+<dl>
+<dt><b>coordinates</b></dt>
+<dd>Coordinates of points for which output: universe, all consequents sets and
+agregate set. It is useful for visual presentation or detail analysis of fuzzy
+rules behaviour. In that cases calculations are peroforemd n=only for selected
+point.</dd>
+<dt><b>membership only flag</b></dt>
+<dd>Prints for all maps sat of values in map range (map universe) and values of
+fuzzy sets (linguistic values). Number of values is taken from resolution
+(default 100). This option is useful for visual control fuzzy set definitions
+for evrey map.</dd>
+</dl>
+
+<h2>OUTPUTS</h2>
+<dl>
+<dt><b>output</b></dt>
+<dd>Map containing deffuzified values. Map is always of type FCELLS and contains
+values defined in output universe. The output name must be the same as one of
+maps in maps definition file.
+</dd>
+<dt><b>multipe output flag</b></dt>
+<dd>This flag is used to create fuzzified maps for every rule. The name of the
+map consist of otput map name, '_' and rule name (for example: output=probs and
+rule name high, the map name: probs_high). Values of maps ranges from 0  to 1.
+If map with such name exists will be overwritten without warning.
+</dd>
+</dl>
+<h2>NOTES</h2>
+<h4>Calculation of boundary shape</h4>
+Depending on type of the boundary different equation are used to determine its
+shape:
+<p>
+<b>Linear:</b> the membership is calculated according following equation:<br>
+
+<pre><code>
+value  <=  A -> x = 0
+A< value > B -> x = (value-A)/(B-A)
+B <= value >= C -> x = 1
+C< value > D -> x = (D-value)/(D-C)
+value  >=  D -> x = 0
+</code></pre>
+<b>S-shaped, G-shaped and J shaped:</b>  use following equation to sommoth
+boundary:
+<pre><code>
+sin(x * Pi/2)^2 (for S-shaped)
+tan(x * Pi/4)^2 (for J-shaped)
+tan(x * Pi/4)^0.5 (for G-shaped)
+
+where:
+x current fuzzy value
+A,B,C,D inflection point,
+</code></pre>
+
+<h2>EXAMPLE</h2>
+<p>
+Fuzzy sets are sets whose elements have degrees of membership. Zadeh (1965)
+introduced Fuzzy sets as an extension of the classical notion of set. Classical 
+membership of elements in a set are binary terms: an element either belongs or
+does not belong to the set. Fuzzy set theory use the gradual membership of
+elements in a set. A membership function use values in the real unit interval
+[0, 1]. Classical sets, are special cases of the membership functions of fuzzy
+sets and only take values 0 or 1. Classical sets are in fuzzy set theory usually
+called crisp sets. The fuzzy set theory can be used in a wide range of domains
+in which information is  imprecise, such as most of the GIS operations.
+<p>
+Suppose we want to determine the flood risk on some area (Spearfish dataset)
+using two maps: distance to streams and elevation above streams. We can write
+some common sense rules:
+<pre>
+IF elevation IS low AND distance IS near THEN risk IS veryprobable
+IF elevation IS low OR distance IS near THEN risk IS probable
+IF elevation IS high AND distance IS far THEN risk IS unprobable
+</pre>
+In clasical boolean sense, we would taken some limits of ideas "near" "far" etc,
+but what about walues near the limit? The fuzzy set uses partial memberships
+which abolish these restrictions. In that sense to set "near" belongs all areas
+with distance no more than 100 m with full membership and from 100 to 200 m with
+partial membership greater than 0. Over 200 m we can assume that is not near.
+This allow to formulate fuzzy rules for distance map:
+<pre>
+near: BELOW 100 = 1; FROM 100 TO 200 = {1 TO 0}; ABOVE 200 = 0;
+</pre>
+
+To recive final map program calculate partial fuzzy set for all rules and next
+agregate it into one fuzzy set. These fuzzy sets are created on value sequence
+called universe. Every set has the number of elements equal to universe
+resolution. Such set cannot be stored as map so finally is deffuzified with
+method choosen by user.
+<p>
+First we need two maps created with r.stream package:
+
+<pre>
+r.stream.extract elevation=elevation.10m at PERMANENT threshold=2000
+stream_rast=streams direction=dirs 
+r.stream.order stream=streams dir=dirs horton=horton
+r.mapcalc "horton3=if(horton>2,horton,null())"
+r.stream.distance stream=streams dir=dirs dem=elevation.10m method=downstream
+distance=distance elevation=elevation 
+</pre>
+
+Next, to perform analysis we need two files: one with definition of map used in
+analysis and definition of fuzzy sets for every map, and second with fuzzy
+rules. For this example:
+
+<p>MAPS
+<pre>
+#flood.map
+	%elevation
+$ low {right; 2,6; sshaped; 0; 1}
+$ high {left; 2,6; sshaped; 0; 1}
+	%distance
+$ near {right; 40,80; sshaped; 0; 1}
+$ far {left; 40,80; sshaped; 0; 1}
+#output map
+	%flood
+$ unprob {both; 0,20,20,40; linear; 0;1}
+$ prob {both; 20,40,40,60; linear; 0;1}
+$ veryprob {both; 40,60,60,80; linear; 0;1}
+
+</pre>
+<p>RULES:
+<pre>
+#flood.rul
+$ unprob {elevation = high & distance = far}
+$ prob {distance = near | elevation = low}
+$ veryprob {distance = near & elevation = low}
+</pre>
+
+finally we need run r.fuzzy.system:
+<pre>
+r.fuzzy.system maps=flood.map rules=flod.rul output=flood 
+</pre>
+
+Resulting map should look like this below. Yellow color means no risk, red high
+risk, green, blue end so on moderate risk.
+<CENTER><img src=f_result.png border=1></CENTER><br>
+
+<h2>SEE ALSO</h2>
+
+<em>
+<a href="r.fuzzy.html">r.fuzzy</a>,
+<a href="r.fuzzy.logic.html">r.fuzzy.logic</a>,
+<a href="r.fuzzy.set.html">r.fuzzy.set</a>,
+<a href="r.mapcalc.html">r.mapcalc</a>,
+</em>
+
+
+
+<h2>REFERENCES</h2>
+
+Zadeh, L.A. (1965). "Fuzzy sets". Information and Control 8 (3): 338–353.
+doi:10.1016/S0019-9958(65)90241-X. ISSN 0019-9958.<p>
+
+Novák, Vilém (1989). Fuzzy Sets and Their Applications. Bristol: Adam Hilger.
+ISBN 0-85274-583-4.<p>
+
+Klir, George J.; Yuan, Bo (1995). Fuzzy sets and fuzzy logic: theory and
+applications. Upper Saddle River, NJ: Prentice Hall PTR. ISBN 0-13-101171-5.<p>
+
+Klir, George J.; St Clair, Ute H.; Yuan, Bo (1997). Fuzzy set theory:
+foundations and applications. Englewood Cliffs, NJ: Prentice Hall. ISBN
+0133410587.<p>
+
+Meyer D, Hornik K (2009a). \Generalized and Customizable Sets in R." Journal of
+Statistical Software, 31(2), 1{27. URL http://www.jstatsoft.org/v31/i02/.<p>
+
+Meyer D, Hornik K (2009b). sets: Sets, Generalized Sets, and Customizable Sets.
+R~package version~1.0, URL http://CRAN.R-project.org/package=sets.<p>
+
+<h2>AUTHOR</h2>
+Jarek  Jasiewicz
+
+<p><i>Last changed: $Date: 2011-11-08 22:56:45 +0100 (Tue, 08 Nov 2011) $</i>

Added: grass-addons/grass7/grass7/raster/r.fuzzy/r.fuzzy.system/rule_parser.c
===================================================================
--- grass-addons/grass7/grass7/raster/r.fuzzy/r.fuzzy.system/rule_parser.c	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.fuzzy/r.fuzzy.system/rule_parser.c	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,309 @@
+#include "local_proto.h"
+
+int parse_rule_file(STRING file)
+{
+    FILE *fd;
+    char buf[1000];
+    char tmp[30];
+    STRING mapset;
+    char map[30];
+    fpos_t init;
+    int rule_num = 0;
+    int n = 0, i;
+
+    fd = fopen(file, "r");
+    if (!fd)
+	G_fatal_error(_("Cannot open rules file '%s'"), file);
+
+    fgetpos(fd, &init);
+
+    while (fgets(buf, sizeof buf, fd)) {
+	G_strip(buf);
+	if (*buf != '$')
+	    continue;
+	nrules++;
+    }
+
+    s_rules = (RULES *) G_malloc((nrules) * sizeof(RULES));
+    rules = (char **)G_malloc((nrules) * sizeof(char *));
+    for (i = 0; i < nrules; ++i)
+	rules[i] = (char *)G_malloc(21 * sizeof(char));
+
+    fsetpos(fd, &init);		/* reset position */
+
+    for (n = nmaps; n > 0; --n)
+	if (!strcmp(s_maps[n - 1].name, output))
+	    break;		/*max index of output map */
+
+    if (n == 0)
+	G_fatal_error(_("No defininition for output map: <%s> in map file"),
+		      output);
+
+    while (fgets(buf, sizeof buf, fd)) {
+	G_strip(buf);
+	if (*buf != '$')
+	    continue;
+
+	parse_rules(rule_num++, n, buf);
+
+	/* next rule */
+    }
+
+			for (i = 0; i < nrules; ++i)
+		G_free(rules[i]);
+		G_free(rules);
+    fclose(fd);
+    return 0;
+
+}				/* END parse_rule_file */
+
+
+
+int parse_rules(int rule_num, int n, char buf[])
+{
+
+    int i, j, l, o;
+    int done = 1;
+    int stack_top;
+    char tmp[30];
+    char opr[] = { '=', '&', '|', '~', '(', ')', '{', '}' };
+
+    i = j = stack_top = 0;	/* variables of the while loop */
+    char_strip(buf, '$');
+
+
+    {				/* check the name of fuzzy value (must be defined in rules) */
+	int s, p;
+
+	sscanf(buf, "%[^{] %[^\n]", tmp, buf);
+	G_strip(buf);
+	G_strip(tmp);
+
+		for (p = 0; p <= rule_num; ++p)
+	strcpy(rules[p],"");
+	
+	done = 1;
+	for (s = 0; s <= s_maps[n - 1].nsets; ++s) {	/* output map */
+
+	    if (!strcmp(s_maps[n - 1].sets[s].setname, tmp)) {
+
+		for (p = 0; p <= rule_num; ++p)	/* check if values are unique */
+		    if (!strcmp(tmp, rules[p]))
+			G_fatal_error(_("Variable value <%s> exist, Variable values must be unique"),
+				      tmp);
+
+		strcpy(rules[rule_num], tmp);
+		done = 0;
+		break;
+	    }
+	}
+	if (done)
+	    G_fatal_error(_("Output map do not have variable value <%s>"),
+			  tmp);
+	strcpy(s_rules[rule_num].outname, tmp);
+	s_rules[rule_num].output_set_index = s;
+
+    }				/* check the name of fuzzy value */
+
+    /* ******************************************************************* */
+
+    {				/* parse rule expression and create parse stack */
+
+
+	do {
+	    for (o = 0; o < (sizeof opr); ++o) {
+		if (buf[i] == opr[o]) {
+		    char_copy(buf, tmp, j, i);
+		    if (i > 0) {
+			char_strip(tmp, buf[j]);
+			s_rules[rule_num].parse_queue[stack_top][0] = buf[j];
+			s_rules[rule_num].parse_queue[stack_top++][1] = '\0';
+			G_strip(tmp);
+		    }
+		    if (strlen(tmp))	/* is not blank */
+			strcpy(s_rules[rule_num].parse_queue[stack_top++],
+			       tmp);
+
+		    j = i;
+		    break;
+		}
+	    }
+	    if (i > 999)
+		G_fatal_error(_("rule string is too long or lack of closing element"));
+
+	} while (buf[i++] != '}');	/* rule has been read */
+
+	strcpy(s_rules[rule_num].parse_queue[stack_top++], "}");	/* add closing element only if OK */
+
+
+    }				/* end parse rule expression and create parse stack */
+
+    /* ******************************************************************* */
+
+
+/*    {				 adding weight: not implemented yet
+
+	char local[900];
+	char weight[10];
+
+	sscanf(buf, "%[^}] %[^;]", local, weight);
+	char_strip(weight, '}');
+	G_strip(weight);
+	if (strlen(weight) == 0)
+	    strcpy(weight, "1");
+	s_rules[rule_num].weight = atof(weight);
+	if (s_rules[rule_num].weight <= 0.)
+	    G_fatal_error(_("Weight must be grater than 0 or non-number character"));
+
+    } */
+
+    {				/* check if rule syntax is proper and map names and vars values exist */
+	int k;
+	int work_queue_pos = 0;
+	int lbrc = 0, rbrc = 0;	/* left and right braces */
+
+	done = 1;
+	for (i = 0; i < stack_top; ++i) {	/* most external loop */
+	    if (*s_rules[rule_num].parse_queue[i] == '{') {
+
+		s_rules[rule_num].work_queue[work_queue_pos] = t_START;
+
+		if (i > 0)
+		    G_fatal_error(_("line %d Syntax error near <%s %s>"),
+				  rule_num + 1,
+				  s_rules[rule_num].parse_queue[i - 1],
+				  s_rules[rule_num].parse_queue[i]);
+
+		work_queue_pos++;
+		continue;
+	    }			/* END { */
+
+	    if (*s_rules[rule_num].parse_queue[i] == '=' || *s_rules[rule_num].parse_queue[i] == '~') {	/* =, ~ */
+
+		for (j = 0; j < nmaps; ++j) {
+		    if (!strcmp
+			(s_rules[rule_num].parse_queue[i - 1],
+			 s_maps[j].name)) {
+			for (k = 0; k < s_maps[j].nsets; ++k) {
+			    if (!strcmp
+				(s_rules[rule_num].parse_queue[i + 1],
+				 s_maps[j].sets[k].setname)) {
+
+				s_rules[rule_num].work_queue[work_queue_pos] =
+				    t_VAL;
+				s_rules[rule_num].value_queue[work_queue_pos].
+				    value = &s_maps[j].cell;
+				s_rules[rule_num].value_queue[work_queue_pos].
+				    set = &s_maps[j].sets[k];
+				s_rules[rule_num].value_queue[work_queue_pos].
+				    oper = *s_rules[rule_num].parse_queue[i];
+				done = 0;
+				break;
+			    }
+			}
+		    }
+		}		/* END for j */
+
+		if (done)
+		    G_fatal_error(_("There is no map <%s> or variable <%s>"),
+				  s_rules[rule_num].parse_queue[i - 1],
+				  s_rules[rule_num].parse_queue[i + 1]);
+		/* end for j */
+
+		if (s_rules[rule_num].work_queue[work_queue_pos - 1] != t_AND
+		    && s_rules[rule_num].work_queue[work_queue_pos - 1] !=
+		    t_OR &&
+		    s_rules[rule_num].work_queue[work_queue_pos - 1] !=
+		    t_START &&
+		    s_rules[rule_num].work_queue[work_queue_pos - 1] !=
+		    t_LBRC)
+		    G_fatal_error(_("line %d Syntax error near <%s %s>"),
+				  rule_num + 1,
+				  s_rules[rule_num].parse_queue[i - 1],
+				  s_rules[rule_num].parse_queue[i]);
+
+		work_queue_pos++;
+		continue;
+	    }			/* END =, ~ */
+
+	    if (*s_rules[rule_num].parse_queue[i] == '&' || *s_rules[rule_num].parse_queue[i] == '|') {	/* operators &, | */
+
+		s_rules[rule_num].work_queue[work_queue_pos] =
+		    (*s_rules[rule_num].parse_queue[i] == '|') ? t_OR : t_AND;
+
+		if (s_rules[rule_num].work_queue[work_queue_pos - 1] != t_VAL
+		    && s_rules[rule_num].work_queue[work_queue_pos - 1] !=
+		    t_RBRC)
+		    G_fatal_error(_("line %d Syntax error near <%s %s>"),
+				  rule_num + 1,
+				  s_rules[rule_num].parse_queue[i - 1],
+				  s_rules[rule_num].parse_queue[i]);
+
+		work_queue_pos++;
+		continue;
+	    }			/* END &, | */
+
+	    if (*s_rules[rule_num].parse_queue[i] == '(') {
+
+		s_rules[rule_num].work_queue[work_queue_pos] = t_LBRC;
+		lbrc++;
+
+		if (s_rules[rule_num].work_queue[work_queue_pos - 1] != t_AND
+		    && s_rules[rule_num].work_queue[work_queue_pos - 1] !=
+		    t_OR &&
+		    s_rules[rule_num].work_queue[work_queue_pos - 1] !=
+		    t_START &&
+		    s_rules[rule_num].work_queue[work_queue_pos - 1] !=
+		    t_LBRC)
+		    G_fatal_error(_("line %d Syntax error near <%s %s>"),
+				  rule_num + 1,
+				  s_rules[rule_num].parse_queue[i - 1],
+				  s_rules[rule_num].parse_queue[i]);
+
+		work_queue_pos++;
+		continue;
+	    }			/* END ( */
+
+	    if (*s_rules[rule_num].parse_queue[i] == ')') {
+
+		s_rules[rule_num].work_queue[work_queue_pos] = t_RBRC;
+		rbrc++;
+
+		if (s_rules[rule_num].work_queue[work_queue_pos - 1] != t_VAL
+		    && s_rules[rule_num].work_queue[work_queue_pos - 1] !=
+		    t_RBRC)
+		    G_fatal_error(_("line %d Syntax error near <%s %s>"),
+				  rule_num + 1,
+				  s_rules[rule_num].parse_queue[i - 1],
+				  s_rules[rule_num].parse_queue[i]);
+
+		work_queue_pos++;
+		continue;
+	    }			/* END ) */
+
+	    if (*s_rules[rule_num].parse_queue[i] == '}') {
+
+		s_rules[rule_num].work_queue[work_queue_pos] = t_STOP;
+
+		if (s_rules[rule_num].work_queue[work_queue_pos - 1] != t_VAL
+		    && s_rules[rule_num].work_queue[work_queue_pos - 1] !=
+		    t_RBRC)
+		    G_fatal_error(_("line %d Syntax error near <%s %s>"),
+				  rule_num + 1,
+				  s_rules[rule_num].parse_queue[i - 1],
+				  s_rules[rule_num].parse_queue[i]);
+
+		work_queue_pos++;
+		continue;
+	    }			/* END } */
+
+	}			/* most external loop */
+
+	if (lbrc != rbrc)
+	    G_fatal_error(_("line %d Left and right of braces do not match"),
+			  rule_num + 1);
+
+    }				/* END check if rule syntax is proper and map names and vars values exist */
+
+    return 0;
+}				/* END parse_rules */

Added: grass-addons/grass7/grass7/raster/r.fuzzy/r.fuzzy.system/system.c
===================================================================
--- grass-addons/grass7/grass7/raster/r.fuzzy/r.fuzzy.system/system.c	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.fuzzy/r.fuzzy.system/system.c	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,198 @@
+#include "local_proto.h"
+
+float implicate(void)
+{
+
+    int i, j;
+    //float *agregate = NULL;
+    int set_index;
+    float consequent;
+    float max_antecedent = 0;
+    float max_agregate = 0;
+    float result;
+
+    memset(agregate,0,resolution * sizeof(float));
+
+    for (j = 0; j < nrules; ++j) {
+	antecedents[j] = parse_expression(j);
+	max_antecedent =
+	    (max_antecedent >
+	     antecedents[j]) ? max_antecedent : antecedents[j]; 
+   }
+
+    if (max_antecedent == 0. && !coor_proc)
+	return -9999;		/* for all rules value is 0 */
+
+    for (j = 0; j < nrules; ++j) {
+
+	if (defuzzyfication > d_BISECTOR && antecedents[j] < max_antecedent && !coor_proc)
+	    continue;
+	    
+	    set_index = s_rules[j].output_set_index;
+
+	for (i = 0; i < resolution; ++i) {
+	    
+	    consequent = fuzzy(universe[i],
+			       &s_maps[output_index].sets[set_index]);
+	    
+	    consequent = (!implication) ? MIN(antecedents[j], consequent) :
+		antecedents[j] * consequent;
+	    agregate[i] = MAX(agregate[i], consequent);
+	    
+	   max_agregate = (max_agregate > agregate[i]) 
+				? max_agregate : agregate[i];
+	   
+
+	    if (coor_proc)
+		visual_output[i][j + 1] = consequent;
+	}
+	
+    }
+    if (coor_proc)
+	for (i = 0; i < resolution; ++i)
+	    visual_output[i][j + 1] = agregate[i];
+
+     result=defuzzify(defuzzyfication, max_agregate);
+     return result;
+}
+
+float parse_expression(int n)
+{
+
+    /*  tokens and actions must heve the same order */
+    actions parse_tab[t_size][t_size] = {
+	/* stk -----------INPUT------------------ */
+	/*  		{   &  | ~   =  (  )  }   */
+	/*      --  -- -- -- -- -- -- -- */
+	/* { */ {E, S, S, E, E, S, E, A},
+	/* & */ {E, R, R, E, E, S, R, R},
+	/* | */ {E, R, R, E, E, S, R, R},
+	/* ~ */ {E, E, E, E, E, E, E, E},
+	/* = */ {E, E, E, E, E, E, E, E},
+	/* ( */ {E, S, S, E, E, S, S, E},
+	/* ) */ {E, R, R, E, E, E, R, R},
+	/* } */ {E, E, E, E, E, E, E, E}
+    };
+
+    tokens operator_stack[STACKMAX];
+    float values_stack[STACKMAX];
+
+    int i = 0, k = 0;
+    int opr_top = 0;
+    int val_top = 0;
+    int set_index;
+    float f_value;
+
+
+    do {
+	if (s_rules[n].work_queue[i] == t_START) {	/* first token */
+	    if (i > 0)
+		G_fatal_error("operator stack error, contact author");
+	    operator_stack[opr_top] = t_START;
+	    continue;
+	}
+
+	if (s_rules[n].work_queue[i] == t_VAL) {
+	    f_value =
+		fuzzy(*s_rules[n].value_queue[i].value, s_rules[n].value_queue[i].set);
+	    values_stack[++val_top] =	(s_rules[n].value_queue[i].oper == '~') ? 
+				f_not(f_value, family) :	f_value;
+	    continue;
+	}
+
+	if (s_rules[n].work_queue[i] < t_size) {
+	    switch (parse_tab[operator_stack[opr_top]]
+		    [s_rules[n].work_queue[i]]) {
+
+	    case E:		/* error */
+		G_fatal_error("Stack error, contact author");
+		break;
+
+	    case S:		/* shift */
+		operator_stack[++opr_top] = s_rules[n].work_queue[i];
+		break;
+
+	    case R:		/* reduce */
+
+		switch (operator_stack[opr_top]) {
+
+		case t_AND:
+		    values_stack[val_top - 1] =
+			f_and(values_stack[val_top],
+			      values_stack[val_top - 1], family);
+		    val_top--;
+		    break;
+
+		case t_OR:
+		    values_stack[val_top - 1] =
+			f_or(values_stack[val_top], values_stack[val_top - 1],
+			     family);
+		    val_top--;
+		    break;
+
+		case t_RBRC:
+		    opr_top--;
+		    break;
+		}
+
+		opr_top--;
+		i--;
+		break;
+
+	    case A:		/* accept */
+	
+		if (!val_top)
+		    G_fatal_error("Stack error at end, contact autor");
+		return values_stack[val_top];
+	
+	    }
+	}
+
+    } while (s_rules[n].work_queue[i++] != t_STOP);
+    
+    G_fatal_error("Parse Stack empty, contact autor");
+}
+
+
+
+float defuzzify(int defuzzyfication, float max_agregate)
+{
+    int i;
+    float d_value = 0;
+    float sum_agregate = 0;
+    float tmp;
+
+    for (i = 0; i < resolution; sum_agregate += agregate[i++]) ;
+
+    switch (defuzzyfication) {
+
+    case d_CENTEROID:
+	for (i = 0; i < resolution; ++i)
+	    d_value += (universe[i] * agregate[i]);
+	return d_value / sum_agregate;
+
+    case d_BISECTOR:
+	for (i = 0, tmp = 0; (tmp += agregate[i]) < sum_agregate / 2; ++i) ;
+	return universe[i];
+
+    case d_MINOFHIGHEST:
+	for (i = 0; agregate[i] < max_agregate;++i) ;
+	return universe[i];
+
+    case d_MAXOFHIGHEST:
+	for (i = resolution; agregate[i] < max_agregate;--i) ;
+	return universe[i];
+
+    case d_MEANOFHIGHEST:
+	sum_agregate = 0;
+	for (i = 0; i < resolution; ++i) {
+	    if (agregate[i] < max_agregate)
+		continue;
+	    d_value += (universe[i] * agregate[i]);
+	    sum_agregate += agregate[i];
+	}
+	return d_value / sum_agregate;
+    }
+
+    return -9999;
+}

Added: grass-addons/grass7/grass7/raster/r.gdd/Makefile
===================================================================
--- grass-addons/grass7/grass7/raster/r.gdd/Makefile	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.gdd/Makefile	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,13 @@
+MODULE_TOPDIR = ../..
+
+PGM = r.gdd
+
+LIBES = $(RASTERLIB) $(GISLIB)
+DEPENDENCIES = $(RASTERDEP) $(GISDEP)
+
+EXTRA_LIBS = $(OMPLIB)
+EXTRA_CFLAGS = $(OMPCFLAGS)
+
+include $(MODULE_TOPDIR)/include/Make/Module.make
+
+default: cmd

Added: grass-addons/grass7/grass7/raster/r.gdd/main.c
===================================================================
--- grass-addons/grass7/grass7/raster/r.gdd/main.c	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.gdd/main.c	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,379 @@
+
+/****************************************************************************
+ *
+ * MODULE:       r.gdd
+ * AUTHOR(S):    Markus Metz
+ *               based on r.series
+ * PURPOSE:      Calculate Growing Degree Days (GDDs)
+ * COPYRIGHT:    (C) 2012 by the GRASS Development Team
+ *
+ *               This program is free software under the GNU General Public
+ *               License (>=v2). Read the file COPYING that comes with GRASS
+ *               for details.
+ *
+ *****************************************************************************/
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <limits.h>
+#include <math.h>
+
+#include <grass/gis.h>
+#include <grass/raster.h>
+#include <grass/glocale.h>
+
+struct input
+{
+    const char *name;
+    int fd;
+    FCELL *buf;
+};
+
+struct output
+{
+    const char *name;
+    int fd;
+    FCELL *buf;
+};
+
+int main(int argc, char *argv[])
+{
+    struct GModule *module;
+    struct
+    {
+	struct Option *input, *gdd, *file, *output, *range,
+	              *scale, *shift, *baseline, *cutoff;
+    } parm;
+    struct
+    {
+	struct Flag *nulls, *lazy, *avg;
+    } flag;
+    int i;
+    int num_inputs, max_inputs, gdd_in;
+    struct input *inputs = NULL;
+    struct output *out = NULL;
+    struct History history;
+    struct Colors colors;
+    int nrows, ncols;
+    int row, col;
+    double lo, hi, tscale, tshift, baseline, cutoff;
+    FCELL fnull;
+
+    G_gisinit(argv[0]);
+
+    module = G_define_module();
+    G_add_keyword(_("raster"));
+    G_add_keyword(_("series"));
+    module->description =
+	_("Makes each output cell value a "
+	  "function of the values assigned to the corresponding cells "
+	  "in the input raster map layers.");
+
+    parm.input = G_define_standard_option(G_OPT_R_INPUTS);
+    parm.input->required = NO;
+
+    parm.gdd = G_define_standard_option(G_OPT_R_INPUT);
+    parm.gdd->key = "gdd";
+    parm.gdd->description = _("Existing GDD map to be added to output");
+    parm.gdd->required = NO;
+
+    parm.file = G_define_standard_option(G_OPT_F_INPUT);
+    parm.file->key = "file";
+    parm.file->description = _("Input file with raster map names, one per line");
+    parm.file->required = NO;
+
+    parm.output = G_define_standard_option(G_OPT_R_OUTPUT);
+    parm.output->multiple = NO;
+
+    parm.scale = G_define_option();
+    parm.scale->key = "scale";
+    parm.scale->type = TYPE_DOUBLE;
+    parm.scale->answer = "1.0";
+    parm.scale->required = NO;
+    parm.scale->description = _("Scale factor for input");
+
+    parm.shift = G_define_option();
+    parm.shift->key = "shift";
+    parm.shift->type = TYPE_DOUBLE;
+    parm.shift->answer = "0.0";
+    parm.shift->required = NO;
+    parm.shift->description = _("Shift factor for input");
+
+    parm.baseline = G_define_option();
+    parm.baseline->key = "baseline";
+    parm.baseline->type = TYPE_DOUBLE;
+    parm.baseline->required = NO;
+    parm.baseline->answer = "10";
+    parm.baseline->description = _("Baseline temperature");
+
+    parm.cutoff = G_define_option();
+    parm.cutoff->key = "cutoff";
+    parm.cutoff->type = TYPE_DOUBLE;
+    parm.cutoff->required = NO;
+    parm.cutoff->answer = "30";
+    parm.cutoff->description = _("Cutoff temperature");
+
+    parm.range = G_define_option();
+    parm.range->key = "range";
+    parm.range->type = TYPE_DOUBLE;
+    parm.range->key_desc = "lo,hi";
+    parm.range->description = _("Ignore values outside this range");
+
+    flag.avg = G_define_flag();
+    flag.avg->key = 'a';
+    flag.avg->description = _("Use average instead of min, max");
+
+    flag.nulls = G_define_flag();
+    flag.nulls->key = 'n';
+    flag.nulls->description = _("Propagate NULLs");
+
+    flag.lazy = G_define_flag();
+    flag.lazy->key = 'z';
+    flag.lazy->description = _("Don't keep files open");
+
+    if (G_parser(argc, argv))
+	exit(EXIT_FAILURE);
+
+    lo = -1.0 / 0.0;
+    hi = 1.0 / 0.0;
+    if (parm.range->answer) {
+	lo = atof(parm.range->answers[0]);
+	hi = atof(parm.range->answers[1]);
+    }
+
+    if (parm.scale->answer)
+	tscale = atof(parm.scale->answer);
+    else
+	tscale = 1.;
+
+    if (parm.shift->answer)
+	tshift = atof(parm.shift->answer);
+    else
+	tshift = 0.;
+
+    baseline = atof(parm.baseline->answer);
+    cutoff = atof(parm.cutoff->answer);
+    
+    if (cutoff <= baseline)
+        G_fatal_error(_("'%s' must be > '%s'"), parm.cutoff->key,
+	                                        parm.baseline->key);
+
+    if (parm.input->answer && parm.file->answer)
+        G_fatal_error(_("input= and file= are mutually exclusive"));
+ 
+    if (!parm.input->answer && !parm.file->answer)
+        G_fatal_error(_("Please specify input= or file="));
+
+    max_inputs = 0;
+    /* process the input maps from the file */
+    if (parm.file->answer) {
+	FILE *in;
+    
+	in = fopen(parm.file->answer, "r");
+	if (!in)
+	    G_fatal_error(_("Unable to open input file <%s>"), parm.file->answer);
+    
+	num_inputs = 0;
+
+	for (;;) {
+	    char buf[GNAME_MAX];
+	    char *name;
+	    struct input *p;
+
+	    if (!G_getl2(buf, sizeof(buf), in))
+		break;
+
+	    name = G_chop(buf);
+
+	    /* Ignore empty lines */
+	    if (!*name)
+		continue;
+
+	    if (num_inputs >= max_inputs) {
+		max_inputs += 100;
+		inputs = G_realloc(inputs, max_inputs * sizeof(struct input));
+	    }
+	    p = &inputs[num_inputs++];
+
+	    p->name = G_store(name);
+	    G_verbose_message(_("Reading raster map <%s>..."), p->name);
+	    p->buf = Rast_allocate_f_buf();
+	    if (!flag.lazy->answer)
+		p->fd = Rast_open_old(p->name, "");
+	}
+
+	if (num_inputs < 1)
+	    G_fatal_error(_("No raster map name found in input file"));
+
+	fclose(in);
+    }
+    else {
+    	for (i = 0; parm.input->answers[i]; i++)
+	    ;
+    	num_inputs = i;
+
+    	if (num_inputs < 1)
+	    G_fatal_error(_("Raster map not found"));
+
+    	inputs = G_malloc(num_inputs * sizeof(struct input));
+
+    	for (i = 0; i < num_inputs; i++) {
+	    struct input *p = &inputs[i];
+
+	    p->name = parm.input->answers[i];
+	    G_verbose_message(_("Reading raster map <%s>..."), p->name);
+	    p->buf = Rast_allocate_f_buf();
+	    if (!flag.lazy->answer)
+		p->fd = Rast_open_old(p->name, "");
+    	}
+	max_inputs = num_inputs;
+    }
+
+    if (parm.gdd->answer) {
+	struct input *p;
+
+	gdd_in = 1;
+	if (num_inputs + 1 >= max_inputs) {
+	    max_inputs += 2;
+	    inputs = G_realloc(inputs, max_inputs * sizeof(struct input));
+	}
+	p = &inputs[num_inputs];
+	p->name = parm.gdd->answer;
+	G_verbose_message(_("Reading raster map <%s>..."), p->name);
+	p->buf = Rast_allocate_f_buf();
+	if (!flag.lazy->answer)
+	    p->fd = Rast_open_old(p->name, "");
+    }
+    else
+	gdd_in = 0;
+
+    out = G_calloc(1, sizeof(struct output));
+
+    out->name = parm.output->answer;
+
+    out->buf = Rast_allocate_f_buf();
+    out->fd = Rast_open_new(out->name, FCELL_TYPE);
+
+    nrows = Rast_window_rows();
+    ncols = Rast_window_cols();
+    
+    Rast_set_f_null_value(&fnull, 1);
+
+    /* process the data */
+    G_verbose_message(_("Percent complete..."));
+
+    for (row = 0; row < nrows; row++) {
+	G_percent(row, nrows, 2);
+
+	if (flag.lazy->answer) {
+	    /* Open the files only on run time */
+	    for (i = 0; i < num_inputs + gdd_in; i++) {
+		inputs[i].fd = Rast_open_old(inputs[i].name, "");
+		Rast_get_f_row(inputs[i].fd, inputs[i].buf, row);
+		Rast_close(inputs[i].fd);
+	    }
+	}
+	else {
+	    for (i = 0; i < num_inputs + gdd_in; i++)
+	        Rast_get_f_row(inputs[i].fd, inputs[i].buf, row);
+	}
+
+        #pragma omp for schedule (static) private (col)
+
+	for (col = 0; col < ncols; col++) {
+	    int null = 0, non_null = 0;
+	    FCELL min, max, avg, gdd;
+
+	    min = fnull;
+	    max = fnull;
+	    avg = 0;
+
+	    for (i = 0; i < num_inputs; i++) {
+		FCELL v = inputs[i].buf[col];
+
+		if (Rast_is_f_null_value(&v))
+		    null = 1;
+		else {
+		    v = v * tscale + tshift;
+		    if (parm.range->answer && (v < lo || v > hi)) {
+			null = 1;
+		    }
+		    else {
+			if (flag.avg->answer)
+			    avg += v;
+			else {
+			    if (Rast_is_f_null_value(&min) || min > v)
+				min = v;
+			    if (Rast_is_f_null_value(&max) || max < v)
+				max = v;
+			}
+			non_null++;
+		    }
+		}
+	    }
+
+	    if (!non_null || (null && flag.nulls->answer)) {
+		if (gdd_in)
+		    gdd = inputs[num_inputs].buf[col];
+		else
+		    gdd = fnull;
+	    }
+	    else {
+
+		if (flag.avg->answer) {
+		    avg /= non_null;
+
+		    if (avg < baseline)
+			avg = baseline;
+		    if (avg > cutoff)
+			avg = cutoff;
+
+		    gdd = avg - baseline;
+		}
+		else {
+		    if (min < baseline)
+			min = baseline;
+		    if (min > cutoff)
+			min = cutoff;
+		    if (max < baseline)
+			max = baseline;
+		    if (max > cutoff)
+			max = cutoff;
+
+		    gdd = (min + max) / 2. - baseline;
+		}
+
+		if (gdd < 0.)
+		    gdd = 0.;
+		if (gdd_in)
+		    gdd += inputs[num_inputs].buf[col];
+
+	    }
+	    out->buf[col] = gdd;
+	}
+
+	Rast_put_f_row(out->fd, out->buf);
+    }
+
+    G_percent(row, nrows, 2);
+
+    /* close output map */
+    Rast_close(out->fd);
+
+    Rast_short_history(out->name, "raster", &history);
+    Rast_command_history(&history);
+    Rast_write_history(out->name, &history);
+
+    /* Close input maps */
+    if (!flag.lazy->answer) {
+    	for (i = 0; i < num_inputs + gdd_in; i++)
+	    Rast_close(inputs[i].fd);
+    }
+
+    /* set gdd color table */
+    Rast_init_colors(&colors);
+    Rast_make_colors(&colors, "gdd", 0, 6000);
+    Rast_write_colors(out->name, G_mapset(), &colors);
+
+    exit(EXIT_SUCCESS);
+}

Added: grass-addons/grass7/grass7/raster/r.gdd/r.gdd.html
===================================================================
--- grass-addons/grass7/grass7/raster/r.gdd/r.gdd.html	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.gdd/r.gdd.html	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,106 @@
+<h2>DESCRIPTION</h2>
+
+<em>r.gdd</em> calculates (accumulated) growing degree days (GDDs) and 
+Winkler indices from several input maps with temperature data for 
+different times of the day.
+<p>
+The formula for calculating GDDs is
+<div class="code"><pre>
+    gdd = (max + min) / 2 - baseline
+</pre></div>
+The formula for calculating the Winkler index is
+<div class="code"><pre>
+    gdd = average - baseline
+</pre></div>
+with <em>min</em> being the minimum daily temperature, <em>max</em> 
+the maximum daily temperature and <em>average</em> the average daily 
+temperature. The <em>min</em>, <em>max</em> and <em>average</em> values 
+are automatically calculated from the input temperature maps.
+<p>
+The <em>shift</em> and <em>scale</em> values are applied directly to the 
+input values. The <em>baseline</em>, <em>cutoff</em>, and <em>range</em> 
+options are applied to the shifted and scaled values.
+<p>
+Any <em>min</em>, <em>max</em> and <em>average</em> temperature values 
+above the <em>cutoff</em> value are set to <em>cutoff</em>, and any 
+<em>min</em>, <em>max</em> and <em>average</em> values below the 
+<em>baseline</em> value are set to <em>baseline</em>. Negative results 
+are set to 0 (zero). 
+<p>
+If an existing map is provided with the <em>gdd</em> option, the 
+values of this map are added to the output, thus accumulating GDDs.
+
+<h2>NOTES</h2>
+
+The <em>scale</em> and <em>shift</em> parameters are used to transform 
+input values with
+<div class="code"><pre>
+    new = old * scale + shift
+</pre></div>
+<p>
+With the <em>-n</em> flag, any cell for which any of the 
+corresponding input cells are NULL is automatically set to NULL 
+(NULL propagation) and the GDD value is not calculated.
+<p>
+Without the <em>-n</em> flag, all non-NULL cells are used to 
+calculate the current GDD.
+<p>
+If the <em>range=</em> option is given, any values which fall outside 
+that range will be treated as if they were NULL. Note that the range is 
+applied to the scaled and shifted input data. The <em>range</em> 
+parameter can be set to <em>low,high</em> thresholds: 
+values outside of this range are treated as NULL (i.e., they will be 
+ignored by most aggregates, or will cause the result to be NULL if -n 
+is given). The <em>low,high</em> thresholds are floating point, so use 
+<em>-inf</em> or <em>inf</em> for a single threshold (e.g., 
+<em>range=0,inf</em> to ignore negative values, or 
+<em>range=-inf,-200.4</em> to ignore values above -200.4).
+<p>
+The number of raster maps to be processed is given by the limit of the 
+operating system. For example, both the hard and soft limits are 
+typically 1024. The soft limit can be changed with e.g. 
+<tt>ulimit -n 1500</tt> (UNIX-based operating systems) but not higher 
+than the hard limit. If it is too low, you can as superuser add an 
+entry in
+
+<div class="code"><pre>
+/etc/security/limits.conf
+# <domain>      <type>  <item>         <value>
+your_username  hard    nofile          1500
+</pre></div>
+
+This would raise the hard limit to 1500 file. Be warned that more
+files open need more RAM.
+
+<p>
+Use the <em>file</em> option to analyze large amount of raster maps 
+without hitting open files limit and the size limit of command line 
+arguments. The computation is slower than the <em>input</em> option 
+method. For every sinlge row in the output map(s) all input maps are 
+opened and closed. The amount of RAM will rise linear with the 
+number of specified input maps. The input and file options are 
+mutually exclusive. Input is a text file with a new line separated 
+list of raster map names and optional weights. As separator between 
+the map name and the weight the charachter | must be used.
+
+<h2>EXAMPLES</h2>
+
+Example with MODIS Land Surface Temperature, transforming values from 
+Kelvin * 50 to degrees Celsius:
+<div class="code"><pre>
+r.gdd in=MOD11A1.Day,MOD11A1.Night,MYD11A1.Day,MYD11A1.Night out=MCD11A1.GDD \
+      scale=0.02 shift=-273.15 baseline=10 cutoff=30
+</pre></div>
+
+<h2>SEE ALSO</h2>
+
+<em><a href="r.series.html">r.series</a>,
+<a href="g.mlist.html">g.mlist</a>,
+<a href="g.region.html">g.region</a>
+</em>
+
+<h2>AUTHOR</h2>
+
+Markus Metz (based on r.series)
+
+<p><i>Last changed: $Date: 2012-07-03 23:47:59 +0200 (Tue, 03 Jul 2012) $</i>

Added: grass-addons/grass7/grass7/raster/r.houghtransform/Makefile
===================================================================
--- grass-addons/grass7/grass7/raster/r.houghtransform/Makefile	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.houghtransform/Makefile	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,20 @@
+# fix this relative to include/
+# or use absolute path to the GRASS source code
+MODULE_TOPDIR = ../..
+
+PGM = r.houghtransform
+
+LIBES = $(VECTORLIB) $(GISLIB) $(RASTERLIB)  $(GMATHLIB)
+DEPENDENCIES = $(VECTORDEP) $(GISDEP) $(RASTERDEP) 
+
+EXTRA_INC = $(VECT_INC)
+
+include $(MODULE_TOPDIR)/include/Make/Module.make
+
+EXTRA_CFLAGS = $(VECT_CFLAGS) -Wno-sign-compare -Wall -Wextra -O0 -Wconversion
+
+LINK = $(CXX)
+
+#ifneq ($(strip $(CXX)),)
+default: cmd
+#endif

Added: grass-addons/grass7/grass7/raster/r.houghtransform/hough.cpp
===================================================================
--- grass-addons/grass7/grass7/raster/r.houghtransform/hough.cpp	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.houghtransform/hough.cpp	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,267 @@
+#include "houghtransform.h"
+
+#include"linesegmentsextractor.h"
+#include "matrix.h"
+
+extern "C" {
+namespace grass {
+#include <grass/gis.h>
+#include <grass/raster.h>
+#include <grass/vector.h>
+#include <grass/glocale.h>
+#include <grass/gmath.h>
+}
+}
+
+using grass::DCELL;
+using grass::CELL;
+using grass::G__calloc;
+using grass::Cell_head;
+using grass::Map_info;
+
+using grass::Vect_new_cats_struct;
+using grass::Vect_new_line_struct;
+
+using grass::Rast_allocate_c_input_buf;
+using grass::Rast_open_old;
+using grass::Rast_get_row;
+using grass::Rast_close;
+
+using grass::Rast_window_rows;
+using grass::Rast_window_cols;
+using grass::Rast_allocate_c_buf;
+using grass::Rast_open_fp_new;
+using grass::Rast_put_c_row;
+using grass::Rast_get_cellhd;
+
+using grass::G_gettext;
+using grass::G_fatal_error;
+using grass::G_debug;
+using grass::G_free;
+
+using grass::Colors;
+using grass::Range;
+using grass::G_mapset;
+
+/** Loads map into memory.
+
+  \param[out] mat map in a matrix (row order), field have to be allocated
+  */
+template <typename Matrix>
+void read_raster_map(const char *name, const char *mapset, int nrows,
+                            int ncols, Matrix& mat)
+{
+
+    int r, c;
+
+    int map_fd;
+
+    CELL *row_buffer;
+
+    CELL cell_value;
+
+    row_buffer = Rast_allocate_c_buf();
+
+    /* load map */
+    map_fd = Rast_open_old(name, mapset);
+    if (map_fd < 0) {
+        G_fatal_error(_("Error opening first raster map <%s>"), name);
+    }
+
+    G_debug(1, "fd %d %s %s", map_fd, name, mapset);
+
+    //    if ((first_map_R_type =
+    //         Rast_map_type(templName, mapset)) < 0)
+    //        G_fatal_error(_("Error getting first raster map type"));
+
+    for (r = 0; r < nrows; r++) {
+        Rast_get_row(map_fd, row_buffer, r, CELL_TYPE);
+
+        for (c = 0; c < ncols; c++) {
+            cell_value = row_buffer[c];
+            if (!Rast_is_c_null_value(&cell_value))
+                mat(r, c) = cell_value;
+            else
+                mat(r, c) = 0.0;
+        }
+    }
+    G_free(row_buffer);
+
+    Rast_close(map_fd);
+}
+
+void apply_hough_colors_to_map(const char *name)
+{
+    struct Colors colors;
+    struct Range range;
+    CELL min, max;
+
+    Rast_read_range(name, G_mapset(), &range);
+    Rast_get_range_min_max(&range, &min, &max);
+    Rast_make_grey_scale_colors(&colors, min, max);
+    Rast_write_colors(name, G_mapset(), &colors);
+}
+
+template <typename Matrix>
+void create_raster_map(const char *name, struct Cell_head *window, const Matrix& mat)
+{
+    struct Cell_head original_window;
+    CELL *cell_real;
+    int rows, cols; /* number of rows and columns */
+    long totsize; /* total number of data points */ // FIXME: make clear the size_t usage
+    int mapfd;
+
+    /* get the rows and columns in the current window */
+    rows = mat.rows();
+    cols = mat.columns();
+    totsize = rows * cols;
+
+    G_get_set_window(&original_window);
+
+    window->bottom = 0;
+    window->top = rows;
+    window->cols = cols;
+    window->east = cols;
+    window->north = rows;
+    window->ns_res = 1;
+    window->rows = rows;
+    window->south = 0;
+    window->west = 0;
+    window->ew_res = 1;
+    window->tb_res = 1;
+
+    Rast_set_window(window);
+
+    /* allocate the space for one row of cell map data */
+    cell_real = Rast_allocate_c_buf();
+
+    /* open the output cell maps */
+    mapfd = Rast_open_fp_new(name);
+
+    for (int i = 0; i < rows; i++) {
+        for (int j = 0; j < cols; j++) {
+            cell_real[j] = mat(i, j);
+        }
+        Rast_put_c_row(mapfd, cell_real);
+    }
+
+    Rast_close(mapfd);
+    G_free(cell_real);
+
+    Rast_set_window(&original_window);
+}
+
+/**
+  \param cellhd raster map header, used for converting rows/cols to easting/northing
+  */
+void create_vector_map(const char * name, const SegmentList& segments,
+                       const Cell_head* cellhd)
+{
+    struct Map_info Map;
+    Vect_open_new(&Map, name, 0);
+
+    struct grass::line_cats *Cats;
+    struct grass::line_pnts *points;
+    Cats = Vect_new_cats_struct();
+    points = Vect_new_line_struct();
+
+
+    for (size_t i = 0; i < segments.size(); ++i)
+    {
+        const Segment& seg = segments[i];
+
+        double y1 = Rast_row_to_northing(seg.first.first, cellhd);
+        double x1 = Rast_col_to_easting(seg.first.second, cellhd);
+        double y2 = Rast_row_to_northing(seg.second.first, cellhd);
+        double x2 = Rast_col_to_easting(seg.second.second, cellhd);
+
+        Vect_reset_cats(Cats);
+        Vect_cat_set(Cats, 1, i+1); // cat is segment number (counting from one)
+
+        Vect_reset_line(points);
+        Vect_append_point(points, x1, y1, 0);
+        Vect_append_point(points, x2, y2, 0);
+
+        Vect_write_line(&Map, GV_LINE, points, Cats);
+    }
+
+    Vect_destroy_cats_struct(Cats);
+    Vect_destroy_line_struct(points);
+    
+    Vect_build(&Map);
+    Vect_close(&Map);
+}
+
+template <typename Matrix>
+void extract_line_segments(const Matrix &I,
+                           const HoughTransform::Peaks& peaks,
+                           const HoughTransform::TracebackMap& houghMap,
+                           ExtractParametres extractParametres,
+                           SegmentList& segments)
+{
+    for (size_t i = 0; i < peaks.size(); ++i)
+    {
+        const HoughTransform::Peak& peak = peaks[i];
+
+        double theta = peak.coordinates.second;
+
+        HoughTransform::TracebackMap::const_iterator coordsIt =
+                houghMap.find(peak.coordinates);
+        if (coordsIt != houghMap.end())
+        {
+            const HoughTransform::CoordinatesList& lineCoordinates = coordsIt->second;
+
+            LineSegmentsExtractor extractor(I, extractParametres);
+
+            extractor.extract(lineCoordinates, (theta-90)/180*M_PI, segments);
+        }
+        else
+        {
+            // logic error
+        }
+    }
+}
+
+void hough_peaks(HoughParametres houghParametres,
+                 ExtractParametres extractParametres,
+                 const char *name, const char *mapset, size_t nrows, size_t ncols,
+                 const char *anglesMapName,
+                 const char *houghImageName, const char *result)
+{
+    typedef matrix::Matrix<DCELL> Matrix;
+    Matrix I(nrows, ncols);
+    read_raster_map(name, mapset, nrows, ncols, I);
+
+    HoughTransform hough(I, houghParametres);
+
+    if (anglesMapName != NULL)
+    {
+        Matrix angles(nrows, ncols);
+        read_raster_map(anglesMapName, mapset, nrows, ncols, angles);
+        hough.compute(angles);
+    }
+    else
+    {
+        hough.compute();
+    }
+
+    hough.findPeaks();
+
+    if (houghImageName != NULL)
+    {
+        struct Cell_head window;
+        Rast_get_cellhd(name, "", &window);
+        create_raster_map(houghImageName, &window, hough.getHoughMatrix());
+        apply_hough_colors_to_map(houghImageName);
+    }
+
+    const HoughTransform::Peaks& peaks = hough.getPeaks();
+    const HoughTransform::TracebackMap& houghMap = hough.getHoughMap();
+    SegmentList segments;
+
+    extract_line_segments(I, peaks, houghMap, extractParametres, segments);
+
+    Cell_head cellhd;
+    Rast_get_window(&cellhd);
+    create_vector_map(result, segments, &cellhd);
+}

Added: grass-addons/grass7/grass7/raster/r.houghtransform/hough.h
===================================================================
--- grass-addons/grass7/grass7/raster/r.houghtransform/hough.h	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.houghtransform/hough.h	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,13 @@
+#ifndef HOUGH_H
+#define HOUGH_H
+
+#include "houghparameters.h"
+
+extern "C" {
+#include <grass/gis.h>
+#include <grass/raster.h>
+}
+
+void hough_peaks(HoughParametres houghParametres, ExtractParametres extractParametres, const char *name, const char *mapset, size_t nrows, size_t ncols, const char *angleMapName, const char *houghImageName, const char *result);
+
+#endif // HOUGH_H

Added: grass-addons/grass7/grass7/raster/r.houghtransform/houghparameters.h
===================================================================
--- grass-addons/grass7/grass7/raster/r.houghtransform/houghparameters.h	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.houghtransform/houghparameters.h	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,21 @@
+#ifndef HOUGHPARAMETERS_H
+#define HOUGHPARAMETERS_H
+
+struct HoughParametres
+{
+    double angleWidth;
+    int maxPeaksNum;
+    int threshold;
+    int sizeOfNeighbourhood;
+};
+
+struct ExtractParametres
+{
+    int gapSize;
+    int maxNumOfGaps;
+    int maxGap;
+    int lineLength;
+    int lineWidth;
+};
+
+#endif // HOUGHPARAMETERS_H

Added: grass-addons/grass7/grass7/raster/r.houghtransform/houghtransform.cpp
===================================================================
--- grass-addons/grass7/grass7/raster/r.houghtransform/houghtransform.cpp	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.houghtransform/houghtransform.cpp	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,243 @@
+#include "houghtransform.h"
+
+/* helpers */
+
+struct SortByX
+{
+    bool operator()(const HoughTransform::Coordinates& c1, const HoughTransform::Coordinates& c2) const
+    {
+
+        return c1.first < c2.first;
+    }
+};
+
+struct SortByY
+{
+    bool operator()(const HoughTransform::Coordinates& c1, const HoughTransform::Coordinates& c2) const
+    {
+
+        return c1.second < c2.second;
+    }
+};
+
+
+/* ctors */
+
+HoughTransform::HoughTransform(const Matrix &matrix, const HoughParametres& parametrs)
+    : mOriginalMatrix(matrix), mParams(parametrs)
+{
+    mNumR = mOriginalMatrix.rows();
+    mNumC = mOriginalMatrix.columns();
+
+    mThetas = ColumnVector(Range(-M_PI/2.0, M_PI/2.0, M_PI/180.0).matrix_value ());
+
+    const float diag_length = std::sqrt(mNumR*mNumR + mNumC*mNumC);
+    mNumBins = ceil(diag_length) - 1;
+
+    mHoughMatrix = Matrix(mNumBins, mThetas.length(), 0.0);
+
+    c_2 = ceil(mNumC/2.);
+    r_2 = ceil(mNumR/2.);
+
+    first_bins = 1 - ceil(mNumBins/2.0);
+}
+
+/* functions */
+
+void HoughTransform::compute()
+{
+    for (int x = 0; x < mNumR; x++)
+    {
+        for (int y = 0; y < mNumC; y++)
+        {
+            if (mOriginalMatrix(x, y) == 1)
+            {
+                computeHoughForXY(x, y, 0, mThetas.length());
+            }
+        }
+    }
+
+}
+
+void HoughTransform::computeHoughForXY(int x, int y, size_t minIndex, size_t maxIndex)
+{
+    for (size_t i = minIndex; i < maxIndex; i++)
+    {
+        const double theta = mThetas(i);
+        const double rho_d = std::cos(theta)*(x - c_2) + std::sin(theta)*(y - r_2);
+        const int rho = floor(rho_d + 0.5);
+        const int bin = rho - first_bins;
+
+        if ((bin > 0) && (bin < mNumBins))
+        {
+            mHoughMatrix(bin, i)++;
+            mHoughMap[Coordinates(bin, i)].push_back(Coordinates(x, y));
+            mOriginalMap[Coordinates(x, y)].push_back(Coordinates(bin, i));
+        }
+    }
+}
+
+/**
+  Expecting angles to be in degrees in range [0,180).
+
+  Size of agles matrix must be the same as size of input edge matrix.
+  mNumR != angles.rows() && mNumC != angles.columns()
+  */
+void HoughTransform::compute(const Matrix& angles, double angleWith)
+{
+    for (int x = 0; x < mNumR; x++)
+    {
+        for (int y = 0; y < mNumC; y++)
+        {
+            if (mOriginalMatrix(x, y) == 1)
+            {
+                // gradient in mathematical axes
+                double angle = angles(x, y);
+                
+                // unify gradients
+                if (angle < 0)
+                    angle += 180;
+
+                // converting angle [0,180) to index
+                // in internal table of angles
+                // assuming that table size is 180
+                // TODO: angleIndex = mThetas.length() * angle/180
+                int angleIndex = angle;
+                int angleShift = angleWith/2 + 0.5;
+
+                 // FIXME: magic number
+                int minIndex = angleIndex - angleShift;
+                int maxIndex = angleIndex + angleShift;
+
+                if (minIndex < 0) {
+                    computeHoughForXY(x, y, 0, maxIndex);
+                    minIndex = 180 + minIndex;
+                    computeHoughForXY(x, y, minIndex, 180);
+                }
+                else if (maxIndex > 180)
+                {
+                    computeHoughForXY(x, y, minIndex, 180);
+                    maxIndex = maxIndex - 180;
+                    computeHoughForXY(x, y, 0, maxIndex);
+                }
+                else
+                {
+                    computeHoughForXY(x, y, minIndex, maxIndex);
+                }
+            }
+        }
+    }
+}
+
+void HoughTransform::findPeaks(int maxPeakNumber, int threshold, int sizeOfNeighbourhood)
+{
+    int maxIt = mHoughMatrix.rows() * mHoughMatrix.columns();
+    int peaksFound = 0;
+    for (int i = 0; i < maxIt; i++)
+    {
+        Coordinates coordinates;
+        int maxValue = findMax(mHoughMatrix, coordinates);
+
+        if (maxValue < threshold || peaksFound == maxPeakNumber )
+            break;
+
+        CoordinatesList neighbours(neighbourhood(coordinates, sizeOfNeighbourhood));
+
+        Coordinates beginLine, endLine;
+
+        removePeakEffect(neighbours, beginLine, endLine);
+
+        Peak peak(coordinates, maxValue, beginLine, endLine);
+        mPeaks.push_back(peak);
+        peaksFound++;
+    }
+}
+
+HoughTransform::CoordinatesList HoughTransform::neighbourhood(Coordinates &coordinates, const int sizeOfNeighbourhood)
+{
+    CoordinatesList list;
+    const int x = coordinates.first;
+    const int y = coordinates.second;
+    for (int i = -sizeOfNeighbourhood; i <= sizeOfNeighbourhood; i++)
+    {
+        for (int j = -sizeOfNeighbourhood; j <= sizeOfNeighbourhood; j++)
+        {
+            list.push_back(Coordinates(x + i, y + j));
+        }
+    }
+    return list;
+}
+
+void HoughTransform::removePeakEffect(const CoordinatesList &neighbours, Coordinates &beginLine, Coordinates &endLine)
+{
+    CoordinatesList lineList;
+    for (CoordinatesList::const_iterator it = neighbours.begin(), end = neighbours.end(); it != end; ++it)
+    {
+        CoordinatesList &toRemove = mHoughMap[*it];
+
+        for (CoordinatesList::const_iterator it1 = toRemove.begin(), end = toRemove.end(); it1 != end; ++it1)
+        {
+            if ( mOriginalMap.find(*it1) != mOriginalMap.end() )
+            {
+                CoordinatesList &toDecrease = mOriginalMap[*it1];
+
+                for (CoordinatesList::const_iterator it2 = toDecrease.begin(), end = toDecrease.end(); it2 != end; ++it2)
+                {
+                    mHoughMatrix(it2->first, it2->second)--;
+                }
+                mOriginalMap.erase(*it1);
+
+               lineList.push_back(*it1);
+            }
+        }
+    }
+    int angle = neighbours.front().second;
+    // what to do if find endpoints finds nothing reasonable?
+    findEndPoints(lineList, beginLine, endLine, angle);
+}
+
+/** \param list[in, out] will be sorted by y cooridinate
+  if angle is in range (45, 135] or by x otherwise
+  */
+bool HoughTransform::findEndPoints(CoordinatesList& list, Coordinates &beginLine, Coordinates &endLine, const value_type angle)
+{
+    if (angle > 45 && angle <= 135)
+    {
+        std::sort(list.begin(), list.end(), SortByY());
+    }
+    else
+    {
+        std::sort(list.begin(), list.end(), SortByX());
+    }
+
+    beginLine = list.front();
+    endLine = list.back();
+
+    return true;
+}
+
+int HoughTransform::findMax(const Matrix& matrix, Coordinates &coordinates)
+{
+    size_t rowIndex = 0;
+    size_t colIndex;
+    std::vector<size_t> colIndexes;
+
+    std::vector<value_type> rowMax = matrix.row_max(colIndexes);
+
+    int max = 0;
+    for (size_t i = 0; i < rowMax.size(); i++)
+    {
+        int tmp = rowMax[i];
+        if (tmp > max)
+        {
+            max = tmp;
+            rowIndex = i;
+        }
+    }
+    colIndex = colIndexes[rowIndex];
+
+    coordinates.first = rowIndex;
+    coordinates.second = colIndex;
+
+    return max;
+}

Added: grass-addons/grass7/grass7/raster/r.houghtransform/houghtransform.h
===================================================================
--- grass-addons/grass7/grass7/raster/r.houghtransform/houghtransform.h	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.houghtransform/houghtransform.h	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,123 @@
+#ifndef HOUGHTRANSFORM_H
+#define HOUGHTRANSFORM_H
+
+#include "houghparameters.h"
+#include "matrix.h"
+
+#include <cmath>
+#include <vector>
+#include <list>
+#include <set>
+#include <map>
+#include <limits>
+#include <algorithm>
+
+#include <stdio.h>
+
+class HoughTransform
+{
+public:
+    /* types */
+    typedef double value_type;
+    typedef matrix::Matrix<value_type> Matrix;
+    typedef matrix::ColumnVector<double> ColumnVector;
+    typedef matrix::Range<double> Range;
+
+    /** This is class to provide compatible syntax with \c std::list. */
+    template <typename T>
+    class Vector: public std::vector<T>
+    {
+    public:
+
+        /**
+          Maybe it would be better to replace by an overload of sort function for list.
+          And use this function for list.
+          */
+        template <typename Comp>
+        void sort(Comp comp)
+        {
+            std::sort(this->begin(), this->end(), comp);
+        }
+        /** only for convenience, with some compiler optimalisation overhead shouldn't be so high  */
+        operator std::list<T>() const
+        {
+            std::list<T> tmp;
+            tmp.insert(tmp.begin(), this->begin(), this->end());
+            return tmp;
+        }
+    };
+
+    typedef std::pair<int, int> Coordinates;
+    typedef Vector<Coordinates> CoordinatesList;
+    typedef std::map<Coordinates, CoordinatesList> TracebackMap;
+
+    struct Peak
+    {
+        Peak(Coordinates coordinates, value_type value, Coordinates begin, Coordinates end)
+            : coordinates(coordinates), value(value), beginLine(begin), endLine(end)
+        {}
+        Coordinates coordinates;
+        int value;
+        Coordinates beginLine;
+        Coordinates endLine;
+    };
+
+    typedef std::vector<Peak> Peaks;
+
+    /* functions */
+
+    HoughTransform(const Matrix &matrix, const HoughParametres &parametrs);
+
+    void compute();
+    void compute(const Matrix& angles)
+    {
+        compute(angles, mParams.angleWidth);
+    }
+    void compute(const Matrix& angles, double angleWith);
+    void findPeaks()
+    {
+        findPeaks(mParams.maxPeaksNum, mParams.threshold, mParams.sizeOfNeighbourhood);
+    }
+    void findPeaks(int maxPeakNumber, int threshold,
+                   const int sizeOfNeighbourhood);
+
+    /* getters */
+
+    const Matrix & getHoughMatrix() const { return mHoughMatrix; }
+    const Matrix & getOrigMatrix()  const { return mOriginalMatrix; }
+    const Peaks & getPeaks() const { return mPeaks; }
+    const TracebackMap & getHoughMap() const { return mHoughMap; }
+
+private:
+
+    /* functions */
+
+    // some of these functions can be changed to non-member
+    CoordinatesList neighbourhood(Coordinates &coordinates, const int sizeOfNeighbourhood);
+    void removePeakEffect(const CoordinatesList &neighbours, Coordinates &beginLine, Coordinates &endLine);
+    bool findEndPoints(CoordinatesList& list, Coordinates &beginLine, Coordinates &endLine, const value_type angle);
+    int findMax(const Matrix& matrix, Coordinates &coordinates);
+    void computeHoughForXY(int x, int y, size_t minIndex, size_t maxIndex);
+
+    /* data members */
+
+    const Matrix& mOriginalMatrix;
+    Matrix mHoughMatrix;
+    TracebackMap mOriginalMap;
+    TracebackMap mHoughMap;
+    Peaks mPeaks;
+
+    HoughParametres mParams;
+
+    /* helper variables for computations */
+    int mNumR;
+    int mNumC;
+    ColumnVector mThetas;
+    int mNumBins;
+    int c_2;
+    int r_2;
+    int first_bins;
+};
+
+
+#endif // HOUGHTRANSFORM_H

Added: grass-addons/grass7/grass7/raster/r.houghtransform/linesegmentsextractor.cpp
===================================================================
--- grass-addons/grass7/grass7/raster/r.houghtransform/linesegmentsextractor.cpp	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.houghtransform/linesegmentsextractor.cpp	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,261 @@
+#include "linesegmentsextractor.h"
+
+#include "matrix.h"
+
+#include <stdio.h>
+
+#include <cmath>
+#include <vector>
+#include <list>
+
+using namespace matrix;
+
+struct Point
+{
+    int x;
+    int y;
+};
+
+/* non-member functions */
+
+double segmentLenght(const Segment& segment)
+{
+    double x = segment.first.first - segment.second.first;
+    double y = segment.first.second - segment.second.second;
+    return std::sqrt(x*x + y*y);
+}
+
+bool checkBounds(int y, int x, int cols, int rows)
+{
+    if ( y < 0 || y >= cols || x < 0 || x >= rows )
+        return false;
+    return true;
+}
+
+template<typename Matrix>
+bool isData(const Matrix &I, const std::vector<int> &y, const std::vector<int> &x, const int cols, const int rows)
+{
+    for (size_t k = 0; k < y.size(); k++)
+    {
+        if (checkBounds(y.at(k), x.at(k), cols, rows) && I(x.at(k), y.at(k)))
+        {
+            return true;
+        }
+    }
+    return false;
+}
+
+void remove_points(LineCoordinates& lineCoordinates, const std::vector<int>& indicesI, const std::vector<int>& indicesJ)
+{
+    for (size_t i = 0; i < indicesI.size(); ++i)
+    {
+        std::pair<int, int> coords;
+        coords.second = indicesI[i];
+        coords.first = indicesJ[i];
+        lineCoordinates.remove(coords);
+    }
+}
+
+void find_indices(std::vector<int>& indicesI, std::vector<int>& indicesJ,
+                  const int shift, const bool xflag, const int x, const int y,
+                  const int line_width)
+{
+    if (xflag)
+    {
+        int tmp1, tmp2;
+        indicesJ[0] = x;
+        tmp1 = y >> shift;
+        tmp2 = tmp1;
+        indicesI[0] = tmp1;
+        for (int l = 1; l < line_width; l += 2)
+        {
+            indicesJ[l] = x;
+            indicesJ[l + 1] = x;
+            indicesI[l] = --tmp1;
+            indicesI[l + 1] = ++tmp2;
+        }
+    }
+    else
+    {
+        int tmp1, tmp2;
+        indicesI[0] = y;
+        tmp1 = x >> shift;
+        tmp2 = tmp1;
+        indicesJ[0] = tmp1;
+        for (int l = 1; l < line_width; l += 2)
+        {
+            indicesI[l] = y;
+            indicesI[l + 1] = y;
+            indicesJ[l] = --tmp1;
+            indicesJ[l + 1] = ++tmp2;
+        }
+    }
+}
+
+bool segmentContainsPoint(const Segment& segment, const std::pair<int, int>& p, bool xFlag, int tol)
+{
+  int min, max;
+  if (xFlag)
+  {
+    min = segment.first.first;
+    max = segment.second.first;
+    if (segment.first.first > segment.second.first)
+    {
+      min = segment.second.first;
+      max = segment.first.first;
+    }
+
+    if (p.first > min + tol && p.first <= max - tol)
+      return true;
+  }
+  else
+  {
+    min = segment.first.second;
+    max = segment.second.second;
+    if (segment.first.second > segment.second.second)
+    {
+      min = segment.second.second;
+      max = segment.first.second;
+    }
+    if (p.second > min + tol && p.second <= max - tol)
+      return true;
+  }
+  return false;
+}
+
+/* member functions */
+
+void LineSegmentsExtractor::extract(LineCoordinates lineCoordinates,
+                                    const double orient,
+                                    SegmentList& segments)
+{
+    const int rows = mImage.rows();
+    const int cols = mImage.columns();
+
+    float rho = 1.0;
+    float irho = 1./rho;
+
+    bool xflag;
+
+    std::vector<Point> line_end(2);
+    SegmentList newSegments;
+
+    // from the current point walk in each direction
+    // along the found line and extract the line segment
+    float a = -(float)(sin(orient) * irho); //-trigtab[theta_n*2+1];
+    float b = (float)(cos(orient) * irho); //trigtab[theta_n*2];
+
+    int dx0, dy0;
+    const int shift = 16;
+
+    std::vector<int> indicesI(lineWidth);
+    std::vector<int> indicesJ(lineWidth);
+
+    int lineNum = 0;
+    while (!lineCoordinates.empty())
+    {
+        lineNum++;
+        std::pair<int, int> startCoordinates = lineCoordinates.front();
+
+        int x0 = startCoordinates.first;
+        int y0 = startCoordinates.second;
+
+        if ( fabs(a) > fabs(b) )
+        {
+            xflag = 1;
+            dx0 = a > 0 ? 1 : -1;
+            dy0 = (int)( b*(1 << shift)/fabs(a) + 0.5);
+            y0 = (y0 << shift) + (1 << (shift-1));
+        }
+        else
+        {
+            xflag = 0;
+            dy0 = b > 0 ? 1 : -1;
+            dx0 = (int)( a*(1 << shift)/fabs(b) + 0.5);
+            x0 = (x0 << shift) + (1 << (shift-1));
+        }
+
+        int numOfGaps = 0;
+        bool useLine = true;
+        for ( int k = 0; k < 2; k++ )
+        {
+            int gap = 0, x = x0, y = y0, dx = dx0, dy = dy0;
+
+            if ( k > 0 )
+                dx = -dx, dy = -dy;
+
+            // walk along the line using fixed-point arithmetics,
+            // stop at the image border or in case of too big gap
+            for ( ;; x += dx, y += dy )
+            {
+                find_indices(indicesI, indicesJ, shift, xflag, x, y, lineWidth);
+
+                remove_points(lineCoordinates, indicesI, indicesJ);
+
+                // for each non-zero point:
+                //    update line end,
+                //    clear the mask element
+                //    reset the gap
+                if ( isData(mImage, indicesI, indicesJ, cols, rows) )
+                {
+                    if (gap > gapSize)
+                    {
+                        numOfGaps++;
+                        if (numOfGaps > maxNumOfGaps)
+                        {
+                            useLine = false;
+                            break;
+                        }
+                    }
+                    gap = 0;
+                    line_end[k].y = indicesI[0];
+                    line_end[k].x = indicesJ[0];
+                }
+                else if ( ++gap > lineGap )
+                {
+                    break;
+                }
+            }
+        }
+
+        bool good_line = abs(line_end[1].x - line_end[0].x) >= lineLength ||
+                abs(line_end[1].y - line_end[0].y) >= lineLength;
+
+        if (good_line && useLine)
+        {
+            Segment newSegment;
+            newSegment.first.first = line_end[0].x;
+            newSegment.first.second = line_end[0].y;
+            newSegment.second.first = line_end[1].x;
+            newSegment.second.second = line_end[1].y;
+            int limit = 5;
+            bool add = true;
+            if (!newSegments.empty())
+            {
+                add = false;
+                const Segment lastSegment = newSegments.back();
+                if (!segmentContainsPoint(lastSegment, newSegment.first, xflag, limit) &&
+                    !segmentContainsPoint(lastSegment, newSegment.second, xflag, limit) &&
+                    !segmentContainsPoint(newSegment, lastSegment.first, xflag, limit) &&
+                    !segmentContainsPoint(newSegment, lastSegment.second, xflag, limit))
+                {
+                    add = true;
+                }
+
+                if (add == false)
+                {
+                    if (segmentLenght(lastSegment) < segmentLenght(newSegment))
+                    {
+                        newSegments.pop_back();
+                        add = true;
+                    }
+                }
+            }
+            if (add)
+            {
+                newSegments.push_back(newSegment);
+            }
+        }
+    }
+    segments.insert(segments.end(), newSegments.begin(), newSegments.end());
+}

Added: grass-addons/grass7/grass7/raster/r.houghtransform/linesegmentsextractor.h
===================================================================
--- grass-addons/grass7/grass7/raster/r.houghtransform/linesegmentsextractor.h	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.houghtransform/linesegmentsextractor.h	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,50 @@
+#ifndef LILESEGMENTSEXTRACTOR_H
+#define LILESEGMENTSEXTRACTOR_H
+
+
+#include "houghparameters.h"
+#include "matrix.h"
+
+#include <vector>
+#include <list>
+
+typedef std::pair<int, int> Coordinates;
+typedef std::pair< Coordinates, Coordinates > Segment;
+typedef std::vector< Segment > SegmentList;
+typedef std::list< std::pair<int, int> > LineCoordinates;
+
+class LineSegmentsExtractor
+{
+public:
+    typedef double value_type;
+    typedef matrix::Matrix<value_type> Matrix;
+
+    /**
+      \param image should exist during existence of LineSegmentsExtractor
+      \param lineCoordinates will be copied to internal variable
+      */
+    LineSegmentsExtractor(const Matrix& image,
+                          const ExtractParametres& parametres)
+        : mImage(image),
+          gapSize(parametres.gapSize), maxNumOfGaps(parametres.maxNumOfGaps),
+          lineGap(parametres.maxGap), lineLength(parametres.lineLength),
+          lineWidth(parametres.lineWidth)
+    {}
+
+    /**
+      \param lineCoordinates list of lines
+      \param orient orientation of lines
+      \param[out] segments extracted segments will be added to this list
+      */
+    void extract(LineCoordinates lineCoordinates, const double orient, SegmentList& segments);
+
+private:
+    const Matrix &mImage;
+    int gapSize;
+    int maxNumOfGaps;
+    int lineGap;
+    int lineLength;
+    int lineWidth;
+};
+
+#endif // LILESEGMENTSEXTRACTOR_H

Added: grass-addons/grass7/grass7/raster/r.houghtransform/main.cpp
===================================================================
--- grass-addons/grass7/grass7/raster/r.houghtransform/main.cpp	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.houghtransform/main.cpp	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,209 @@
+
+/****************************************************************************
+ *
+ * MODULE:       r.houghtransform
+ * AUTHOR(S):    Anna Kratochvilova - kratochanna gmail.com
+ *               Vaclav Petras - wenzeslaus gmail.com
+ *
+ * PURPOSE:      Line segment extraction using Hough transformation.
+ *
+ * COPYRIGHT:    (C) 2012 by the GRASS Development Team
+ *
+ *               This program is free software under the GNU General Public
+ *   	    	 License (>=v2). Read the file COPYING that comes with GRASS
+ *   	    	 for details.
+ *
+ *****************************************************************************/
+
+#include "hough.h"
+
+extern "C" {
+#include <grass/gis.h>
+#include <grass/raster.h>
+#include <grass/glocale.h>
+#include <grass/gmath.h>
+}
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+/**
+
+  \todo Floats are used instead of doubles.
+  \todo Be able to work with FCELL (and CELL?).
+  */
+int main(int argc, char *argv[])
+{
+    struct Cell_head cell_head;	/* it stores region information,
+                                   and header information of rasters */
+    char *name;			/* input raster name */
+
+    char *mapset;		/* mapset name */
+
+    char *result;		/* output raster name */
+
+    int nrows, ncols;
+
+    struct GModule *module;	/* GRASS module for parsing arguments */
+
+    /* options */
+    struct Option *input, *output, *anglesOption, *houghImageNameOption,
+            *angleWidthOption,
+            *minGapOption, *maxNumberOfGapsOption,
+            *maxLinesOption, *maxGapOption, *minSegmentLengthOption,
+            *lineWidthOption;
+
+    /* initialize GIS environment */
+    G_gisinit(argv[0]);		/* reads grass env, stores program name to G_program_name() */
+
+    /* initialize module */
+    module = G_define_module();
+    G_add_keyword(_("raster"));
+    G_add_keyword(_("hought"));
+    G_add_keyword(_("ht"));
+    module->description =
+            _("Perform Hough transformation and extracts line segments from image."
+              " Region shall be set to input map."
+              " Can work only on small images since map is loaded into memory.");
+
+    /* Define the different options as defined in gis.h */
+    input = G_define_standard_option(G_OPT_R_INPUT);
+
+    output = G_define_standard_option(G_OPT_V_OUTPUT);
+
+    anglesOption = G_define_standard_option(G_OPT_R_INPUT);
+    anglesOption->key = "angles";
+    anglesOption->required = NO;
+    anglesOption->description = _("Name of input image with angles from i.edge.");
+
+    houghImageNameOption = G_define_standard_option(G_OPT_R_OUTPUT);
+    houghImageNameOption->key = "hough_image";
+    houghImageNameOption->required = NO;
+    houghImageNameOption->description = _("Name of output image containing Hough transform");
+
+    angleWidthOption = G_define_option();
+    angleWidthOption->key = "angle_width";
+    angleWidthOption->type = TYPE_INTEGER;
+    angleWidthOption->required = NO;
+    angleWidthOption->multiple = NO;
+    angleWidthOption->description = _("Width of circle sector (only when you provide angle map)");
+    angleWidthOption->answer = const_cast<char *>("5");
+
+    // this option will become max peaks number to find in HT
+    maxLinesOption = G_define_option();
+    maxLinesOption->key = "lines_number";
+    maxLinesOption->type = TYPE_INTEGER;
+    maxLinesOption->required = NO;
+    maxLinesOption->multiple = NO;
+    maxLinesOption->label = _("Approximate number of line segments");
+    maxLinesOption->description = _(
+                "This number represents"
+                " maximal number of line candidates"
+                " detected in Hough transform image."
+                " Final number of line segments can be"
+                " smaller or greater.");
+    maxLinesOption->answer = const_cast<char *>("20");
+
+    minGapOption = G_define_option();
+    minGapOption->key = "gap_size";
+    minGapOption->type = TYPE_INTEGER;
+    minGapOption->required = NO;
+    minGapOption->multiple = NO;
+    minGapOption->description = _("Minimal cell count considered as a gap");
+    minGapOption->answer = const_cast<char *>("5");
+
+    maxNumberOfGapsOption = G_define_option();
+    maxNumberOfGapsOption->key = "max_gap_count";
+    maxNumberOfGapsOption->type = TYPE_INTEGER;
+    maxNumberOfGapsOption->required = NO;
+    maxNumberOfGapsOption->multiple = NO;
+    maxNumberOfGapsOption->description = _("Maximal number of gaps in line segment");
+    maxNumberOfGapsOption->answer = const_cast<char *>("5");
+
+    maxGapOption = G_define_option();
+    maxGapOption->key = "max_gap";
+    maxGapOption->type = TYPE_INTEGER;
+    maxGapOption->required = NO;
+    maxGapOption->multiple = NO;
+    maxGapOption->description = _("Maximum gap in pixels");
+    maxGapOption->answer = const_cast<char *>("5");
+
+    minSegmentLengthOption = G_define_option();
+    minSegmentLengthOption->key = "min_segment_length";
+    minSegmentLengthOption->type = TYPE_INTEGER;
+    minSegmentLengthOption->required = NO;
+    minSegmentLengthOption->multiple = NO;
+    minSegmentLengthOption->description = _("Minimal length of line segment");
+    minSegmentLengthOption->answer = const_cast<char *>("50");
+
+    lineWidthOption = G_define_option();
+    lineWidthOption->key = "line_width";
+    lineWidthOption->type = TYPE_INTEGER;
+    lineWidthOption->required = NO;
+    lineWidthOption->multiple = NO;
+    lineWidthOption->description = _("Expected width of line (used for searching segments)");
+    lineWidthOption->answer = const_cast<char *>("3");
+
+    /* options and flags parser */
+    if (G_parser(argc, argv))
+        exit(EXIT_FAILURE);
+
+    /* stores options and flags to variables */
+    result = output->answer;
+    name = input->answer;
+
+
+    HoughParametres houghParametres;
+    houghParametres.maxPeaksNum = atoi(maxLinesOption->answer);
+    houghParametres.threshold = 10; // TODO: consider option
+    houghParametres.angleWidth = atoi(angleWidthOption->answer);
+    houghParametres.sizeOfNeighbourhood = 1; // TODO: consider option
+
+    ExtractParametres extractParametres;
+    extractParametres.gapSize = atoi(minGapOption->answer);
+    extractParametres.maxGap = atoi(maxGapOption->answer);
+    extractParametres.maxNumOfGaps = atoi(maxNumberOfGapsOption->answer);
+    extractParametres.lineLength = atoi(minSegmentLengthOption->answer);
+    extractParametres.lineWidth = atoi(lineWidthOption->answer);
+
+    /* returns NULL if the map was not found in any mapset,
+     * mapset name otherwise */
+    mapset = (char *)G_find_raster2(name, "");
+    if (mapset == NULL)
+        G_fatal_error(_("Raster map <%s> not found"), name);
+
+    /* determine the inputmap type (CELL/FCELL/DCELL) */
+    //data_type = Rast_map_type(name, mapset);
+
+    //    struct Cell_head templCellhd;
+
+    //    Rast_get_cellhd(name, mapset, &cellhd);
+    //    Rast_get_cellhd(first_map_R_name, first_map_R_mapset, &cellhd_zoom1);
+
+    /* controlling, if we can open input raster */
+    Rast_get_cellhd(name, mapset, &cell_head);
+
+    G_debug(3, "number of rows %d", cell_head.rows);
+
+    nrows = Rast_window_rows();
+
+    ncols = Rast_window_cols();
+
+    /* **** */
+
+    hough_peaks(houghParametres, extractParametres, name, mapset, nrows, ncols, anglesOption->answer, houghImageNameOption->answer, result);
+
+    /* **** */
+
+    /* memory cleanup */
+    G_free(name);
+
+    /* add command line incantation to history file */
+    //    Rast_short_history(templName, "raster", &history);
+    //    Rast_command_history(&history);
+    //    Rast_write_history(templName, &history);
+
+    exit(EXIT_SUCCESS);
+}

Added: grass-addons/grass7/grass7/raster/r.houghtransform/matrix.h
===================================================================
--- grass-addons/grass7/grass7/raster/r.houghtransform/matrix.h	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.houghtransform/matrix.h	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,200 @@
+#ifndef MATRIX_H
+#define MATRIX_H
+
+#include <vector>
+#include <algorithm>
+#include <limits>
+#include <cmath>
+
+/* mimics Octave matrices and other classes */
+
+namespace matrix {
+
+template <typename T>
+class Matrix
+{
+public:
+    typedef T value_type;
+
+    Matrix(size_t r, size_t c, value_type val = 0)
+        : mRows(r), mCols(c)
+    {
+        resize(r, c, val);
+    }
+    Matrix() : mRows(0), mCols(0) {}
+
+    void resize(size_t r, size_t c, value_type val = 0)
+    {
+        mRows = r;
+        mCols = c;
+        std::vector<value_type> row;
+        row.resize(c, val);
+        mat.resize(r, row);
+    }
+
+    /**
+
+      if (r > rows() || c > columns()) error;
+      */
+    value_type& operator ()(size_t r, size_t c)
+    {
+        return mat[r][c];
+    }
+    /**
+
+      if (r > rows() || c > columns()) error;
+      */
+    const value_type& operator ()(size_t r, size_t c) const
+    {
+        return mat[r][c];
+    }
+    size_t rows() const { return mRows; }
+    size_t columns() const { return mCols; }
+
+    std::vector<value_type> row_max(std::vector<size_t>& colIndexes) const
+    {
+        std::vector<value_type> ret;
+        ret.reserve(rows());
+        colIndexes.reserve(rows());
+        for (size_t i = 0; i < rows(); ++i)
+        {
+            typename std::vector<value_type>::const_iterator maxe = std::max_element(mat[i].begin(), mat[i].end());
+            value_type max = *maxe;
+            size_t maxi = maxe - mat[i].begin();
+
+            ret.push_back(max);
+            colIndexes.push_back(maxi);
+        }
+        return ret;
+    }
+
+private:
+    std::vector< std::vector<value_type> > mat;
+    size_t mRows;
+    size_t mCols;
+};
+
+template <typename T>
+class ColumnVector
+{
+public:
+    typedef T value_type;
+
+    ColumnVector(Matrix<value_type> mat)
+    {
+        for (size_t i = 0; i < mat.columns(); ++i)
+        {
+            vec.push_back(mat(0, i));
+        }
+    }
+    ColumnVector() {}
+
+    value_type& operator ()(size_t i)
+    {
+        return vec[i];
+    }
+    const value_type& operator ()(size_t i) const
+    {
+        return vec[i];
+    }
+    size_t length() { return vec.size(); }
+
+private:
+    std::vector<value_type> vec;
+};
+
+template <typename T>
+class Range
+{
+public:
+    typedef T value_type;
+
+    Range (double b, double l, double i)
+        : rng_base(b), rng_limit(l), rng_inc(i), rng_nelem(nelem_internal())
+    { }
+
+    Range (double b, double l)
+      : rng_base(b), rng_limit(l), rng_inc(1),
+        rng_nelem(nelem_internal()) { }
+
+    Matrix<value_type> matrix_value() const
+    {
+        Matrix<value_type> cache;
+        //if (rng_nelem > 0 && cache.nelem () == 0)
+          //{
+            cache.resize(1, rng_nelem);
+            double b = rng_base;
+            double increment = rng_inc;
+            for (size_t i = 0; i < rng_nelem; i++)
+              cache(0, i) = b + i * increment;
+
+            // On some machines (x86 with extended precision floating point
+            // arithmetic, for example) it is possible that we can overshoot
+            // the limit by approximately the machine precision even though
+            // we were very careful in our calculation of the number of
+            // elements.
+
+            if ((rng_inc > 0 && cache(0, rng_nelem-1) > rng_limit)
+                || (rng_inc < 0 && cache(0, rng_nelem-1) < rng_limit))
+              cache(0, rng_nelem-1) = rng_limit;
+        //  }
+        return cache;
+    }
+
+private:
+    /* from Octave source codes */
+    size_t nelem_internal() const
+    {
+      size_t retval = -1;
+
+      if (rng_inc == 0
+          || (rng_limit > rng_base && rng_inc < 0)
+          || (rng_limit < rng_base && rng_inc > 0))
+        {
+          retval = 0;
+        }
+      else
+        {
+          // double ct = 3.0 * std::numeric_limits<double>::epsilon(); // FIXME: not used
+          // was DBL_EPSILON;
+
+          // double tmp = tfloor ((rng_limit - rng_base + rng_inc) / rng_inc, ct); // octave code
+          double tmp = floor ((rng_limit - rng_base + rng_inc) / rng_inc);
+
+          size_t n_elt = (tmp > 0.0 ? static_cast<size_t> (tmp) : 0);
+
+          // If the final element that we would compute for the range is
+          // equal to the limit of the range, or is an adjacent floating
+          // point number, accept it.  Otherwise, try a range with one
+          // fewer element.  If that fails, try again with one more
+          // element.
+          //
+          // I'm not sure this is very good, but it seems to work better than
+          // just using tfloor as above.  For example, without it, the
+          // expression 1.8:0.05:1.9 fails to produce the expected result of
+          // [1.8, 1.85, 1.9].
+
+          // octave code
+          // if (! teq (rng_base + (n_elt - 1) * rng_inc, rng_limit))
+          //   {
+          //     if (teq (rng_base + (n_elt - 2) * rng_inc, rng_limit))
+          //       n_elt--;
+          //     else if (teq (rng_base + n_elt * rng_inc, rng_limit))
+          //       n_elt++;
+          //   }
+
+          retval = (n_elt >= std::numeric_limits<size_t>::max () - 1) ? -1 : n_elt;
+        }
+
+      return retval;
+    }
+
+ double rng_base;
+ double rng_limit;
+ double rng_inc;
+ size_t rng_nelem;
+};
+
+}
+
+#endif // MATRIX_H

Added: grass-addons/grass7/grass7/raster/r.houghtransform/r.houghtransform.html
===================================================================
--- grass-addons/grass7/grass7/raster/r.houghtransform/r.houghtransform.html	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.houghtransform/r.houghtransform.html	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,19 @@
+<h2>DESCRIPTION</h2>
+
+<em>r.houghtransform</em> is performing line extraction from edges in 
+a raster map using the Hough transform.
+
+<h2>SEE ALSO</h2>
+
+<em>
+<a href="r.thin.html">r.thin</a>
+</em>
+
+
+<h2>AUTHORS</h2>
+
+Anna Kratochvilova,
+Vaclav Petras
+
+<p><i>Last changed: $Date: 2012-08-02 12:35:50 +0200 (Thu, 02 Aug 2012) $</i>
+

Added: grass-addons/grass7/grass7/raster/r.hydrodem/Makefile
===================================================================
--- grass-addons/grass7/grass7/raster/r.hydrodem/Makefile	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.hydrodem/Makefile	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,10 @@
+MODULE_TOPDIR = ../..
+
+PGM = r.hydrodem
+
+LIBES     = $(SEGMENTLIB) $(RASTERLIB) $(GISLIB)
+DEPENDENCIES = $(SEGMENTDEP) $(RASTERDEP) $(GISDEP)
+
+include $(MODULE_TOPDIR)/include/Make/Module.make
+
+default: cmd

Added: grass-addons/grass7/grass7/raster/r.hydrodem/bseg.c
===================================================================
--- grass-addons/grass7/grass7/raster/r.hydrodem/bseg.c	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.hydrodem/bseg.c	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,159 @@
+#include <unistd.h>
+#include <fcntl.h>
+#include <grass/glocale.h>
+#include "seg.h"
+
+int bseg_open(BSEG *bseg, int srows, int scols, int nsegs_in_memory)
+{
+    char *filename;
+    int errflag;
+    int fd;
+
+    bseg->filename = NULL;
+    bseg->fd = -1;
+    bseg->name = NULL;
+    bseg->mapset = NULL;
+
+    filename = G_tempfile();
+    if (-1 == (fd = creat(filename, 0666))) {
+	G_warning(_("bseg_open(): unable to create segment file"));
+	return -2;
+    }
+    if (0 > (errflag = segment_format(fd, Rast_window_rows(),
+				      Rast_window_cols(), srows, scols,
+				      sizeof(char)))) {
+	close(fd);
+	unlink(filename);
+	if (errflag == -1) {
+	    G_warning(_("bseg_open(): could not write segment file"));
+	    return -1;
+	}
+	else {
+	    G_warning(_("bseg_open(): illegal configuration parameter(s)"));
+	    return -3;
+	}
+    }
+    close(fd);
+    if (-1 == (fd = open(filename, 2))) {
+	unlink(filename);
+	G_warning(_("bseg_open(): unable to re-open segment file"));
+	return -4;
+    }
+    if (0 > (errflag = segment_init(&(bseg->seg), fd, nsegs_in_memory))) {
+	close(fd);
+	unlink(filename);
+	if (errflag == -1) {
+	    G_warning(_("bseg_open(): could not read segment file"));
+	    return -5;
+	}
+	else {
+	    G_warning(_("bseg_open(): out of memory"));
+	    return -6;
+	}
+    }
+    bseg->filename = filename;
+    bseg->fd = fd;
+    return 0;
+}
+
+int bseg_close(BSEG *bseg)
+{
+    segment_release(&(bseg->seg));
+    close(bseg->fd);
+    unlink(bseg->filename);
+    if (bseg->name) {
+	G_free(bseg->name);
+	bseg->name = NULL;
+    }
+    if (bseg->mapset) {
+	G_free(bseg->mapset);
+	bseg->mapset = NULL;
+    }
+    return 0;
+}
+
+int bseg_put(BSEG *bseg, char *value, int row, int col)
+{
+    if (segment_put(&(bseg->seg), value, row, col) < 0) {
+	G_warning(_("bseg_put(): could not write segment file"));
+	return -1;
+    }
+    return 0;
+}
+
+int bseg_put_row(BSEG *bseg, char *value, int row)
+{
+    if (segment_put_row(&(bseg->seg), value, row) < 0) {
+	G_warning(_("bseg_put_row(): could not write segment file"));
+	return -1;
+    }
+    return 0;
+}
+
+int bseg_get(BSEG *bseg, char *value, int row, int col)
+{
+    if (segment_get(&(bseg->seg), value, row, col) < 0) {
+	G_warning(_("bseg_get(): could not read segment file"));
+	return -1;
+    }
+    return 0;
+}
+
+
+int bseg_read_raster(BSEG *bseg, char *map_name, char *mapset)
+{
+    int row, nrows;
+    int col, ncols;
+    int map_fd;
+    CELL *buffer;
+    char cbuf;
+
+    bseg->name = NULL;
+    bseg->mapset = NULL;
+
+    map_fd = Rast_open_old(map_name, mapset);
+    nrows = Rast_window_rows();
+    ncols = Rast_window_cols();
+    buffer = Rast_allocate_c_buf();
+    for (row = 0; row < nrows; row++) {
+	Rast_get_c_row(map_fd, buffer, row);
+	for (col = ncols; col >= 0; col--) {
+	    cbuf = (char) buffer[col];
+	    bseg_put(bseg, &cbuf, row, col);
+	}
+    }
+
+    Rast_close(map_fd);
+    G_free(buffer);
+
+    bseg->name = G_store(map_name);
+    bseg->mapset = G_store(mapset);
+
+    return 0;
+}
+
+int bseg_write_raster(BSEG *bseg, char *map_name)
+{
+    int map_fd;
+    int row, nrows;
+    int col, ncols;
+    CELL *buffer;
+    char value;
+
+    map_fd = Rast_open_c_new(map_name);
+    nrows = Rast_window_rows();
+    ncols = Rast_window_cols();
+    buffer = Rast_allocate_c_buf();
+    for (row = 0; row < nrows; row++) {
+	G_percent(row, nrows, 1);
+	for (col = 0; col < ncols; col++) {
+	    bseg_get(bseg, &value, row, col);
+	    buffer[col] = value;
+	}
+	Rast_put_row(map_fd, buffer, CELL_TYPE);
+    }
+    G_percent(row, nrows, 1);    /* finish it */
+    G_free(buffer);
+    Rast_close(map_fd);
+    return 0;
+}

Added: grass-addons/grass7/grass7/raster/r.hydrodem/close.c
===================================================================
--- grass-addons/grass7/grass7/raster/r.hydrodem/close.c	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.hydrodem/close.c	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,57 @@
+#include <grass/gis.h>
+#include <grass/raster.h>
+#include <grass/glocale.h>
+#include "local_proto.h"
+
+int close_map(char *ele_rast, int ele_map_type)
+{
+    int ele_fd, r, c;
+    void *ele_buf, *ele_ptr;
+    struct History history;
+    size_t ele_size;
+    CELL ele_val;
+
+    G_message(_("Write conditioned DEM"));
+
+    ele_fd = Rast_open_new(ele_rast, ele_map_type);
+    ele_size = Rast_cell_size(ele_map_type);
+    ele_buf = Rast_allocate_buf(ele_map_type);
+
+    for (r = 0; r < nrows; r++) {
+	G_percent(r, nrows, 2);
+
+	Rast_set_null_value(ele_buf, ncols, ele_map_type);	/* reset row to all NULL */
+
+	ele_ptr = ele_buf;
+
+	for (c = 0; c < ncols; c++) {
+	    cseg_get(&ele, &ele_val, r, c);
+
+	    if (!Rast_is_c_null_value(&ele_val)) {
+
+		switch (ele_map_type) {
+		case CELL_TYPE:
+		    *((CELL *) ele_ptr) = ele_val;
+		    break;
+		case FCELL_TYPE:
+		    *((FCELL *) ele_ptr) = (FCELL) ele_val / ele_scale;
+		    break;
+		case DCELL_TYPE:
+		    *((DCELL *) ele_ptr) = (DCELL) ele_val / ele_scale;
+		    break;
+		}
+	    }
+	    ele_ptr = G_incr_void_ptr(ele_ptr, ele_size);
+	}
+	Rast_put_row(ele_fd, ele_buf, ele_map_type);
+    }
+    G_percent(nrows, nrows, 2);	/* finish it */
+
+    Rast_close(ele_fd);
+    G_free(ele_buf);
+    Rast_short_history(ele_rast, "raster", &history);
+    Rast_command_history(&history);
+    Rast_write_history(ele_rast, &history);
+
+    return 1;
+}

Added: grass-addons/grass7/grass7/raster/r.hydrodem/cseg.c
===================================================================
--- grass-addons/grass7/grass7/raster/r.hydrodem/cseg.c	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.hydrodem/cseg.c	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,154 @@
+#include <unistd.h>
+#include <fcntl.h>
+#include <grass/glocale.h>
+#include "seg.h"
+
+int cseg_open(CSEG *cseg, int srows, int scols, int nsegs_in_memory)
+{
+    char *filename;
+    int errflag;
+    int fd;
+
+    cseg->filename = NULL;
+    cseg->fd = -1;
+    cseg->name = NULL;
+    cseg->mapset = NULL;
+
+    filename = G_tempfile();
+    if (-1 == (fd = creat(filename, 0666))) {
+	G_warning(_("cseg_open(): unable to create segment file"));
+	return -2;
+    }
+    if (0 >
+	(errflag =
+	 segment_format(fd, Rast_window_rows(), Rast_window_cols(), srows, scols,
+			sizeof(CELL)))) {
+	close(fd);
+	unlink(filename);
+	if (errflag == -1) {
+	    G_warning(_("cseg_open(): could not write segment file"));
+	    return -1;
+	}
+	else {
+	    G_warning(_("cseg_open(): illegal configuration parameter(s)"));
+	    return -3;
+	}
+    }
+    close(fd);
+    if (-1 == (fd = open(filename, 2))) {
+	unlink(filename);
+	G_warning(_("cseg_open(): unable to re-open segment file"));
+	return -4;
+    }
+    if (0 > (errflag = segment_init(&(cseg->seg), fd, nsegs_in_memory))) {
+	close(fd);
+	unlink(filename);
+	if (errflag == -1) {
+	    G_warning(_("cseg_open(): could not read segment file"));
+	    return -5;
+	}
+	else {
+	    G_warning(_("cseg_open(): out of memory"));
+	    return -6;
+	}
+    }
+    cseg->filename = filename;
+    cseg->fd = fd;
+    return 0;
+}
+
+int cseg_close(CSEG *cseg)
+{
+    segment_release(&(cseg->seg));
+    close(cseg->fd);
+    unlink(cseg->filename);
+    if (cseg->name) {
+	G_free(cseg->name);
+	cseg->name = NULL;
+    }
+    if (cseg->mapset) {
+	G_free(cseg->mapset);
+	cseg->mapset = NULL;
+    }
+    return 0;
+}
+
+int cseg_put(CSEG *cseg, CELL *value, int row, int col)
+{
+    if (segment_put(&(cseg->seg), value, row, col) < 0) {
+	G_warning(_("cseg_put(): could not write segment file"));
+	return -1;
+    }
+    return 0;
+}
+
+int cseg_put_row(CSEG *cseg, CELL *value, int row)
+{
+    if (segment_put_row(&(cseg->seg), value, row) < 0) {
+	G_warning(_("cseg_put_row(): could not write segment file"));
+	return -1;
+    }
+    return 0;
+}
+
+int cseg_get(CSEG *cseg, CELL *value, int row, int col)
+{
+    if (segment_get(&(cseg->seg), value, row, col) < 0) {
+	G_warning(_("cseg_get(): could not read segment file"));
+	return -1;
+    }
+    return 0;
+}
+
+int cseg_read_raster(CSEG *cseg, char *map_name, char *mapset)
+{
+    int row, nrows;
+    int map_fd;
+    CELL *buffer;
+
+    cseg->name = NULL;
+    cseg->mapset = NULL;
+
+    map_fd = Rast_open_old(map_name, mapset);
+    nrows = Rast_window_rows();
+    buffer = Rast_allocate_c_buf();
+    for (row = 0; row < nrows; row++) {
+	Rast_get_c_row(map_fd, buffer, row);
+	if (segment_put_row(&(cseg->seg), buffer, row) < 0) {
+	    G_free(buffer);
+	    Rast_close(map_fd);
+	    G_warning(_("cseg_read_cell(): unable to segment put row for <%s> in <%s>"),
+		    map_name, mapset);
+	    return (-1);
+	}
+    }
+
+    Rast_close(map_fd);
+    G_free(buffer);
+
+    cseg->name = G_store(map_name);
+    cseg->mapset = G_store(mapset);
+
+    return 0;
+}
+
+int cseg_write_raster(CSEG *cseg, char *map_name)
+{
+    int map_fd;
+    int row, nrows;
+    CELL *buffer;
+
+    map_fd = Rast_open_c_new(map_name);
+    nrows = Rast_window_rows();
+    buffer = Rast_allocate_c_buf();
+    segment_flush(&(cseg->seg));
+    for (row = 0; row < nrows; row++) {
+	G_percent(row, nrows, 1);
+	segment_get_row(&(cseg->seg), buffer, row);
+	Rast_put_row(map_fd, buffer, CELL_TYPE);
+    }
+    G_percent(row, nrows, 1);    /* finish it */
+    G_free(buffer);
+    Rast_close(map_fd);
+    return 0;
+}

Added: grass-addons/grass7/grass7/raster/r.hydrodem/do_astar.c
===================================================================
--- grass-addons/grass7/grass7/raster/r.hydrodem/do_astar.c	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.hydrodem/do_astar.c	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,356 @@
+#include <stdlib.h>
+#include <math.h>
+#include <grass/gis.h>
+#include <grass/glocale.h>
+#include "local_proto.h"
+
+#define GET_PARENT(c) ((unsigned int)(((c) - 2) >> 2) + 1)
+#define GET_CHILD(p) ((unsigned int)((p) << 2) - 2)
+
+#define HEAP_CMP(a, b) (((a)->ele < (b)->ele) ? 1 : \
+                       (((a)->ele > (b)->ele) ? 0 : \
+		       (((a)->added < (b)->added) ? 1 : 0)))
+
+
+struct heap_point heap_drop(void);
+
+double get_slope(CELL, CELL, double);
+
+int do_astar(void)
+{
+    int r, c, r_nbr, c_nbr, ct_dir;
+    unsigned int count;
+    int nextdr[8] = { 1, -1, 0, 0, -1, 1, 1, -1 };
+    int nextdc[8] = { 0, 0, -1, 1, 1, -1, 1, -1 };
+    int asp_r[9] = { 0, -1, -1, -1, 0, 1, 1, 1, 0 };
+    int asp_c[9] = { 0, 1, 0, -1, -1, -1, 0, 1, 1 };
+    CELL ele_val, ele_down, ele_nbr[8];
+    char is_bottom;
+    char asp_val, asp_val_this;
+    char flag_value, is_in_list, is_worked;
+    struct heap_point heap_p;
+    /* sides
+     * |7|1|4|
+     * |2| |3|
+     * |5|0|6|
+     */
+    int nbr_ew[8] = { 0, 1, 2, 3, 1, 0, 0, 1};
+    int nbr_ns[8] = { 0, 1, 2, 3, 3, 2, 3, 2};
+    double dx, dy, dist_to_nbr[8], ew_res, ns_res;
+    double slope[8];
+    int skip_diag;
+    struct Cell_head window;
+
+    count = 0;
+
+    first_cum = n_points;
+
+    sinks = first_sink = NULL;
+    n_sinks = 0;
+
+    G_message(_("A* Search..."));
+
+    Rast_get_window(&window);
+
+    for (ct_dir = 0; ct_dir < sides; ct_dir++) {
+	/* get r, c (r_nbr, c_nbr) for neighbours */
+	r_nbr = nextdr[ct_dir];
+	c_nbr = nextdc[ct_dir];
+	/* account for rare cases when ns_res != ew_res */
+	dy = abs(r_nbr) * window.ns_res;
+	dx = abs(c_nbr) * window.ew_res;
+	if (ct_dir < 4)
+	    dist_to_nbr[ct_dir] = dx + dy;
+	else
+	    dist_to_nbr[ct_dir] = sqrt(dx * dx + dy * dy);
+    }
+    ew_res = window.ew_res;
+    ns_res = window.ns_res;
+
+    while (heap_size > 0) {
+	G_percent(count++, n_points, 1);
+	if (count > n_points)
+	    G_fatal_error(_("BUG in A* Search: %d surplus points"),
+	                  heap_size);
+
+	if (heap_size > n_points)
+	    G_fatal_error
+		(_("BUG in A* Search: too many points in heap %d, should be %d"),
+		 heap_size, n_points);
+
+	heap_p = heap_drop();
+
+	/* flow accumulation order is not needed */
+	r = heap_p.r;
+	c = heap_p.c;
+
+	first_cum--;
+	bseg_get(&bitflags, &flag_value, r, c);
+	FLAG_SET(flag_value, WORKEDFLAG);
+	bseg_put(&bitflags, &flag_value, r, c);
+
+	ele_val = ele_down = heap_p.ele;
+	is_bottom = 0;
+	bseg_get(&draindir, &asp_val_this, r, c);
+	if (asp_val_this > 0 && !FLAG_GET(flag_value, EDGEFLAG)) {
+	    r_nbr = r + asp_r[(int)asp_val_this];
+	    c_nbr = c + asp_c[(int)asp_val_this];
+	    cseg_get(&ele, &ele_down, r_nbr, c_nbr);
+	    if (ele_down > ele_val)
+		is_bottom = 1;
+	}
+
+	for (ct_dir = 0; ct_dir < sides; ct_dir++) {
+	    /* get r, c (r_nbr, c_nbr) for neighbours */
+	    r_nbr = r + nextdr[ct_dir];
+	    c_nbr = c + nextdc[ct_dir];
+	    slope[ct_dir] = ele_nbr[ct_dir] = 0;
+
+	    /* check that neighbour is within region */
+	    if (r_nbr < 0 || r_nbr >= nrows || c_nbr < 0 || c_nbr >= ncols)
+		continue;
+
+	    bseg_get(&bitflags, &flag_value, r_nbr, c_nbr);
+	    is_in_list = FLAG_GET(flag_value, INLISTFLAG);
+	    is_worked = FLAG_GET(flag_value, WORKEDFLAG);
+	    skip_diag = 0;
+
+	    /* avoid diagonal flow direction bias */
+	    if (!is_worked) {
+		cseg_get(&ele, &ele_nbr[ct_dir], r_nbr, c_nbr);
+		slope[ct_dir] = get_slope(ele_val, ele_nbr[ct_dir],
+		                          dist_to_nbr[ct_dir]);
+	    }
+
+	    if (!is_in_list) {
+		if (ct_dir > 3 && slope[ct_dir] > 0) {
+		    if (slope[nbr_ew[ct_dir]] > 0) {
+			/* slope to ew nbr > slope to center */
+			if (slope[ct_dir] < get_slope(ele_nbr[nbr_ew[ct_dir]],
+			                              ele_nbr[ct_dir], ew_res))
+			    skip_diag = 1;
+		    }
+		    if (!skip_diag && slope[nbr_ns[ct_dir]] > 0) {
+			/* slope to ns nbr > slope to center */
+			if (slope[ct_dir] < get_slope(ele_nbr[nbr_ns[ct_dir]],
+			                              ele_nbr[ct_dir], ns_res))
+			    skip_diag = 1;
+		    }
+		}
+	    }
+
+	    if (is_in_list == 0 && skip_diag == 0) {
+		asp_val = drain[r_nbr - r + 1][c_nbr - c + 1];
+		heap_add(r_nbr, c_nbr, ele_nbr[ct_dir], asp_val, flag_value);
+
+		if (ele_nbr[ct_dir] < ele_val)
+		    is_bottom = 0;
+	    }
+	    else if (is_in_list && is_worked == 0) {
+		if (FLAG_GET(flag_value, EDGEFLAG)) {
+		    bseg_get(&draindir, &asp_val, r_nbr, c_nbr);
+		    if (asp_val < 0) {
+			/* update edge cell ? no */
+			/* asp_val = drain[r_nbr - r + 1][c_nbr - c + 1]; */
+			/* check if this causes trouble */
+			bseg_put(&draindir, &asp_val, r_nbr, c_nbr);
+
+			if (ele_nbr[ct_dir] < ele_val)
+			    is_bottom = 0;
+		    }
+		}
+		else if (FLAG_GET(flag_value, DEPRFLAG)) {
+		    G_debug(3, "real depression");
+		    /* neighbour is inside real depression, not yet worked */
+		    bseg_get(&draindir, &asp_val, r_nbr, c_nbr);
+		    if (asp_val == 0 && ele_val <= ele_nbr[ct_dir]) {
+			asp_val = drain[r_nbr - r + 1][c_nbr - c + 1];
+			bseg_put(&draindir, &asp_val, r_nbr, c_nbr);
+			FLAG_UNSET(flag_value, DEPRFLAG);
+			bseg_put(&bitflags, &flag_value, r_nbr, c_nbr);
+		    }
+		}
+	    }
+	}    /* end neighbours */
+
+
+	if (is_bottom) {
+	    /* add sink bottom */
+	    /* process upstream */
+	    if (1) {
+		if (first_sink) {
+		    sinks->next =
+			(struct sink_list *)
+			G_malloc(sizeof(struct sink_list));
+		    sinks = sinks->next;
+		}
+		/* first sink */
+		else {
+		    first_sink =
+			(struct sink_list *)
+			G_malloc(sizeof(struct sink_list));
+		    sinks = first_sink;
+		}
+		sinks->next = NULL;
+	    }
+	    /* process downstream */
+	    if (0) {
+		sinks =
+		    (struct sink_list *)
+		    G_malloc(sizeof(struct sink_list));
+		sinks->next = first_sink;
+		first_sink = sinks;
+	    }
+	    sinks->r = r;
+	    sinks->c = c;
+	    n_sinks++;
+	}
+    }    /* end A* search */
+
+    G_percent(n_points, n_points, 1);	/* finish it */
+
+    if (first_cum)
+	G_warning(_("processed points mismatch of %u"), first_cum);
+
+    return 1;
+}
+
+/*
+ * compare function for heap
+ * returns 1 if point1 < point2 else 0
+ */
+
+static int heap_cmp(struct heap_point *a, struct heap_point *b)
+{
+    if (a->ele < b->ele)
+	return 1;
+    else if (a->ele == b->ele) {
+	if (a->added < b->added)
+	    return 1;
+    }
+    return 0;
+}
+
+int sift_up(unsigned int start, struct heap_point child_p)
+{
+    unsigned int parent, child;
+    struct heap_point heap_p;
+
+    child = start;
+
+    while (child > 1) {
+	parent = GET_PARENT(child);
+
+	seg_get(&search_heap, (char *)&heap_p, 0, parent);
+
+	/* push parent point down if child is smaller */
+	if (heap_cmp(&child_p, &heap_p)) {
+	    seg_put(&search_heap, (char *)&heap_p, 0, child);
+	    child = parent;
+	}
+	else
+	    /* no more sifting up, found new slot for child */
+	    break;
+    }
+
+    /* add child to heap */
+    seg_put(&search_heap, (char *)&child_p, 0, child);
+
+    return 0;
+}
+
+/*
+ * add item to heap
+ * returns heap_size
+ */
+unsigned int heap_add(int r, int c, CELL ele, char asp, char flag_value)
+{
+    struct heap_point heap_p;
+
+    /* add point to next free position */
+
+    heap_size++;
+
+    if (heap_size > n_points)
+	G_fatal_error(_("Heapsize too large"));
+
+    heap_p.r = r;
+    heap_p.c = c;
+    heap_p.ele = ele;
+    heap_p.added = nxt_avail_pt;
+
+    bseg_put(&draindir, &asp, r, c);
+    FLAG_SET(flag_value, INLISTFLAG);
+    bseg_put(&bitflags, &flag_value, r, c);
+
+    nxt_avail_pt++;
+
+    /* sift up: move new point towards top of heap */
+
+    sift_up(heap_size, heap_p);
+
+    return heap_size;
+}
+
+/*
+ * drop item from heap
+ * returns heap size
+ */
+struct heap_point heap_drop(void)
+{
+    unsigned int child, childr, parent;
+    unsigned int i;
+    struct heap_point child_p, childr_p, last_p, root_p;
+
+    seg_get(&search_heap, (char *)&last_p, 0, heap_size);
+    seg_get(&search_heap, (char *)&root_p, 0, 1);
+
+    if (heap_size == 1) {
+	heap_size = 0;
+	return root_p;
+    }
+
+    parent = 1;
+    while ((child = GET_CHILD(parent)) <= heap_size) {
+
+	seg_get(&search_heap, (char *)&child_p, 0, child);
+
+	if (child < heap_size) {
+	    childr = child + 1;
+	    i = child + 4;
+	    while (childr <= heap_size && childr < i) {
+		seg_get(&search_heap, (char *)&childr_p, 0, childr);
+		if (heap_cmp(&childr_p, &child_p)) {
+		    child = childr;
+		    child_p = childr_p;
+		}
+		childr++;
+	    }
+	}
+	if (heap_cmp(&last_p, &child_p)) {
+	    break;
+	}
+
+	/* move hole down */
+	seg_put(&search_heap, (char *)&child_p, 0, parent);
+	parent = child;
+    }
+
+    /* fill hole */
+    if (parent < heap_size) {
+	seg_put(&search_heap, (char *)&last_p, 0, parent);
+    }
+
+    /* the actual drop */
+    heap_size--;
+
+    return root_p;
+}
+
+double get_slope(CELL ele, CELL up_ele, double dist)
+{
+    if (ele >= up_ele)
+	return 0.0;
+    else
+	return (double)(up_ele - ele) / dist;
+}

Added: grass-addons/grass7/grass7/raster/r.hydrodem/dseg.c
===================================================================
--- grass-addons/grass7/grass7/raster/r.hydrodem/dseg.c	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.hydrodem/dseg.c	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,156 @@
+#include <unistd.h>
+#include <fcntl.h>
+#include <grass/glocale.h>
+#include "seg.h"
+
+int dseg_open(DSEG *dseg, int srows, int scols, int nsegs_in_memory)
+{
+    char *filename;
+    int errflag;
+    int fd;
+
+    dseg->filename = NULL;
+    dseg->fd = -1;
+    dseg->name = NULL;
+    dseg->mapset = NULL;
+
+    filename = G_tempfile();
+    if (-1 == (fd = creat(filename, 0666))) {
+	G_warning(_("dseg_open(): unable to create segment file"));
+	return -2;
+    }
+    if (0 >
+	(errflag =
+	 segment_format(fd, Rast_window_rows(), Rast_window_cols(), srows, scols,
+			sizeof(DCELL)))) {
+	close(fd);
+	unlink(filename);
+	if (errflag == -1) {
+	    G_warning(_("dseg_open(): could not write segment file"));
+	    return -1;
+	}
+	else {
+	    G_warning(_("dseg_open(): illegal configuration parameter(s)"));
+	    return -3;
+	}
+    }
+    close(fd);
+    if (-1 == (fd = open(filename, 2))) {
+	unlink(filename);
+	G_warning(_("dseg_open(): unable to re-open segment file"));
+	return -4;
+    }
+    if (0 > (errflag = segment_init(&(dseg->seg), fd, nsegs_in_memory))) {
+	close(fd);
+	unlink(filename);
+	if (errflag == -1) {
+	    G_warning(_("dseg_open(): could not read segment file"));
+	    return -5;
+	}
+	else {
+	    G_warning(_("dseg_open(): out of memory"));
+	    return -6;
+	}
+    }
+    dseg->filename = filename;
+    dseg->fd = fd;
+    return 0;
+}
+
+int dseg_close(DSEG *dseg)
+{
+    segment_release(&(dseg->seg));
+    close(dseg->fd);
+    unlink(dseg->filename);
+    if (dseg->name) {
+	G_free(dseg->name);
+	dseg->name = NULL;
+    }
+    if (dseg->mapset) {
+	G_free(dseg->mapset);
+	dseg->mapset = NULL;
+    }
+    return 0;
+}
+
+int dseg_put(DSEG *dseg, DCELL *value, int row, int col)
+{
+    if (segment_put(&(dseg->seg), (DCELL *) value, row, col) < 0) {
+	G_warning(_("dseg_put(): could not write segment file"));
+	return -1;
+    }
+    return 0;
+}
+
+int dseg_put_row(DSEG *dseg, DCELL *value, int row)
+{
+    if (segment_put_row(&(dseg->seg), (DCELL *) value, row) < 0) {
+	G_warning(_("dseg_put(): could not write segment file"));
+	return -1;
+    }
+    return 0;
+}
+
+int dseg_get(DSEG *dseg, DCELL *value, int row, int col)
+{
+    if (segment_get(&(dseg->seg), (DCELL *) value, row, col) < 0) {
+	G_warning(_("dseg_get(): could not read segment file"));
+	return -1;
+    }
+    return 0;
+}
+
+int dseg_read_raster(DSEG *dseg, char *map_name, char *mapset)
+{
+    int row, nrows, ncols;
+    int map_fd;
+    DCELL *dbuffer;
+
+    dseg->name = NULL;
+    dseg->mapset = NULL;
+
+    map_fd = Rast_open_old(map_name, mapset);
+    nrows = Rast_window_rows();
+    ncols = Rast_window_cols();
+    dbuffer = Rast_allocate_d_buf();
+    for (row = 0; row < nrows; row++) {
+	Rast_get_d_row(map_fd, dbuffer, row);
+	if (segment_put_row(&(dseg->seg), (DCELL *) dbuffer, row) < 0) {
+	    G_free(dbuffer);
+	    Rast_close(map_fd);
+	    G_warning(_("dseg_read_raster(): unable to segment put row for <%s> in <%s>"),
+		    map_name, mapset);
+	    return (-1);
+	}
+    }
+
+    Rast_close(map_fd);
+    G_free(dbuffer);
+
+    dseg->name = G_store(map_name);
+    dseg->mapset = G_store(mapset);
+
+    return 0;
+}
+
+int dseg_write_cellfile(DSEG *dseg, char *map_name)
+{
+    int map_fd;
+    int row, nrows, ncols;
+    DCELL *dbuffer;
+
+    map_fd = Rast_open_new(map_name, DCELL_TYPE);
+    nrows = Rast_window_rows();
+    ncols = Rast_window_cols();
+    dbuffer = Rast_allocate_d_buf();
+    segment_flush(&(dseg->seg));
+    for (row = 0; row < nrows; row++) {
+	G_percent(row, nrows, 1);
+	segment_get_row(&(dseg->seg), (DCELL *) dbuffer, row);
+	Rast_put_row(map_fd, dbuffer, DCELL_TYPE);
+    }
+    G_percent(row, nrows, 1);    /* finish it */
+    G_free(dbuffer);
+    Rast_close(map_fd);
+    return 0;
+}

Added: grass-addons/grass7/grass7/raster/r.hydrodem/flag.h
===================================================================
--- grass-addons/grass7/grass7/raster/r.hydrodem/flag.h	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.hydrodem/flag.h	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,36 @@
+#ifndef __FLAG_H__
+#define __FLAG_H__
+
+/* a set of routines that allow the programmer to "flag" cells in a
+ * raster map. A flag is of type unsigned char, i.e. 8 bits can be set. 
+ *
+ * int flag_set(flag, bitno)
+ *     sets the flag at position bitno to one.
+ *
+ * int flag_unset(flag, bitno)
+ *     sets the flag at position bitno to zero.
+ *
+ * int flag_get(flag, bitno)
+ *     checks if the flag is set at postion bitno.
+ *
+ * Examples:
+ * set flag at position 0: FLAG_SET(flag, 0)
+ * unset (clear) flag at position 7: FLAG_UNSET(flag, 7)
+ * check flag at position 5: is_set_at_5 = FLAG_GET(flag, 5)
+ */
+
+/* flag positions */
+#define NULLFLAG         0      /* elevation is NULL */
+#define EDGEFLAG         1      /* edge cell */
+#define INLISTFLAG       2      /* in open A* list */
+#define WORKEDFLAG       3      /* in closed A* list/ accumulation done */
+#define STREAMFLAG       4      /* stream */
+#define DEPRFLAG         5      /* real depression */
+#define WORKED2FLAG      6      /* extraction done */
+/* last bit is unused */
+
+#define FLAG_SET(flag,bitno) ((flag) |= (1 << (bitno)))
+#define FLAG_UNSET(flag,bitno) ((flag) &= ~(1 << (bitno)))
+#define FLAG_GET(flag,bitno) ((flag) & (1 << (bitno)))
+
+#endif /* __FLAG_H__ */

Added: grass-addons/grass7/grass7/raster/r.hydrodem/hydro_con.c
===================================================================
--- grass-addons/grass7/grass7/raster/r.hydrodem/hydro_con.c	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.hydrodem/hydro_con.c	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,878 @@
+#include <stdlib.h>
+#include <math.h>
+#include <limits.h>
+#include <grass/gis.h>
+#include <grass/raster.h>
+#include <grass/glocale.h>
+#include "local_proto.h"
+
+struct ns
+{
+    int r, c;
+    int next_side;
+    int n_ngbrs;
+};
+
+static struct ns *n_stack;
+static int stack_alloc;
+
+static int asp_r[9] = { 0, -1, -1, -1, 0, 1, 1, 1, 0 };
+static int asp_c[9] = { 0, 1, 0, -1, -1, -1, 0, 1, 1 };
+
+static int nextdr[8] = { 1, -1, 0, 0, -1, 1, 1, -1 };
+static int nextdc[8] = { 0, 0, -1, 1, 1, -1, 1, -1 };
+
+
+static int count_fill(int peak_r, int peak_c, CELL peak_ele, int *n_splits,
+               CELL *next_ele)
+{
+    int r, c, r_nbr, c_nbr, ct_dir;
+    CELL ele_val, ele_nbr;
+    int n_to_fill;
+    int top, done;
+    char drain_val;
+
+    /* go upstream from spill point */
+    r = peak_r;
+    c = peak_c;
+    ele_val = peak_ele;
+    *n_splits = 0;
+    n_to_fill = 0;
+    /* post-order traversal */
+    /* add spill point as root to stack */
+    top = 0;
+    n_stack[top].r = peak_r;
+    n_stack[top].c = peak_c;
+    n_stack[top].next_side = 0;
+    n_stack[top].n_ngbrs = 0;
+    while (top >= 0) {
+	done = 1;
+	r = n_stack[top].r;
+	c = n_stack[top].c;
+	for (ct_dir = n_stack[top].next_side; ct_dir < sides; ct_dir++) {
+	    r_nbr = r + nextdr[ct_dir];
+	    c_nbr = c + nextdc[ct_dir];
+	    /* check that neighbour is within region */
+	    if (r_nbr >= 0 && r_nbr < nrows && c_nbr >= 0 &&
+	        c_nbr < ncols) {
+
+		cseg_get(&ele, &ele_nbr, r_nbr, c_nbr);
+		bseg_get(&draindir, &drain_val, r_nbr, c_nbr);
+		if (drain_val > 0) {
+		    /* contributing cell */
+		    if (r_nbr + asp_r[(int)drain_val] == r &&
+			c_nbr + asp_c[(int)drain_val] == c) {
+
+			/* contributing neighbour is lower than
+			 * spill point, add to stack */
+			if (peak_ele >= ele_nbr) {
+
+			    if (peak_ele > ele_nbr)
+				n_to_fill++;
+			    n_stack[top].next_side = ct_dir + 1;
+			    n_stack[top].n_ngbrs++;
+			    top++;
+			    if (top >= stack_alloc) {
+				stack_alloc += nrows + ncols;
+				n_stack =
+				    (struct ns *)G_realloc(n_stack,
+							   stack_alloc *
+							   sizeof(struct ns));
+			    }
+			    n_stack[top].r = r_nbr;
+			    n_stack[top].c = c_nbr;
+			    n_stack[top].next_side = 0;
+			    n_stack[top].n_ngbrs = 0;
+			    done = 0;
+			    break;
+			}
+			else if (next_ele && peak_ele < ele_nbr) {
+			    if (*next_ele > ele_nbr)
+				*next_ele = ele_nbr;
+			}
+		    }
+		}    /* end contributing */
+		else if (drain_val == 0 && peak_ele > ele_nbr)
+		    /* found bottom of real depression, don't fill */
+		    return -1;
+	    }    /* end in region */
+	}    /* end sides */
+
+	if (done) {
+	    *n_splits += (n_stack[top].n_ngbrs > 1);
+	    n_stack[top].next_side = sides;
+
+	    top--;
+	}
+    }
+    return n_to_fill;
+}
+
+/* detect flat area:
+ * count neighbouring cells with same ele
+ * exclude contributing cells and cell this one is contributing to */
+static int is_flat(int r, int c, CELL this_ele)
+{
+    int r_nbr, c_nbr, ct_dir;
+    CELL ele_nbr;
+    char drain_val, drain_val_nbr;
+    int counter = 0;
+
+    bseg_get(&draindir, &drain_val, r, c);
+
+    if (drain_val < 1)
+	return 0;
+
+    for (ct_dir = 0; ct_dir < sides; ct_dir++) {
+	r_nbr = r + nextdr[ct_dir];
+	c_nbr = c + nextdc[ct_dir];
+	/* check that neighbour is within region */
+	if (r_nbr >= 0 && r_nbr < nrows && c_nbr >= 0 && c_nbr < ncols) {
+	    
+	    cseg_get(&ele, &ele_nbr, r_nbr, c_nbr);
+	    bseg_get(&draindir, &drain_val_nbr, r_nbr, c_nbr);
+	    if (drain_val_nbr > 0) {
+		/* not a contributing cell */
+		if (r_nbr + asp_r[(int)drain_val_nbr] != r ||
+		    c_nbr + asp_c[(int)drain_val_nbr] != c) {
+		    /* does not contribute to this cell */
+		    if (r + asp_r[(int)drain_val] != r_nbr ||
+		        c + asp_c[(int)drain_val] != c_nbr) {
+			if (ele_nbr == this_ele)
+			    counter++;
+		    }
+		}
+	    }
+	}
+    }
+
+    return (counter > 0);
+}
+
+static int fill_sink(int peak_r, int peak_c, CELL peak_ele)
+{
+    int r, c, r_nbr, c_nbr, ct_dir;
+    CELL ele_nbr;
+    int n_to_fill = 0;
+    int top, done;
+    char drain_val;
+
+    /* post-order traversal */
+    /* add spill point as root to stack */
+    top = 0;
+    n_stack[top].r = peak_r;
+    n_stack[top].c = peak_c;
+    n_stack[top].next_side = 0;
+    n_stack[top].n_ngbrs = 0;
+    while (top >= 0) {
+	done = 1;
+	r = n_stack[top].r;
+	c = n_stack[top].c;
+	for (ct_dir = n_stack[top].next_side; ct_dir < sides; ct_dir++) {
+	    r_nbr = r + nextdr[ct_dir];
+	    c_nbr = c + nextdc[ct_dir];
+	    /* check that neighbour is within region */
+	    if (r_nbr >= 0 && r_nbr < nrows && c_nbr >= 0 &&
+	        c_nbr < ncols) {
+
+		cseg_get(&ele, &ele_nbr, r_nbr, c_nbr);
+		bseg_get(&draindir, &drain_val, r_nbr, c_nbr);
+		if (drain_val > 0) {
+		    /* contributing cell */
+		    if (r_nbr + asp_r[(int)drain_val] == r &&
+			c_nbr + asp_c[(int)drain_val] == c) {
+
+			/* contributing neighbour is lower than
+			 * spill point, add to stack */
+			if (peak_ele >= ele_nbr) {
+
+			    n_to_fill++;
+			    n_stack[top].next_side = ct_dir + 1;
+			    n_stack[top].n_ngbrs++;
+			    top++;
+			    if (top >= stack_alloc) {
+				stack_alloc += nrows + ncols;
+				n_stack =
+				    (struct ns *)G_realloc(n_stack,
+							   stack_alloc *
+							   sizeof(struct ns));
+			    }
+			    n_stack[top].r = r_nbr;
+			    n_stack[top].c = c_nbr;
+			    n_stack[top].next_side = 0;
+			    n_stack[top].n_ngbrs = 0;
+			    done = 0;
+			    break;
+			}
+		    }
+		}		/* end contributing */
+	    }			/* end in region */
+	}			/* end sides */
+
+	if (done) {
+	    cseg_put(&ele, &peak_ele, r, c);
+	    n_stack[top].next_side = sides;
+	    top--;
+	}
+    }
+
+    return n_to_fill;
+}
+
+/* carve channel */
+static int carve(int bottom_r, int bottom_c, CELL bottom_ele,
+          int peak_r, int peak_c)
+{
+    int r, c, r_nbr, c_nbr, carved = 0;
+    char drain_val;
+    int ct_dir;
+    CELL ele_val, ele_nbr;
+    int top, done;
+
+    /* carve upstream from spill point --> */
+    /* post-order traversal */
+    /* add spill point as root to stack */
+    top = 0;
+    n_stack[top].r = peak_r;
+    n_stack[top].c = peak_c;
+    n_stack[top].next_side = 0;
+    n_stack[top].n_ngbrs = 0;
+    while (top >= 0) {
+	done = 1;
+	r = n_stack[top].r;
+	c = n_stack[top].c;
+	cseg_get(&ele, &ele_val, r, c);
+	for (ct_dir = n_stack[top].next_side; ct_dir < sides; ct_dir++) {
+	    r_nbr = r + nextdr[ct_dir];
+	    c_nbr = c + nextdc[ct_dir];
+	    /* check that neighbour is within region */
+	    if (r_nbr >= 0 && r_nbr < nrows && c_nbr >= 0 &&
+	        c_nbr < ncols) {
+
+		cseg_get(&ele, &ele_nbr, r_nbr, c_nbr);
+		bseg_get(&draindir, &drain_val, r_nbr, c_nbr);
+		if (drain_val > 0) {
+		    /* contributing cell */
+		    if (r_nbr + asp_r[(int) drain_val] == r &&
+			c_nbr + asp_c[(int) drain_val] == c) {
+
+			/* contributing neighbour is lower than 
+			 * current point, add to stack */
+			if (ele_val > ele_nbr && ele_nbr >= bottom_ele) {
+
+			    n_stack[top].next_side = ct_dir + 1;
+			    n_stack[top].n_ngbrs++;
+			    top++;
+			    if (top >= stack_alloc) {
+				stack_alloc += nrows + ncols;
+				n_stack =
+				    (struct ns *)G_realloc(n_stack,
+							   stack_alloc *
+							   sizeof(struct ns));
+			    }
+			    n_stack[top].r = r_nbr;
+			    n_stack[top].c = c_nbr;
+			    n_stack[top].next_side = 0;
+			    n_stack[top].n_ngbrs = 0;
+			    done = 0;
+			    break;
+			}
+		    }
+		}		/* end contributing */
+	    }			/* end in region */
+	}			/* end sides */
+
+	if (done) {
+	    /* lower all cells to bottom ele
+	     * that have lower lying contributing neighbours */
+	    if (n_stack[top].n_ngbrs > 0)
+		cseg_put(&ele, &bottom_ele, r, c);
+	    n_stack[top].next_side = sides;
+	    top--;
+	}
+    }
+    /* <-- carve upstream from spill point */
+
+    /* carve downstream from sink bottom */
+    bseg_get(&draindir, &drain_val, bottom_r, bottom_c);
+    if (drain_val < 1) {
+	G_warning(_("Can't carve downstream from r %d, c %d"), bottom_r,
+		  bottom_c);
+	return 0;
+    }
+
+    r_nbr = bottom_r + asp_r[(int) drain_val];
+    c_nbr = bottom_c + asp_c[(int) drain_val];
+
+    cseg_get(&ele, &ele_nbr, r_nbr, c_nbr);
+
+    /* go downstream up to peak and down to bottom again */
+    while (ele_nbr >= bottom_ele) {
+	bseg_get(&draindir, &drain_val, r_nbr, c_nbr);
+	cseg_put(&ele, &bottom_ele, r_nbr, c_nbr);
+	carved++;
+
+	if (drain_val > 0) {
+	    r_nbr = r_nbr + asp_r[(int) drain_val];
+	    c_nbr = c_nbr + asp_c[(int) drain_val];
+	    cseg_get(&ele, &ele_nbr, r_nbr, c_nbr);
+	}
+	else {
+	    G_debug(2, "%d carved to edge", carved);
+	    return carved;
+	}
+    }
+
+    return carved;
+}
+
+/* remove sinks */
+int hydro_con(void)
+{
+    int counter = 1;
+    int r, c, r_nbr, c_nbr, peak_r, peak_c, noedge, force_carve;
+    CELL ele_val, ele_nbr, ele_last, peak_ele, bottom_ele;
+    int down_uphill, down_downhill, n_cells;
+    struct sink_list *last_sink;
+    char drain_val, flag_value;
+    int n_splits, n_to_fill;
+    int n_filled, n_carved, n_just_a_bit, n_processed;
+    int carve_to_edge, skipme;
+
+    stack_alloc = nrows + ncols;
+
+    n_stack = (struct ns *)G_malloc(stack_alloc * sizeof(struct ns));
+
+    G_message(_("Processing %d sinks"), n_sinks);
+
+    n_filled = n_carved = n_just_a_bit = n_processed = 0;
+
+    while (first_sink) {
+	G_percent(counter++, n_sinks, 1);
+
+	r = first_sink->r;
+	c = first_sink->c;
+
+	cseg_get(&ele, &ele_val, r, c);
+	bottom_ele = ele_val;
+
+	skipme = 0;
+
+	G_debug(1, "get spill point");
+
+	/* go downstream, get spill point */
+	peak_r = r;
+	peak_c = c;
+	bseg_get(&draindir, &drain_val, r, c);
+
+	r_nbr = r + asp_r[(int) drain_val];
+	c_nbr = c + asp_c[(int) drain_val];
+
+	cseg_get(&ele, &ele_nbr, r_nbr, c_nbr);
+
+	down_uphill = down_downhill = 0;
+	noedge = 1;
+	ele_last = bottom_ele;
+	n_cells = 0;
+	while (ele_nbr >= ele_last) {
+	    n_cells++;
+	    if (ele_nbr > ele_last) {
+		down_uphill = n_cells;
+		peak_r = r_nbr;
+		peak_c = c_nbr;
+	    }
+	    bseg_get(&draindir, &drain_val, r_nbr, c_nbr);
+
+	    if (drain_val > 0) {
+		r_nbr = r_nbr + asp_r[(int) drain_val];
+		c_nbr = c_nbr + asp_c[(int) drain_val];
+
+		ele_last = ele_nbr;
+		cseg_get(&ele, &ele_nbr, r_nbr, c_nbr);
+	    }
+	    else {
+		break;
+	    }
+	}
+
+	cseg_get(&ele, &peak_ele, peak_r, peak_c);
+
+	bseg_get(&bitflags, &flag_value, peak_r, peak_c);
+	noedge = (FLAG_GET(flag_value, EDGEFLAG) == 0);
+	r_nbr = peak_r;
+	c_nbr = peak_c;
+	ele_nbr = peak_ele;
+
+	/* check */
+	if (down_uphill == 0) {
+	    G_debug(2, "sink already processed");
+	    n_processed++;
+
+	    last_sink = first_sink;
+	    first_sink = first_sink->next;
+	    G_free(last_sink);
+	    continue;
+	}
+
+	carve_to_edge = 0;
+	if (noedge) {
+	    G_debug(1, "go downstream from spill point");
+	    /* go downstream from spill point
+	     * until we reach bottom ele again */
+	    while (ele_nbr >= bottom_ele) {
+		if (ele_nbr > bottom_ele)
+		    down_downhill++;
+		bseg_get(&draindir, &drain_val, r_nbr, c_nbr);
+
+		/* detect flat area ? */
+
+		if (drain_val > 0) {
+		    r_nbr = r_nbr + asp_r[(int) drain_val];
+		    c_nbr = c_nbr + asp_c[(int) drain_val];
+
+		    cseg_get(&ele, &ele_nbr, r_nbr, c_nbr);
+		}
+		else {
+		    carve_to_edge = 1;
+		    break;
+		}
+	    }
+	}
+	G_debug(1, "%d cells downstream from spill point", down_downhill);
+
+	/* count number of cells
+	 * that would be filled from current spill point upstream */
+	G_debug(1, "count fill");
+	n_to_fill = count_fill(peak_r, peak_c, peak_ele, &n_splits, NULL);
+	
+	skipme = (!do_all && n_to_fill <= size_max);
+
+	nat_thresh = 10;
+
+	/* shallow inland pans:
+	 * - bottom is close to center of the depression 
+	 * - long channel to carve downstream from spill point
+	 * - shallowness */
+	if (n_to_fill > nat_thresh && peak_ele - bottom_ele < 10 &&
+	    sqrt(n_to_fill) / 4.0 < down_uphill)
+	    G_debug(1, "shallow inland pan?");
+
+
+	/*************************/
+	/* set correction method */
+	/*************************/
+
+	/* force carving if edge not past spill point ? */
+	force_carve = (noedge == 0);
+	force_carve = 0;
+	if (!force_carve && (do_all || n_mod_max >= 4) &&
+	    down_uphill + down_downhill <= 4 && 
+	    down_uphill + down_downhill <= n_to_fill)
+	    force_carve = 0;
+
+	/************************************/
+	/* apply selected correction method */
+	/************************************/
+
+	/* force carve channel to edge if edge not past spill point */
+	if (force_carve) {
+	    G_debug(1, "force carve small channel or to edge");
+	    carve(first_sink->r, first_sink->c, bottom_ele,
+	          peak_r, peak_c);
+	    n_carved++;
+	}
+	/* impact reduction algorithm */
+	else if (!skipme) {
+	    int next_r, next_c;
+	    int n_new_splits, is_edge = 0, this_is_flat;
+	    CELL min_bottom_ele, last_ele, next_bottom_ele;
+	    int least_impact, li_max;
+	    int least_impact_r, least_impact_c;
+	    CELL least_impact_ele;
+
+	    /* initialize least impact */
+	    li_max = n_to_fill + down_uphill + down_downhill;
+	    least_impact = down_uphill + down_downhill;
+	    least_impact_r = first_sink->r;
+	    least_impact_c = first_sink->c;
+	    least_impact_ele = bottom_ele;
+
+	    /* IRA --> */
+
+	    G_debug(1, "impact reduction algorithm");
+
+	    /* start with sink bottom, proceed to spill point
+	     * fill incrementally
+	     * for each step check if IRA condition fulfilled
+	     * proceed until condition no longer met
+	     * then use least impact solution
+	     * the determined new sink bottom can be
+	     * - the original sink bottom: no filling, only carving
+	     * - the spill point: no carving, only filling
+	     * - any cell in between the two */
+
+	    next_r = first_sink->r;
+	    next_c = first_sink->c;
+	    min_bottom_ele = bottom_ele;
+
+	    G_debug(1, "find new fill point");
+
+	    /* include no filling, full carving,
+	     * and full filling, no carving */
+	    while (bottom_ele <= peak_ele) {
+
+		/* get n_to_fill, down_uphill, down_downhill */
+
+		down_uphill = 0;
+		down_downhill = 0;
+
+		/* count cells to fill */
+		next_bottom_ele = peak_ele;
+		n_to_fill = count_fill(next_r, next_c, bottom_ele,
+		                       &n_new_splits, &next_bottom_ele);
+
+		if (n_to_fill < 0)
+		    break;
+
+		/* count channel length from spill point */
+		/* go downstream from spill point
+		 * until we reach bottom ele again */
+		G_debug(2, "count channel length from spill point");
+		r_nbr = peak_r;
+		c_nbr = peak_c;
+		last_ele = ele_nbr = peak_ele;
+		min_bottom_ele = bottom_ele;
+		this_is_flat = 0;
+		while (ele_nbr >= bottom_ele && this_is_flat < 4) {
+		    if (ele_nbr > bottom_ele) {
+			down_downhill++;
+			/* catch min 2 consecutive cells
+			 * in flat area with same ele */
+			if (is_flat(r_nbr, c_nbr, ele_nbr)) {
+			    if (ele_nbr == last_ele) {
+				this_is_flat++;
+				if (this_is_flat > 2 &&
+				    ele_nbr > min_bottom_ele)
+				    min_bottom_ele = bottom_ele + 1;
+			    }
+			    else
+				this_is_flat = 1;
+			}
+			if (next_bottom_ele > ele_nbr)
+			    next_bottom_ele = ele_nbr;
+		    }
+		    bseg_get(&draindir, &drain_val, r_nbr, c_nbr);
+
+		    if (drain_val > 0) {
+			r_nbr = r_nbr + asp_r[(int) drain_val];
+			c_nbr = c_nbr + asp_c[(int) drain_val];
+
+			last_ele = ele_nbr;
+			cseg_get(&ele, &ele_nbr, r_nbr, c_nbr);
+		    }
+		    else {
+			G_debug(2, "reached edge past spill point");
+			break;
+		    }
+		}
+
+		/* carving ok */
+		if (this_is_flat < 4) {
+		    min_bottom_ele = bottom_ele;
+		    /* count cells to carve from sink bottom to spill point */
+		    ele_last = ele_nbr = bottom_ele;
+		    r_nbr = next_r;
+		    c_nbr = next_c;
+		    n_cells = 0;
+		    while (ele_nbr >= ele_last) {
+			n_cells++;
+			if (ele_nbr > bottom_ele) {
+			    down_uphill = n_cells;
+			}
+			bseg_get(&draindir, &drain_val, r_nbr, c_nbr);
+
+			if (drain_val > 0) {
+			    r_nbr = r_nbr + asp_r[(int) drain_val];
+			    c_nbr = c_nbr + asp_c[(int) drain_val];
+
+			    ele_last = ele_nbr;
+			    cseg_get(&ele, &ele_nbr, r_nbr, c_nbr);
+			}
+			else {
+			    break;
+			}
+		    }
+		    /* remember least impact */
+		    if (least_impact > n_to_fill + down_uphill +
+			down_downhill) {
+			least_impact = n_to_fill + down_uphill +
+			               down_downhill;
+			least_impact_r = next_r;
+			least_impact_c = next_c;
+			least_impact_ele = bottom_ele;
+		    }
+		}
+		/* carving not ok, need to fill more */
+		else {
+		    G_debug(2, "carving not ok");
+		    least_impact = li_max;
+		    least_impact_r = peak_r;
+		    least_impact_c = peak_c;
+		    least_impact_ele = peak_ele;
+		    min_bottom_ele = bottom_ele + 1;
+		}
+
+		/* there is no better solution by filling more */
+		if (n_to_fill > least_impact)
+		    break;
+
+		G_debug(2,
+			"channel length to spill point %d, channel length from spill point %d, cells to fill %d",
+			down_uphill, down_downhill, n_to_fill);
+
+		/* check IRA condition */
+		/* preference for channel carving, relaxed stream split condition */
+		/* continue filling ? */
+		/* remains a mystery why n_new_splits results in less modifications... */
+		if (sqrt(n_to_fill) < (down_uphill + down_downhill) ||
+		    n_new_splits <= 4 ||
+		    bottom_ele <= min_bottom_ele ||
+		    least_impact == li_max) {
+		    /* continue with IRA */
+		    G_debug(2, "IRA conditions fulfilled");
+		}
+		/* IRA condition no longer fulfilled */
+		else {
+		    G_debug(2, "IRA conditions not met");
+		    G_debug(2, "n to fill: %d", n_to_fill);
+		    G_debug(2, "down_uphill: %d", down_uphill);
+		    G_debug(2, "down_downhill: %d", down_downhill);
+		    break;
+		}
+
+		if (bottom_ele >= peak_ele)
+		    break;
+
+		/* below spill point
+		 * get next higher cell downstream of current bottom */
+		G_debug(2, "get next fill point candidate");
+
+		r_nbr = next_r;
+		c_nbr = next_c;
+		bseg_get(&draindir, &drain_val, r_nbr, c_nbr);
+		if (drain_val > 0) {
+
+		    cseg_get(&ele, &ele_nbr, r_nbr, c_nbr);
+		    /* go to next higher cell downstream */
+		    while (ele_nbr == bottom_ele ||
+		           ele_nbr < min_bottom_ele) {
+			bseg_get(&draindir, &drain_val, r_nbr, c_nbr);
+
+			if (drain_val > 0) {
+			    r_nbr = r_nbr + asp_r[(int) drain_val];
+			    c_nbr = c_nbr + asp_c[(int) drain_val];
+
+			    cseg_get(&ele, &ele_nbr, r_nbr, c_nbr);
+			}
+			else {
+			    is_edge = 1;
+			    break;
+			}
+		    }
+		    /* got next downstream cell that's higher than sink bottom */
+		    G_debug(2, "got next downstream cell");
+		}
+		else
+		    is_edge = 1;
+
+		if (is_edge) {
+		    G_debug(1,"IRA reached edge");
+		    break;
+		}
+
+		/* increase ele or go to next point */
+		if (ele_nbr > next_bottom_ele &&
+		    next_bottom_ele >= min_bottom_ele) {
+		    G_debug(2, "increase ele, keep point");
+		    bottom_ele = next_bottom_ele;
+		}
+		else {
+		    next_r = r_nbr;
+		    next_c = c_nbr;
+		    bottom_ele = ele_nbr;
+		}
+	    }
+	    /* <-- IRA */
+	    
+	    if (n_to_fill > -1 && least_impact == li_max)
+		G_warning(_("IRA error"));
+
+	    if (n_to_fill > -1 && (do_all || least_impact <= n_mod_max)) {
+
+		/* (partially) fill the sink */
+		n_to_fill = 0;
+		cseg_get(&ele, &ele_val, first_sink->r, first_sink->c);
+		if (least_impact_ele != ele_val) {
+		    G_debug(1, "IRA sink filling");
+
+		    cseg_get(&ele, &ele_val, least_impact_r,
+		             least_impact_c);
+		    if (ele_val != least_impact_ele) {
+			G_debug(1, "changing ele from %d to %d",
+				ele_val, least_impact_ele);
+			cseg_put(&ele, &least_impact_ele, least_impact_r,
+			         least_impact_c);
+		    }
+		    n_to_fill = fill_sink(least_impact_r, least_impact_c,
+		                          least_impact_ele);
+		    first_sink->r = least_impact_r;
+		    first_sink->c = least_impact_c;
+		    if (least_impact_ele < peak_ele)
+			n_just_a_bit++;
+		    else
+			n_filled++;
+		}
+		else {
+		    n_carved++;
+		    G_debug(1, "IRA at bottom");
+		}
+
+		/* carve if not completely filled */
+		down_downhill = 0;
+		if (least_impact_ele < peak_ele) {
+		    G_debug(2, "IRA carving");
+		    down_downhill = carve(first_sink->r, first_sink->c,
+				          least_impact_ele,
+					  peak_r, peak_c);
+		}
+	    }
+	}
+
+	G_debug(1, "get next sink");
+
+	last_sink = first_sink;
+	first_sink = first_sink->next;
+	G_free(last_sink);
+    }
+
+    G_verbose_message
+	("------------------------------------------------------");
+    G_verbose_message(_("%d sinks processed"), n_sinks);
+    G_verbose_message(_("%d sinks within larger sinks"), n_processed);
+    G_verbose_message(_("%d sinks completely filled"), n_filled);
+    G_verbose_message(_("%d sinks partially filled and carved with IRA"),
+                      n_just_a_bit);
+    G_verbose_message(_("%d channels carved"), n_carved);
+    G_verbose_message
+	("------------------------------------------------------");
+
+    return 1;
+}
+
+int one_cell_extrema(int do_peaks, int do_pits, int all)
+{
+    int r, c, r_nbr, c_nbr;
+    int ct_dir;
+    int skipme;
+    CELL ele_min, ele_max, ele_this, ele_nbr;
+    unsigned int n_pits = 0;
+    unsigned int n_peaks = 0;
+    unsigned int counter = 0;
+    double sumofsquares, mean, stddev, upperci, lowerci;
+    int n_valid;
+
+    G_message(_("Remove one cell extremas"));
+
+    /* not for edges */
+    for (r = 0; r < nrows; r++) {
+	G_percent(r, nrows, 2);
+
+	for (c = 0; c < ncols; c++) {
+
+	    skipme = 0;
+	    cseg_get(&ele, &ele_this, r, c);
+
+	    if (Rast_is_c_null_value(&ele_this))
+		continue;
+
+	    ele_min = INT_MAX;
+	    ele_max = INT_MIN;
+	    sumofsquares = mean = n_valid = 0;
+
+	    /* TODO: better use 5x5 neighbourhood ? */
+	    for (ct_dir = 0; ct_dir < sides; ct_dir++) {
+		/* get r, c (r_nbr, c_nbr) for neighbours */
+		r_nbr = r + nextdr[ct_dir];
+		c_nbr = c + nextdc[ct_dir];
+		/* check that neighbour is within region */
+		if (r_nbr >= 0 && r_nbr < nrows && c_nbr >= 0 &&
+		    c_nbr < ncols) {
+
+		    cseg_get(&ele, &ele_nbr, r_nbr, c_nbr);
+
+		    if (Rast_is_c_null_value(&ele_nbr)) {
+			skipme = 1;
+			break;
+		    }
+		    
+		    n_valid++;
+		    sumofsquares += ele_nbr * ele_nbr;
+		    mean += ele_nbr;
+
+		    if (ele_min > ele_nbr) {
+			ele_min = ele_nbr;
+		    }
+		    if (ele_max < ele_nbr) {
+			ele_max = ele_nbr;
+		    }
+		}
+		else {
+		    skipme = 1;
+		    break;
+		}
+	    }
+
+	    if (skipme)
+		continue;
+
+	    counter++;
+
+	    if (all) {
+		upperci = ele_this - 1;
+		lowerci = ele_this + 1;
+	    }
+	    else {
+		/* remove extremas only if outside 95% CI = mean +- 1.96 * SD */
+		mean /= n_valid;
+		stddev = sqrt(sumofsquares / n_valid - mean * mean);
+		upperci = mean + 1.96 * stddev;
+		lowerci = mean - 1.96 * stddev;
+	    }
+	    
+	    /* one cell pit, lower than all surrounding neighbours */
+	    if (do_pits) {
+		if (ele_this < ele_min && ele_this < lowerci) {
+		    ele_this = ele_min;
+		    cseg_put(&ele, &ele_this, r, c);
+		    n_pits++;
+		}
+	    }
+
+	    /* one cell peak, higher than all surrounding neighbours */
+	    if (do_peaks) {
+		if (ele_this > ele_max && ele_this > upperci) {
+		    ele_this = ele_max;
+		    cseg_put(&ele, &ele_this, r, c);
+		    n_peaks++;
+		}
+	    }
+	}
+    }
+    G_percent(nrows, nrows, 1);	/* finish it */
+
+    G_verbose_message("%u cells checked", counter);
+    G_verbose_message("%u one-cell peaks removed", n_peaks);
+    G_verbose_message("%u one-cell pits removed", n_pits);
+
+    return 1;
+}

Added: grass-addons/grass7/grass7/raster/r.hydrodem/init_search.c
===================================================================
--- grass-addons/grass7/grass7/raster/r.hydrodem/init_search.c	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.hydrodem/init_search.c	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,140 @@
+#include <grass/raster.h>
+#include <grass/glocale.h>
+#include "local_proto.h"
+
+int init_search(int depr_fd)
+{
+    int r, c, r_nbr, c_nbr, ct_dir;
+    void *depr_buf, *depr_ptr;
+    CELL ele_value;
+    int nextdr[8] = { 1, -1, 0, 0, -1, 1, 1, -1 };
+    int nextdc[8] = { 0, 0, -1, 1, 1, -1, 1, -1 };
+    char flag_value, flag_value_nbr, is_null;
+    char asp_value;
+    unsigned int n_depr_cells = 0;
+    unsigned int n_null_cells = nrows * ncols - n_points;
+    int depr_map_type, depr_size;
+
+    nxt_avail_pt = heap_size = 0;
+
+    /* load edge cells and real depressions to A* heap */
+    G_message(_("Set edge points"));
+
+    if (depr_fd > -1) {
+	depr_map_type = Rast_get_map_type(depr_fd);
+	depr_size = Rast_cell_size(depr_map_type);
+	depr_buf = Rast_allocate_buf(depr_map_type);
+    }
+    else {
+	depr_buf = NULL;
+	depr_map_type = 0;
+	depr_size = 0;
+    }
+    depr_ptr = NULL;
+
+    for (r = 0; r < nrows; r++) {
+	G_percent(r, nrows, 2);
+
+	if (depr_fd >= 0) {
+	    Rast_get_row(depr_fd, depr_buf, r, depr_map_type);
+	    depr_ptr = depr_buf;
+	}
+
+	for (c = 0; c < ncols; c++) {
+
+	    bseg_get(&bitflags, &flag_value, r, c);
+	    is_null = FLAG_GET(flag_value, NULLFLAG);
+
+	    if (is_null) {
+		if (depr_fd > -1)
+		    depr_ptr = G_incr_void_ptr(depr_ptr, depr_size);
+		    
+		continue;
+	    }
+
+	    asp_value = 0;
+
+	    if (r == 0 || r == nrows - 1 || c == 0 || c == ncols - 1) {
+
+		if (r == 0 && c == 0)
+		    asp_value = -7;
+		else if (r == 0 && c == ncols - 1)
+		    asp_value = -5;
+		else if (r == nrows - 1 && c == 0)
+		    asp_value = -1;
+		else if (r == nrows - 1 && c == ncols - 1)
+		    asp_value = -3;
+		else if (r == 0)
+		    asp_value = -2;
+		else if (c == 0)
+		    asp_value = -4;
+		else if (r == nrows - 1)
+		    asp_value = -6;
+		else if (c == ncols - 1)
+		    asp_value = -8;
+
+		cseg_get(&ele, &ele_value, r, c);
+		FLAG_SET(flag_value, EDGEFLAG);
+		heap_add(r, c, ele_value, asp_value, flag_value);
+
+		if (depr_fd > -1)
+		    depr_ptr = G_incr_void_ptr(depr_ptr, depr_size);
+
+		continue;
+	    }
+
+	    if (n_null_cells > 0) {
+		/* any neighbour NULL ? */
+		for (ct_dir = 0; ct_dir < sides; ct_dir++) {
+		    /* get r, c (r_nbr, c_nbr) for neighbours */
+		    r_nbr = r + nextdr[ct_dir];
+		    c_nbr = c + nextdc[ct_dir];
+
+		    bseg_get(&bitflags, &flag_value_nbr, r_nbr, c_nbr);
+		    is_null = FLAG_GET(flag_value_nbr, NULLFLAG);
+
+		    if (is_null) {
+			asp_value = -1 * drain[r - r_nbr + 1][c - c_nbr + 1];
+			cseg_get(&ele, &ele_value, r, c);
+			FLAG_SET(flag_value, EDGEFLAG);
+			heap_add(r, c, ele_value, asp_value, flag_value);
+
+			break;
+		    }
+		}
+	    }
+
+	    if (asp_value) { /* some neighbour was NULL, point added to list */
+
+		if (depr_fd > -1)
+		    depr_ptr = G_incr_void_ptr(depr_ptr, depr_size);
+
+		continue;
+	    }
+	    
+	    /* real depression ? */
+	    if (depr_fd > -1) {
+		DCELL depr_val = Rast_get_d_value(depr_ptr, depr_map_type);
+
+		if (!Rast_is_null_value(depr_ptr, depr_map_type) && depr_val != 0) {
+		    cseg_get(&ele, &ele_value, r, c);
+		    FLAG_SET(flag_value, DEPRFLAG);
+		    heap_add(r, c, ele_value, asp_value, flag_value);
+		    n_depr_cells++;
+		}
+		depr_ptr = G_incr_void_ptr(depr_ptr, depr_size);
+	    }
+	}
+    }
+    G_percent(nrows, nrows, 2);	/* finish it */
+
+    if (depr_fd > -1) {
+	G_free(depr_buf);
+    }
+
+    G_debug(1, "%d edge cells", heap_size - n_depr_cells);
+    if (n_depr_cells)
+	G_debug(1, "%d cells in depressions", n_depr_cells);
+
+    return 1;
+}

Added: grass-addons/grass7/grass7/raster/r.hydrodem/load.c
===================================================================
--- grass-addons/grass7/grass7/raster/r.hydrodem/load.c	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.hydrodem/load.c	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,97 @@
+#include <grass/gis.h>
+#include <grass/raster.h>
+#include <grass/glocale.h>
+#include "local_proto.h"
+
+int ele_round(double x)
+{
+    return (x > 0.0 ? x + .5 : x - .5);
+}
+
+/*
+ * loads elevation map to segment file and gets start points for A* Search,
+ * start points are edges
+ */
+int load_map(int ele_fd)
+{
+    int r, c;
+    char flag_value, asp_value = 0;
+    void *ele_buf, *ptr;
+    CELL ele_value;
+    DCELL dvalue;
+    int ele_size;
+    int ele_map_type;
+
+    G_message(_("Load elevation map"));
+
+    n_search_points = n_points = 0;
+
+    ele_map_type = Rast_get_map_type(ele_fd);
+    ele_size = Rast_cell_size(ele_map_type);
+    ele_buf = Rast_allocate_buf(ele_map_type);
+
+    if (ele_buf == NULL) {
+	G_warning(_("Could not allocate memory"));
+	return -1;
+    }
+
+    ele_scale = 1;
+    if (ele_map_type == FCELL_TYPE || ele_map_type == DCELL_TYPE)
+	ele_scale = 1000;	/* should be enough to do the trick */
+
+    G_debug(1, "start loading %d rows, %d cols", nrows, ncols);
+    for (r = 0; r < nrows; r++) {
+
+	G_percent(r, nrows, 2);
+
+	Rast_get_row(ele_fd, ele_buf, r, ele_map_type);
+	ptr = ele_buf;
+
+	for (c = 0; c < ncols; c++) {
+
+	    flag_value = 0;
+
+	    /* check for masked and NULL cells */
+	    if (Rast_is_null_value(ptr, ele_map_type)) {
+		FLAG_SET(flag_value, NULLFLAG);
+		FLAG_SET(flag_value, INLISTFLAG);
+		FLAG_SET(flag_value, WORKEDFLAG);
+		FLAG_SET(flag_value, WORKED2FLAG);
+		Rast_set_c_null_value(&ele_value, 1);
+	    }
+	    else {
+		switch (ele_map_type) {
+		case CELL_TYPE:
+		    ele_value = *((CELL *) ptr);
+		    break;
+		case FCELL_TYPE:
+		    dvalue = *((FCELL *) ptr);
+		    dvalue *= ele_scale;
+		    ele_value = ele_round(dvalue);
+		    break;
+		case DCELL_TYPE:
+		    dvalue = *((DCELL *) ptr);
+		    dvalue *= ele_scale;
+		    ele_value = ele_round(dvalue);
+		    break;
+		}
+
+		n_points++;
+	    }
+
+	    cseg_put(&ele, &ele_value, r, c);
+	    bseg_put(&draindir, &asp_value, r, c);
+	    bseg_put(&bitflags, &flag_value, r, c);
+
+	    ptr = G_incr_void_ptr(ptr, ele_size);
+	}
+    }
+    G_percent(nrows, nrows, 1);	/* finish it */
+
+    Rast_close(ele_fd);
+    G_free(ele_buf);
+
+    G_debug(1, "%d non-NULL cells", n_points);
+
+    return 1;
+}

Added: grass-addons/grass7/grass7/raster/r.hydrodem/local_proto.h
===================================================================
--- grass-addons/grass7/grass7/raster/r.hydrodem/local_proto.h	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.hydrodem/local_proto.h	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,89 @@
+
+#ifndef __LOCAL_PROTO_H__
+#define __LOCAL_PROTO_H__
+
+#include <grass/gis.h>
+#include <grass/raster.h>
+#include "seg.h"
+#include "flag.h"
+
+#define INDEX(r, c) ((r) * ncols + (c))
+#define MAXDEPTH 1000     /* maximum supported tree depth of stream network */
+
+struct ddir
+{
+    int pos;
+    int dir;
+};
+
+struct point
+{
+    int r, c;
+};
+
+struct heap_point {
+   unsigned int added;
+   CELL ele;
+   int r, c;
+};
+
+struct sink_list
+{
+    int r, c;
+    struct sink_list *next;
+};
+
+struct snode
+{
+    int r, c;
+    int id;
+    int n_trib;           /* number of tributaries */
+    int n_trib_total;     /* number of all upstream stream segments */
+    int n_alloc;          /* n allocated tributaries */
+    int *trib;
+    double *acc;
+};
+
+extern struct snode *stream_node;
+extern int nrows, ncols;
+extern unsigned int n_search_points, n_points, nxt_avail_pt;
+extern unsigned int heap_size;
+extern unsigned int n_sinks;
+extern int n_mod_max, size_max;
+extern int do_all, keep_nat, nat_thresh;
+extern unsigned int n_stream_nodes, n_alloc_nodes;
+extern struct point *outlets;
+extern struct sink_list *sinks, *first_sink;
+extern unsigned int n_outlets, n_alloc_outlets;
+extern char drain[3][3];
+extern unsigned int first_cum;
+extern char sides;
+extern int c_fac;
+extern int ele_scale;
+extern struct RB_TREE *draintree;
+
+extern SSEG search_heap;
+extern SSEG astar_pts;
+extern BSEG bitflags;
+extern CSEG ele;
+extern BSEG draindir;
+extern CSEG stream;
+
+/* load.c */
+int load_map(int);
+
+/* init_search.c */
+int init_search(int);
+
+/* do_astar.c */
+int do_astar(void);
+unsigned int heap_add(int, int, CELL, char, char);
+
+/* hydro_con.c */
+int hydro_con(void);
+int one_cell_extrema(int, int, int);
+
+/* close.c */
+int close_map(char *, int);
+
+#endif /* __LOCAL_PROTO_H__ */

Added: grass-addons/grass7/grass7/raster/r.hydrodem/main.c
===================================================================
--- grass-addons/grass7/grass7/raster/r.hydrodem/main.c	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.hydrodem/main.c	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,348 @@
+
+/****************************************************************************
+ *
+ * MODULE:       r.hydrodem
+ * AUTHOR(S):    Markus Metz <markus.metz.giswork gmail.com>
+ * PURPOSE:      Hydrological analysis
+ *               DEM hydrological conditioning based on A* Search
+ * COPYRIGHT:    (C) 1999-2009 by the GRASS Development Team
+ *
+ *               This program is free software under the GNU General Public
+ *               License (>=v2). Read the file COPYING that comes with GRASS
+ *               for details.
+ *
+ *****************************************************************************/
+#include <stdlib.h>
+#include <string.h>
+#include <float.h>
+#include <grass/gis.h>
+#include <grass/raster.h>
+#include <grass/glocale.h>
+#include "local_proto.h"
+
+struct snode *stream_node;
+int nrows, ncols;
+unsigned int n_search_points, n_points, nxt_avail_pt;
+unsigned int heap_size;
+unsigned int n_sinks;
+int n_mod_max, size_max;
+int do_all, keep_nat, nat_thresh;
+unsigned int n_stream_nodes, n_alloc_nodes;
+struct point *outlets;
+struct sink_list *sinks, *first_sink;
+unsigned int n_outlets, n_alloc_outlets;
+
+char drain[3][3] = { {7, 6, 5}, {8, 0, 4}, {1, 2, 3} };
+
+unsigned int first_cum;
+char sides;
+int c_fac;
+int ele_scale;
+struct RB_TREE *draintree;
+
+SSEG search_heap;
+BSEG bitflags;
+CSEG ele;
+BSEG draindir;
+CSEG stream;
+
+
+int main(int argc, char *argv[])
+{
+    struct
+    {
+	struct Option *ele, *depr, *memory;
+    } input;
+    struct
+    {
+	struct Option *ele_hydro;
+	struct Option *mod_max;
+	struct Option *size_max;
+	struct Flag *do_all;
+    } output;
+    struct GModule *module;
+    int ele_fd, ele_map_type, depr_fd;
+    int memory;
+    int seg_cols, seg_rows;
+    double seg2kb;
+    int num_open_segs, num_open_array_segs, num_seg_total;
+    double memory_divisor, heap_mem, disk_space;
+    const char *mapset;
+    struct Colors colors;
+
+    G_gisinit(argv[0]);
+
+    /* Set description */
+    module = G_define_module();
+    G_add_keyword(_("raster"));
+    G_add_keyword(_("hydrology"));
+    module->description = _("Hydrological conditioning, sink removal");
+
+    input.ele = G_define_standard_option(G_OPT_R_INPUT);
+    input.ele->key = "input";
+    input.ele->label = _("Elevation map");
+    input.ele->description =
+	_("Elevation map to be hydrologically corrected");
+
+    input.depr = G_define_standard_option(G_OPT_R_INPUT);
+    input.depr->key = "depression";
+    input.depr->required = NO;
+    input.depr->label = _("Depression map");
+    input.depr->description =
+	_("Map indicating real depressions that must not be modified");
+
+    input.memory = G_define_option();
+    input.memory->key = "memory";
+    input.memory->type = TYPE_INTEGER;
+    input.memory->required = NO;
+    input.memory->answer = "300";
+    input.memory->description = _("Maximum memory to be used in MB");
+
+    output.ele_hydro = G_define_standard_option(G_OPT_R_OUTPUT);
+    output.ele_hydro->key = "output";
+    output.ele_hydro->description =
+	_("Name of hydrologically conditioned raster map");
+    output.ele_hydro->required = YES;
+
+    output.mod_max = G_define_option();
+    output.mod_max->key = "mod";
+    output.mod_max->description =
+	(_("Only remove sinks requiring not more than <mod> cell modifications."));
+    output.mod_max->type = TYPE_INTEGER;
+    output.mod_max->answer = "4";
+    output.mod_max->required = YES;
+
+    output.size_max = G_define_option();
+    output.size_max->key = "size";
+    output.size_max->description =
+	(_("Only remove sinks not larger than <size> cells."));
+    output.size_max->type = TYPE_INTEGER;
+    output.size_max->answer = "4";
+    output.size_max->required = YES;
+
+    output.do_all = G_define_flag();
+    output.do_all->key = 'a';
+    output.do_all->label = (_("Remove all sinks."));
+    output.do_all->description =
+	(_("By default only minor corrections are done to the DEM and "
+	  "the result will not be 100% hydrologically correct."
+	  "Use this flag to override default."));
+
+    if (G_parser(argc, argv))
+	exit(EXIT_FAILURE);
+
+    /***********************/
+    /*    check options    */
+    /***********************/
+
+    /* input maps exist ? */
+    if (!G_find_raster(input.ele->answer, ""))
+	G_fatal_error(_("Raster map <%s> not found"), input.ele->answer);
+	
+    if (input.depr->answer) {
+	if (!G_find_raster(input.depr->answer, ""))
+	    G_fatal_error(_("Raster map <%s> not found"),
+	                  input.depr->answer);
+    }
+
+    if ((n_mod_max = atoi(output.mod_max->answer)) <= 0)
+	G_fatal_error(_("'%s' must be a positive integer"),
+	              output.mod_max->key);
+
+    if ((size_max = atoi(output.size_max->answer)) <= 0)
+	G_fatal_error(_("'%s' must be a positive integer"),
+		      output.size_max->key);
+
+    if (input.memory->answer) {
+	memory = atoi(input.memory->answer);
+	if (memory <= 0)
+	    G_fatal_error(_("Memory must be positive but is %d"),
+			  memory);
+    }
+    else
+	memory = 300;
+
+    do_all = output.do_all->answer;
+
+    if (!do_all) {
+	G_verbose_message(_("All sinks with max %d cells to be modified will be removed"),
+			  n_mod_max);
+	G_verbose_message(_("All sinks not larger than %d cells will be removed."),
+			  size_max);
+    }
+
+    /*********************/
+    /*    preparation    */
+    /*********************/
+
+    /* open input maps */
+    mapset = G_find_raster2(input.ele->answer, "");
+    ele_fd = Rast_open_old(input.ele->answer, mapset);
+    if (ele_fd < 0)
+	G_fatal_error(_("Could not open input map %s"), input.ele->answer);
+
+    if (input.depr->answer) {
+	mapset = G_find_raster2(input.depr->answer, "");
+	depr_fd = Rast_open_old(input.depr->answer, mapset);
+	if (depr_fd < 0)
+	    G_fatal_error(_("Could not open input map %s"),
+	                  input.depr->answer);
+    }
+    else
+	depr_fd = -1;
+
+    /* set global variables */
+    nrows = Rast_window_rows();
+    ncols = Rast_window_cols();
+    sides = 8;			/* not a user option */
+
+    ele_map_type = Rast_get_map_type(ele_fd);
+
+    /* segment structures */
+    seg_rows = seg_cols = 64;
+    seg2kb = seg_rows * seg_cols / 1024.;
+    
+    /* balance segment files */
+    /* elevation: * 2 */
+    memory_divisor = seg2kb * sizeof(CELL) * 2;
+    /* drainage direction: as is */
+    memory_divisor += seg2kb * sizeof(char);
+    /* flags: * 4 */
+    memory_divisor += seg2kb * sizeof(char) * 4;
+    /* heap points: / 4 */
+    memory_divisor += seg2kb * sizeof(struct heap_point) / 4.;
+    
+    /* KB -> MB */
+    memory_divisor /= 1024.;
+
+    num_open_segs = memory / memory_divisor;
+    /* heap_mem is in MB */
+    heap_mem = num_open_segs * seg2kb * sizeof(struct heap_point) /
+               (4. * 1024.);
+    num_seg_total = (ncols / seg_cols + 1) * (nrows / seg_rows + 1);
+    if (num_open_segs > num_seg_total) {
+	heap_mem += (num_open_segs - num_seg_total) * memory_divisor;
+	heap_mem -= (num_open_segs - num_seg_total) * seg2kb *
+	            sizeof(struct heap_point) / (4. * 1024.);
+	num_open_segs = num_seg_total;
+    }
+    if (num_open_segs < 16) {
+	num_open_segs = 16;
+	heap_mem = num_open_segs * seg2kb * sizeof(struct heap_point) /
+	           (4. * 1024.);
+    }
+    disk_space = (1. * sizeof(CELL) + 2 * sizeof(char) +
+                 sizeof(struct heap_point));
+    disk_space *= (num_seg_total * seg2kb / 1024.);  /* KB -> MB */
+    
+    G_verbose_message(_("%.2f of data are kept in memory"),
+                      100. * num_open_segs / num_seg_total);
+    G_verbose_message(_("Will need up to %.2f MB of disk space"), disk_space);
+
+    /* open segment files */
+    G_verbose_message(_("Create temporary files..."));
+    cseg_open(&ele, seg_rows, seg_cols, num_open_segs * 2);
+    if (num_open_segs * 2 > num_seg_total)
+	heap_mem += (num_open_segs * 2 - num_seg_total) * seg2kb * sizeof(CELL) / 1024.;
+    bseg_open(&draindir, seg_rows, seg_cols, num_open_segs);
+    bseg_open(&bitflags, seg_rows, seg_cols, num_open_segs * 4);
+    if (num_open_segs * 4 > num_seg_total)
+	heap_mem += (num_open_segs * 4 - num_seg_total) * seg2kb / 1024.;
+
+    /* load map */
+    if (load_map(ele_fd) < 0) {
+	cseg_close(&ele);
+	bseg_close(&draindir);
+	bseg_close(&bitflags);
+	G_fatal_error(_("Could not load input map"));
+    }
+    
+    if (n_points == 0) {
+	cseg_close(&ele);
+	bseg_close(&draindir);
+	bseg_close(&bitflags);
+	G_fatal_error(_("No non-NULL cells loaded from input map"));
+    }
+
+    /* one-based d-ary search_heap */
+    G_debug(1, "open segments for A* search heap");
+	
+    /* allowed memory for search heap in MB */
+    G_debug(1, "heap memory %.2f MB", heap_mem);
+    /* columns per segment */
+    /* larger is faster */
+    seg_cols = seg_rows * seg_rows * seg_rows;
+    num_seg_total = n_points / seg_cols;
+    if (n_points % seg_cols > 0)
+	num_seg_total++;
+    /* no need to have more segments open than exist */
+    num_open_array_segs = (1 << 20) * heap_mem / 
+                           (seg_cols * sizeof(struct heap_point));
+    if (num_open_array_segs > num_seg_total)
+	num_open_array_segs = num_seg_total;
+    if (num_open_array_segs < 2)
+	num_open_array_segs = 2;
+
+    G_debug(1, "A* search heap open segments %d, total %d",
+            num_open_array_segs, num_seg_total);
+    G_debug(1, "segment size for heap points: %d", seg_cols);
+    /* the search heap will not hold more than 5% of all points at any given time ? */
+    /* chances are good that the heap will fit into one large segment */
+    seg_open(&search_heap, 1, n_points + 1, 1, seg_cols,
+	     num_open_array_segs, sizeof(struct heap_point), 1);
+
+    /********************/
+    /*    processing    */
+    /********************/
+
+    /* remove one cell extrema */
+    one_cell_extrema(1, 1, 0);
+
+    /* initialize A* search */
+    if (init_search(depr_fd) < 0) {
+	seg_close(&search_heap);
+	cseg_close(&ele);
+	bseg_close(&draindir);
+	bseg_close(&bitflags);
+	G_fatal_error(_("Could not initialize search"));
+    }
+
+    if (depr_fd >= 0) {
+	Rast_close(depr_fd);
+    }
+
+    /* sort elevation and get initial stream direction */
+    if (do_astar() < 0) {
+	seg_close(&search_heap);
+	cseg_close(&ele);
+	bseg_close(&draindir);
+	bseg_close(&bitflags);
+	G_fatal_error(_("Could not sort elevation map"));
+    }
+    seg_close(&search_heap);
+
+    /* hydrological corrections */
+    if (hydro_con() < 0) {
+	cseg_close(&ele);
+	bseg_close(&draindir);
+	bseg_close(&bitflags);
+	G_fatal_error(_("Could not apply hydrological conditioning"));
+    }
+
+    /* write output maps */
+    if (close_map(output.ele_hydro->answer, ele_map_type) < 0) {
+	cseg_close(&ele);
+	bseg_close(&draindir);
+	bseg_close(&bitflags);
+	G_fatal_error(_("Could not write output map"));
+    }
+
+    cseg_close(&ele);
+    bseg_close(&draindir);
+    bseg_close(&bitflags);
+
+    Rast_read_colors(input.ele->answer, mapset, &colors);
+    Rast_write_colors(output.ele_hydro->answer, G_mapset(), &colors);
+
+    exit(EXIT_SUCCESS);
+}

Added: grass-addons/grass7/grass7/raster/r.hydrodem/r.hydrodem.html
===================================================================
--- grass-addons/grass7/grass7/raster/r.hydrodem/r.hydrodem.html	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.hydrodem/r.hydrodem.html	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,84 @@
+<h2>DESCRIPTION</h2>
+
+<em>r.hydrodem</em> applies hydrological conditioning (sink removal) to 
+a required input <em>elevation</em> map. If the conditioned elevation 
+map is going to be used as input elevation for <em>r.watershed</em>, 
+only small sinks should be removed and the amount of modifications 
+restricted with the <b>mod</b> option. For other modules such as 
+<em>r.terraflow</em> or third-party software, full sink removal is 
+recommended.
+
+<h2>OPTIONS</h2>
+
+<dl>
+<dt><b>input</b> 
+
+<dd>Input map, required: Digital elevation model to be corrected. Gaps
+in the elevation map that are located within the area of interest should
+be filled beforehand, e.g. with <em>r.fillnulls</em> or 
+<em>r.resamp.bspline</em>, to avoid distortions.
+<p>
+<dt><b>output</b>
+<dd>Output map, required: Hydrologically conditioned digital elevation
+model. By default, only minor modifications are done and not all sinks 
+are removed.
+<p>
+<dt><b>size</b>
+<dd>All sinks of up to <b>size</b> cells will be removed.
+Default is 4, if in doubt, decrease and not increase.
+<p>
+<dt><b>mod</b>
+<dd>All sinks will be removed that require not more than <b>mod</b> 
+cells to be modifed. Often, rather large sinks can be removed by 
+carving through only few cells. Default is 4, if in doubt, increase
+and not decrease.
+<p>
+<dt><b>-a</b>
+<dd><b>Not recommended if input for <em>r.watershed</em> is generated.</b>
+<br>
+With the <b>-a</b> flag set, all sinks will be removed using an impact 
+reduction approach based on Lindsay & Creed (2005). The output will be a 
+depression-less digital elevation model, suitable for e.g.
+<em>r.terraflow</em> or other hydrological analyses that require a 
+depression-less DEM as input.
+</dl>
+
+<h2>NOTES</h2>
+
+This module is designed for <em>r.watershed</em> with the purpose to
+slightly denoise a DEM prior to analysis. First, all one-cell peaks and
+pits are removed, then the actual hydrological corrections are applied.
+In most cases, the removal of one-cell extrema could already be
+sufficient to improve <em>r.watershed</em> results in difficult terrain,
+particularly nearly flat areas.
+<p>
+The impact reduction algorithm used by <em>r.hydrodem</em> is based on 
+Lindsay & Creed (2005), with some additional checks for 
+hydrological consistency. With complete sink removal, results of 
+<em>r.terraflow</em> are very similar to results of <em>r.watershed</em>.
+<p>
+<em>r.hydrodem</em> uses the same method to determine drainage directions 
+like <em>r.watershed</em>.
+<p>
+
+<h2>REFERENCES</h2>
+Lindsay, J. B., and Creed, I. F. 2005. Removal of artifact depressions 
+from digital elevation models: towards a minimum impact approach. 
+Hydrological Processes 19, 3113-3126. 
+DOI: <a href=http://dx.doi.org/10.1002/hyp.5835>10.1002/hyp.5835</a>
+
+
+<h2>SEE ALSO</h2>
+
+<em>
+<a href="r.watershed.html">r.watershed</a>,
+<a href="r.terraflow.html">r.terraflow</a>,
+<a href="r.fill.dir.html">r.fill.dir</a>, 
+<a href="r.fillnulls.html">r.fillnulls</a>, 
+<a href="r.resamp.bspline.html">r.resamp.bspline</a>
+</em>
+
+<h2>AUTHOR</h2>
+Markus Metz
+
+<p><i>Last changed: $Date: 2012-01-09 18:41:56 +0100 (Mon, 09 Jan 2012) $</i>

Added: grass-addons/grass7/grass7/raster/r.hydrodem/seg.c
===================================================================
--- grass-addons/grass7/grass7/raster/r.hydrodem/seg.c	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.hydrodem/seg.c	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,112 @@
+#include <unistd.h>
+#include <fcntl.h>
+#include <grass/glocale.h>
+#include "seg.h"
+
+int
+seg_open(SSEG *sseg, int nrows, int ncols, int row_in_seg, int col_in_seg,
+	 int nsegs_in_memory, int size_struct, int fill)
+{
+    char *filename;
+    int errflag;
+    int fd;
+
+    sseg->filename = NULL;
+    sseg->fd = -1;
+
+    filename = G_tempfile();
+    if (-1 == (fd = creat(filename, 0666))) {
+	G_warning(_("seg_open(): unable to create segment file"));
+	return -2;
+    }
+    if (fill)
+	errflag = segment_format(fd, nrows, ncols, row_in_seg,
+	                         col_in_seg, size_struct);
+    else
+	errflag = segment_format_nofill(fd, nrows, ncols, row_in_seg,
+	                         col_in_seg, size_struct);
+
+    if (0 > errflag) {
+	close(fd);
+	unlink(filename);
+	if (errflag == -1) {
+	    G_warning(_("seg_open(): could not write segment file"));
+	    return -1;
+	}
+	else {
+	    G_warning(_("seg_open(): illegal configuration parameter(s)"));
+	    return -3;
+	}
+    }
+    close(fd);
+    if (-1 == (fd = open(filename, 2))) {
+	unlink(filename);
+	G_warning(_("seg_open(): unable to re-open segment file"));
+	return -4;
+    }
+    if (0 > (errflag = segment_init(&(sseg->seg), fd, nsegs_in_memory))) {
+	close(fd);
+	unlink(filename);
+	if (errflag == -1) {
+	    G_warning(_("seg_open(): could not read segment file"));
+	    return -5;
+	}
+	else {
+	    G_warning(_("seg_open(): out of memory"));
+	    return -6;
+	}
+    }
+    sseg->filename = filename;
+    sseg->fd = fd;
+    return 0;
+}
+
+int seg_close(SSEG *sseg)
+{
+    segment_release(&(sseg->seg));
+    close(sseg->fd);
+    unlink(sseg->filename);
+    return 0;
+}
+
+int seg_put(SSEG *sseg, char *value, int row, int col)
+{
+    if (segment_put(&(sseg->seg), value, row, col) < 0) {
+	G_warning(_("seg_put(): could not write segment file"));
+	return -1;
+    }
+    return 0;
+}
+
+int seg_put_row(SSEG *sseg, char *value, int row)
+{
+    if (segment_put_row(&(sseg->seg), value, row) < 0) {
+	G_warning(_("seg_put_row(): could not write segment file"));
+	return -1;
+    }
+    return 0;
+}
+
+int seg_get(SSEG *sseg, char *value, int row, int col)
+{
+    if (segment_get(&(sseg->seg), value, row, col) < 0) {
+	G_warning(_("seg_get(): could not read segment file"));
+	return -1;
+    }
+    return 0;
+}
+
+int seg_get_row(SSEG *sseg, char *value, int row)
+{
+    if (segment_get_row(&(sseg->seg), value, row) < 0) {
+	G_warning(_("seg_get_row(): could not read segment file"));
+	return -1;
+    }
+    return 0;
+}
+
+int seg_flush(SSEG *sseg)
+{
+    segment_flush(&(sseg->seg));
+    return 0;
+}

Added: grass-addons/grass7/grass7/raster/r.hydrodem/seg.h
===================================================================
--- grass-addons/grass7/grass7/raster/r.hydrodem/seg.h	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.hydrodem/seg.h	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,78 @@
+#ifndef __SEG_H__
+#define __SEG_H__
+
+#include <grass/raster.h>
+#include <grass/segment.h>
+
+#define CSEG struct _c_s_e_g_
+CSEG {
+    SEGMENT seg;		/* segment structure */
+    int fd;			/* fd for reading/writing segment file */
+    char *filename;		/* name of segment file */
+    char *name;			/* raster map read into segment file */
+    char *mapset;
+};
+
+#define DSEG struct _d_s_e_g_
+DSEG {
+    SEGMENT seg;		/* segment structure */
+    int fd;			/* fd for reading/writing segment file */
+    char *filename;		/* name of segment file */
+    char *name;			/* raster map read into segment file */
+    char *mapset;
+};
+
+#define BSEG struct _b_s_e_g_
+BSEG {
+    SEGMENT seg;		/* segment structure */
+    int fd;			/* fd for reading/writing segment file */
+    char *filename;		/* name of segment file */
+    char *name;			/* raster map read into segment file */
+    char *mapset;
+};
+
+#define SSEG struct _s_s_e_g_
+SSEG {
+    SEGMENT seg;		/* segment structure */
+    int fd;			/* fd for reading/writing segment file */
+    char *filename;		/* name of segment file */
+};
+
+/* bseg.c */
+int bseg_close(BSEG *);
+int bseg_get(BSEG *, char *, int, int);
+int bseg_open(BSEG *, int, int, int);
+int bseg_put(BSEG *, char *, int, int);
+int bseg_put_row(BSEG *, char *, int);
+int bseg_read_raster(BSEG *, char *, char *);
+int bseg_write_raster(BSEG *, char *);
+
+/* cseg.c */
+int cseg_close(CSEG *);
+int cseg_get(CSEG *, CELL *, int, int);
+int cseg_open(CSEG *, int, int, int);
+int cseg_put(CSEG *, CELL *, int, int);
+int cseg_put_row(CSEG *, CELL *, int);
+int cseg_read_raster(CSEG *, char *, char *);
+int cseg_write_raster(CSEG *, char *);
+
+/* dseg.c */
+int dseg_close(DSEG *);
+int dseg_get(DSEG *, double *, int, int);
+int dseg_open(DSEG *, int, int, int);
+int dseg_put(DSEG *, double *, int, int);
+int dseg_put_row(DSEG *, double *, int);
+int dseg_read_raster(DSEG *, char *, char *);
+int dseg_write_raster(DSEG *, char *);
+
+/* seg.c */
+int seg_close(SSEG *);
+int seg_get(SSEG *, char *, int, int);
+int seg_open(SSEG *, int, int, int, int, int, int, int);
+int seg_put(SSEG *, char *, int, int);
+int seg_put_row(SSEG *, char *, int);
+int seg_get(SSEG *, char *, int, int);
+int seg_get_row(SSEG *, char *, int);
+int seg_flush(SSEG *);
+
+#endif /* __SEG_H__ */

Added: grass-addons/grass7/grass7/raster/r.in.srtm.region/Makefile
===================================================================
--- grass-addons/grass7/grass7/raster/r.in.srtm.region/Makefile	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.in.srtm.region/Makefile	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,7 @@
+MODULE_TOPDIR = ../..
+
+PGM = r.in.srtm.region
+
+include $(MODULE_TOPDIR)/include/Make/Script.make
+
+default: script

Added: grass-addons/grass7/grass7/raster/r.in.srtm.region/r.in.srtm.region.html
===================================================================
--- grass-addons/grass7/grass7/raster/r.in.srtm.region/r.in.srtm.region.html	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.in.srtm.region/r.in.srtm.region.html	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,36 @@
+<h2>DESCRIPTION</h2>
+
+<em>r.in.srtm.region</em> imports all SRTM V2.1 tiles covering the 
+current region or region extents given with <b>region</b> into GRASS, 
+patches the tiles together and optionally interpolates holes.
+<p>
+<em>r.in.srtm.region</em> downloads SRTM tiles from:<br>
+<a href="http://dds.cr.usgs.gov/srtm/version2_1/SRTM3/">http://dds.cr.usgs.gov/srtm/</a>
+<br>
+or optionally uses a local folder with previously downloaded files if 
+the <b>local</b> option is given.
+
+<h2>NOTES</h2>
+
+<em>r.in.srtm.region</em> imports only SRTM tiles with 3 arcsec resolution.
+
+<h2>SEE ALSO</h2>
+
+<em>
+<a href="r.in.srtm.html">r.in.srtm</a>
+</em>
+<p>The <a href="http://www2.jpl.nasa.gov/srtm/">Shuttle Radar Topography Mission</a>
+homepage at NASA's JPL.
+<br>
+The <a href="http://pub7.bravenet.com/forum/537683448/">SRTM Web Forum</a>
+
+<h2>REFERENCES</h2>
+
+M. Neteler, 2005. <a href="http://grass.osgeo.org/newsletter/GRASSNews_vol3.pdf">SRTM and VMAP0 data in OGR and GRASS.</a> <i><a href="http://grass.osgeo.org/newsletter/">GRASS Newsletter</a></i>, Vol.3, pp. 2-6, June 2005. ISSN 1614-8746.
+
+
+<h2>AUTHORS</h2>
+
+Markus Metz<br>
+
+<p><i>Last changed: $Date: 2012-01-07 12:33:11 +0100 (Sat, 07 Jan 2012) $</i>

Added: grass-addons/grass7/grass7/raster/r.in.srtm.region/r.in.srtm.region.py
===================================================================
--- grass-addons/grass7/grass7/raster/r.in.srtm.region/r.in.srtm.region.py	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.in.srtm.region/r.in.srtm.region.py	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,347 @@
+#!/usr/bin/env python
+
+############################################################################
+#
+# MODULE:       r.in.srtm.region
+#
+# AUTHOR(S):    Markus Metz
+#
+# PURPOSE:      Create a DEM from 3 arcsec SRTM v2.1 tiles
+#
+# COPYRIGHT:    (C) 2011 GRASS development team
+#
+#               This program is free software under the GNU General
+#               Public License (>=v2). Read the file COPYING that
+#               comes with GRASS for details.
+#
+#############################################################################
+
+#%module
+#% description: Creates a DEM from 3 arcsec SRTM v2.1 tiles.
+#% keywords: raster
+#% keywords: import
+#%end
+#%option G_OPT_R_OUTPUT
+#% description: Name for output raster map
+#% required: yes
+#%end
+#%option
+#% key: url
+#% description: base url to fetch SRTM v2.1 tiles
+#% answer: http://dds.cr.usgs.gov/srtm/version2_1/SRTM3/
+#% required: no
+#%end
+#%option G_OPT_M_DIR
+#% key: local
+#% label: local folder with SRTM v2.1 tiles
+#% description: use local folder instead of url to retrieve SRTM tiles
+#% required: no
+#%end
+#%option
+#% key: region
+#% type: double
+#% label: Import subregion only (default is current region)
+#% description: Format: xmin,ymin,xmax,ymax - usually W,S,E,N
+#% key_desc: xmin,ymin,xmax,ymax
+#% multiple: yes
+#% required: no
+#%end
+#%option
+#% key: memory
+#% type: integer
+#% description: Memory in MB for interpolation
+#% answer: 300
+#% required: no
+#%end
+#%flag
+#%  key: n
+#%  description: Fill null cells
+#%end
+
+
+proj = ''.join([
+    'GEOGCS[',
+    '"wgs84",',
+    'DATUM["WGS_1984",SPHEROID["wgs84",6378137,298.257223563],TOWGS84[0.000000,0.000000,0.000000]],',
+    'PRIMEM["Greenwich",0],',
+    'UNIT["degree",0.0174532925199433]',
+    ']'])
+
+import sys
+import os
+import shutil
+import atexit
+import urllib
+import urllib2
+import time
+
+import grass.script as grass
+
+def import_local_tile(tile, local, pid):
+    output = tile + '.r.in.srtm2.tmp.' + str(pid)
+    local_tile = str(tile) + '.hgt.zip'
+    
+    path = os.path.join(local, local_tile)
+    if os.path.exists(path):
+	path = os.path.join(local, tile)
+	grass.run_command('r.in.srtm', input = path, output = output, quiet = True)
+	return 1
+
+    # SRTM subdirs: Africa, Australia, Eurasia, Islands, North_America, South_America
+    for srtmdir in ('Africa', 'Australia', 'Eurasia', 'Islands', 'North_America', 'South_America'):
+	path = os.path.join(local, srtmdir, local_tile)
+
+	if os.path.exists(path):
+	    path = os.path.join(local, srtmdir, tile)
+	    grass.run_command('r.in.srtm', input = path, output = output, quiet = True)
+	    return 1
+
+    return 0
+
+def download_tile(tile, url, pid):
+    output = tile + '.r.in.srtm2.tmp.' + str(pid)
+    local_tile = str(tile) + '.hgt.zip'
+
+    urllib.urlcleanup()
+
+    # SRTM subdirs: Africa, Australia, Eurasia, Islands, North_America, South_America
+    for srtmdir in ('Africa', 'Australia', 'Eurasia', 'Islands', 'North_America', 'South_America'):
+	remote_tile = str(url) + str(srtmdir) + '/' + local_tile
+	goturl = 1
+    
+	try:
+	    f = urllib2.urlopen(remote_tile)
+	    fo = open(local_tile, 'w+b')
+	    fo.write(f.read())
+	    fo.close
+	    time.sleep(0.5)
+	    # does not work:
+	    #urllib.urlretrieve(remote_tile, local_tile, data = None)
+	except:
+	    goturl = 0
+	    pass
+	
+	if goturl == 1:
+	    return 1
+
+    return 0
+    
+    
+def cleanup():
+    if not in_temp:
+	return
+    os.chdir(currdir)
+    grass.run_command('g.region', region = tmpregionname)
+    grass.run_command('g.remove', region = tmpregionname, quiet = True)
+    #grass.try_rmdir(tmpdir)
+
+def main():
+    global tile, tmpdir, in_temp, currdir, tmpregionname
+
+    in_temp = False
+
+    url = options['url']
+    local = options['local']
+    output = options['output']
+    memory = options['memory']
+    fillnulls = flags['n']
+    
+    if len(url) == 0 and len(local) == 0:
+	grass.fatal(_("Either 'url' or 'local' is needed"))
+	
+    if len(local) == 0:
+	local = None
+
+    # are we in LatLong location?
+    s = grass.read_command("g.proj", flags='j')
+    kv = grass.parse_key_val(s)
+    if kv['+proj'] != 'longlat':
+	grass.fatal(_("This module only operates in LatLong locations"))
+
+    if fillnulls == 1 and memory <= 0:
+	grass.warning(_("Amount of memory to use for interpolation must be positive, setting to 300 MB"))
+	memory = '300'
+
+    # make a temporary directory
+    tmpdir = grass.tempfile()
+    grass.try_remove(tmpdir)
+    os.mkdir(tmpdir)
+    currdir = os.getcwd()
+    pid = os.getpid()
+
+    # change to temporary directory
+    os.chdir(tmpdir)
+    in_temp = True
+    if local is None:
+	local = tmpdir
+
+    # get extents
+    reg = grass.region()
+    tmpregionname = 'r_in_srtm2_tmp_region'
+    grass.run_command('g.region', save = tmpregionname)
+    if options['region'] is None or options['region'] == '':
+	north = reg['n']
+	south = reg['s']
+	east = reg['e']
+	west = reg['w']
+    else:
+	west, south, east, north = options['region'].split(',')
+	west = float(west)
+	south = float(south)
+	east = float(east)
+	north = float(north)
+
+    # adjust extents to cover SRTM tiles: 1 degree bounds
+    tmpint = int(north)
+    if tmpint < north:
+	north = tmpint + 1
+    else:
+	north = tmpint
+    tmpint = int(south)
+    if tmpint > south:
+	south = tmpint - 1
+    else:
+	south = tmpint
+    tmpint = int(east)
+    if tmpint < east:
+	east = tmpint + 1
+    else:
+	east = tmpint
+    tmpint = int(west)
+    if tmpint > west:
+	west = tmpint - 1
+    else:
+	west = tmpint
+	
+    rows = abs(north - south)
+    cols = abs(east - west)
+    ntiles = rows * cols
+    grass.message(_("Importing %d SRTM tiles...") % ntiles, flag = 'i')
+    counter = 1
+
+    srtmtiles = ''
+    valid_tiles = 0
+    for ndeg in range(south, north):
+	for edeg in range(west, east):
+	    grass.percent(counter, ntiles, 1)
+	    counter += 1
+	    if ndeg < 0:
+		tile = 'S'
+	    else:
+		tile = 'N'
+	    tile = tile + '%02d' % abs(ndeg)
+	    if edeg < 0:
+		tile = tile + 'W'
+	    else:
+		tile = tile + 'E'
+	    tile = tile + '%03d' % abs(edeg)
+	    grass.debug("Tile: %s" % tile, debug = 1)
+	    
+	    if local != tmpdir:
+		gotit = import_local_tile(tile, local, pid)
+	    else:
+		gotit = download_tile(tile, url, pid)
+		if gotit == 1:
+		    gotit = import_local_tile(tile, tmpdir, pid)
+	    if gotit == 1:
+		grass.verbose(_("Tile %s successfully imported") % tile)
+		valid_tiles += 1
+	    else:
+		# create tile with zeros
+		# north
+		if ndeg < 0:
+		    tmpn = '%02d:59:58.5S' % (abs(ndeg) - 2)
+		else:
+		    tmpn = '%02d:00:01.5N' % (ndeg + 1)
+		# south
+		if ndeg <= 0:
+		    tmps = '%02d:00:01.5S' % abs(ndeg)
+		else:
+		    tmps = '%02d:59:58.5N' % (ndeg - 1)
+		# east
+		if edeg < 0:
+		    tmpe = '%03d:59:58.5W' % (abs(edeg) - 2)
+		else:
+		    tmpe = '%03d:00:01.5E' % (edeg + 1)
+		# west
+		if edeg <= 0:
+		    tmpw = '%03d:00:01.5W' % abs(edeg)
+		else:
+		    tmpw = '%03d:59:58.5E' % (edeg - 1)
+
+		grass.run_command('g.region', n = tmpn, s = tmps, e = tmpe, w = tmpw, res = '00:00:03')
+		grass.run_command('r.mapcalc', expression = "%s = 0" % (tile + '.r.in.srtm2.tmp.' + str(pid)), quiet = True)
+		grass.run_command('g.region', region = tmpregionname)
+
+
+    # g.mlist with fs = comma does not work ???
+    srtmtiles = grass.read_command('g.mlist',
+                                   type = 'rast',
+				   pattern = '*.r.in.srtm2.tmp.%d' % pid,
+				   fs = 'newline',
+				   quiet = True)
+
+    srtmtiles = srtmtiles.splitlines()
+    srtmtiles = ','.join(srtmtiles)
+
+    if valid_tiles == 0:
+	grass.run_command('g.remove', rast = str(srtmtiles), quiet = True)
+	grass.warning(_("No tiles imported"))
+	if local != tmpdir:
+	    grass.fatal(_("Please check if local folder <%s> is correct.") % local)
+	else:
+	    grass.fatal(_("Please check internet connection and if url <%s> is correct.") % url)
+
+    grass.run_command('g.region', rast = str(srtmtiles));
+    
+    if fillnulls == 0:
+	grass.run_command('r.patch', input = srtmtiles, output = output)
+    else:
+	ncells = grass.region()['cells'] 
+	if long(ncells) > 1000000000:
+	    grass.message(_("%s cells to interpolate, this will take some time") % str(ncells), flag = 'i')
+	grass.run_command('r.patch', input = srtmtiles, output = output + '.holes')
+	mapstats = grass.parse_command('r.univar', map = output + '.holes', flags = 'g', quiet = True)
+	if mapstats['null_cells'] == '0':
+	    grass.run_command('g.rename', rast = '%s,%s' % (output + '.holes', output), quiet = True)
+	else:
+	    grass.run_command('r.resamp.bspline',
+			      input = output + '.holes',
+			      output = output + '.interp',
+			      se = '0.0025', sn = '0.0025',
+			      method = 'bilinear',
+			      memory = memory,
+			      flags = 'n')
+	    grass.run_command('r.patch',
+	                      input = '%s,%s' % (output + '.holes',
+			      output + '.interp'),
+			      output = output + '.float',
+			      flags = 'z')
+	    grass.run_command('r.mapcalc', expression = '%s = round(%s)' % (output, output + '.float'))
+	    grass.run_command('g.remove',
+			      rast = '%s,%s,%s' % (output + '.holes', output + '.interp', output + '.float'),
+			      quiet = True)
+
+    grass.run_command('g.remove', rast = str(srtmtiles), quiet = True)
+
+    # nice color table
+    grass.run_command('r.colors', map = output, color = 'srtm', quiet = True)
+
+    # write metadata:
+    tmphist = grass.tempfile()
+    f = open(tmphist, 'w+')
+    f.write(os.environ['CMDLINE'])
+    f.close()
+    grass.run_command('r.support', map = output,
+		      loadhistory = tmphist,
+		      description = 'generated by r.in.srtm.region',
+		      source1 = 'SRTM V2.1',
+		      source2 = (local if local != tmpdir else url))
+    grass.try_remove(tmphist)
+
+    grass.message(_("Done: generated map <%s>") % output)
+
+if __name__ == "__main__":
+    options, flags = grass.parser()
+    atexit.register(cleanup)
+    main()


Property changes on: grass-addons/grass7/grass7/raster/r.in.srtm.region/r.in.srtm.region.py
___________________________________________________________________
Added: svn:executable
   + 

Added: grass-addons/grass7/grass7/raster/r.in.wms2/Makefile
===================================================================
--- grass-addons/grass7/grass7/raster/r.in.wms2/Makefile	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.in.wms2/Makefile	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,18 @@
+MODULE_TOPDIR = ../..
+
+PGM = r.in.wms2
+
+MODULES = wms_base wms_drv wms_gdal_drv
+PYFILES := $(patsubst %,$(ETC)/%.py,$(MODULES))
+PYCFILES := $(patsubst %,$(ETC)/%.pyc,$(MODULES))
+
+include $(MODULE_TOPDIR)/include/Make/Script.make
+include $(MODULE_TOPDIR)/include/Make/Python.make
+
+default: script $(PYFILES) $(PYCFILES)
+
+$(ETCDIR):
+	$(MKDIR) $@
+
+$(ETC)/%: % | $(ETC)
+	$(INSTALL_DATA) $< $@

Added: grass-addons/grass7/grass7/raster/r.in.wms2/r.in.wms2.html
===================================================================
--- grass-addons/grass7/grass7/raster/r.in.wms2/r.in.wms2.html	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.in.wms2/r.in.wms2.html	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,81 @@
+<h2>DESCRIPTION</h2>
+
+<em>r.in.wms2</em> handles all of downloading and importing raster
+data from an <a href="http://www.opengeospatial.org/standards/wms">OGC
+WMS</a> and <a href="http://www.opengeospatial.org/standards/wmts">OGC
+WMTS</a> web mapping servers. It need only be told the desired data to
+collect (bounds and resolution) via a region, the server to get the
+data from, and the layer or layers to get. It downloads the data in
+tiles, reprojects it, imports it, and patches it back together.
+
+<h2>NOTES</h2>
+
+<!--
+By default data is downloaded to <tt>$GISDBASE/wms_download</tt>. This can be changed
+by setting the <b>folder</b> option when using <em>r.in.wms</em>.
+-->
+
+<p>To understand the data you are getting it is necessary to look at the
+capabilities of the WMS server. This should be available via a capabilities
+request. This is an
+<a href="http://wms.jpl.nasa.gov/wms.cgi?request=GetCapabilities">example
+capabilities request to NASA's OnEarth server</a>.
+
+<h2>EXAMPLES</h2>
+
+<h3>General Get Capabilities Request</h3>
+
+<div class="code"><pre>
+r.in.wms2 -c url=http://wms.cuzk.cz/wms.asp
+</pre></div>
+
+<h3>>Download raster data from WMS server (GetMap request)</h3>
+
+
+World extend data:
+
+<div class="code"><pre>
+r.in.wms2 url=http://iceds.ge.ucl.ac.uk/cgi-bin/icedswms layers=bluemarble,landsat_1_01 styles=default,default output=landsat srs=4326 format=png 
+</pre></div>
+* Server supports only WMS 1.1.1 <br>
+
+<div class="code"><pre>
+r.in.wms2 url=http://132.156.97.59/cgi-bin/worldmin_en-ca_ows layers=GSC:WORLD_PrecambrianDomains output=pokus srs=4326 format=jpeg 
+</pre></div>
+* Server supports only WMS 1.1.1 
+<br>
+<br>
+
+<div class="code"><pre>
+r.in.wms2 url=http://gpp3-wxs.ign.fr/yourAPIkey/geoportail/wmts layers=ORTHOIMAGERY.ORTHOPHOTOS output=orthophoto srs=3857 format=jpeg driver=WMTS_GRASS style=normal password=* username=*
+</pre></div>
+* Username, password and API key can be get at <a href="http://api.ign.fr/">IGN API</a> website
+<br>
+<br>
+
+Data in extend of Czech Republic:
+
+<div class="code"><pre>
+r.in.wms2 output=kn url=http://wms.cuzk.cz/wms.asp layers=prehledka_kraju-linie srs=4326 format=png
+</pre></div>
+
+<div class="code"><pre>
+r.in.wms2 url=http://geoportal.cuzk.cz/WMTS_ORTOFOTO/WMTService.aspx layers=orto output=ortofoto srs=3857 format=jpeg driver=WMTS_GRASS style=default
+</pre></div>
+
+<h2>SEE ALSO</h2>
+
+<em>
+  <a href="r.in.gdal.html">r.in.gdal</a>,
+  <a href="r.patch.html">r.patch</a>,
+  <a href="r.colors.html">r.colors</a>,
+  <a href="r.composite.html">r.composite</a>,
+  <a href="v.in.wfs.html">v.in.wfs</a>
+</em>
+
+<h2>AUTHORS</h2>
+
+Stepan Turek, Czech Technical University in Prague, Czech Republic (bachelor's final project 2012, mentor: Martin Landa) 
+
+<p>
+<i>Last changed: $Date: 2012-10-10 00:02:55 +0200 (Wed, 10 Oct 2012) $</i>

Added: grass-addons/grass7/grass7/raster/r.in.wms2/r.in.wms2.py
===================================================================
--- grass-addons/grass7/grass7/raster/r.in.wms2/r.in.wms2.py	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.in.wms2/r.in.wms2.py	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,182 @@
+#!/usr/bin/env python
+"""
+MODULE:    r.in.wms2
+
+AUTHOR(S): Stepan Turek <stepan.turek AT seznam.cz>
+
+PURPOSE:   Downloads and imports data from WMS server.
+
+COPYRIGHT: (C) 2012 Stepan Turek, and by the GRASS Development Team
+
+This program is free software under the GNU General Public License
+(>=v2). Read the file COPYING that comes with GRASS for details.
+"""
+
+#%module
+#% description: Downloads and imports data from WMS servers.
+#% keywords: raster
+#% keywords: import
+#% keywords: wms
+#%end
+
+#%option
+#% key: url
+#% type: string
+#% description:URL of WMS server 
+#% required: yes
+#%end
+
+#%option
+#% key: layers
+#% type: string
+#% description: Layers to request from map server
+#% multiple: yes
+#% required: yes
+#%end
+
+#%option G_OPT_R_OUTPUT
+#% description: Name for output raster map
+#%end
+
+#%option
+#% key: srs
+#% type: integer
+#% description: EPSG number of source projection for request 
+#% answer:4326 
+#% guisection: Request properties
+#%end
+
+#%option
+#% key: region
+#% type: string
+#% description: Named region to request data for. Current region used if omitted
+#% guisection: Request properties
+#%end
+
+#%option
+#% key: wms_version
+#% type:string
+#% description:WMS standard
+#% options:1.1.1,1.3.0
+#% answer:1.1.1
+#% guisection: Request properties
+#%end
+
+#%option
+#% key: format
+#% type: string
+#% description: Image format requested from the server
+#% options: geotiff,tiff,jpeg,gif,png
+#% answer: geotiff
+#% guisection: Request properties
+#%end
+
+#%option
+#% key: method
+#% type: string
+#% description: Reprojection method to use
+#% options:near,bilinear,cubic,cubicspline
+#% answer:near
+#% guisection: Request properties
+#%end
+
+#%option
+#% key: maxcols
+#% type:integer
+#% description: Maximum columns to request at a time
+#% answer:400
+#% guisection: Request properties
+#%end
+
+#%option
+#% key: maxrows
+#% type: integer
+#% description: Maximum rows to request at a time
+#% answer: 300
+#% guisection: Request properties
+#%end
+
+#%option
+#% key: urlparams
+#% type:string
+#% description: Additional query parameters for server
+#% guisection: Request properties
+#%end
+
+#%option
+#% key: username
+#% type:string
+#% description: Username for server connection
+#% guisection: Request properties
+#%end
+
+#%option
+#% key: password
+#% type:string
+#% description: Password for server connection
+#% guisection: Request properties
+#%end
+
+#%option
+#% key: styles
+#% type: string
+#% description: Styles to request from map server
+#% multiple: yes
+#% guisection: Map style
+#%end
+
+#%option
+#% key: bgcolor
+#% type: string
+#% description: Color of map background
+#% guisection: Map style
+#%end
+
+#%flag
+#% key: o
+#% description: Don't request transparent data
+#% guisection: Map style
+#%end
+
+#%flag
+#% key: c
+#% description: Get capabilities
+#% guisection: Request properties
+#% suppress_required: yes
+#%end
+
+#%option
+#% key: driver
+#% type:string
+#% description: Driver for communication with server
+#% options:WMS_GDAL, WMS_GRASS, WMTS_GRASS
+#% answer:WMS_GDAL
+#%end
+
+
+import os
+import sys
+sys.path.insert(1, os.path.join(os.path.dirname(sys.path[0]), 'etc', 'r.in.wms2'))
+
+import grass.script as grass
+
+def main():
+    if 'GRASS' in options['driver']:
+        grass.debug("Using GRASS driver")
+        from wms_drv import WMSDrv
+        wms = WMSDrv()
+    elif 'GDAL' in options['driver']:
+        grass.debug("Using GDAL WMS driver")
+        from wms_gdal_drv import WMSGdalDrv
+        wms = WMSGdalDrv()
+    
+    if flags['c']:
+        wms.GetCapabilities(options)
+    else:
+        wms.GetMap(options, flags)  
+    
+    return 0
+
+if __name__ == "__main__":
+    options, flags = grass.parser()
+    sys.exit(main())


Property changes on: grass-addons/grass7/grass7/raster/r.in.wms2/r.in.wms2.py
___________________________________________________________________
Added: svn:executable
   + 

Added: grass-addons/grass7/grass7/raster/r.in.wms2/wms_base.py
===================================================================
--- grass-addons/grass7/grass7/raster/r.in.wms2/wms_base.py	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.in.wms2/wms_base.py	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,400 @@
+import os
+from   math import ceil
+
+from urllib2 import urlopen, HTTPError, URLError
+from httplib import HTTPException
+
+import grass.script as grass
+
+class WMSBase:
+    def __init__(self):
+        # these variables are information for destructor
+        self.temp_files_to_cleanup = []
+        self.cleanup_mask   = False
+        self.cleanup_layers = False
+        
+        self.params = {}
+        self.tile_size = {'bbox' : None}
+
+        self.temp_map = None
+        
+    def __del__(self):
+        # removes temporary mask, used for import transparent or warped temp_map
+        if self.cleanup_mask:
+            # clear temporary mask, which was set by module      
+            if grass.run_command('r.mask',
+                                 quiet = True,
+                                 flags = 'r') != 0:  
+                grass.fatal(_('%s failed') % 'r.mask')
+            
+            # restore original mask, if exists 
+            if grass.find_file(self.params['output'] + self.original_mask_suffix, element = 'cell', mapset = '.' )['name']:
+                if grass.run_command('g.copy',
+                                     quiet = True,
+                                     rast =  self.params['output'] + self.original_mask_suffix + ',MASK') != 0:
+                    grass.fatal(_('%s failed') % 'g.copy')
+        
+        # tries to remove temporary files, all files should be
+        # removed before, implemented just in case of unexpected
+        # stop of module
+        for temp_file in self.temp_files_to_cleanup:
+            grass.try_remove(temp_file)
+        
+        # remove temporary created rasters
+        if self.cleanup_layers: 
+            maps = []
+            for suffix in ('.red', '.green', '.blue', '.alpha', self.original_mask_suffix):
+                rast = self.params['output'] + suffix
+                if grass.find_file(rast, element = 'cell', mapset = '.')['file']:
+                    maps.append(rast)
+            
+            if maps:
+                grass.run_command('g.remove',
+                                  quiet = True,
+                                  flags = 'f',
+                                  rast  = ','.join(maps))
+        
+        # deletes environmental variable which overrides region 
+        if 'GRASS_REGION' in os.environ.keys():
+            os.environ.pop('GRASS_REGION')
+        
+    def _debug(self, fn, msg):
+        grass.debug("%s.%s: %s" %
+                    (self.__class__.__name__, fn, msg))
+        
+    def _initializeParameters(self, options, flags):
+        self._debug("_initialize_parameters", "started")
+        
+        # initialization of module parameters (options, flags)
+
+        self.params['driver'] = options['driver']
+
+        self.flags = flags
+
+        if self.flags['o'] and 'WMS' not in self.params['driver']:
+            grass.warning(_("Flag '%s' is relevant only for WMS.") % 'o')
+        elif self.flags['o']:
+            self.params['transparent'] = 'FALSE'
+        else:
+            self.params['transparent'] = 'TRUE'   
+
+        for key in ['url', 'layers', 'styles', 'output', 'method']:
+            self.params[key] = options[key].strip()
+
+        for key in ['password', 'username', 'urlparams']:
+            self.params[key] = options[key] 
+            if self.params[key] != "" and 'GRASS' not in self.params['driver']:
+                grass.warning(_("Parameter '%s' is relevant only for %s drivers.") % (key, '*_GRASS'))
+        
+        self.params['bgcolor'] = options['bgcolor'].strip()
+        if self.params['bgcolor'] != "" and 'WMS_GRASS' not in self.params['driver']:
+            grass.warning(_("Parameter '%s' is relevant only for %s driver.") % ('bgcolor', 'WMS_GRASS'))
+                
+        self.params['wms_version'] = options['wms_version']        
+        if self.params['wms_version'] == "1.3.0":
+            self.params['proj_name'] = "CRS"
+        else:
+            self.params['proj_name'] = "SRS" 
+        
+        if  options['format'] == "geotiff":
+            self.params['format'] = "image/geotiff"
+        elif options['format'] == "tiff":
+            self.params['format'] = "image/tiff"
+        elif options['format'] == "png":
+            self.params['format'] = "image/png"
+        elif  options['format'] == "jpeg":
+            self.params['format'] = "image/jpeg"
+            if flags['o']:
+                grass.warning(_("JPEG format does not support transparency"))
+        elif self.params['format'] == "gif":
+            self.params['format'] = "image/gif"
+        else:
+            self.params['format'] = self.params['format']
+        
+        self.params['srs'] = int(options['srs'])
+        if self.params['srs'] <= 0:
+            grass.fatal(_("Invalid EPSG code %d") % self.params['srs'])
+        
+        # read projection info
+        self.proj_location = grass.read_command('g.proj', 
+                                                flags ='jf').rstrip('\n')
+
+        if self.params['srs'] in [3857, 900913]:
+            # HACK: epsg 3857 def: http://spatialreference.org/ref/sr-org/7483/
+            # g.proj can return: ...+a=6378137 +rf=298.257223563... (WGS84 elipsoid def instead of sphere), it can make 20km shift in Y, when raster is transformed
+            # needed to be tested on more servers
+            self.proj_srs = '+proj=merc +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0 +k=1.0 +no_defs +a=6378137 +b=6378137 +nadgrids=@null +to_meter=1 +wktext'
+        else:
+            self.proj_srs = grass.read_command('g.proj', 
+                                               flags = 'jf', 
+                                               epsg = str(self.params['srs']) ).rstrip('\n')
+
+        if not self.proj_srs or not self.proj_location:
+            grass.fatal(_("Unable to get projection info"))
+        
+        # set region 
+        self.params['region'] = options['region']
+        if self.params['region']:                 
+            if not grass.find_file(name = self.params['region'], element = 'windows', mapset = '.' )['name']:
+                grass.fatal(_("Region <%s> not found") % self.params['region'])
+        
+        if self.params['region']:
+            s = grass.read_command('g.region',
+                                   quiet = True,
+                                   flags = 'ug',
+                                   region = self.params['region'])
+            self.region = grass.parse_key_val(s, val_type = float)
+        else:
+            self.region = grass.region()
+        
+        min_tile_size = 100
+        maxcols = int(options['maxcols'])
+        if maxcols <= min_tile_size:
+            grass.fatal(_("Maxcols must be greater than 100"))
+        
+        maxrows = int(options['maxrows'])
+        if maxrows <= min_tile_size:
+            grass.fatal(_("Maxrows must be greater than 100"))
+        
+        # setting optimal tile size according to maxcols and maxrows constraint and region cols and rows      
+        self.tile_size['cols'] = int(self.region['cols'] / ceil(self.region['cols'] / float(maxcols)))
+        self.tile_size['rows'] = int(self.region['rows'] / ceil(self.region['rows'] / float(maxrows)))
+        
+        # suffix for existing mask (during overriding will be saved
+        # into raster named:self.params['output'] + this suffix)
+        self.original_mask_suffix = "_temp_MASK"
+        
+        # check names of temporary rasters, which module may create 
+        maps = []
+        for suffix in ('.red', '.green', '.blue', '.alpha', self.original_mask_suffix ):
+            rast = self.params['output'] + suffix
+            if grass.find_file(rast, element = 'cell', mapset = '.')['file']:
+                maps.append(rast)
+        
+        if len(maps) != 0:
+            grass.fatal(_("Please change output name, or change names of these rasters: %s, "
+                          "module needs to create this temporary maps during runing") % ",".join(maps))
+        
+        # default format for GDAL library
+        self.gdal_drv_format = "GTiff"
+        
+        self._debug("_initialize_parameters", "finished")
+
+    def GetMap(self, options, flags):
+        """!Download data from WMS server and import data
+        (using GDAL library) into GRASS as a raster map."""
+
+        self._initializeParameters(options, flags)  
+
+        self.bbox     = self._computeBbox()
+        
+        self.temp_map = self._download()
+
+        if not self.temp_map:
+            return
+
+        self._createOutputMap() 
+    
+    def _fetchCapabilities(self, options): 
+        """!Download capabilities from WMS server
+        """
+        # download capabilities file
+        cap_url = options['url']
+
+        if 'WMTS' in options['driver']:
+            cap_url += "?SERVICE=WMTS&REQUEST=GetCapabilities&VERSION=1.0.0"
+        else:
+            cap_url += "?SERVICE=WMS&REQUEST=GetCapabilities&VERSION=" + options['wms_version'] 
+
+        try:
+            cap = urlopen(cap_url)
+        except (IOError, HTTPError):
+            grass.fatal(_("Unable to get capabilities from '%s'") % options['url'])
+        
+        return cap
+
+    def GetCapabilities(self, options): 
+        """!Get capabilities from WMS server
+        """
+        cap  = self._fetchCapabilities(options)
+        cap_lines = cap.readlines()
+        for line in cap_lines: 
+            print line 
+        
+    def _computeBbox(self):
+        """!Get region extent for WMS query (bbox)
+        """
+        self._debug("_computeBbox", "started")
+        
+        bbox_region_items = {'maxy' : 'n', 'miny' : 's', 'maxx' : 'e', 'minx' : 'w'}  
+        bbox = {}
+
+        if self.proj_srs == self.proj_location: # TODO: do it better
+            for bbox_item, region_item in bbox_region_items.iteritems():
+                bbox[bbox_item] = self.region[region_item]
+        
+        # if location projection and wms query projection are
+        # different, corner points of region are transformed into wms
+        # projection and then bbox is created from extreme coordinates
+        # of the transformed points
+        else:
+            for bbox_item, region_item  in bbox_region_items.iteritems():
+                bbox[bbox_item] = None
+
+            temp_region = self._tempfile()
+            
+            try:
+                temp_region_opened = open(temp_region, 'w')
+                temp_region_opened.write("%f %f\n%f %f\n%f %f\n%f %f\n"  %\
+                                       (self.region['e'], self.region['n'],\
+                                        self.region['w'], self.region['n'],\
+                                        self.region['w'], self.region['s'],\
+                                        self.region['e'], self.region['s'] ))
+            except IOError:
+                 grass.fatal(_("Unable to write data into tempfile"))
+            finally:           
+                temp_region_opened.close()            
+
+            points = grass.read_command('m.proj', flags = 'd',
+                                        proj_output = self.proj_srs,
+                                        proj_input = self.proj_location,
+                                        input = temp_region) # TODO: stdin
+            grass.try_remove(temp_region)
+            if not points:
+                grass.fatal(_("Unable to determine region, %s failed") % 'm.proj')
+            
+            points = points.splitlines()
+            if len(points) != 4:
+                grass.fatal(_("Region definition: 4 points required"))
+            
+            for point in points:
+                try:
+                    point = map(float, point.split("|"))
+                except ValueError:
+                    grass.fatal(_('Reprojection of region using m.proj failed.'))
+                if not bbox['maxy']:
+                    bbox['maxy'] = point[1]
+                    bbox['miny'] = point[1]
+                    bbox['maxx'] = point[0]
+                    bbox['minx'] = point[0]
+                    continue
+                
+                if   bbox['maxy'] < point[1]:
+                    bbox['maxy'] = point[1]
+                elif bbox['miny'] > point[1]:
+                    bbox['miny'] = point[1]
+                
+                if   bbox['maxx'] < point[0]:
+                    bbox['maxx'] = point[0]
+                elif bbox['minx'] > point[0]:
+                    bbox['minx'] = point[0]  
+        
+        self._debug("_computeBbox", "finished -> %s" % bbox)
+
+        # Ordering of coordinates axis of geographic coordinate
+        # systems in WMS 1.3.0 is flipped. If  self.tile_size['flip_coords'] is 
+        # True, coords in bbox need to be flipped in WMS query.
+
+        return bbox
+
+    def _createOutputMap(self): 
+        """!Import downloaded data into GRASS, reproject data if needed
+        using gdalwarp
+        """
+        # reprojection of raster
+        if self.proj_srs != self.proj_location: # TODO: do it better
+            grass.message(_("Reprojecting raster..."))
+            temp_warpmap = self._tempfile()
+            
+            if int(os.getenv('GRASS_VERBOSE', '2')) <= 2:
+                nuldev = file(os.devnull, 'w+')
+            else:
+                nuldev = None
+            
+            #"+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0 +k=1.0 +units=m +nadgrids=@null +no_defs"
+            # RGB rasters - alpha layer is added for cropping edges of projected raster
+            if self.temp_map_bands_num == 3:
+                ps = grass.Popen(['gdalwarp',
+                                  '-s_srs', '%s' % self.proj_srs,
+                                  '-t_srs', '%s' % self.proj_location,
+                                  '-r', self.params['method'], '-dstalpha',
+                                  self.temp_map, temp_warpmap], stdout = nuldev)
+            # RGBA rasters
+            else:
+                ps = grass.Popen(['gdalwarp',
+                                  '-s_srs', '%s' % self.proj_srs,
+                                  '-t_srs', '%s' % self.proj_location,
+                                  '-r', self.params['method'],
+                                  self.temp_map, temp_warpmap], stdout = nuldev)
+            ps.wait()
+            
+            if nuldev:
+                nuldev.close()
+            
+            if ps.returncode != 0:
+                grass.fatal(_('%s failed') % 'gdalwarp')
+        # raster projection is same as projection of location
+        else:
+            temp_warpmap = self.temp_map
+        
+        grass.message(_("Importing raster map into GRASS..."))
+        # importing temp_map into GRASS
+        if grass.run_command('r.in.gdal',
+                             quiet = True,
+                             input = temp_warpmap,
+                             output = self.params['output']) != 0:
+            grass.fatal(_('%s failed') % 'r.in.gdal')
+        
+        # information for destructor to cleanup temp_layers, created
+        # with r.in.gdal
+        self.cleanup_layers = True
+        
+        # setting region for full extend of imported raster
+        os.environ['GRASS_REGION'] = grass.region_env(rast = self.params['output'] + '.red')
+        
+        # mask created from alpha layer, which describes real extend
+        # of warped layer (may not be a rectangle), also mask contains
+        # transparent parts of raster
+        if grass.find_file( self.params['output'] + '.alpha', element = 'cell', mapset = '.' )['name']:
+            # saving current mask (if exists) into temp raster
+            if grass.find_file('MASK', element = 'cell', mapset = '.' )['name']:
+                if grass.run_command('g.copy',
+                                     quiet = True,
+                                     rast = 'MASK,' + self.params['output'] + self.original_mask_suffix) != 0:    
+                    grass.fatal(_('%s failed') % 'g.copy')
+            
+            # info for destructor
+            self.cleanup_mask = True
+            if grass.run_command('r.mask',
+                                 quiet = True,
+                                 overwrite = True,
+                                 maskcats = "0",
+                                 flags = 'i',
+                                 input = self.params['output'] + '.alpha') != 0: 
+                grass.fatal(_('%s failed') % 'r.mask')
+        
+        if grass.run_command('r.composite',
+                             quiet = True,
+                             red = self.params['output'] + '.red',
+                             green = self.params['output'] +  '.green',
+                             blue = self.params['output'] + '.blue',
+                             output = self.params['output'] ) != 0:
+                grass.fatal(_('%s failed') % 'r.composite')
+        
+        grass.try_remove(temp_warpmap)
+        grass.try_remove(self.temp_map) 
+
+    def _tempfile(self):
+        """!Create temp_file and append list self.temp_files_to_cleanup 
+            with path of file 
+     
+        @return string path to temp_file
+        """
+        temp_file = grass.tempfile()
+        if temp_file is None:
+            grass.fatal(_("Unable to create temporary files"))
+        
+        # list of created tempfiles for destructor
+        self.temp_files_to_cleanup.append(temp_file)
+        
+        return temp_file

Added: grass-addons/grass7/grass7/raster/r.in.wms2/wms_drv.py
===================================================================
--- grass-addons/grass7/grass7/raster/r.in.wms2/wms_drv.py	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.in.wms2/wms_drv.py	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,603 @@
+
+import grass.script as grass 
+from urllib2 import urlopen, HTTPError
+from httplib import HTTPException
+
+try:
+    from osgeo import gdal
+    from osgeo import gdalconst 
+except:
+    grass.fatal(_("Unable to load GDAL python bindings"))
+
+import urllib2
+import xml.etree.ElementTree as etree
+
+import numpy as Numeric
+Numeric.arrayrange = Numeric.arange
+
+from math import pi, floor
+from wms_base import WMSBase
+
+class WMSDrv(WMSBase):
+    def _download(self):
+        """!Downloads data from WMS server using own driver
+        
+        @return temp_map with downloaded data
+        """ 
+        grass.message(_("Downloading data from WMS server..."))
+
+        # initialize correct manager according to chosen OGC service
+        if self.params['driver'] == 'WMTS_GRASS':
+            req_mgr = WMTSRequestMgr(self.params, self.bbox, self.region, self.proj_srs, self._fetchCapabilities(self.params))
+        elif self.params['driver'] == 'WMS_GRASS':
+            req_mgr = WMSRequestMgr(self.params, self.bbox, self.region, self.tile_size, self.proj_srs)
+
+        # set password and username to urlib2
+        if self.params['username']:
+            passman = urllib2.HTTPPasswordMgrWithDefaultRealm()
+            passman.add_password(None, self.params['url'], self.params['username'], self.params['password'])
+            auth_handler = urllib2.HTTPBasicAuthHandler(passman)
+            opener = urllib2.build_opener(auth_handler)
+            urllib2.install_opener(opener)
+
+        # get information about size in pixels and bounding box of raster, where all tiles will be joined
+        map_region = req_mgr.GetMapRegion()
+
+        init = True
+        temp_map = None
+
+        # iterate through all tiles and download them
+        while True:
+
+            # get url for request the tile and information for placing the tile into raster with other tiles
+            tile = req_mgr.GetNextTile()
+
+            # if last tile has been already downloaded 
+            if not tile:
+                break
+
+            # url for request the tile
+            query_url = tile[0]
+
+            # the tile size and offset in pixels for placing it into raster where tiles are joined
+            tileRef = tile[1]
+
+            grass.debug(query_url)
+            try: 
+                wms_data = urllib2.urlopen(query_url)
+            except (IOError, HTTPException), e:
+                if HTTPError == type(e) and e.code == 401:
+                    grass.fatal(_("Authorization failed"))           
+                else:
+                    grass.fatal(_("Unable to fetch data from server")) 
+
+            temp_tile = self._tempfile()
+                
+            # download data into temporary file
+            try:
+                temp_tile_opened = open(temp_tile, 'w')
+                temp_tile_opened.write(wms_data.read())
+            except IOError:
+                grass.fatal(_("Unable to write data into tempfile"))
+            finally:
+                temp_tile_opened.close()
+                
+            tile_dataset_info = gdal.Open(temp_tile, gdal.GA_ReadOnly) 
+            if tile_dataset_info is None:
+                # print error xml returned from server
+                try:
+                    error_xml_opened = open(temp_tile, 'r')
+                    err_str = error_xml_opened.read()     
+                except IOError:
+                    grass.fatal(_("Unable to read data from tempfile"))
+                finally:
+                    error_xml_opened.close()
+
+                if  err_str is not None:
+                    grass.fatal(_("WMS server error: %s") %  err_str)
+                else:
+                    grass.fatal(_("WMS server unknown error") )
+                
+            band = tile_dataset_info.GetRasterBand(1) 
+            cell_type_func = band.__swig_getmethods__["DataType"]#??
+            bands_number_func = tile_dataset_info.__swig_getmethods__["RasterCount"]
+                
+            temp_tile_pct2rgb = None
+            if bands_number_func(tile_dataset_info) == 1 and band.GetRasterColorTable() is not None:
+                # expansion of color table into bands 
+                temp_tile_pct2rgb = self._tempfile()
+                tile_dataset = self._pct2rgb(temp_tile, temp_tile_pct2rgb)
+            else: 
+                tile_dataset = tile_dataset_info
+                
+            # initialization of temp_map_dataset, where all tiles are merged
+            if init:
+                temp_map = self._tempfile()
+                    
+                driver = gdal.GetDriverByName(self.gdal_drv_format)
+                metadata = driver.GetMetadata()
+                if not metadata.has_key(gdal.DCAP_CREATE) or \
+                       metadata[gdal.DCAP_CREATE] == 'NO':
+                    grass.fatal(_('Driver %s does not supports Create() method') % drv_format)  
+                    
+                self.temp_map_bands_num = bands_number_func(tile_dataset)
+                temp_map_dataset = driver.Create(temp_map, map_region['cols'], map_region['rows'],
+                                                 self.temp_map_bands_num, cell_type_func(band))
+                init = False
+                
+            # tile is written into temp_map
+            tile_to_temp_map = tile_dataset.ReadRaster(0, 0, tileRef['sizeX'], tileRef['sizeY'],
+                                                             tileRef['sizeX'], tileRef['sizeY'])
+                
+            temp_map_dataset.WriteRaster(tileRef['t_cols_offset'], tileRef['t_rows_offset'],
+                                         tileRef['sizeX'],  tileRef['sizeY'], tile_to_temp_map) 
+                
+            tile_dataset = None
+            tile_dataset_info = None
+            grass.try_remove(temp_tile)
+            grass.try_remove(temp_tile_pct2rgb)    
+        
+        if not temp_map:
+            return temp_map
+        # georeferencing and setting projection of temp_map
+        projection = grass.read_command('g.proj', 
+                                        flags = 'wf',
+                                        epsg =self.params['srs']).rstrip('\n')
+        temp_map_dataset.SetProjection(projection)
+
+        pixel_x_length = (map_region['maxx'] - map_region['minx']) / int(map_region['cols'])
+        pixel_y_length = (map_region['miny'] - map_region['maxy']) / int(map_region['rows'])
+
+        geo_transform = [map_region['minx'] , pixel_x_length  , 0.0 , map_region['maxy'] , 0.0 , pixel_y_length] 
+        temp_map_dataset.SetGeoTransform(geo_transform )
+        temp_map_dataset = None
+        
+        return temp_map
+    
+    def _pct2rgb(self, src_filename, dst_filename):
+        """!Create new dataset with data in dst_filename with bands according to src_filename 
+        raster color table - modified code from gdal utility pct2rgb
+        
+        @return new dataset
+        """  
+        out_bands = 4
+        band_number = 1
+        
+        # open source file
+        src_ds = gdal.Open(src_filename)
+        if src_ds is None:
+            grass.fatal(_('Unable to open %s ' % src_filename))
+            
+        src_band = src_ds.GetRasterBand(band_number)
+        
+        # Build color table
+        lookup = [ Numeric.arrayrange(256), 
+                   Numeric.arrayrange(256), 
+                   Numeric.arrayrange(256), 
+                   Numeric.ones(256)*255 ]
+        
+        ct = src_band.GetRasterColorTable()	
+        if ct is not None:
+            for i in range(min(256,ct.GetCount())):
+                entry = ct.GetColorEntry(i)
+                for c in range(4):
+                    lookup[c][i] = entry[c]
+        
+        # create the working file
+        gtiff_driver = gdal.GetDriverByName(self.gdal_drv_format)
+        tif_ds = gtiff_driver.Create(dst_filename,
+                                     src_ds.RasterXSize, src_ds.RasterYSize, out_bands)
+        
+        # do the processing one scanline at a time
+        for iY in range(src_ds.RasterYSize):
+            src_data = src_band.ReadAsArray(0,iY,src_ds.RasterXSize,1)
+            
+            for iBand in range(out_bands):
+                band_lookup = lookup[iBand]
+                
+                dst_data = Numeric.take(band_lookup,src_data)
+                tif_ds.GetRasterBand(iBand+1).WriteArray(dst_data,0,iY)
+        
+        return tif_ds       
+
+class BaseRequestMgr:
+    """!Base class for request managers. 
+    """
+    def _isGeoProj(self, proj):
+        """!Is it geographic projection? 
+        """       
+        if (proj.find("+proj=latlong")  != -1 or \
+            proj.find("+proj=longlat")  != -1):
+
+            return True
+        return False
+
+    def find(self, etreeElement, tag, ns = None):
+        """!Wraper for etree element find method. 
+        """
+        if not ns:
+            res = etreeElement.find(tag)
+        else:
+            res = etreeElement.find(ns(tag))
+
+        if res is None:
+            grass.fatal(_("Unable to parse capabilities file. \n Tag '%s' was not found.") % tag)
+
+        return res
+
+    def findall(self, etreeElement, tag, ns = None):
+        """!Wraper for etree element findall method. 
+        """
+        if not ns:
+            res = etreeElement.findall(tag)
+        else:
+            res = etreeElement.findall(ns(tag))
+
+        if not res:
+            grass.fatal(_("Unable to parse capabilities file. \n Tag '%s' was not found.") % tag)
+
+        return res
+
+class WMSRequestMgr(BaseRequestMgr):
+    def __init__(self, params, bbox, region, tile_size, proj_srs, cap_file = None):
+        """!Initialize data needed for iteration through tiles.
+        """
+        self.version = params['wms_version']
+        proj = params['proj_name'] + "=EPSG:"+ str(params['srs'])
+        self.url = params['url'] + ("?SERVICE=WMS&REQUEST=GetMap&VERSION=%s&LAYERS=%s&WIDTH=%s&HEIGHT=%s&STYLES=%s&BGCOLOR=%s&TRANSPARENT=%s" % \
+                  (params['wms_version'], params['layers'], tile_size['cols'], tile_size['rows'], params['styles'], \
+                   params['bgcolor'], params['transparent']))
+        self.url += "&" +proj+ "&" + "FORMAT=" + params['format']
+        
+        self.bbox = bbox
+        self.proj_srs = proj_srs
+        self.tile_rows = tile_size['rows']
+        self.tile_cols = tile_size['cols']
+
+        if params['urlparams'] != "":
+            self.url += "&" + params['urlparams']
+        
+        cols = int(region['cols'])
+        rows = int(region['rows'])
+        
+        # computes parameters of tiles 
+        self.num_tiles_x = cols / self.tile_cols 
+        self.last_tile_x_size = cols % self.tile_cols
+        self.tile_length_x =  float(self.tile_cols) / float(cols) * (self.bbox['maxx'] - self.bbox['minx']) 
+        
+        self.last_tile_x = False
+        if self.last_tile_x_size != 0:
+            self.last_tile_x = True
+            self.num_tiles_x = self.num_tiles_x + 1
+        
+        self.num_tiles_y = rows / self.tile_rows 
+        self.last_tile_y_size = rows % self.tile_rows
+        self.tile_length_y =  float(self.tile_rows) / float(rows) * (self.bbox['maxy'] - self.bbox['miny']) 
+        
+        self.last_tile_y = False
+        if self.last_tile_y_size != 0:
+            self.last_tile_y = True
+            self.num_tiles_y = self.num_tiles_y + 1
+        
+        self.tile_bbox = dict(self.bbox)
+        self.tile_bbox['maxx'] = self.bbox['minx']  + self.tile_length_x
+
+        self.i_x = 0 
+        self.i_y = 0
+
+        self.map_region = self.bbox
+        self.map_region['cols'] = cols
+        self.map_region['rows'] = rows
+
+    def GetMapRegion(self):
+        """!Get size in pixels and bounding box of raster where all tiles will be merged.
+        """
+        return self.map_region
+
+    def GetNextTile(self):
+        """!Get url for request the tile from server and information for merging the tile with other tiles
+        """
+
+        tileRef = {}
+
+        if self.i_x >= self.num_tiles_x:
+            return None
+            
+        tileRef['sizeX'] = self.tile_cols
+        if self.i_x == self.num_tiles_x - 1 and self.last_tile_x:
+            tileRef['sizeX'] = self.last_tile_x_size
+         
+        # set bbox for tile (N, S)
+        if self.i_y != 0:
+            self.tile_bbox['miny'] -= self.tile_length_y 
+            self.tile_bbox['maxy'] -= self.tile_length_y
+        else:
+            self.tile_bbox['maxy'] = self.bbox['maxy']
+            self.tile_bbox['miny'] = self.bbox['maxy'] - self.tile_length_y
+
+        tileRef['sizeY'] = self.tile_rows
+        if self.i_y == self.num_tiles_y - 1 and self.last_tile_y:
+            tileRef['sizeY'] = self.last_tile_y_size 
+
+        if self._isGeoProj(self.proj_srs) and self.version == "1.3.0":                
+            query_bbox = self._flipBbox(self.tile_bbox, self.proj_srs)
+        else:
+            query_bbox = self.tile_bbox
+        query_url = self.url + "&" + "BBOX=%s,%s,%s,%s" % ( query_bbox['minx'],  query_bbox['miny'],  query_bbox['maxx'],  query_bbox['maxy'])
+
+        tileRef['t_cols_offset'] = int(self.tile_cols * self.i_x)
+        tileRef['t_rows_offset'] = int(self.tile_rows * self.i_y)
+
+        if self.i_y >= self.num_tiles_y - 1:
+            self.i_y = 0
+            self.i_x += 1
+            # set bbox for next tile (E, W)      
+            self.tile_bbox['maxx'] += self.tile_length_x 
+            self.tile_bbox['minx'] += self.tile_length_x 
+        else:
+            self.i_y += 1
+
+        return query_url, tileRef
+
+    def _flipBbox(self, bbox, proj, version):
+        """ 
+        Flips coordinates if WMS standard is 1.3.0 and 
+        projection is geographic.
+
+        value flips between this keys:
+        maxy -> maxx
+        maxx -> maxy
+        miny -> minx
+        minx -> miny
+        @return copy of bbox with flipped coordinates
+        """  
+
+        temp_bbox = dict(bbox)
+        new_bbox = {}
+        new_bbox['maxy'] = temp_bbox['maxx']
+        new_bbox['miny'] = temp_bbox['minx']
+        new_bbox['maxx'] = temp_bbox['maxy']
+        new_bbox['minx'] = temp_bbox['miny']
+
+        return new_bbox
+
+
+class WMTSRequestMgr(BaseRequestMgr):
+    def __init__(self, params, bbox, region, proj_srs, cap_file = None):
+        """!Initializes data needed for iteration through tiles.
+        """
+
+        self.proj_srs = proj_srs
+        self.meters_per_unit = None
+
+        # constant defined in WMTS standard (in meters)
+        self.pixel_size = 0.00028
+
+        # parse capabilities file
+        cap_tree = etree.parse(cap_file)
+        root = cap_tree.getroot()
+
+        # get layer tile matrix sets with same projection
+        mat_sets = self._getMatSets(root, params)
+
+        # TODO: what if more tile matrix sets are returned?
+        params['tile_matrix_set'] = mat_sets[0].find(self._ns_ows('Identifier')).text
+
+        # find tile matrix with resolution closest and smaller to wanted resolution 
+        tile_mat  = self._findTileMats(mat_sets[0].findall(self._ns_wmts('TileMatrix')), region, bbox)
+
+        # initialize data needed for iteration through tiles
+        self._computeRequestData(tile_mat, params, bbox)
+
+    def GetMapRegion(self):
+        """!Get size in pixels and bounding box of raster where all tiles will be merged.
+        """
+        return self.map_region
+
+    def _getMatSets(self, root, params):
+        """!Get matrix sets which are available for chosen layer and have required EPSG.
+        """
+        contents = self.find(root, 'Contents', self._ns_wmts)
+        layers = self.findall(contents, 'Layer', self._ns_wmts)
+
+        ch_layer = None
+        for layer in layers:
+            layer_id = layer.find(self._ns_ows('Identifier')).text
+            if layer_id and layer_id == params['layers']:
+                ch_layer = layer 
+                break  
+
+        if ch_layer is None:
+            grass.fatal(_("Layer '%s' was not found in capabilities file") % params['layers'])
+
+        mat_set_links = self.findall(ch_layer, 'TileMatrixSetLink', self._ns_wmts)
+
+        suitable_mat_sets = []
+        tileMatrixSets = self.findall(contents, 'TileMatrixSet', self._ns_wmts)
+
+        for link in  mat_set_links:
+            mat_set_link_id = link.find(self._ns_wmts('TileMatrixSet')).text
+            if not mat_set_link_id:
+                continue
+            for mat_set in tileMatrixSets:
+                mat_set_id = mat_set.find(self._ns_ows('Identifier')).text 
+                if mat_set_id and mat_set_id != mat_set_link_id:
+                    continue
+                mat_set_srs = mat_set.find(self._ns_ows('SupportedCRS')).text
+                if mat_set_srs and mat_set_srs.lower() == ("EPSG:"+ str(params['srs'])).lower():
+                    suitable_mat_sets.append(mat_set)
+
+        if not suitable_mat_sets:
+            grass.fatal(_("Layer '%s' is not available with %s code.") % (params['layers'],  "EPSG:" + str(params['srs'])))
+
+        return suitable_mat_sets
+
+    def _findTileMats(self, tile_mats, region, bbox):
+        """!Find tile matrix set with closest and smaller resolution to requested resolution
+        """        
+        scale_dens = []
+
+        scale_dens.append((bbox['maxy'] - bbox['miny']) / region['rows'] * self._getMetersPerUnit()  / self.pixel_size)
+        scale_dens.append((bbox['maxx'] - bbox['minx']) / region['cols'] * self._getMetersPerUnit() / self.pixel_size)
+
+        scale_den = min(scale_dens)
+
+        first = True
+        for t_mat in tile_mats:
+            mat_scale_den = float(t_mat.find(self._ns_wmts('ScaleDenominator')).text)
+            if first:
+                best_scale_den = mat_scale_den
+                best_t_mat = t_mat
+                first = False
+                continue
+                
+            best_diff = best_scale_den - scale_den
+            mat_diff = mat_scale_den - scale_den
+            if (best_diff < mat_diff  and  mat_diff < 0) or \
+               (best_diff > mat_diff  and  best_diff > 0):
+                best_t_mat = t_mat
+                best_scale_den = mat_scale_den
+
+        return best_t_mat
+
+    def _getMetersPerUnit(self):
+        """!Get coefficient which allows to convert units of request projection into meters 
+        """  
+        if self.meters_per_unit:
+            return self.meters_per_unit
+
+        # for geographic projection
+        if self._isGeoProj(self.proj_srs):
+            proj_params = proj_srs.split(' ')
+            for param in proj_parmas:
+                if '+a' in param:
+                    a = float(param.split('=')[1])
+                    break
+            equator_perim = 2 * pi * a
+            # meters per degree on equator
+            self.meters_per_unit = equator_perim / 360 
+
+        # other units
+        elif '+to_meter' in self.proj_srs:
+            proj_params = self.proj_srs.split(' ')
+            for param in proj_params:
+                if '+to_meter' in param:
+                    self.meters_per_unit = 1/float(param.split('=')[1])
+                    break
+        # coordinate system in meters        
+        else:
+            self.meters_per_unit = 1
+
+        return self.meters_per_unit
+
+    def _computeRequestData(self, tile_mat, params, bbox):
+        """!Initialize data needed for iteration through tiles.
+        """  
+        scale_den = float(tile_mat.find(self._ns_wmts('ScaleDenominator')).text)
+
+        pixel_span = scale_den * self.pixel_size / self._getMetersPerUnit()
+
+        tl_corner = tile_mat.find(self._ns_wmts('TopLeftCorner')).text.split(' ')
+
+        self.t_cols = int(tile_mat.find(self._ns_wmts('TileWidth')).text)
+        t_length_x = pixel_span * self.t_cols
+        
+        self.t_rows = int(tile_mat.find(self._ns_wmts('TileHeight')).text)
+        t_length_y = pixel_span * self.t_rows
+    
+        t_mat_min_x = float(tl_corner[0])
+        t_mat_max_y = float(tl_corner[1])
+        
+        epsilon = 2e-15
+
+        self.t_num_bbox = {}
+        self.t_num_bbox['min_col'] = int(floor((bbox['minx'] - t_mat_min_x) / t_length_x + epsilon))
+        self.t_num_bbox['max_col'] = int(floor((bbox['maxx'] - t_mat_min_x) / t_length_x - epsilon))
+
+        self.t_num_bbox['min_row'] = int(floor((t_mat_max_y - bbox['maxy']) / t_length_y + epsilon))
+        self.t_num_bbox['max_row'] = int(floor((t_mat_max_y - bbox['miny']) / t_length_y - epsilon))
+
+        matWidth = int(tile_mat.find(self._ns_wmts('MatrixWidth')).text)
+        matHeight = int(tile_mat.find(self._ns_wmts('MatrixHeight')).text)
+
+        self.intersects = False
+        for col in ['min_col', 'max_col']:
+            for row in ['min_row', 'max_row']:
+                if (0 <= self.t_num_bbox[row] and self.t_num_bbox[row] <= matHeight) and \
+                   (0 <= self.t_num_bbox[col] and self.t_num_bbox[col] <= matWidth):
+                    self.intersects = True
+                    
+        if not self.intersects:
+            grass.warning(_('Region is out of server data extend.'))
+            self.map_region = None
+            return
+
+        if self.t_num_bbox['min_col'] < 0:
+            self.t_num_bbox['min_col']  = 0
+
+        if self.t_num_bbox['max_col'] > (matWidth - 1):
+            self.t_num_bbox['max_col']  = matWidth - 1
+
+        if self.t_num_bbox['min_row'] < 0:
+            self.t_num_bbox['min_row']  = 0
+
+        if self.t_num_bbox['max_row'] > (matHeight - 1):
+            self.t_num_bbox['max_row'] = matHeight - 1
+
+        num_tiles = (self.t_num_bbox['max_col'] - self.t_num_bbox['min_col'] + 1) * (self.t_num_bbox['max_row'] - self.t_num_bbox['min_row'] + 1) 
+        grass.message(_('Fetching %d tiles with %d x %d pixel size per tile...') % (num_tiles, self.t_cols, self.t_rows))
+
+        self.url = params['url'] + ("?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&" \
+                                    "LAYER=%s&STYLE=%s&FORMAT=%s&TILEMATRIXSET=%s&TILEMATRIX=%s" % \
+                                   (params['layers'], params['styles'], params['format'],
+                                    params['tile_matrix_set'], tile_mat.find(self._ns_ows('Identifier')).text ))
+
+        if params['urlparams'] != "":
+            self.url += "&" + params['urlparams']
+
+        self.map_region = {}
+        self.map_region['minx'] = self.t_num_bbox['min_col'] * t_length_x + t_mat_min_x
+        self.map_region['maxy'] = t_mat_max_y - (self.t_num_bbox['min_row']) * t_length_y
+
+        self.map_region['maxx'] = (self.t_num_bbox['max_col'] + 1) * t_length_x + t_mat_min_x
+        self.map_region['miny'] = t_mat_max_y - (self.t_num_bbox['max_row'] + 1) * t_length_y
+
+        self.map_region['cols'] = self.t_cols * (self.t_num_bbox['max_col'] -  self.t_num_bbox['min_col'] + 1)
+        self.map_region['rows'] = self.t_rows * (self.t_num_bbox['max_row'] -  self.t_num_bbox['min_row'] + 1)
+
+        self.i_col = self.t_num_bbox['min_col']
+        self.i_row = self.t_num_bbox['min_row'] 
+
+        self.tileRef = {
+                          'sizeX' : self.t_cols,
+                          'sizeY' : self.t_rows
+                        }
+
+    def GetNextTile(self):
+        """!Get url for request the tile from server and information for merging the tile with other tiles
+        """
+        if not self.intersects or self.i_col > self.t_num_bbox['max_col']:
+            return None 
+                
+        query_url = self.url + "&TILECOL=%i&TILEROW=%i" % (int(self.i_col), int(self.i_row)) 
+
+        self.tileRef['t_cols_offset'] = int(self.t_cols * (self.i_col - self.t_num_bbox['min_col']))
+        self.tileRef['t_rows_offset'] = int(self.t_rows * (self.i_row - self.t_num_bbox['min_row']))
+
+        if self.i_row >= self.t_num_bbox['max_row']:
+            self.i_row =  self.t_num_bbox['min_row']
+            self.i_col += 1
+        else:
+            self.i_row += 1 
+
+        return query_url, self.tileRef
+
+    def _ns_wmts(self, tag):
+        """!Helper method - XML namespace
+        """       
+        return "{http://www.opengis.net/wmts/1.0}" + tag
+
+    def _ns_ows(self, tag):
+        """!Helper method - XML namespace
+        """
+        return "{http://www.opengis.net/ows/1.1}" + tag

Added: grass-addons/grass7/grass7/raster/r.in.wms2/wms_gdal_drv.py
===================================================================
--- grass-addons/grass7/grass7/raster/r.in.wms2/wms_gdal_drv.py	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.in.wms2/wms_gdal_drv.py	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,139 @@
+import os
+import grass.script as grass 
+
+try:
+    from osgeo import gdal
+    from osgeo import gdalconst
+except:
+    grass.fatal(_("Unable to load GDAL Python bindings"))
+
+import xml.etree.ElementTree as etree
+
+from wms_base import WMSBase
+
+class NullDevice():
+    def write(self, s):
+        pass
+
+class WMSGdalDrv(WMSBase):
+    def _createXML(self):
+        """!Create XML for GDAL WMS driver
+        
+        @return path to XML file
+        """
+        self._debug("_createXML", "started")
+        
+        gdal_wms = etree.Element("GDAL_WMS")
+        service = etree.SubElement(gdal_wms, "Service")
+        name = etree.Element("name")
+        service.set("name","WMS")
+        
+        version = etree.SubElement(service, "Version")
+        version.text =self.params['wms_version']
+        
+        server_url = etree.SubElement(service, "ServerUrl")
+        server_url.text =self.params['url']
+        
+        srs = etree.SubElement(service, self.params['proj_name'])   
+        srs.text = 'EPSG:' + str(self.params['srs'])
+        
+        image_format = etree.SubElement(service, "ImageFormat")
+        image_format.text = self.params['format']
+        
+        image_format = etree.SubElement(service, "Transparent")
+        image_format.text = self.params['transparent']
+        
+        layers = etree.SubElement(service, "Layers")
+        layers.text = self.params['layers']
+        
+        styles = etree.SubElement(service, "Styles")
+        styles.text = self.params['styles']
+        
+        data_window = etree.SubElement(gdal_wms, "DataWindow")
+        
+        upper_left_x = etree.SubElement(data_window, "UpperLeftX")
+        upper_left_x.text = str(self.bbox['minx']) 
+        
+        upper_left_y = etree.SubElement(data_window, "UpperLeftY")
+        upper_left_y.text = str(self.bbox['maxy']) 
+        
+        lower_right_x = etree.SubElement(data_window, "LowerRightX")
+        lower_right_x.text = str(self.bbox['maxx']) 
+        
+        lower_right_y = etree.SubElement(data_window, "LowerRightY")
+        lower_right_y.text = str(self.bbox['miny'])
+        
+        size_x = etree.SubElement(data_window, "SizeX")
+        size_x.text = str(self.region['cols']) 
+        
+        size_y = etree.SubElement(data_window, "SizeY")
+        size_y.text = str(self.region['rows']) 
+        
+        # RGB + alpha
+        self.temp_map_bands_num = 4
+        block_size_x = etree.SubElement(gdal_wms, "BandsCount")
+        block_size_x.text = str(self.temp_map_bands_num)
+        
+        block_size_x = etree.SubElement(gdal_wms, "BlockSizeX")
+        block_size_x.text = str(self.tile_size['cols']) 
+        
+        block_size_y = etree.SubElement(gdal_wms, "BlockSizeY")
+        block_size_y.text = str(self.tile_size['rows'])
+        
+        xml_file = self._tempfile()
+        
+        etree.ElementTree(gdal_wms).write(xml_file)
+        
+        self._debug("_createXML", "finished -> %s" % xml_file)
+        
+        return xml_file
+    
+    def _download(self):
+        """!Downloads data from WMS server using GDAL WMS driver
+        
+        @return temp_map with stored downloaded data
+        """
+        grass.message("Downloading data from WMS server...")
+
+        # GDAL WMS driver does not flip geographic coordinates 
+        # according to WMS standard 1.3.0.
+        if ("+proj=latlong" in self.proj_srs or \
+            "+proj=longlat" in self.proj_srs) and \
+            self.params['wms_version'] == "1.3.0":
+            grass.warning(_("If module will not be able to fetch the data in this\
+                           geographic projection, \n try 'WMS_GRASS' driver or use WMS version 1.1.1."))
+
+        self._debug("_download", "started")
+        
+        temp_map = self._tempfile()        
+
+        xml_file = self._createXML()
+        wms_dataset = gdal.Open(xml_file, gdal.GA_ReadOnly)
+        grass.try_remove(xml_file)
+        if wms_dataset is None:
+            grass.fatal(_("Unable to open GDAL WMS driver"))
+        
+        self._debug("_download", "GDAL dataset created")
+        
+        driver = gdal.GetDriverByName(self.gdal_drv_format)
+        if driver is None:
+            grass.fatal(_("Unable to find %s driver" % format))
+        
+        metadata = driver.GetMetadata()
+        if not metadata.has_key(gdal.DCAP_CREATECOPY) or \
+           metadata[gdal.DCAP_CREATECOPY] == 'NO':
+            grass.fatal(_('Driver %s supports CreateCopy() method.') % self.gdal_drv_name)
+        
+        self._debug("_download", "calling GDAL CreateCopy...")
+        
+        temp_map_dataset = driver.CreateCopy(temp_map, wms_dataset, 0)
+        
+        if temp_map_dataset is None:
+            grass.fatal(_("Incorrect WMS query"))
+        
+        temp_map_dataset  = None
+        wms_dataset = None
+        
+        self._debug("_download", "finished")
+        
+        return temp_map

Added: grass-addons/grass7/grass7/raster/r.massmov/Makefile
===================================================================
--- grass-addons/grass7/grass7/raster/r.massmov/Makefile	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.massmov/Makefile	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,11 @@
+MODULE_TOPDIR = ../..
+
+PGM = r.massmov
+
+LIBES = $(RASTERLIB) $(GISLIB) $(MATHLIB)
+DEPENDENCIES = $(RASTERDEP) $(GISDEP)
+
+include $(MODULE_TOPDIR)/include/Make/Module.make
+
+default: cmd
+

Added: grass-addons/grass7/grass7/raster/r.massmov/filters.c
===================================================================
--- grass-addons/grass7/grass7/raster/r.massmov/filters.c	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.massmov/filters.c	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,353 @@
+#include <math.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <grass/gis.h>
+#include <grass/raster.h>
+#include <grass/glocale.h>
+
+
+#define nullo -999.9f
+
+float gradx3(float **matrix, int row, int col, float dx, int abs) {
+	float v;
+
+	if (matrix[row][col] != nullo && matrix[row][col + 1] != nullo
+			&& matrix[row - 1][col + 1] != nullo
+			&& matrix[row + 1][col + 1] != nullo
+			&& matrix[row][col - 1] != nullo
+			&& matrix[row - 1][col - 1] != nullo
+			&& matrix[row + 1][col - 1] != nullo) {
+
+		if (abs == 1){
+			v = (fabs((matrix[row - 1][col + 1]) + 2 * fabs(matrix[row][col + 1])
+							+ fabs(matrix[row + 1][col + 1]))
+							- (fabs(matrix[row - 1][col - 1]) + 2 * fabs(matrix[row][col - 1])
+									+ fabs(matrix[row + 1][col - 1]))) / (8 * dx);
+			return v;
+		}
+		else{
+			v = ((matrix[row - 1][col + 1] + 2 * matrix[row][col + 1]
+										+ matrix[row + 1][col + 1])
+										- (matrix[row - 1][col - 1] + 2 * matrix[row][col - 1]
+												+ matrix[row + 1][col - 1])) / (8 * dx);
+			return v;
+		}
+	} else {
+		return nullo;
+	}
+}
+
+float grady3(float **matrix, int row, int col, float dy, int abs) {
+	float v;
+
+	if (matrix[row][col] != nullo && matrix[row - 1][col - 1] != nullo
+			&& matrix[row - 1][col] != nullo
+			&& matrix[row - 1][col + 1] != nullo
+			&& matrix[row + 1][col - 1] != nullo
+			&& matrix[row + 1][col] != nullo
+			&& matrix[row + 1][col + 1] != nullo) {
+
+		if (abs == 1){
+			v = ((fabs(matrix[row - 1][col - 1]) + 2 * fabs(matrix[row - 1][col])
+							+ fabs(matrix[row - 1][col + 1]))
+							- fabs((matrix[row + 1][col - 1]) + 2 * fabs(matrix[row + 1][col])
+									+ fabs(matrix[row + 1][col + 1]))) / (8 * dy);
+			return v;
+		}
+		else {
+			v = ((matrix[row - 1][col - 1] + 2 * matrix[row - 1][col]
+										+ matrix[row - 1][col + 1])
+										- (matrix[row + 1][col - 1] + 2 * matrix[row + 1][col]
+												+ matrix[row + 1][col + 1])) / (8 * dy);
+			return v;
+		}
+
+	} else {
+		return nullo;
+	}
+}
+
+float gradx2(float **matrix, int row, int col, float dx, int abs) {
+	float v;
+
+	if (matrix[row][col] != nullo && matrix[row][col + 1] != nullo
+			&& matrix[row][col - 1] != nullo) {
+
+		if (abs == 1){
+			v = (fabs(matrix[row][col + 1]) - fabs(matrix[row][col - 1])) / (2 * dx);
+			return v;
+		}
+		else {
+			v = (matrix[row][col + 1] - matrix[row][col - 1]) / (2 * dx);
+			return v;
+		}
+	} else {
+		return nullo;
+	}
+}
+
+float gradPx2(float **matrix1, float **matrix2, float **matrix3, int row,
+		int col, float dx) {
+	float v;
+
+	if (matrix1[row][col] != nullo && matrix2[row][col] != nullo
+			&& (cos(atan(matrix3[row][col]))) != nullo
+			&& matrix1[row][col + 1] != nullo && matrix2[row][col + 1] != nullo
+			&& (cos(atan(matrix3[row][col + 1]))) != nullo
+			&& matrix1[row][col - 1] != nullo && matrix2[row][col - 1] != nullo
+			&& (cos(atan(matrix3[row][col - 1]))) != nullo) {
+		v = ((9.8 * (matrix1[row][col + 1] + matrix2[row][col + 1])
+				* (cos(atan(matrix3[row][col + 1]))))
+				- (9.8 * (matrix1[row][col - 1] + matrix2[row][col - 1])
+						* (cos(atan(matrix3[row][col - 1]))))) / (2 * dx);
+		return v;
+
+	} else
+		return nullo;
+}
+
+float grady2(float **matrix, int row, int col, float dy, int abs) {
+	float v;
+
+	if (matrix[row][col] != nullo && matrix[row + 1][col] != nullo
+			&& matrix[row - 1][col] != nullo) {
+
+		if (abs == 1){
+			v = (fabs(matrix[row - 1][col]) - fabs(matrix[row + 1][col])) / (2 * dy);
+			return v;
+		}
+
+		else {
+			v = (matrix[row - 1][col] - matrix[row + 1][col]) / (2 * dy);
+			return v;
+		}
+	} else {
+		return nullo;
+	}
+}
+
+/* calcolo del gradiente combinato della somma di 2 matrici (usato per P)
+ * gradPy2 (pendenza y, matrice 1, matrice 2, riga, col, res y)
+ *
+ * */
+float gradPy2(float **matrix1, float **matrix2, float **matrix3, int row,
+		int col, float dy) {
+	float v;
+
+	if (matrix1[row][col] != nullo && matrix2[row][col] != nullo
+			&& (cos(atan(matrix3[row][col]))) != nullo
+			&& matrix1[row + 1][col] != nullo && matrix2[row + 1][col] != nullo
+			&& (cos(atan(matrix3[row + 1][col]))) != nullo
+			&& matrix1[row - 1][col] != nullo && matrix2[row - 1][col] != nullo
+			&& (cos(atan(matrix3[row - 1][col]))) != nullo) {
+		v = ((9.8 * (matrix1[row - 1][col] + matrix2[row - 1][col])
+				* (cos(atan(matrix3[row - 1][col]))))
+				- (9.8 * (matrix1[row + 1][col] + matrix2[row + 1][col])
+						* (cos(atan(matrix3[row + 1][col]))))) / (2 * dy);
+		return v;
+
+	} else
+		return nullo;
+}
+
+float lax(float **matrix, int row, int col, float laxfactor) {
+
+	float gg = 0.0;
+	float hh = 0.0;
+	float v;
+
+	if (matrix[row][col] != nullo) {
+
+		if (matrix[row - 1][col - 1] != nullo) {
+			gg = gg + 2 * matrix[row - 1][col - 1];
+			hh = hh + 2;
+		}
+
+
+		if (matrix[row - 1][col] != nullo) {
+			gg = gg + 3 * matrix[row - 1][col];
+			hh = hh + 3;
+		}
+
+		if (matrix[row - 1][col + 1] != nullo) {
+			gg = gg + 2 * matrix[row - 1][col + 1];
+			hh = hh + 2;
+		}
+
+		if (matrix[row][col - 1] != nullo) {
+			gg = gg + 3 * matrix[row][col - 1];
+			hh = hh + 3;
+		}
+
+		if (matrix[row][col + 1] != nullo) {
+			gg = gg + 3 * matrix[row][col + 1];
+			hh = hh + 3;
+		}
+
+		if (matrix[row + 1][col - 1] != nullo) {
+			gg = gg + 2 * matrix[row + 1][col - 1];
+			hh = hh + 2;
+		}
+
+		if (matrix[row + 1][col] != nullo) {
+			gg = gg + 3 * matrix[row + 1][col];
+			hh = hh + 3;
+		}
+
+		if (matrix[row + 1][col + 1] != nullo) {
+			gg = gg + 2 * matrix[row + 1][col + 1];
+			hh = hh + 2;
+		}
+
+		if (/*gg != 0.0 &&*/ hh != 0.0)
+			v = ((1 - laxfactor) * matrix[row][col] + laxfactor * (gg / hh));
+		else
+			v = matrix[row][col];
+
+		return v;
+	}
+
+	else {
+		return nullo;
+	}
+
+}
+
+float filter_lax(float **matrix, int row, int col, float laxfactor, float **filter_matrix,float threshold,float val) {
+
+
+	float gg = 0.0;
+	float hh = 0.0;
+	float v;
+
+
+	if (matrix[row][col] != nullo && (filter_matrix[row][col] > threshold)) {
+
+		if ((matrix[row - 1][col - 1] != nullo)&&(filter_matrix[row - 1][col - 1] > threshold)) {
+			gg = gg + 2 * matrix[row - 1][col - 1];
+			hh = hh + 2;
+		}
+
+
+		if ((matrix[row - 1][col] != nullo)&&(filter_matrix[row - 1][col] > threshold)) {
+			gg = gg + 3 * matrix[row - 1][col];
+			hh = hh + 3;
+		}
+
+		if ((matrix[row - 1][col + 1] != nullo)&&(filter_matrix[row - 1][col + 1] > threshold)) {
+			gg = gg + 2 * matrix[row - 1][col + 1];
+			hh = hh + 2;
+		}
+
+		if ((matrix[row][col - 1] != nullo)&&(filter_matrix[row][col - 1] > threshold)) {
+			gg = gg + 3 * matrix[row][col - 1];
+			hh = hh + 3;
+		}
+
+		if ((matrix[row][col + 1] != nullo)&&(filter_matrix[row][col + 1] > threshold)) {
+			gg = gg + 3 * matrix[row][col + 1];
+			hh = hh + 3;
+		}
+
+		if ((matrix[row + 1][col - 1] != nullo)&&(filter_matrix[row + 1][col - 1] > threshold)) {
+			gg = gg + 2 * matrix[row + 1][col - 1];
+			hh = hh + 2;
+		}
+
+		if ((matrix[row + 1][col] != nullo)&&(filter_matrix[row + 1][col] > threshold)) {
+			gg = gg + 3 * matrix[row + 1][col];
+			hh = hh + 3;
+		}
+
+		if ((matrix[row + 1][col + 1] != nullo)&&(filter_matrix[row + 1][col + 1] > threshold)) {
+			gg = gg + 2 * matrix[row + 1][col + 1];
+			hh = hh + 2;
+		}
+
+		if (/*gg != 0.0 &&*/ hh != 0.0)
+			v = ((1 - laxfactor) * matrix[row][col] + laxfactor * (gg / hh));
+		else
+			v = matrix[row][col];
+
+		return v;
+	}
+
+	else {
+		v=val;
+		return v;
+	}
+
+}
+
+
+float filter_lax_print(float **matrix, int row, int col, float laxfactor, float **filter_matrix,float threshold,float val) {
+
+
+	float gg = 0.0;
+	float hh = 0.0;
+	float v;
+
+	if (matrix[row][col] != nullo && (filter_matrix[row][col] > threshold)) {
+		if ((matrix[row - 1][col - 1] != nullo)&&(filter_matrix[row - 1][col - 1] > threshold)) {
+			gg = gg + 2 * matrix[row - 1][col - 1];
+			hh = hh + 2;
+			while (getchar() != 'y') {}
+		}
+
+
+		if ((matrix[row - 1][col] != nullo)&&(filter_matrix[row - 1][col] > threshold)) {
+			gg = gg + 3 * matrix[row - 1][col];
+			hh = hh + 3;
+			while (getchar() != 'y') {}
+		}
+
+		if ((matrix[row - 1][col + 1] != nullo)&&(filter_matrix[row - 1][col + 1] > threshold)) {
+			gg = gg + 2 * matrix[row - 1][col + 1];
+			hh = hh + 2;
+			while (getchar() != 'y') {}
+		}
+
+		if ((matrix[row][col - 1] != nullo)&&(filter_matrix[row][col - 1] > threshold)) {
+			gg = gg + 3 * matrix[row][col - 1];
+			hh = hh + 3;
+			while (getchar() != 'y') {}
+		}
+
+		if ((matrix[row][col + 1] != nullo)&&(filter_matrix[row][col + 1] > threshold)) {
+			gg = gg + 3 * matrix[row][col + 1];
+			hh = hh + 3;
+			while (getchar() != 'y') {}
+		}
+
+		if ((matrix[row + 1][col - 1] != nullo)&&(filter_matrix[row + 1][col - 1] > threshold)) {
+			gg = gg + 2 * matrix[row + 1][col - 1];
+			hh = hh + 2;
+			while (getchar() != 'y') {}
+		}
+
+		if ((matrix[row + 1][col] != nullo)&&(filter_matrix[row + 1][col] > threshold)) {
+			gg = gg + 3 * matrix[row + 1][col];
+			hh = hh + 3;
+			while (getchar() != 'y') {}
+		}
+
+		if ((matrix[row + 1][col + 1] != nullo)&&(filter_matrix[row + 1][col + 1] > threshold)) {
+			gg = gg + 2 * matrix[row + 1][col + 1];
+			hh = hh + 2;
+			while (getchar() != 'y') {}
+		}
+
+		if (/*gg != 0.0 &&*/ hh != 0.0)
+			v = ((1 - laxfactor) * matrix[row][col] + laxfactor * (gg / hh));
+		else
+			v = matrix[row][col];
+
+		return v;
+	}
+
+	else {
+		v=val;
+		return v;
+	}
+}

Added: grass-addons/grass7/grass7/raster/r.massmov/filters.h
===================================================================
--- grass-addons/grass7/grass7/raster/r.massmov/filters.h	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.massmov/filters.h	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,12 @@
+float gradx3(float **matrix, int row, int col, float dx, int abs);
+float grady3(float **matrix, int row, int col, float dy, int abs);
+float gradx2(float **matrix, int row, int col, float dx, int abs);
+float grady2(float **matrix, int row, int col, float dy, int abs);
+float lax(float **matrix, int row, int col, float laxfactor);
+float filter_lax(float **matrix, int row, int col, float laxfactor, float **filter_matrix,float threshold,float val);
+float gradPx2(float **matrix1, float **matrix2, float **matrix3, int row,
+		int col, float dx);
+float gradPy2(float **matrix1, float **matrix2, float **matrix3, int row,
+		int col, float dy);
+float isocell(float **matrix,int row,int col,float val);
+float filter_lax_print(float **matrix, int row, int col, float laxfactor, float **filter_matrix,float threshold,float val);

Added: grass-addons/grass7/grass7/raster/r.massmov/general_f.c
===================================================================
--- grass-addons/grass7/grass7/raster/r.massmov/general_f.c	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.massmov/general_f.c	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,261 @@
+#include <math.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <grass/gis.h>
+#include <grass/raster.h>
+#include <grass/glocale.h>
+#include <grass/linkm.h>
+
+#define HBExp 1
+#define verysmall 0.01
+#define min(A,B) ((A) < (B) ? (A):(B))
+#define max(A,B) ((A) > (B) ? (A):(B))
+
+float **G_alloc_fmatrix(int rows, int cols) {
+	float **m;
+	int i;
+	m = (float **) G_calloc(rows, sizeof(float *));
+	m[0] = (float *) G_calloc(rows * cols, sizeof(float));
+	for (i = 1; i < rows; i++)
+		m[i] = m[i - 1] + cols;
+	return m;
+}
+
+int **G_alloc_imatrix(int rows, int cols) {
+	int **mmm;
+	int i;
+	mmm = (int **) G_calloc(rows, sizeof(int *));
+	mmm[0] = (int *) G_calloc(rows * cols, sizeof(int));
+	for (i = 1; i < rows; i++)
+		mmm[i] = mmm[i - 1] + cols;
+	return mmm;
+}
+
+void G_free_fmatrix(float **m) {
+	G_free(m[0]);
+	G_free(m);
+	m = NULL;
+	return;
+}
+
+void G_free_imatrix(int **mmm) {
+	G_free(mmm[0]);
+	G_free(mmm);
+	mmm = NULL;
+	return;
+}
+
+int check_rheol_par(int rheol_type, float chezy, float visco, float rho) {
+	if (rheol_type == 2) {
+		if (chezy > 0)
+			return 1;
+		else
+			return -2;
+	}
+
+	if (rheol_type == 3) {
+		if (visco > 0 && rho > 0)
+			return 1;
+		else
+			return -3;
+	}
+}
+
+float t_frict(float **h, int row, int col, float b_frict) {
+	float t;
+
+	if (h[row][col] > verysmall) {
+		t = tan((M_PI * b_frict) / 180.0);
+	} else {
+		t = 5 * tan((M_PI * b_frict) / 180.0);
+	}
+	return t;
+}
+
+float t_voellmy(float v, float **h, int row, int col, float b_frict,
+		float chezy) {
+	float t;
+	if (h[row][col] > verysmall) {
+		t = tan((M_PI * b_frict) / 180.0) + pow(v, 2) / (chezy * h[row][col]);
+	} else {
+		t = 5 * tan((M_PI * b_frict) / 180.0);
+	}
+	return t;
+}
+
+float t_visco(float v, float **h, int row, int col, float b_frict, float rho,
+		float visco, float ystress) {
+	float t;
+
+	if (h[row][col] > verysmall) {
+		if (ystress > 0) {
+			t =
+					tan((M_PI * b_frict) / 180.0)
+							+ (1.5 * ystress
+									+ (3 * visco * pow(v, HBExp) / h[row][col]))
+									/ (rho * h[row][col]);
+		} else {
+			t = tan((M_PI * b_frict) / 180.0)
+					+ (3 * visco * pow(v, HBExp) / h[row][col] / h[row][col]);
+		}
+	} else {
+		if (ystress > 0) {
+			t = 5 * ystress;
+		} else {
+			t = 5 * tan((M_PI * b_frict) / 180.0);  ///// CHECK settare a 0  ???
+		}
+	}
+	return t;
+}
+
+
+float veldt(float ua, float t, float g_x, float p_x, float i_x, float t_x) {
+	float v;
+
+	if (ua>0)
+		v = max(0, ua + t * (g_x + p_x + i_x - t_x));
+
+	else if (ua<0)
+		v = min(ua + t * (g_x + p_x - i_x + t_x),0);
+
+	else {
+		if ((g_x+p_x)>0)
+			v = max(0, t * (g_x + p_x + i_x - t_x));
+
+		else if ((g_x+p_x)<0){
+			v = min(t * (g_x + p_x - i_x + t_x),0);
+		}
+		else
+			v=0;
+	}
+
+	return v;
+}
+
+float shift0(float **m, int r, int c, int maxR, int maxC, int minR, int minC, int n, int w) {
+	float v;
+
+	if ((r+n<minR) || (r+n>maxR))
+		v=0;
+	else if ((c+w<minC)|| (c+w>maxC))
+		v=0;
+	else
+		v = m[r+n][c+w];
+
+	return v;
+}
+
+
+void out_print (float **matrix,char *name, int nr, int nc){
+	int row,col;
+	float *outrast;
+	int outfd;
+
+	outrast = Rast_allocate_f_buf();
+	outfd = Rast_open_fp_new(name);
+	for (row = 0; row < nr; row++) {
+		for (col = 0; col < nc; col++) {
+			if (matrix[row][col]==0)
+				Rast_set_f_null_value(&outrast[col], 1);
+			else
+				((FCELL *) outrast)[col] = matrix[row][col];
+		}
+		Rast_put_f_row(outfd, outrast);
+	}
+	G_free(outrast);
+	Rast_close(outfd);
+}
+
+
+void out_sum_print (float **matrix1, float **matrix2, float **matrix3, float **matrix4,char *name, int nr, int nc, int mode, float threshold){
+	int row,col;
+	float *outrast;
+	int outfd;
+	/*struct History history; * holds meta-data */
+	
+	outrast = Rast_allocate_f_buf();
+	outfd = Rast_open_fp_new(name);
+	for (row = 0; row < nr; row++) {
+		for (col = 0; col < nc; col++) {
+			if (mode==1){
+				if (matrix1[row][col]+matrix2[row][col]>0)
+					((FCELL *) outrast)[col] = matrix1[row][col]+matrix2[row][col];
+				else
+					Rast_set_f_null_value(&outrast[col], 1);
+				}
+			if (mode==2){
+				if (matrix1[row][col]+matrix2[row][col]>0)
+					if (matrix2[row][col]>threshold)
+						((FCELL *) outrast)[col] = sqrt(pow(matrix3[row][col],2)+pow(matrix4[row][col],2));
+					else
+						((FCELL *) outrast)[col] = 0.0;
+				else
+					Rast_set_f_null_value(&outrast[col], 1);
+				}
+			}
+		Rast_put_f_row(outfd, outrast);
+		/**
+		Rast_short_history(name, "raster", &history);
+		Rast_command_history(&history);
+		Rast_write_history(name, &history);
+		**/
+	}
+	G_free(outrast);
+	Rast_close(outfd);
+}
+
+float nash_sutcliffe(float **m_t1,float**m_t2, int nr, int nc){
+	float sum_den=0;
+	float sum_num=0;
+	float sum_ave=0;
+	int row,col,c=0;
+	float ns_res,ave;
+
+	for (row = 0; row < nr; row++) {
+		for (col = 0; col < nc; col++) {
+			sum_ave +=m_t1[row][col];
+			c+=1;
+		}
+	}
+
+	ave = sum_ave/c;
+
+	for (row = 0; row < nr; row++) {
+		for (col = 0; col < nc; col++) {
+			sum_num += pow(m_t1[row][col]-m_t2[row][col],2);
+			sum_den += pow(m_t1[row][col]-ave,2);
+		}
+	}
+	if (sum_den==0){
+		ns_res = -9999999;
+		G_message("WARNING: -inf value obtained for NS coefficient; the new value -9999999 has been set");
+	} else {
+		ns_res = 1 - (sum_num/sum_den);
+	}
+	return ns_res;
+}
+
+
+void report_input(float ifrict,float rho,float ystress,float visco,float chezy,float bfrict,float fluid,float NS_thres,int t,int delta){
+	fprintf(stdout, "-----------Input data:-----------\n");
+	fprintf(stdout, "Internal friction angle = %.2f\n",ifrict);
+	if (rho!=-1)
+		fprintf(stdout, "Density = %.2f\n",rho);
+	if (ystress!=-1)
+		fprintf(stdout, "Yield stress = %.2f\n",ystress);
+	if (visco!=-1)
+		fprintf(stdout, "Viscosity = %.2f\n",visco);
+	if (chezy!=-1)
+		fprintf(stdout, "Chézy coefficient = %.2f\n",chezy);
+	if (bfrict!=-1)
+		fprintf(stdout, "Basal friction angle = %.2f\n",bfrict);
+	if (fluid!=-1)
+		fprintf(stdout, "Fluidization rate = %.2f\n",fluid);
+	if (NS_thres!=-1)
+		fprintf(stdout, "Nash-Sutcliffe threshold = %.4f\n",NS_thres);
+	fprintf(stdout, "Maximum timesteps number  = %i\n",t);
+	if (delta!=-1)
+		fprintf(stdout, "Reporting time frequency = %i\n",delta);
+	fprintf(stdout, "---------------------------------\n");
+}

Added: grass-addons/grass7/grass7/raster/r.massmov/general_f.h
===================================================================
--- grass-addons/grass7/grass7/raster/r.massmov/general_f.h	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.massmov/general_f.h	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,16 @@
+float **G_alloc_fmatrix(int rows, int cols);
+int **G_alloc_imatrix(int rows, int cols);
+void G_free_fmatrix(float **m);
+void G_free_imatrix(int **mmm);
+int check_rheol_par(int rheol_type, float chezy, float visco, float rho);
+float t_frict(float **h, int row, int col, float b_frict);
+float t_voellmy(float vel, float **h, int row, int col, float b_frict,
+		float chezy);
+float t_visco(float v, float **h, int row, int col, float b_frict, float rho,
+		float visco, float ystress);
+float veldt(float ua, float t, float g_x, float p_x, float i_x, float t_x);
+float shift0(float **m, int r, int c, int maxR, int maxC, int minR, int minC, int n, int w);
+void out_print (float **matrix,char *name, int nr, int nc);
+void out_sum_print (float **matrix1,float **matrix2,float **matrix3,float **matrix4, char *name, int nr, int nc, int mode, float threshold);
+float nash_sutcliffe(float **m_t1,float**m_t2, int nr, int nc);
+void report_input(float ifrict,float rho,float ystress,float visco,float chezy,float bfrict,float fluid,float NS_thres,int t,int delta);

Added: grass-addons/grass7/grass7/raster/r.massmov/main.c
===================================================================
--- grass-addons/grass7/grass7/raster/r.massmov/main.c	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.massmov/main.c	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,1122 @@
+/*****************************************************************************
+ *
+ * MODULE:	r.massmov
+ *
+ * AUTHOR(S):	Original author:
+ *              Santiago Begueria (EEAD-CSIC)
+ * 		Monia Molinari <monia.molinari supsi.ch>
+ * 		Massimiliano Cannata <massimiliano.cannata supsi.ch>
+ *		
+ *
+ * PURPOSE: This module is intended to provide the capability of simulating 
+ *          mass movement (fast landslide) over complex topography. This module
+ *          applies the Shallow Water Equation (SWE) with different types of 
+ *          rheologies (frictional,Voellmy,viscoplastic) 
+ *
+ *
+ * COPYRIGHT:	(C) 2012 by the GRASS Development Team
+ *
+ *		This program is free software under the GNU General Public
+ *		Licence (>=2). Read the file COPYING that cames with GRASS
+ *		for details.
+ *
+ ****************************************************************************/
+
+/* libraries*/
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <grass/gis.h>
+#include <grass/raster.h>
+#include <grass/glocale.h>
+#include "filters.h"
+#include "general_f.h"
+
+/* numerical stability control */
+#define CFLlimsup  0.5 			/* Higher value of the Courant-Friedrichs-Levy */
+#define CFLliminf  0.3			/* Lower value of the Courant-Friedrichs-Levy */
+#define MinNLoops  1 			  /* Minimum number of internal loops */
+#define MaxNLoops  124 			/* Maximum number of internal loops */
+#define InitialLoops  1  		/* Initial number of internal loops */
+#define laxfactor  0.5 			/* Low pass filtering for the lax function (0 = no filtering) */
+#define dTLeap  0.3 	   		/* Fraction of dT, used for time extrapolation of fluxes */
+#define verysmall  0.01 		/* threshold to avoid div by very small values */
+#define nullo -999.9f
+
+/* timestep control */
+#define dT 1.0              /* Timeslice */
+
+/* other constants */
+#define grav 9.8		        /* Gravity acceleration */
+
+/* functions definition  */
+#define min(A,B) ((A) < (B) ? (A):(B))
+#define max(A,B) ((A) > (B) ? (A):(B))
+
+/*
+ * global functions declaration
+ */
+
+/*
+ * main function
+ *
+ *
+ */
+
+int main(int argc, char *argv[]) {
+	struct Cell_head cellhd; /* it stores region information and header information of rasters */
+	struct Cell_head window;
+	struct History history; /*  holds meta-data */
+
+	/* mapset name locator */
+	char *mapset_ELEV;
+	char *mapset_HINI;
+	char *mapset_DIST;
+
+	/* input buffer */
+	FCELL *inrast_ELEV;
+	FCELL *inrast_HINI;
+	FCELL *inrast_DIST;
+
+	/* output buffer */
+	float *outrast_H;
+	float *outrast_V;
+
+	/* input file descriptor */
+	int infd_ELEV;
+	int infd_HINI;
+	int infd_DIST;
+
+	/* output file descriptor */
+	int outfd_H;
+	int outfd_V;
+
+	/* cell counters */
+	int row, col;
+	int nrows, ncols;
+	float res_ns, res_ew, ca;
+
+	/* input & output arguments */
+	int TIMESTEPS, DELTAT, RHEOL_TYPE;
+	float RHO, YSTRESS, CHEZY, VISCO, BFRICT, IFRICT, FLUID,NS_THRES;
+	char RHEOL;
+	char name1[20];
+	char *name_ELEV;
+	char *name_HINI;
+	char *name_DIST;
+	char *result_H;
+	char *result_V;
+	char *result_HMAX;
+	char *result_VMAX;
+
+	/* memory matrix */
+	float **m_ELEV, **m_HINI, **m_DIST;
+	int **m_OUTLET;
+	float **m_gx, **m_gy, **m_slope;
+	float **m_H, **m_Hloop_dt, **m_Hloop, **m_V, **m_Vloop, **m_Vloop_dt, **m_U,
+			**m_Uloop, **m_Uloop_dt, **m_HUloop, **m_HVloop, **m_Hold, **m_Hmax, **m_Vmax;
+	float **m_K, **m_Kloop, **m_Hland, **TEST;
+
+	/*int variables */
+
+	float elev_fcell_val, dist_fcell_val, hini_fcell_val;
+	int outlet_cell_val;
+
+	float gx, gy, slope;
+	float k_act, k_pas;
+	float G_x, G_y, I_x, I_y, P_x, P_y, T, T_x, T_y, T_x_b, T_y_b, T_b;
+	float ddt, dt;
+	float Uloop_a, Vloop_a, Uloop_b, Vloop_b, vel, vel_b, Uloop_dt, Vloop_dt, Hloop_a, Hloop_dt, dH_dT, H_fluid;
+	float CFL, CFL_u, CFL_v;
+	float Vol_gone_loop, Vol_exp_loop, mbe;
+	float NS,NSold;
+	int testPar;
+
+	/***********************************************************************************************************************/
+	/* GRASS structure */
+	struct GModule *module;
+	struct Option *input_ELEV, *input_HINI,*input_DIST,
+			*input_RHEOL, *input_RHO, *input_YSTRESS, *input_CHEZY,
+			*input_VISCO, *input_BFRICT, *input_IFRICT, *input_FLUID,
+			*input_TIMESTEPS, *input_DELTAT, *output_H, *output_VEL, *input_NS_THRES, *output_HMAX, *output_VMAX;
+	struct Flag *flag_i;
+
+	/* initialize GIS environment */
+	G_gisinit(argv[0]);
+
+	/* initialize module */
+	module = G_define_module();
+	G_add_keyword(_("raster"));
+	G_add_keyword(_("landslide"));
+	G_add_keyword(_("model"));
+	module->description =_("Estimation of run-out and deposition of landslide phenomena over a complex topography");
+
+	/* define the different options */
+
+	input_ELEV = G_define_option();
+	input_ELEV->key = "elev";
+	input_ELEV->type = TYPE_STRING;
+	input_ELEV->required = YES;
+	input_ELEV->gisprompt = "old,cell,raster";
+	input_ELEV->description = _("Name of elevation raster map");
+	input_ELEV->guisection = _("Input options");
+
+	input_HINI = G_define_option();
+	input_HINI->key = "h_ini";
+	input_HINI->type = TYPE_STRING;
+	input_HINI->required = YES;
+	input_HINI->gisprompt = "old,cell,raster";
+	input_HINI->description = _("Name of landslide initial body thickness raster map");
+	input_HINI->guisection = _("Input options");
+
+	input_DIST = G_define_option();
+	input_DIST->key = "fluiddist";
+	input_DIST->type = TYPE_STRING;
+	input_DIST->required = YES;
+	input_DIST->gisprompt = "old,cell,raster";
+	input_DIST->description = _("Name of distance from the landlide toe raster map");
+	input_DIST->guisection = _("Input options");
+
+	input_RHEOL = G_define_option();
+	input_RHEOL->key = "rheology";
+	input_RHEOL->type = TYPE_STRING;
+	input_RHEOL->required = YES;
+	input_RHEOL->options = "frictional,Voellmy,viscoplastic";
+	input_RHEOL->description = _("Name of rheological law");
+	input_RHEOL->guisection = _("Input options");
+
+	input_RHO = G_define_option();
+	input_RHO->key = "rho";
+	input_RHO->type = TYPE_DOUBLE;
+	input_RHO->required = NO;
+	input_RHO->multiple = NO;
+	input_RHO->description =_("Density of the flow [Kg/m3]. Required only for viscous rheologies.");
+	input_RHO->guisection = _("Input options");
+
+	input_YSTRESS = G_define_option();
+	input_YSTRESS->key = "ystress";
+	input_YSTRESS->type = TYPE_DOUBLE;
+	input_YSTRESS->required = NO;
+	input_YSTRESS->multiple = NO;
+	input_YSTRESS->description =_("Apparent yield stress [Pa]. Used only for viscous rheologies (optional).");
+	input_YSTRESS->guisection = _("Input options");
+
+	input_VISCO = G_define_option();
+	input_VISCO->key = "visco";
+	input_VISCO->type = TYPE_DOUBLE;
+	input_VISCO->required = NO;
+	input_VISCO->multiple = NO;
+	input_VISCO->description = _("Dynamic viscosity [Pa*s]. Required only for viscous rheologies");
+	input_VISCO->guisection = _("Input options");
+
+	input_CHEZY = G_define_option();
+	input_CHEZY->key = "chezy";
+	input_CHEZY->type = TYPE_DOUBLE;
+	input_CHEZY->required = NO;
+	input_CHEZY->multiple = NO;
+	input_CHEZY->description =_("Chezy roughness coefficient [m/s2]. Required only for Voellmy rheology");
+	input_CHEZY->guisection = _("Input options");
+
+	input_BFRICT = G_define_option();
+	input_BFRICT->key = "bfrict";
+	input_BFRICT->type = TYPE_DOUBLE;
+	input_BFRICT->required = NO;
+	input_BFRICT->multiple = NO;
+	input_BFRICT->description = _("Angle of basal friction [deg]");
+	input_BFRICT->guisection = _("Input options");
+
+	input_IFRICT = G_define_option();
+	input_IFRICT->key = "ifrict";
+	input_IFRICT->type = TYPE_DOUBLE;
+	input_IFRICT->required = YES;
+	input_IFRICT->multiple = NO;
+	input_IFRICT->description = _("Angle of internal friction [deg]");
+	input_IFRICT->guisection = _("Input options");
+
+	input_FLUID = G_define_option();
+	input_FLUID->key = "fluid";
+	input_FLUID->type = TYPE_DOUBLE;
+	input_FLUID->required = YES;
+	input_FLUID->multiple = NO;
+	input_FLUID->description = _("Upward velocity of transition from solid to fluid of the landsliding mass [m/s]");
+	input_FLUID->guisection = _("Input options");
+
+	input_TIMESTEPS = G_define_option();
+	input_TIMESTEPS->key = "timesteps";
+	input_TIMESTEPS->type = TYPE_INTEGER;
+	input_TIMESTEPS->required = YES;
+	input_TIMESTEPS->multiple = NO;
+	input_TIMESTEPS->description = _(
+			"Maximum number of time steps of the simulation [s]");
+	input_TIMESTEPS->guisection = _("Input options");
+
+	input_DELTAT = G_define_option();
+	input_DELTAT->key = "deltatime";
+	input_DELTAT->type = TYPE_INTEGER;
+	input_DELTAT->required = NO;
+	input_DELTAT->multiple = NO;
+	input_DELTAT->description = _("Reporting time frequency [s]");
+	input_DELTAT->guisection = _("Input options");
+
+	input_NS_THRES = G_define_option();
+	input_NS_THRES->key = "ns_thres";
+	input_NS_THRES->type = TYPE_DOUBLE;
+	input_NS_THRES->required = NO;
+	input_NS_THRES->multiple = NO;
+	input_NS_THRES->description = _("Threshold for Nash-Sutcliffe convergence [-]");
+	input_NS_THRES->guisection = _("Input options");
+
+	output_H = G_define_option();
+	output_H->key = "h";
+	output_H->type = TYPE_STRING;
+	output_H->required = NO;
+	output_H->gisprompt = "new,cell,raster";
+	output_H->description = _("Prefix for flow thickness output raster maps");
+	output_H->guisection = _("Output options");
+
+	output_HMAX = G_define_option();
+	output_HMAX->key = "h_max";
+	output_HMAX->type = TYPE_STRING;
+	output_HMAX->required = NO;
+	output_HMAX->gisprompt = "new,cell,raster";
+	output_HMAX->description = _("Prefix for maximum flow thickness output raster maps");
+	output_HMAX->guisection = _("Output options");
+
+	output_VEL = G_define_option();
+	output_VEL->key = "v";
+	output_VEL->type = TYPE_STRING;
+	output_VEL->required = NO;
+	output_VEL->gisprompt = "new,cell,raster";
+	output_VEL->description = _("Prefix for flow velocity output raster maps");
+	output_VEL->guisection = _("Output options");
+
+	output_VMAX = G_define_option();
+	output_VMAX->key = "v_max";
+	output_VMAX->type = TYPE_STRING;
+	output_VMAX->required = NO;
+	output_VMAX->gisprompt = "new,cell,raster";
+	output_VMAX->description = _("Prefix for maximum flow velocity output raster maps");
+	output_VMAX->guisection = _("Output options");
+
+    flag_i = G_define_flag();
+    flag_i->key = 'i';
+    flag_i->description = _("Print input data");
+
+	if (G_parser(argc, argv))
+		exit(EXIT_FAILURE);
+
+	/***********************************************************************************************************************/
+	/* get entered parameters */
+
+	name_ELEV = input_ELEV->answer;
+	name_DIST = input_DIST->answer;
+	name_HINI = input_HINI->answer;
+
+	result_H = output_H->answer;
+	result_V = output_VEL->answer;
+	result_HMAX = output_HMAX->answer;
+	result_VMAX = output_VMAX->answer;
+
+	G_debug(1,"Getting numeric input data...");
+
+	if (strcmp(input_RHEOL->answer, "frictional") == 0)
+		RHEOL_TYPE = 1;
+	if (strcmp(input_RHEOL->answer, "Voellmy") == 0)
+		RHEOL_TYPE = 2;
+	if (strcmp(input_RHEOL->answer, "viscoplastic") == 0)
+		RHEOL_TYPE = 3;
+
+
+	if (input_RHO->answer)
+		sscanf(input_RHO->answer, "%f", &RHO);
+	else
+		RHO = -1;
+
+	if (input_YSTRESS->answer)
+		sscanf(input_YSTRESS->answer, "%f", &YSTRESS);
+	else
+		YSTRESS = -1;
+
+	if (input_CHEZY->answer)
+		sscanf(input_CHEZY->answer, "%f", &CHEZY);
+	else
+		CHEZY = -1;
+	
+	if (input_VISCO->answer)
+		sscanf(input_VISCO->answer, "%f", &VISCO);
+	else
+		VISCO = -1;
+	
+	if (input_BFRICT->answer)
+		sscanf(input_BFRICT->answer, "%f", &BFRICT);
+	else
+		BFRICT = -1;
+
+	if (input_NS_THRES->answer)
+		sscanf(input_NS_THRES->answer, "%f", &NS_THRES);
+	else
+		NS_THRES = -1;
+
+	sscanf(input_IFRICT->answer, "%f", &IFRICT);
+
+	sscanf(input_FLUID->answer, "%f", &FLUID);
+
+	if (input_DELTAT->answer)
+		DELTAT = atoi(input_DELTAT->answer);
+	else
+		DELTAT = -1;
+
+	TIMESTEPS = atoi(input_TIMESTEPS->answer);
+
+	/* check outputs required */
+	if (!((result_H) || (result_V) || (result_HMAX) || (result_VMAX))){
+		G_fatal_error(_("No output specified"));
+	}
+	
+	/* check rheology parameters */
+	testPar = check_rheol_par(RHEOL_TYPE, CHEZY, VISCO, RHO);
+	
+	if (testPar == -2)
+		G_fatal_error(_("For the selected rheology Chezy parameter is required"));
+	
+	if (testPar == -3)
+		G_fatal_error(_("For the selected rheology viscosity and density parameters are required"));
+	
+	/* report Input Data */
+	if (flag_i->answer){
+		report_input(IFRICT,RHO, YSTRESS, VISCO, CHEZY, BFRICT,FLUID, NS_THRES, TIMESTEPS, DELTAT);
+	}
+
+	G_debug(2,"Verifiyng raster maps input data...");
+
+	/* find maps in mapset */
+	mapset_ELEV = (char *) G_find_raster2(name_ELEV, "");
+	if (mapset_ELEV == NULL)
+		G_fatal_error(_("cell file [%s] not found"), name_ELEV);
+
+	mapset_DIST = (char *) G_find_raster2(name_DIST, "");
+	if (mapset_DIST == NULL)
+		G_fatal_error(_("cell file [%s] not found"), name_DIST);
+
+	mapset_HINI = (char *) G_find_raster2(name_HINI, "");
+	if (mapset_HINI == NULL)
+		G_fatal_error(_("cell file [%s] not found"), name_HINI); 
+
+	/* rast_open_old */
+	if ((infd_ELEV = Rast_open_old(name_ELEV, mapset_ELEV)) < 0)
+		G_fatal_error(_("Cannot open cell file [%s]"), name_ELEV);
+
+
+	if ((infd_DIST = Rast_open_old(name_DIST, mapset_DIST)) < 0)
+		G_fatal_error(_("Cannot open cell file [%s]"), name_DIST);
+
+	if ((infd_HINI = Rast_open_old(name_HINI, mapset_HINI)) < 0)
+		G_fatal_error(_("Cannot open cell file [%s]"), name_HINI);
+
+
+	/* controlling if we can open input raster */
+	Rast_get_cellhd(name_ELEV, mapset_ELEV, &cellhd);
+	G_debug(3, "number of rows %d", cellhd.rows);
+
+	Rast_get_cellhd(name_DIST, mapset_DIST, &cellhd);
+	G_debug(3, "number of rows %d", cellhd.rows);
+
+	Rast_get_cellhd(name_HINI, mapset_HINI, &cellhd); 
+	G_debug(3, "number of rows %d", cellhd.rows);
+
+
+	/* allocate input buffer */
+	inrast_ELEV = Rast_allocate_f_buf(); 
+	inrast_DIST = Rast_allocate_f_buf();
+	inrast_HINI = Rast_allocate_f_buf();
+
+	G_debug(1,"Getting region extension...");
+
+	/* get windows rows & cols */
+	nrows = Rast_window_rows();
+	ncols = Rast_window_cols();
+	G_get_window(&window);
+	res_ew = window.ew_res;
+	res_ns = window.ns_res;
+	ca = res_ns * res_ew;
+
+
+	G_debug(2,"Allocating memory matrix...");
+
+	/* allocate memory matrix */
+	m_ELEV = G_alloc_fmatrix(nrows, ncols);
+	m_OUTLET = G_alloc_imatrix(nrows, ncols);
+	m_DIST = G_alloc_fmatrix(nrows, ncols);
+	m_HINI = G_alloc_fmatrix(nrows, ncols);
+	m_gx = G_alloc_fmatrix(nrows, ncols);
+	m_gy = G_alloc_fmatrix(nrows, ncols);
+	m_slope = G_alloc_fmatrix(nrows, ncols);
+	m_U = G_alloc_fmatrix(nrows, ncols);
+	m_Uloop = G_alloc_fmatrix(nrows, ncols);
+	m_Uloop_dt = G_alloc_fmatrix(nrows, ncols);
+	m_V = G_alloc_fmatrix(nrows, ncols);
+	m_Vloop = G_alloc_fmatrix(nrows, ncols);
+	m_Vloop_dt = G_alloc_fmatrix(nrows, ncols);
+	m_H = G_alloc_fmatrix(nrows, ncols);
+	m_Hloop = G_alloc_fmatrix(nrows, ncols);
+	m_Hloop_dt = G_alloc_fmatrix(nrows, ncols);
+	m_Hland = G_alloc_fmatrix(nrows, ncols);
+	m_K = G_alloc_fmatrix(nrows, ncols);
+	m_Kloop = G_alloc_fmatrix(nrows, ncols);
+	m_HUloop = G_alloc_fmatrix(nrows, ncols);
+	m_HVloop = G_alloc_fmatrix(nrows, ncols);
+
+	if (NS_THRES!=-1){
+		m_Hold= G_alloc_fmatrix(nrows, ncols);
+	}
+
+	if (result_HMAX){
+		m_Hmax = G_alloc_fmatrix(nrows, ncols);
+	}
+
+	if (result_VMAX){
+		m_Vmax = G_alloc_fmatrix(nrows, ncols);
+	}
+
+	/* read rows */
+	G_debug(2,"Reading input maps...");
+	for (row = 0; row < nrows; row++) {
+
+		/* read a line input maps into buffers*/
+		Rast_get_f_row(infd_ELEV, inrast_ELEV, row);
+		Rast_get_f_row(infd_DIST, inrast_DIST, row);
+		Rast_get_f_row(infd_HINI, inrast_HINI, row);
+
+		for (col = 0; col < ncols; col++) {
+			elev_fcell_val = ((FCELL *) inrast_ELEV)[col];
+			dist_fcell_val = ((FCELL *) inrast_DIST)[col];
+			hini_fcell_val = ((FCELL *) inrast_HINI)[col];
+
+			/* elevation map */
+			if (Rast_is_f_null_value(&elev_fcell_val) == 1) {
+				m_ELEV[row][col] = nullo;
+			} else {
+				m_ELEV[row][col] = ((FCELL *) inrast_ELEV)[col];
+			}
+
+			/* distance map */
+			if (Rast_is_f_null_value(&dist_fcell_val) == 1) {
+				m_DIST[row][col] = nullo;
+			} else {
+				m_DIST[row][col] = ((FCELL *) inrast_DIST)[col];
+			}
+
+			/* hini map */      
+			if (Rast_is_f_null_value(&hini_fcell_val) == 1) {
+				m_HINI[row][col] = nullo;
+			} else {
+				m_HINI[row][col] = ((FCELL *) inrast_HINI)[col];
+			}
+
+		}
+	}
+
+	/* memory cleanup */
+	G_free(inrast_ELEV);
+	G_free(inrast_DIST);
+	G_free(inrast_HINI);
+
+	/* closing raster map */
+	Rast_close(infd_ELEV);
+	Rast_close(infd_DIST);
+	Rast_close(infd_HINI);
+
+
+	/* earth pressure coefficient */
+	k_act = (1 - sin((M_PI * IFRICT) / 180.0))
+			/ (1 + sin((M_PI * IFRICT) / 180.0));
+
+	k_pas = (1 + sin((M_PI * IFRICT) / 180.0))
+			/ (1 - sin((M_PI * IFRICT) / 180.0));
+
+	G_debug(1,"K_pas value = %f",k_pas);
+	G_debug(1,"K_act value = %f",k_act);
+
+
+	/* inizializzazione matrici in memoria: U,V,H,gx,gz,slope */
+
+	for (row = 0; row < nrows; row++) {
+		for (col = 0; col < ncols; col++) {
+
+			m_H[row][col] = 0;
+			m_Hloop[row][col] = 0;
+			m_Hloop_dt[row][col] = 0;
+			m_Hland[row][col] = 0;
+			m_U[row][col] = 0;
+			m_Uloop[row][col] = 0;
+			m_Uloop_dt[row][col] = 0;
+			m_V[row][col] = 0;
+			m_Vloop[row][col] = 0;
+			m_Vloop_dt[row][col] = 0;
+			m_K[row][col] = nullo;
+			m_gx[row][col] = nullo;
+			m_gy[row][col] = nullo;
+			m_slope[row][col] = nullo;
+			m_HUloop[row][col] = 0;
+			m_HVloop[row][col] = 0;
+		}
+	}
+
+	for (row = 0; row < nrows; row++) {
+		for (col = 0; col < ncols; col++) {
+			if (row==0 || row==1 || col==0 || col==1 || row==nrows-1 || col==ncols-1 || row==nrows-2 || col==ncols-2)
+				m_OUTLET[row][col]=1;
+			else
+				m_OUTLET[row][col]=0;
+		}
+	}
+
+
+	if (NS_THRES!=-1){
+		for (row = 0; row < nrows; row++) {
+			for (col = 0; col < ncols; col++) {
+				m_Hold[row][col] = 0;
+			}
+		}
+	}
+
+
+	if (result_HMAX){
+		for (row = 0; row < nrows; row++) {
+			for (col = 0; col < ncols; col++) {
+				m_Hmax[row][col] = 0;
+			}
+		}
+	}
+
+	if (result_VMAX){
+		for (row = 0; row < nrows; row++) {
+			for (col = 0; col < ncols; col++) {
+				m_Vmax[row][col] = 0;
+			}
+		}
+	}
+
+
+
+   /*---------------------------------------------------------- */
+   /* calcolo matrici gx, gy, slope */
+
+	for (row = 1; row < nrows - 1; row++) {
+		for (col = 1; col < ncols - 1; col++) {
+
+			gx = gradx2(m_ELEV, row, col, res_ew, 0);
+			gy = grady2(m_ELEV, row, col, res_ns, 0);
+
+			/* slope calcolata con Horn 3x3 */
+			slope = sqrt(pow(gradx3(m_ELEV, row, col, res_ew, 0), 2) + pow(grady3(m_ELEV, row, col, res_ns, 0), 2));
+			m_gx[row][col] = gx;
+			m_gy[row][col] = gy;
+			m_slope[row][col] = slope;
+
+		}
+	}
+
+
+	/* Starting loops*/
+	int t=1;
+	int i;
+	int loop, n_loops = 1;
+	float incr_volexp = 0;
+	float Vol_gone=0;
+	float Vol_exp=0;
+	float Vol_actual=0;
+	int NS_count = 0;
+
+
+	/* while: for each timestep or until NS_count<3 */
+    while (NS_count<3 && t<=TIMESTEPS) {
+		i = t - 1;
+
+		float CFL_max = 0;
+		int stable = 0;
+
+		for (row = 1; row < nrows - 1; row++) {
+			for (col = 1; col < ncols - 1; col++) {
+
+				/* Ricalcolo H in funzione di H_fluid e calcolo incremento di Volume aspettato */
+				if (m_DIST[row][col] <= i * dT * FLUID
+						&& m_DIST[row][col] > (i - 1) * dT * FLUID) {
+					H_fluid = m_HINI[row][col];
+					m_H[row][col] += H_fluid;
+				} else {
+					H_fluid = 0.0;
+				}
+				incr_volexp += H_fluid/(cos(atan(m_slope[row][col])))*ca;
+
+
+				/* Calcolo Hland */
+				if (m_DIST[row][col] > i * dT * FLUID) {
+					m_Hland[row][col] = m_HINI[row][col];
+				} else {
+					m_Hland[row][col] = 0.0;
+				}
+			}
+		}
+
+		G_debug(1,"\nTIMESTEP %i",t);
+		G_debug(1,"Volume expected increment = %f",incr_volexp);
+
+		/* ciclo while */
+		while (stable==0) {
+			int exit = 0;
+
+
+			G_debug(2,"Updating maps and volumes");
+
+			/* Aggiornamento Hloop,Vloop e Uloop */
+			for (row = 1; row < nrows - 1; row++) {
+				for (col = 1; col < ncols - 1; col++) {
+					m_Hloop[row][col] = m_H[row][col];
+					m_Uloop[row][col] = m_U[row][col];
+					m_Vloop[row][col] = m_V[row][col];
+				}
+			}
+
+			/* Aggiornamento Volumi */
+			Vol_gone_loop = Vol_gone;
+			Vol_exp_loop = Vol_exp;
+			Vol_actual = 0;
+
+
+			/* Per ogni iterazione */
+			G_debug(1,"\n---NLOOPS=%i---",n_loops);
+			for (loop = 1; loop <= n_loops && exit == 0; loop++) {
+				G_debug(1,"\n-LOOP=%i",loop);
+
+
+				G_debug(2,"Updating K and Kloop matrix");
+
+				for (row = 1; row < nrows - 1; row++) {
+					for (col = 1; col < ncols - 1; col++) {
+						if ((gradx2(m_Uloop, row, col, res_ew, 0)
+								+ grady2(m_Vloop, row, col, res_ns, 0)) >= 0)
+							m_K[row][col] = k_act;
+						else
+							m_K[row][col] = k_pas;
+					}
+				}
+
+
+				for (row = 1; row < nrows - 1; row++) {
+					for (col = 1; col < ncols - 1; col++) {
+						m_Kloop[row][col] = lax(m_K, row, col, laxfactor);
+					}
+				}
+
+
+				/* ciclo row-col per calcolare G, P, I, T, Tb */
+				G_debug(2,"Calculating G, P, I, T, Tb");
+
+				for (row = 1; row < nrows - 1 && exit == 0; row++) {
+					for (col = 1; col < ncols - 1 && exit == 0; col++) {
+
+						/* Calcolo G_x e G_y */
+
+						if (m_Hloop[row][col] > verysmall) {
+							G_x = -grav * (sin(atan(m_gx[row][col])));
+						} else {
+							G_x = 0.0;
+						}
+
+
+						if (m_Hloop[row][col] > verysmall) {
+							G_y = -grav * (sin(atan(m_gy[row][col])));
+						} else {
+							G_y = 0.0;
+						}
+
+
+						/* Calcolo I_x e I_y */
+
+						I_x = -((m_Uloop[row][col] * (cos(atan(m_gx[row][col])))
+								* gradx2(m_Uloop, row, col, res_ew, 1))
+								+ (m_Vloop[row][col] * (cos(atan(m_gy[row][col])))
+										* grady2(m_Uloop, row, col, res_ew, 1)));
+
+						I_y = -((m_Uloop[row][col] * (cos(atan(m_gx[row][col])))
+								* gradx2(m_Vloop, row, col, res_ew, 1))
+								+ (m_Vloop[row][col] * (cos(atan(m_gy[row][col])))
+										* grady2(m_Vloop, row, col, res_ns, 1)));
+
+
+						/* Calcolo P_x e P_y */
+
+						if (m_Hloop[row][col] > verysmall) {
+							P_x = -m_Kloop[row][col] * cos(atan(m_gx[row][col]))
+									* gradPx2(m_Hloop, m_Hland, m_gx, row, col,
+											res_ew);
+						} else {
+							P_x = 0.0;
+						}
+
+						if (m_Hloop[row][col] > verysmall) {
+							P_y = -m_Kloop[row][col] * cos(atan(m_gy[row][col]))
+									* gradPy2(m_Hloop, m_Hland, m_gy, row, col,
+											res_ns);
+						} else {
+							P_y = 0.0;
+						}
+
+
+						/* Calcolo T_x e T_y */
+
+						vel = sqrt(
+								pow(m_Uloop[row][col], 2)
+										+ pow(m_Vloop[row][col], 2));
+
+
+						if (RHEOL_TYPE == 1) {
+							T = t_frict(m_Hloop, row, col, BFRICT);
+						}
+
+						if (RHEOL_TYPE == 2) {
+							T = t_voellmy(vel, m_Hloop, row, col, BFRICT, CHEZY);
+						}
+
+						if (RHEOL_TYPE == 3) {
+							T = t_visco(vel, m_Hloop, row, col, BFRICT, RHO, VISCO,
+									YSTRESS);
+						}
+
+						if (m_Hloop[row][col] > verysmall && vel > verysmall) {
+							T_x = fabs(m_Uloop[row][col]) / vel * grav
+									* (cos(atan(m_gx[row][col]))) * T;
+							T_y = fabs(m_Vloop[row][col]) / vel * grav
+									* (cos(atan(m_gy[row][col]))) * T;
+						}
+
+						else {
+							T_x = grav * (cos(atan(m_gx[row][col]))) * T;
+							T_y = grav * (cos(atan(m_gy[row][col]))) * T;
+						}
+
+
+						/* Stima del flusso a t + ddt */
+						ddt = dTLeap * dT / n_loops;
+
+						/* Lax su Uloop e Vloop se is_df altrimenti 0 */
+
+						Uloop_a = filter_lax(m_Uloop, row, col, laxfactor, m_Hloop, 0.01, 0.0);
+						Vloop_a = filter_lax(m_Vloop, row, col, laxfactor, m_Hloop, 0.01, 0.0);
+
+						/* Calcolo U_loop_b e V_loop_b */
+
+						Uloop_b = veldt(Uloop_a, ddt, G_x, P_x, I_x, T_x);
+						Vloop_b = veldt(Vloop_a, ddt, G_y, P_y, I_y, T_y);
+
+
+						/* Calcolo T_x_b, T_y_b in funzione delle nuove Uloop_b, Vloop_b */
+
+						vel_b = sqrt(pow(Uloop_b, 2) + pow(Vloop_b, 2));
+
+
+						if (RHEOL_TYPE == 1) {
+							T_b = T;
+						}
+
+						if (RHEOL_TYPE == 2) {
+							T_b = t_voellmy(vel_b, m_Hloop, row, col, BFRICT,
+									CHEZY);
+						}
+
+						if (RHEOL_TYPE == 3) {
+							T_b = t_visco(vel_b, m_Hloop, row, col, BFRICT, RHO,
+									VISCO, YSTRESS);
+						}
+
+
+						if (m_Hloop[row][col] > verysmall && vel_b > verysmall) {
+							T_x_b = fabs(Uloop_b) / vel_b * grav
+									* (cos(atan(m_gx[row][col]))) * T_b;
+							T_y_b = fabs(Vloop_b) / vel_b * grav
+									* (cos(atan(m_gy[row][col]))) * T_b;
+						} else {
+							T_x_b = grav * (cos(atan(m_gx[row][col]))) * T_b;
+							T_y_b = grav * (cos(atan(m_gy[row][col]))) * T_b;
+						}
+
+
+						/* Stima del flusso a t + dt*/
+
+						dt = dT / n_loops;
+						Uloop_dt = veldt(Uloop_a, dt, G_x, P_x, I_x, T_x_b);
+						Vloop_dt = veldt(Vloop_a, dt, G_y, P_y, I_y, T_y_b);
+
+						/* Calcolo del valore Courant-Friendrichs-Levy */
+
+						CFL_u = dt * sqrt(2)
+								* fabs((cos(atan(m_gx[row][col]))) * Uloop_dt)
+								/ res_ew;
+
+						CFL_v = dt * sqrt(2)
+								* fabs((cos(atan(m_gy[row][col]))) * Vloop_dt)
+								/ res_ns;
+
+						CFL = max(CFL_u,CFL_v);
+
+
+						if (CFL > CFL_max)
+							CFL_max = CFL;
+
+						/*	Verifica della condizione di stabilità */
+
+						if (CFL_max > CFLlimsup && n_loops < MaxNLoops) {
+							exit = 1;
+							n_loops += 1;
+							CFL_max=0;
+						} else {
+							m_Uloop_dt[row][col] = Uloop_dt;
+							m_Vloop_dt[row][col] = Vloop_dt;
+
+
+							if (m_Hloop[row][col] > verysmall) {
+								m_HUloop[row][col] = m_Hloop[row][col] * Uloop_dt;
+								m_HVloop[row][col] = m_Hloop[row][col] * Vloop_dt;
+							} else {
+								m_HUloop[row][col] = 0.0;
+								m_HVloop[row][col] = 0.0;
+							}
+						}
+					} /*chiusura FOR cols*/
+				} /*chiusura FOR rows*/
+
+				G_debug(2,"CFL_max=%f",CFL_max);
+
+				if (exit==0) {
+					G_debug(2,"Calculating Hloop_dt without mbe for loop");
+
+					for (row = 1; row < nrows - 1 && exit == 0; row++) {
+						for (col = 1; col < ncols - 1 && exit == 0; col++) {
+
+							/* calcolo dH/dT */
+							dH_dT = -cos(atan(m_gx[row][col]))* (shift0(m_HUloop,row,col,nrows-1,ncols-1,1,1,0,-1)-shift0(m_HUloop,row,col,nrows-1,ncols-1,1,1,0,1))/(2*res_ew/cos(atan(m_gx[row][col])))
+									-cos(atan(m_gy[row][col]))* (shift0(m_HVloop,row,col,nrows-1,ncols-1,1,1,1,0)-shift0(m_HVloop,row,col,nrows-1,ncols-1,1,1,-1,0))/(2*res_ns/cos(atan(m_gy[row][col])));
+
+							/* Lax su Hloop e calcolo Hloop_dt (senza mbe) */
+
+							if (dH_dT==0) {
+								Hloop_a=m_Hloop[row][col];
+							} else {
+								Hloop_a = filter_lax(m_Hloop, row, col, laxfactor, m_Hloop, 0.01, 0.0);
+							}
+
+							Hloop_dt = Hloop_a - dT/n_loops * dH_dT;
+
+
+							/* Vol_gone_loop */
+							Vol_actual += Hloop_dt/(cos(atan(m_slope[row][col])))*ca;
+							if (m_OUTLET[row][col]==1){
+								/*Vol_gone_no_mbe = Hloop_dt/(cos(atan(m_slope[row][col])))*ca;*/
+								Vol_gone_loop += Hloop_dt/(cos(atan(m_slope[row][col])))*ca;
+								Hloop_dt = 0.0;
+							}
+
+							/* matrice H_loop_dtemp */
+							m_Hloop_dt[row][col] = Hloop_dt;
+
+						}/*chiusura FOR col*/
+					}/*chiusura FOR row*/
+
+
+					/* m.b.e */
+					G_debug(2,"Calculating mass balance error");
+
+					Vol_exp_loop += incr_volexp/n_loops;
+
+					if (Vol_exp_loop > 0.01) {
+						mbe = Vol_actual/Vol_exp_loop;
+					} else {
+						mbe = 1;
+					}
+
+					G_debug(2,"mbe=%f",mbe);
+					
+					/*Vol_gone_loop += Vol_gone_no_mbe/mbe;*/
+					Vol_actual = 0;
+
+					/* Hloop_dt con mbe */
+					G_debug(2,"Calculating Hloop_dt with mbe for loop");
+
+					for (row = 1; row < nrows - 1 && exit == 0; row++) {
+						for (col = 1; col < ncols - 1 && exit == 0; col++) {
+							if (mbe > 0.01){
+								m_Hloop_dt[row][col]=m_Hloop_dt[row][col]/mbe;
+							}
+						}
+					}
+
+					/* loop<n_loops */
+					if (loop<n_loops) {
+						G_debug(2,"loop<n_loops");
+
+						for (row = 1; row < nrows - 1 && exit == 0; row++) {
+							for (col = 1; col < ncols - 1 && exit == 0; col++) {
+								m_Hloop[row][col]=m_Hloop_dt[row][col];
+								m_Uloop[row][col]=m_Uloop_dt[row][col];
+								m_Vloop[row][col]=m_Vloop_dt[row][col];
+							}
+						}
+					}
+
+				}/* chiusura IF exit*/
+
+			} /*chiusura FOR loops*/
+
+			if (exit==0) {
+				G_debug(2,"FINISH N_LOOPS");
+
+
+				/*------Nash-Sutcliffe-------*/
+				if (NS_THRES!=-1){
+					G_debug(1,"Calculating Nash-Sutcliffe value");
+					if (t==1){
+						NSold = nash_sutcliffe(m_Hold,m_Hloop_dt,nrows, ncols);
+					} else {
+						NS = nash_sutcliffe(m_Hold,m_Hloop_dt, nrows, ncols);
+						G_debug(1,"NS old value=%f",NSold);
+						G_debug(1,"NS value=%f",NS);
+
+						if(fabs(NS-NSold) <= NS_THRES){
+							NS_count += 1;
+						} else {
+							NS_count = 0;
+						}
+						NSold = NS;
+					}
+					G_debug(1,"NS count=%i",NS_count);
+				}
+				
+				for (row = 1; row < nrows - 1; row++) {
+					for (col = 1; col < ncols - 1; col++) {
+						m_H[row][col]=m_Hloop_dt[row][col];
+						m_U[row][col]=m_Uloop_dt[row][col];
+						m_V[row][col]=m_Vloop_dt[row][col];
+						if (NS_THRES!=-1){
+							m_Hold[row][col]=m_Hloop_dt[row][col];
+						}
+					}
+				}
+
+				if (result_HMAX){
+					for (row = 1; row < nrows - 1; row++) {
+						for (col = 1; col < ncols - 1; col++) {
+							if(m_H[row][col]+m_Hland[row][col] > m_Hmax[row][col])
+								m_Hmax[row][col] = m_H[row][col]+m_Hland[row][col];
+						}
+					}
+				}
+
+				if (result_VMAX){
+					for (row = 1; row < nrows - 1; row++) {
+						for (col = 1; col < ncols - 1; col++) {
+							if (m_H[row][col]>verysmall){
+								if ((sqrt(pow(m_U[row][col],2)+pow(m_V[row][col],2)))>m_Vmax[row][col]){
+									m_Vmax[row][col]=(sqrt(pow(m_U[row][col],2)+pow(m_V[row][col],2)));
+								}
+							}
+						}
+					}
+				}
+
+				stable=1;
+				G_debug(1,"Vol_gone_loop=%f\n",Vol_gone_loop);
+
+
+				Vol_exp=Vol_exp_loop;
+				Vol_gone=Vol_gone_loop;
+
+				incr_volexp=0.0;
+				if (CFL_max<=CFLliminf) {
+					n_loops=max(n_loops-1,MinNLoops);
+				}
+
+				/*------- DEFAULT OUTPUT SERIES--------*/
+
+				if((DELTAT!=-1 && t%DELTAT==0) || (t==TIMESTEPS) || (NS_count==3)){
+
+					if(result_H){
+						sprintf(name1,"%s_t%d",result_H,t);
+						out_sum_print(m_Hland,m_H,m_U,m_V,name1,nrows,ncols,1,0.01);
+						Rast_short_history(name1, "raster", &history);
+						Rast_command_history(&history);
+						Rast_write_history(name1, &history);
+					}
+					if(result_V){
+						sprintf(name1,"%s_t%d",result_V,t);
+						out_sum_print(m_Hland,m_H,m_U,m_V,name1,nrows,ncols,2,0.01);
+						Rast_short_history(name1, "raster", &history);
+						Rast_command_history(&history);
+						Rast_write_history(name1, &history);
+					}
+				}
+
+
+				if((result_HMAX) && ((t==TIMESTEPS) || (NS_count==3))){
+					sprintf(name1,"%s",result_HMAX);
+					out_print(m_Hmax,name1,nrows,ncols);
+					Rast_short_history(name1, "raster", &history);
+					Rast_command_history(&history);
+					Rast_write_history(name1, &history);
+				}
+
+				if((result_VMAX) && ((t==TIMESTEPS) || (NS_count==3))){
+					sprintf(name1,"%s",result_VMAX);
+					out_print(m_Vmax,name1,nrows,ncols);
+					Rast_short_history(name1, "raster", &history);
+					Rast_command_history(&history);
+					Rast_write_history(name1, &history);
+				}
+
+
+			} /*chiusura IF exit*/
+		} /*chiusura WHILE*/
+		t++;
+	} /* chiusura WHILE NS_count*/
+
+	if (Vol_gone>0){
+		G_warning("The flow is out of the current computational domain. You may need to change the region extension.");
+		G_warning("Volume gone: %f",Vol_gone);
+	}
+
+
+	/* deallocate memory matrix */
+	G_free_fmatrix(m_ELEV);
+	G_free_imatrix(m_OUTLET);
+	G_free_fmatrix(m_DIST);
+	G_free_fmatrix(m_HINI);
+	G_free_fmatrix(m_gx);
+	G_free_fmatrix(m_gy);
+	G_free_fmatrix(m_slope);
+	G_free_fmatrix(m_H);
+	G_free_fmatrix(m_Hloop);
+	G_free_fmatrix(m_Hloop_dt);
+	G_free_fmatrix(m_Hland);
+	G_free_fmatrix(m_U);
+	G_free_fmatrix(m_Uloop);
+	G_free_fmatrix(m_Uloop_dt);
+	G_free_fmatrix(m_V);
+	G_free_fmatrix(m_Vloop);
+	G_free_fmatrix(m_Vloop_dt);
+	G_free_fmatrix(m_K);
+	G_free_fmatrix(m_Kloop);
+	G_free_fmatrix(m_HUloop);
+	G_free_fmatrix(m_HVloop);
+
+	if (NS_THRES!=-1)
+		G_free_fmatrix(m_Hold);
+
+	if (result_VMAX)
+		G_free_fmatrix(m_Vmax);
+
+	if (result_HMAX)
+		G_free_fmatrix(m_Hmax);
+		
+	exit(EXIT_SUCCESS);
+}

Added: grass-addons/grass7/grass7/raster/r.massmov/r.massmov.html
===================================================================
--- grass-addons/grass7/grass7/raster/r.massmov/r.massmov.html	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.massmov/r.massmov.html	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,81 @@
+<h2>DESCRIPTION</h2>
+
+MassMov2D is a numerical model that allows users to simulate the expansion (runout)
+and deposition of mass movements over a complex topography by approximating the
+heterogeneous sliding mass to a homogeneous one-phase fluid (following the approach
+proposed by Savage and Hutter (1989) and Iverson and Denlinger (2001).
+The model describes the mass movements as a two-dimensional flux taking advantage
+of the shallow water equations. This formula is derived from the general Navier-
+Stokes equations under the hypothesis that the vertical components of velocity and
+pressure are negligible with respect to the horizontal components, and that the vertical
+pressure profile can be considered as almost hydrostatic (Kinnmark 1985).
+
+<p>
+The required inputs can be classified in three categories based on the information type:
+<ul>
+<li> raster maps of the topography, in particular the sliding surface topography (digital terrain
+model without the sliding body), the initial sliding mass thickness and the 'distance map',
+representing the cells distance from the collapsing body lower limit;</li>
+<li> numerical parameters for the characterization of the mass material, density [kg/m3], apparent
+yield stress [Pa], Chezy roughness coefficient [m/s2], dynamic viscosity [Pa*s], basal friction
+angle [deg], internal friction angle of the sliding mass during the expansion [deg] and the fluid rate [m/s].This last parameter provides information on the transaction velocity of the
+sliding mass when passes from a solid state to a fluid state; together with the 'distance map'
+it allows to define the amount of mass mobilized as a function of time. It is worth noting that
+depending on the selected rheological law different sets of parameters are mandatory;</li>
+<li>control parameters that are used to stop the simulation, like maximum time step number and/or Nash-Sutcliff tresholds value.</li>
+</ul>
+
+The model outputs a series of flux velocity map and deposit depth raster map at different time step according to the setted <i>deltatime</i> parameter; Additionally the module outputs two raster maps representing the maximum thickness and velocity registered during the simulation.
+
+<h2>NOTES</h2>
+The generation of the model input maps, in case the simulation refer to en existing collapse and pre and post event DTM is available, can be performed taking advantage of the GRASS modules; in
+particular:
+
+<ul>
+<li>the sliding surface can be calculated by subtracting the collapsing body from the pre-event
+DTM (r.mapcalc) </li>
+<li>the collapsing body thickness can  evaluated by considering the negative differences between
+the post and pre-event DTM multiplied for the cosine of the slope (r.mapcalc and
+r.slope.aspect)</li>
+<li>the distance map from the landslide toe can be obtained by applying the r.grow.distance module to the rasterized limits of the landslide</li>
+</ul>
+
+<h2>DIAGNOSTICS</h2>
+The module has been tested in several cases (see references), but up to now most of the simulations was done using a Voellmy rheology thus other rheology laws should be better investigated.
+
+
+<h2>REFERENCES</h2>
+<ul>
+<li>Savage S B and Hutter K 1989 The motion of a finite mass of granular material down a rough
+incline. Journal of Fluid Mechanics 199:177-215</li>
+
+<li>Iverson R M and Denlinger R P 2001 Flow of variably fluidized granular masses across 
+threedimensional terrain: 1, Coulomb mixture theory. Journal of Geophysical Research 106:537-52</li>
+
+<li>Kinnmark I P E 1985 The shallow water equations: Formulation, analysis and application. In
+Brebia C A and Orszag S A (eds) Lecture Notes in Engineering 15. Berlin, Springer-Verlag:1-187</li>
+
+<li>Begueria S, Van Asch T W J, Malet J P and Grondahl S 2009 A GIS based numerical model for simulating the kinematics 
+of mud and debris flows over complex terrain. Nat Hazards Earth Syst Sci, 9, 1897-1909.</li>
+
+<li>Molinari M, Cannata M, Begueria S and Ambrosi C 2012 GIS-based Calibration of MassMov2D. 
+Transactions in GIS, 2012, 16(2):215-231</li>
+</ul>
+
+<h2>SEE ALSO</h2>
+
+<em>
+<a href="r.grow.distance.html">r.grow.distance</a>,
+<a href="r.slope.aspect.html">r.slope.aspect</a>,
+<a href="r.mapcalc.html">r.mapcalc</a>
+</em>
+
+<h2>AUTHORS</h2>
+
+<p><i>Original version of program:</i>
+<br>Santiago Begueria
+
+<p><i>The current version of the program (ported to GRASS7.0)</i>:
+<br>Monia Molinari, Massimiliano Cannata, Santiago Begueria.<br>
+
+<p><i>Last changed: $Date: 2012-06-02 09:28:14 +0200 (Sat, 02 Jun 2012) $</i>

Added: grass-addons/grass7/grass7/raster/r.mess/Makefile
===================================================================
--- grass-addons/grass7/grass7/raster/r.mess/Makefile	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.mess/Makefile	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,7 @@
+MODULE_TOPDIR = ../..
+
+PGM = r.mess
+
+include $(MODULE_TOPDIR)/include/Make/Script.make
+
+default: script

Added: grass-addons/grass7/grass7/raster/r.mess/r.mess
===================================================================
--- grass-addons/grass7/grass7/raster/r.mess/r.mess	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.mess/r.mess	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,349 @@
+#!/bin/sh
+# 
+########################################################################
+# 
+# MODULE:       r.mess
+# AUTHOR(S):    Paulo van Breugel <p.vanbreugel AT gmail.com>
+# PURPOSE:      Calculate the multivariate environmental similarity 
+#               surface (MESS) as proposed by Elith et al., 2010, 
+#               Methods in Ecology & Evolution, 1(330–342). 
+#
+# NOTES:        This GRASS script should give results very close (but
+#               due to rounding differences probably not exactly the 
+#               same) to those calculated in Maxent. However, note that
+#               Maxent uses, as far as I understand, the background 
+#               points. Therefore, if you want to compare the MESS layer 
+#               as calculated by Maxent with the results of this script
+#               you need to make sure to use the same points as input
+#
+# Disclaimer:   I use it in my work, but I am aware that it needs
+#               improvements. Suggestions for improvements are most
+#               welcome. In the meantime, use it at your own risk
+#   
+# COPYRIGHT: (C) 2012 Paulo van Breugel
+#            http://ecodiv.org
+#            http://pvanb.wordpress.com/
+# 
+#            This program is free software under the GNU General Public 
+#            License (>=v2). Read the file COPYING that comes with GRASS 
+#            for details. 
+# 
+########################################################################
+#
+#%Module 
+#% description: Computes multivariate environmental similarity surface
+#%End 
+
+#%option
+#% key: vector_input
+#% type: string
+#% gisprompt: old,vector
+#% description: Reference points
+#% key_desc: name
+#% required: yes
+#% multiple: no
+#%end
+
+#%option
+#% key: raster_input
+#% type: string
+#% gisprompt: old,cell,raster
+#% description: Input raster map(s) 
+#% key_desc: names
+#% required: yes
+#% multiple: yes
+#%end
+
+#%option
+#% key: output
+#% type: string
+#% gisprompt: new
+#% description: Root name of the output MESS data layers
+#% key_desc: name
+#% required: yes
+#%end
+
+#%option
+#% key: columns
+#% type: string
+#% description: Columns with environmental variables
+#% key_desc: string
+#% answer: Same names as input layers
+#% required: no
+#%end
+
+##%flag
+##% key: n
+##% description: Keep individual environmental dissimilarity layers (IED)
+##%end
+
+#%flag
+#% key: m
+#% description: Most dissimilar variable (MoD)
+#%end
+
+#%flag
+#% key: k
+#% description: Calculate MESS_mean
+#%end
+
+#%flag
+#% key: l
+#% description: Calculate MESS_median
+#%end
+
+#=======================================================================
+## GRASS team recommandations
+#=======================================================================
+
+## Check if in GRASS
+if  [ -z "$GISBASE" ] ; then
+    echo "You must be in GRASS GIS to run this program." 1>&2
+    exit 1
+fi
+
+## check for awk
+if [ ! -x "$(which awk)" ] ; then
+    g.message -e "<awk> required, please install <awk> or <gawk> first"
+    exit 1
+fi
+
+## To parse the code into interactive menu
+if [ "$1" != "@ARGS_PARSED@" ] ; then
+    exec g.parser "$0" "$@"
+fi
+
+## set environment so that awk works properly in all languages ##
+unset LC_ALL
+export LC_NUMERIC=C
+
+
+## what to do in case of user break:
+exitprocedure()
+{
+    echo "User break!"
+    cleanup
+    exit 1
+}
+
+## shell check for user break (signal list: trap -l)
+trap "exitprocedure" 2 3 15
+
+#=======================================================================
+## testing if output maps already exist
+#=======================================================================
+
+## Set easier variable names
+OUTMAPS="${GIS_OPT_OUTPUT}"
+INMAPS="${GIS_OPT_RASTER_INPUT}"
+
+# test for output raster map
+g.findfile element=cell file=${OUTMAPS}_combined  > /dev/null
+    if [ $? -eq 0 ] ; then
+        g.message -e 'There is already a raster <${OUTMAPS}>'
+    exit 1
+fi
+
+# test for output raster maps
+oIFS=$IFS
+IFS=,
+for nvar in $INMAPS ; do
+    arrIN=${OUTMAPS}_`echo $nvar | awk 'BEGIN{FS="@"}{print $1}'`
+    g.findfile element=cell file=${arrIN} > /dev/null
+    if [ $? -eq 0 ] ; then 
+        g.message -e 'There is already a raster <${OUTMAPS}>'
+    exit 1
+    fi
+done
+IFS=$oIFS
+unset arrIN
+
+#=======================================================================
+## Config and general procedures
+#=======================================================================
+
+##fix this path
+if [ -z "$PROCESSDIR" ] ; then
+	PROCESSDIR="$HOME"
+fi
+
+#fix this path
+if [ -z "$LOGDIR" ] ; then
+	LOGDIR="$HOME"
+fi
+LOGFILE="$LOGDIR/r.mess.log"
+
+echo "r.mess :" >> "$LOGFILE"
+
+#=======================================================================
+## Preparing input variables for use in R script
+#=======================================================================
+
+# Create vectors with names output maps [arrOUT]
+# Create vector with names temporary layers [tmpLY]
+# Create vector with names input layers without mapset name [arrIN]
+# The 'removeThis' elements are to initiate the vector. How can I avoid this?
+
+arrOUT="${OUTMAPS}_MESS"
+tmpLY="removeThis"
+arrIN="removeThis2"
+counter=0
+IFS=,
+for nvar in ${INMAPS} ; do
+    arrOUT="$arrOUT;${OUTMAPS}_`echo $nvar | awk 'BEGIN{FS="@"}{print $1}'`"
+    counter=`expr $counter + 1`
+    tmpLY="${tmpLY};tmp.mess_$$_$counter"
+    arrIN="${arrIN};`echo $nvar | awk 'BEGIN{FS="@"}{print $1}'`"
+done
+
+#=======================================================================
+## Creating the R script
+#=======================================================================
+
+writeScript(){ 
+cat > $1 << "EOF"
+
+options(echo = FALSE)
+require(spgrass6)
+
+## Get vector with variables
+args <- commandArgs(trailingOnly=TRUE)
+ipn <- unlist(strsplit(args[1],";"))[-1]   # variable names
+ipl <- unlist(strsplit(args[2],","))       # environmental layers
+opl <- unlist(strsplit(args[3],";"))       # output layers
+opi <- opl[-1]                             # base name individual layers
+opc <- opl[1]                              # name of MESS layer
+tml <- unlist(strsplit(args[4], ";"))[-1]  # temporary layers
+vtl <- args[5]                             # vector layer
+cln <- args[6]
+
+# Import the vector point layer
+spl <- readVECT6(vtl)
+
+# Extract columns and create table
+# Use column names if given, otherwise,
+# use names input layers (ipl)
+if(cln == "Same names as input layers"){
+    spld <- spl at data[,ipn]
+}else{
+    cln <- unlist(strsplit(cln,","))
+    spld <- spl at data
+    spld <- spld[,cln]
+    }
+
+#-----------------------------------------------------------------------
+
+# Create the r.mapcalc expressions to calculate the mess for the 
+# individual layers. The main step is to define the graph function to 
+# be used (check out: possible alternative would be to use reclass)
+if(is.null(dim(spld))){
+    minp <- min(spld)
+    maxp <- max(spld)
+}else{
+    minp <- apply(spld, 2, min)
+    maxp <- apply(spld, 2, max)
+}
+
+for(i in 1:length(ipl)){
+    envir <- system(paste("r.univar -t map=", ipl[i], " fs=,", sep=""), intern=TRUE)
+    envir <- as.numeric(unlist(strsplit(envir[2], split=",")))
+    envmax <- ifelse(envir[4]==maxp[i],maxp[i]+(maxp[i]-minp[i])*0.001,envir[4])
+    envmin <- ifelse(envir[3]==minp[i],minp[i]-(maxp[i]-minp[i])*0.001,envir[3])
+    if(is.null(dim(spld))){
+        a  <- table(spld)
+    }else{a  <- table(spld[,i])
+    }
+    x1 <- as.numeric(rownames(a))
+    x2 <- c(x1[-1],envmax)
+    x3 <- x1 + (x2-x1)/1000
+    a1 <- paste(envmin, paste(x1,x3,sep=",", collapse=","), envmax, sep=",")
+    b  <- round(cumsum(as.numeric(a))/sum(a)*100,3)
+    a2 <- paste(0, 0, paste(b, b, sep=",", collapse=","), sep=",")
+    a3 <- paste(strsplit(a1,",")[[1]],strsplit(a2,",")[[1]],sep=",", collapse=",")
+    
+    system(paste("r.mapcalc '", tml[i], " = graph(", ipl[i], ",", a3, ")'", sep=""))
+    system(paste("r.mapcalc '", opi[i], " = if(", tml[i], "==0, (float(", ipl[i], ")-", minp[i], ")/(", maxp[i], "-", minp[i], ") *100.0, if(", tml[i], "<=50, 2 * ", tml[i], ", if(", tml[i], "<100.0, 2 * (100.0- ", tml[i], "), (", maxp[i], "- float(", ipl[i], "))/(", maxp[i], "-", minp[i], ") * 100.0)))'", sep=""))
+    system(paste("g.remove rast=", tml[i], sep=""))
+
+    # plotting the accumulative frequency plots for each bioclim variable
+    #d1 <- paste(envir[3], paste(x1,x3,sep=",", collapse=","), envir[4], sep=",")
+    #d2 <- paste(0, 0, paste(b, b, sep=",", collapse=","), sep=",")
+    #png(paste(ipn, ".png", sep=""))
+    #plot(strsplit(d1,",")[[1]],strsplit(d2,",")[[1]],type="l", xlab=ipn[i], ylab="% plots")
+    #dev.off()
+}
+
+system(paste("r.series output=", opc, " input=", paste(opi, collapse=","), " method=minimum", sep=""))
+
+# Optionally, calculating extra layers (min_raster, mean and median)
+# Defines categories for min_raster 
+
+if(args[7]==1){
+    system(paste("r.series output=", opc, "_MoD input=", paste(opi, collapse=","), " method=min_raster", sep=""))
+    nuv <- cbind(seq(from=0, to=length(ipn)-1, by = 1), ipn)
+    reclvar <- apply(nuv,1,function(x){paste(x[1],x[2], sep=":")})
+    tmpclas <- tempfile(pattern = "classification.rules.")
+    sink(tmpclas)
+    for(i in 1:length(reclvar)){
+        cat(reclvar[i]); cat("\n")
+    }
+    sink()
+    system(paste("r.category map=", opc, "_MoD rules=", tmpclas, sep=""))
+    unlink(tmpclas)
+}
+if(args[8]==1){
+    system(paste("r.series output=", opc, "_mean input=", paste(opi, collapse=","), " method=minimum", sep=""))
+}
+if(args[9]==1){
+    system(paste("r.series output=", opc, "_median input=", paste(opi, collapse=","), " method=median", sep=""))
+}
+
+EOF
+}
+
+# RGrass script generation
+# --------------------------
+RGRASSSCRIPT="`g.tempfile pid=$$`"
+if [ $? -ne 0 ] || [ -z "$RGRASSSCRIPT" ] ; then
+	g.message -e 'ERROR: unable to create temporary file for RGrass script' 1>&2
+    exit 1
+fi
+writeScript "$RGRASSSCRIPT"
+
+
+#=======================================================================
+## RGrass call
+#=======================================================================
+
+# Message
+g.message message='Calculating MESS layers.. this may take some time'
+
+##using R to create MESS layers
+#--slave
+R --vanilla --args "$arrIN" "${INMAPS}" "$arrOUT" "$tmpLY" "${GIS_OPT_VECTOR_INPUT}" "${GIS_OPT_COLUMNS}" "$GIS_FLAG_M" "$GIS_FLAG_K" "$GIS_FLAG_L" < "$RGRASSSCRIPT" >> "$LOGFILE" 2>&1
+if [ $? -ne 0 ] ; then
+	echo "ERROR: an error occurred during R script execution" 1>&2
+    exit 1
+fi
+
+g.message "Finished"
+
+#=======================================================================
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+


Property changes on: grass-addons/grass7/grass7/raster/r.mess/r.mess
___________________________________________________________________
Added: svn:executable
   + 

Added: grass-addons/grass7/grass7/raster/r.mess/r.mess.html
===================================================================
--- grass-addons/grass7/grass7/raster/r.mess/r.mess.html	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.mess/r.mess.html	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,126 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+<title>GRASS GIS manual: r.mess</title>
+<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+<link rel="stylesheet" href="grassdocs.css" type="text/css">
+</head>
+<body bgcolor="white">
+
+<img src="grass_logo.png" alt="GRASS logo">
+<hr align="center" noshade="noshade" size="6">
+
+<h2>NAME</h2>
+
+<em><b>r.mess</b></em> - Computes the individual and multivariate
+environmental similarity surfaces (IESS and MESS)<br>
+
+<h2>KEYWORDS</h2>
+
+<h2>SYNOPSIS</h2>
+
+<div id="name"><b>r.mess</b><br>
+</div>
+
+<b>r.mess help</b><br>
+
+<div id="synopsis"><b>r.mess</b> [-<b>mkl</b>] <b>vector_input</b>=<em>name</em>
+<b>raster_input</b>=<em>names</em>[,<i>names</i>,...] <b>output</b>=<em>name</em>
+[<b>columns</b>=<em>string</em>] [--<b>overwrite</b>] [--<b>verbose</b>]
+[--<b>quiet</b>] </div>
+
+<div id="flags">
+<h3>Flags:</h3>
+<dl>
+  <dt><b>-m</b></dt>
+  <dd>Most dissimilar variable (MoD)</dd>
+  <dt><b>-k</b></dt>
+  <dd>Calculate MESS_mean - the mean value of the individual <br>
+  </dd>
+  <dt><b>-l</b></dt>
+  <dd>Calculate MESS_median</dd>
+  <dt><b>--overwrite</b></dt>
+  <dd>Allow output files to overwrite existing files</dd>
+  <dt><b>--verbose</b></dt>
+  <dd>Verbose module output</dd>
+  <dt><b>--quiet</b></dt>
+  <dd>Quiet module output</dd>
+</dl>
+</div>
+
+<div id="parameters">
+<h3>Parameters:</h3>
+<dl>
+  <dt><b>vector_input</b>=<em>name</em> <b>[required]</b></dt>
+  <dd>Reference points</dd>
+  <dt><b>raster_input</b>=<em>names[,<i>names</i>,...]</em> <b>[required]</b></dt>
+  <dd>Input raster map(s)</dd>
+  <dt><b>output</b>=<em>name</em> <b>[required]</b></dt>
+  <dd>Root name of the output MESS data layers</dd>
+  <dt><b>columns</b>=<em>string</em></dt>
+  <dd>Columns with environmental variables</dd>
+  <dd>Default: <em>Same names as input layers</em></dd>
+</dl>
+</div>
+
+<div id="description">
+<h2>DESCRIPTION</h2>
+<dl>
+  <p><em>r.mess</em> computes the "Multivariate Environmental
+Similarity
+Surfaces" (MESS) in GRASS using R as backend. The
+MESS index was proposed by Elith et al (2010) and is also
+implemented in the Maxent software. The MESS approach
+can be described as follows (from Elith et al 2010):
+"The multivariate environmental similarity surface (MESS) calculation
+represents how similar a point is to a reference set of points, with
+respect to a set of predictor variables (V1, V2, ...). The values in
+the MESS are
+influenced by the full distribution of the reference points, so that
+sites within the environmental range of the reference points but in
+relatively unusual environments will have a smaller value than those in
+very common environments."</p>
+  <p>This module will also compute the individual environmental
+similarity surfaces (IESS), which represents how similar a point is to
+a set of reference set of points for each of the input variable. MESS
+is then simply calculated as the minimum of its similarity with respect
+to each variable.<br>
+  <br>
+The IESS can have negative values – these are sites where the variable
+has a
+value that is outside the range in the reference set. A negative MESS
+thus represents sites where at least one variable has a value that is
+outside the range of environments over the reference set, so these are
+novel environments.<br>
+  </p>
+  <p>In addition to the MESS, which is the minimum(IESS), the r.mess
+function also allows to compute mean and medium of the IESS layers.<br>
+  </p>
+</dl>
+</div>
+
+<div id="see also">
+<h2>SEE ALSO</h2>
+There is also a similar function implemented for R using the R package <span style="font-style: italic;">raster</span>. See <a href="http://rossijeanpierre.wordpress.com/2012/08/13/computing-the-multivariate-environmental-similarity-surfaces-mess-index-in-r/">here</a>. Since October 3 2012, this function is part of the dismo package in R.
+for more information and the script.<br>
+</div>
+
+<div id="authors">
+<h2>AUTHORS</h2>
+Contact: <a href="http://ecodiv.org/contact.html">Paulo van Breugel</a>
+</div>
+
+<div id="references">
+<h2>REFERENCES</h2>
+<ol>
+  <li>Elith, J., Kearney, M., & Phillips, S. 2010. The art of
+modelling range-shifting species. Methods in Ecology and Evolution 1:
+330–342.</li>
+</ol>
+</div>
+
+<br>
+
+<br>
+
+</body></html>

Added: grass-addons/grass7/grass7/raster/r.modis/Makefile
===================================================================
--- grass-addons/grass7/grass7/raster/r.modis/Makefile	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.modis/Makefile	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,14 @@
+MODULE_TOPDIR =../..
+
+PGM = r.modis
+
+SUBDIRS = \
+        r.modis.download \
+        r.modis.import \
+		libmodis
+
+include $(MODULE_TOPDIR)/include/Make/Dir.make
+
+default: parsubdirs htmldir
+
+install: installsubdirs

Added: grass-addons/grass7/grass7/raster/r.modis/libmodis/Makefile
===================================================================
--- grass-addons/grass7/grass7/raster/r.modis/libmodis/Makefile	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.modis/libmodis/Makefile	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,22 @@
+MODULE_TOPDIR = ../../..
+
+include $(MODULE_TOPDIR)/include/Make/Other.make
+include $(MODULE_TOPDIR)/include/Make/Python.make
+
+MODULES = downmodis rmodislib convertmodis parsemodis
+
+DSTDIR = $(ETC)/r.modis
+
+PYFILES := $(patsubst %,$(DSTDIR)/%.py,$(MODULES))
+PYCFILES := $(patsubst %,$(DSTDIR)/%.pyc,$(MODULES))
+
+default: $(PYFILES) $(PYCFILES)
+
+$(DSTDIR):
+	$(MKDIR) $@
+
+$(DSTDIR)/%: % | $(DSTDIR)
+	$(INSTALL_DATA) $< $@
+
+install:
+	cp -r $(DSTDIR) $(INST_DIR)/etc/

Added: grass-addons/grass7/grass7/raster/r.modis/libmodis/convertmodis.py
===================================================================
--- grass-addons/grass7/grass7/raster/r.modis/libmodis/convertmodis.py	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.modis/libmodis/convertmodis.py	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,221 @@
+#!/usr/bin/env python
+#  class to convert/process modis data
+#
+#  (c) Copyright Luca Delucchi 2010
+#  Authors: Luca Delucchi
+#  Email: luca dot delucchi at iasma dot it
+#
+##################################################################
+#
+#  This MODIS Python class is licensed under the terms of GNU GPL 2.
+#  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 implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+#  See the GNU General Public License for more details.
+#
+##################################################################
+
+from datetime import *
+import string
+import os
+import sys
+import glob
+import logging
+import socket
+from ftplib import FTP
+import ftplib
+
+class convertModis:
+  """A class to convert modis data from hdf to tif using resample (from MRT tools)
+  """
+  def __init__(self, hdfname, confile, mrtpath):
+    """Initialization function :
+       hdfname = the full path to the hdf file
+       confile = the full path to the paramater file
+       mrtpath = the full path to mrt directory where inside you have bin and 
+                 data directories
+    """
+    # check if the hdf file exists
+    if os.path.exists(hdfname):
+      self.name = hdfname
+    else:
+      raise IOError('%s not exists' % hdfname)
+    # check if confile exists
+    if os.path.exists(confile):
+      self.conf = confile
+    else:
+      raise IOError('%s not exists' % confile)
+    # check if mrtpath and subdirectories exists and set environment variables
+    if os.path.exists(mrtpath):
+      if os.path.exists(os.path.join(mrtpath,'bin')):
+        self.mrtpathbin = os.path.join(mrtpath,'bin')
+        os.environ['PATH'] = "%s:%s" % (os.environ['PATH'],os.path.join(mrtpath,
+                                                                        'data'))
+      else:
+        raise IOError('The path %s not exists' % os.path.join(mrtpath,'bin'))
+      if os.path.exists(os.path.join(mrtpath,'data')):
+        self.mrtpathdata = os.path.join(mrtpath,'data')
+        os.environ['MRTDATADIR'] = os.path.join(mrtpath,'data')
+      else:
+        raise IOError('The path %s not exists' % os.path.join(mrtpath,'data'))
+    else:
+      raise IOError('The path %s not exists' % mrtpath)
+
+  def executable(self):
+    """Return the executable of resample MRT software
+    """
+    if sys.platform.count('linux') != -1:
+      if os.path.exists(os.path.join(self.mrtpathbin,'resample')):
+        return os.path.join(self.mrtpathbin,'resample')
+    elif sys.platform.count('win32') != -1:
+      if os.path.exists(os.path.join(self.mrtpathbin,'resample.exe')):
+        return os.path.join(self.mrtpath,'resample.exe')
+
+  def run(self):
+    """Exec the process"""
+    import subprocess
+    execut = self.executable()
+    if not os.path.exists(execut):
+      raise IOError('The path %s not exists, could be an erroneus path or '\
+                    + 'software') % execut
+    else:
+      subprocess.call([execut,'-p',self.conf])
+    return "The hdf file %s was converted" % self.name
+
+class createMosaic:
+  """A class to convert a mosaic of different modis tiles"""
+  def __init__(self,
+              listfile,
+              outprefix,
+              mrtpath,
+              subset = False
+              ):
+    # check if the hdf file exists
+    if os.path.exists(listfile):
+      self.basepath = os.path.split(listfile)[0]
+      self.listfiles = listfile
+      self.HDFfiles = open(listfile).readlines()
+    else:
+      raise IOError('%s not exists' % hdfname)
+    # check if mrtpath and subdirectories exists and set environment variables
+    if os.path.exists(mrtpath):
+      if os.path.exists(os.path.join(mrtpath,'bin')):
+        self.mrtpathbin = os.path.join(mrtpath,'bin')
+        os.environ['PATH'] = "%s:%s" % (os.environ['PATH'],os.path.join(mrtpath,
+                                                                        'data'))
+      else:
+        raise IOError('The path %s not exists' % os.path.join(mrtpath,'bin'))
+      if os.path.exists(os.path.join(mrtpath,'data')):
+        self.mrtpathdata = os.path.join(mrtpath,'data')
+        os.environ['MRTDATADIR'] = os.path.join(mrtpath,'data')
+      else:
+        raise IOError('The path %s not exists' % os.path.join(mrtpath,'data'))
+    else:
+      raise IOError('The path %s not exists' % mrtpath)
+    self.out = os.path.join(self.basepath, outprefix + '.hdf')
+    self.outxml = os.path.join(self.basepath, self.out + '.xml')
+    self.subset = subset
+
+  def write_mosaic_xml(self):
+    from parsemodis import parseModisMulti
+    listHDF = []
+    for i in self.HDFfiles:
+      if i.find(self.basepath) == -1:
+        print "Attection maybe you have the not full path in the HDF file list"
+        listHDF.append(os.path.join(self.basepath,i.strip()))
+      else:
+        listHDF.append(i.strip())
+    pmm = parseModisMulti(listHDF)
+    pmm.writexml(self.outxml)
+
+
+  def executable(self):
+    """Return the executable of mrtmosaic MRT software
+    """
+    if sys.platform.count('linux') != -1:
+      if os.path.exists(os.path.join(self.mrtpathbin,'mrtmosaic')):
+        return os.path.join(self.mrtpathbin,'mrtmosaic')
+    elif sys.platform.count('win32') != -1:
+      if os.path.exists(os.path.join(self.mrtpathbin,'mrtmosaic.exe')):
+        return os.path.join(self.mrtpath,'mrtmosaic.exe')
+
+  def run(self):
+    """Exect the mosaic process"""
+    import subprocess
+    execut = self.executable()
+    if not os.path.exists(execut):
+      raise IOError('The path %s not exists, could be an erroneus path or '\
+                    + 'software') % execut
+    else:
+      self.write_mosaic_xml()
+      if self.subset:
+        subprocess.call([execut,'-i',self.listfiles,'-o',self.out,'-s',self.subset], 
+                        stderr = subprocess.STDOUT)
+      else:
+        subprocess.call([execut,'-i',self.listfiles,'-o',self.out], stderr = 
+                        subprocess.STDOUT)
+    return "The mosaic file %s is created" % self.out
+
+class processModis:
+  """A class to process raw modis data from hdf to tif using swath2grid (from MRT Swath tools)
+  """
+  def __init__(self, 
+              hdfname, confile, mrtpath, 
+              inputhdf = None, outputhdf = None, geolocfile = None
+  ):
+    """Initialization function :
+       hdfname = the full path to the hdf file
+       confile = the full path to the paramater file
+       mrtpath = the full path to mrt directory where inside you have bin and 
+                 data directories
+    """
+    # check if the hdf file exists
+    if os.path.exists(hdfname):
+      self.name = hdfname
+    else:
+      raise IOError('%s not exists' % hdfname)
+    # check if confile exists
+    if os.path.exists(confile):
+      self.conf = confile
+    else:
+      raise IOError('%s not exists' % confile)
+    # check if mrtpath and subdirectories exists and set environment variables
+    if os.path.exists(mrtpath):
+      if os.path.exists(os.path.join(mrtpath,'bin')):
+        self.mrtpathbin = os.path.join(mrtpath,'bin')
+        os.environ['PATH'] = "%s:%s" % (os.environ['PATH'],os.path.join(mrtpath,
+                                                                        'data'))
+      else:
+        raise IOError('The path %s not exists' % os.path.join(mrtpath,'bin'))
+      if os.path.exists(os.path.join(mrtpath,'data')):
+        self.mrtpathdata = os.path.join(mrtpath,'data')
+        os.environ['MRTDATADIR'] = os.path.join(mrtpath,'data')
+      else:
+        raise IOError('The path %s not exists' % os.path.join(mrtpath,'data'))
+    else:
+      raise IOError('The path %s not exists' % mrtpath)
+
+  def executable(self):
+    """Return the executable of resample MRT software
+    """
+    if sys.platform.count('linux') != -1:
+      if os.path.exists(os.path.join(self.mrtpathbin,'swath2grid')):
+        return os.path.join(self.mrtpathbin,'swath2grid')
+    elif sys.platform.count('win32') != -1:
+      if os.path.exists(os.path.join(self.mrtpathbin,'swath2grid.exe')):
+        return os.path.join(self.mrtpath,'swath2grid.exe')
+
+  def run(self):
+    """Exec the process"""
+    import subprocess
+    execut = self.executable()
+    if not os.path.exists(execut):
+      raise IOError('The path %s not exists, could be an erroneus path or '\
+                    + 'software') % execut
+    else:
+      subprocess.call([execut,'-pf=%s' % self.conf])
+    return "The hdf file %s was converted" % self.name

Added: grass-addons/grass7/grass7/raster/r.modis/libmodis/downmodis.py
===================================================================
--- grass-addons/grass7/grass7/raster/r.modis/libmodis/downmodis.py	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.modis/libmodis/downmodis.py	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,381 @@
+#!/usr/bin/env python
+#  class to download modis data
+#
+#  (c) Copyright Luca Delucchi 2010
+#  Authors: Luca Delucchi
+#  Email: luca dot delucchi at iasma dot it
+#
+##################################################################
+#
+#  This MODIS Python class is licensed under the terms of GNU GPL 2.
+#  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 implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+#  See the GNU General Public License for more details.
+#
+##################################################################
+
+from datetime import *
+import string
+import os
+import sys
+import glob
+import logging
+import socket
+from ftplib import FTP
+import ftplib
+
+class downModis:
+  """A class to download MODIS data from NASA FTP repository"""
+  def __init__(self, 
+                password,
+                destinationFolder,
+                user = "anonymous",
+                url = "e4ftl01.cr.usgs.gov",
+                tiles = None,
+                path = "MOLT/MOD11A1.005",
+                today = None,
+                enddate = None,
+                delta = 10,
+                jpg = False,
+                debug = False
+              ):
+    """Initialization function :
+        password = is your password, usually your email address
+        destinationFolder = where the files will be stored
+        user = your username, by default anonymous
+        url = the url where to download the MODIS data
+        path = the directory where the data that you want to download are 
+               stored on the ftp server
+        tiles = a list of tiles that you want to download, None == all tiles
+        today = the day to start downloading; in order to pass a date different from
+                today use the format YYYY-MM-DD
+        delta = timelag i.e. the number of days starting from today 
+                (backwards
+
+        Creates a ftp instance, connects user to ftp server and goes into the 
+        directory where the MODIS data are stored
+    """
+
+    # url modis
+    self.url = url
+    # user for download
+    self.user = user
+    # password for download
+    self.password = password
+    # directory where data are collected
+    self.path = path
+    # tiles to downloads
+    if tiles:
+        self.tiles = tiles.split(',')
+    else:
+        self.tiles = tiles
+    # set destination folder
+    if os.access(destinationFolder,os.W_OK):
+      self.writeFilePath = destinationFolder
+    else:
+      raise IOError("Folder to store downloaded files does not exist or is not" \
+    + "writeable")
+    # return the name of product
+    if len(self.path.split('/')) == 2:
+      self.product = self.path.split('/')[1]
+    elif len(self.path.split('/')) == 3:
+      self.product = self.path.split('/')[2]
+    # write a file with the name of file downloaded
+    self.filelist = open(os.path.join(self.writeFilePath, 'listfile' \
+    + self.product + '.txt'),'w')
+    # set jpg download
+    self.jpeg = jpg
+    # today
+    self.today = today
+    # force the last day
+    self.enday = enddate
+    # delta of days
+    self.delta = delta
+    # status of tile download
+    self.status = True
+    # for debug, you can download only xml files
+    self.debug = debug
+    # for logging
+    LOG_FILENAME = os.path.join(self.writeFilePath, 'modis' \
+    + self.product + '.log')
+    LOGGING_FORMAT='%(asctime)s - %(levelname)s - %(message)s'
+    logging.basicConfig(filename=LOG_FILENAME, level=logging.DEBUG, \
+    format=LOGGING_FORMAT)
+    self.nconnection = 0
+    
+  def connectFTP(self, ncon = 20):
+    """ Set connection to ftp server, move to path where data are stored
+    and create a list of directory for all days"""
+    self.nconnection += 1
+    try:
+      # connect to ftp server
+      self.ftp = FTP(self.url)
+      self.ftp.login(self.user,self.password)
+      # enter in directory
+      self.ftp.cwd(self.path)
+      self.dirData = []
+      # return data inside directory
+      self.ftp.dir(self.dirData.append)
+      # reverse order of data for have first the nearest to today
+      self.dirData.reverse()
+      # check if dirData contain only directory, delete all files
+      self.dirData = [elem.split()[-1] for elem in self.dirData if elem.startswith("d")]
+      if self.debug==True:
+        logging.debug("Open connection %s" % self.url)
+    except (EOFError, ftplib.error_perm), e:
+      logging.error('Error in connection: %s' % e)
+      if self.nconnection <= ncon:
+        self.connectFTP()
+
+  def closeFTP(self):
+    """ Close ftp connection """
+    self.ftp.quit()
+    self.filelist.close()
+    if self.debug==True:
+      logging.debug("Close connection %s" % self.url)
+
+  def setDirectoryIn(self,day):
+    """ Enter in the directory of the day """
+    try:
+      self.ftp.cwd(day)
+    except (ftplib.error_reply,socket.error), e:
+      logging.error("Error %s entering in directory %s" % e, day)
+      self.setDirectoryIn(day)
+
+  def setDirectoryOver(self):
+    """ Come back to old path """
+    try:
+      self.ftp.cwd('..')
+    except (ftplib.error_reply,socket.error), e:
+      logging.error("Error %s when try to come back" % e)
+      self.setDirectoryOver()
+
+  def str2date(self,strin):
+      """Return a date object from a string"""
+      todaySplit = strin.split('-')
+      return date(int(todaySplit[0]), int(todaySplit[1]),int(todaySplit[2]))
+
+  def getToday(self):
+    """Return the first day for start to download"""
+    if self.today == None:
+      # set today variable to today
+      self.today = date.today()
+    else:
+      # set today variable to data pass from user
+      self.today = self.str2date(self.today)
+      # set enday variable to data
+    if self.enday != None:
+      self.enday = self.str2date(self.enday)
+      
+  def getListDays(self):
+      """ Return a list of all selected days """
+      self.getToday()
+
+      today_s = self.today.strftime("%Y.%m.%d")
+      # dirData is reverse sorted
+      for i, d in enumerate(self.dirData):
+        if d <= today_s:
+          today_avail = d
+          today_index = i
+          break
+      else:
+        logging.error("No data available for requested days")
+        import sys
+        sys.exit()
+      days = self.dirData[today_index:][:self.delta]
+      # this is useful for 8/16 days data, delta could download more images
+      # that you want
+      if self.enday != None:
+        enday_s = self.enday.strftime("%Y.%m.%d")
+        delta = 0
+        # it make a for cicle from the last value and find the internal delta
+        #to remove file outside temporaly range
+        for i in range(-(len(days)),0):
+          if days[i] < enday_s:
+            break
+          else:
+            delta = delta + 1
+        # remove days outside new delta
+        days = days[:delta]
+      return days
+
+  def getFilesList(self):
+    """ Create a list of files to download, it is possible choose to download 
+    also the jpeg files or only the hdf files"""
+    def cicle_file(jpeg=False,tile=True):
+      finalList = []
+      for i in self.listfiles:
+        File = i.split('.')
+        # distinguish jpeg files from hdf files by the number of index 
+        # where find the tile index
+        if not tile and not (File.count('jpg') or File.count('BROWSE')):
+          finalList.append(i)
+        if tile and self.tiles.count(File[3]) == 1 and jpeg: #is a jpeg of tiles number
+          finalList.append(i)
+        if tile and self.tiles.count(File[2]) == 1: #is a hdf of tiles number
+          finalList.append(i)
+      return finalList
+
+    # return the file's list inside the directory of each day
+    try:
+      self.listfiles = self.ftp.nlst() 
+      # download also jpeg
+      if self.jpeg:
+        # finallist is ugual to all file with jpeg file
+        if not self.tiles:
+          finalList = self.listfiles
+        # finallist is ugual to tiles file with jpeg file
+        else:
+          finalList = cicle_file(jpeg=True)
+      # not download jpeg
+      else:
+        if not self.tiles:
+          finalList = cicle_file(tile=False)          
+        else:
+          finalList = cicle_file()
+      if self.debug==True:
+        logging.debug("The number of file to download is: %i" % len(finalList))
+      return finalList
+    except (ftplib.error_reply,socket.error), e:
+      logging.error("Error %s when try to receive list of files" % e)
+      self.getFilesList()
+
+  def checkDataExist(self,listNewFile, move = 0):
+    """ Check if a data already exists in the directory of download 
+    Move serve to know if function is called from download or move function"""
+    fileInPath = []
+    # add all files in the directory where we will save new modis data
+    for f in os.listdir(self.writeFilePath):
+      if os.path.isfile(os.path.join(self.writeFilePath, f)):
+        fileInPath.append(f)
+    # different return if this method is used from downloadsAllDay() or 
+    # moveFile()
+    if move == 0:
+      listOfDifferent = list(set(listNewFile) - set(fileInPath))
+    elif move == 1:
+      listOfDifferent = list(set(fileInPath) - set(listNewFile))
+    return listOfDifferent
+
+  def getNewerVersion(self,oldFile,newFile):
+    """ Return newer version of a file"""
+    oldFileSplit = oldFile.split('.')
+    newFileSplit = newFile.split('.')
+    if oldFileSplit[4] > newFileSplit[4]:
+      return oldFile
+    else:
+      return newFile
+
+  def downloadFile(self,filDown,filSave):
+    """Download the single file"""
+    #try to download file
+    try:
+      self.ftp.retrbinary("RETR " + filDown, filSave.write)
+      self.filelist.write("%s\n" % filDown)
+      if self.debug==True:
+        logging.debug("File %s downloaded" % filDown)
+    #if it have an error it try to download again the file
+    except (ftplib.error_reply,socket.error), e:
+      logging.error("Cannot download %s, retry.." % filDown)
+      self.connectFTP()
+      self.downloadFile(filDown,filSave)
+
+  def dayDownload(self,listFilesDown):
+    """ Downloads tiles are in files_hdf_consider """
+    # for each file in files' list
+    for i in listFilesDown:
+        fileSplit = i.split('.')
+        filePrefix = fileSplit[0] + '.' + fileSplit[1] + '.' + fileSplit[2] \
+        + '.' + fileSplit[3]
+        #for debug, download only xml
+        if (self.debug and fileSplit[-1] == 'xml') or not self.debug:
+          # check data exists in the return directory, if it doesn't exists
+          oldFile = glob.glob1(self.writeFilePath, filePrefix + "*" \
+          + fileSplit[-1])
+          numFiles = len(oldFile)
+          if numFiles == 0:
+            file_hdf = open(os.path.join(self.writeFilePath,i), "wb")
+          elif numFiles == 1:
+            # check the version of file  
+            fileDown = self.getNewerVersion(oldFile[0],i)
+            if fileDown != oldFile[0]:
+              os.remove(os.path.join(self.writeFilePath,oldFile[0]))
+              file_hdf = open(os.path.join(self.writeFilePath,fileDown), "wb")
+          elif numFiles > 1:
+            logging.error("There are to much files for %s" % i)
+            #raise EOFError("There are to much file with the same prefix")
+          if numFiles == 0 or (numFiles == 1 and fileDown != oldFile[0]):
+            self.downloadFile(i,file_hdf)
+
+  def downloadsAllDay(self):
+    """ Downloads all the tiles considered """
+    #return the days to download
+    days = self.getListDays()
+    if self.debug==True:
+      logging.debug("The number of days to download is: %i" % len(days))
+    #for each day
+    for day in days:
+      #enter in the directory of day
+      self.setDirectoryIn(day)
+      #obtain list of all files
+      listAllFiles = self.getFilesList()
+      #obtain list of files to download
+      listFilesDown = self.checkDataExist(listAllFiles)
+      #download files for a day
+      self.dayDownload(listFilesDown)
+      self.setDirectoryOver()
+    self.closeFTP()
+    if self.debug==True:
+      logging.debug("Download terminated")
+    return 0
+
+  def debugLog(self):
+    # create logger
+    logger = logging.getLogger("PythonLibModis debug")
+    logger.setLevel(logging.DEBUG)
+    # create console handler and set level to debug
+    ch = logging.StreamHandler()
+    ch.setLevel(logging.DEBUG)
+    # create formatter
+    formatter = logging.Formatter("%(asctime)s - %(name)s - " \
+                + "%(levelname)s - %(message)s")
+    # add formatter to ch
+    ch.setFormatter(formatter)
+    # add ch to logger
+    logger.addHandler(ch)
+    return logger
+
+  def debugDays(self):
+    """This function is useful to debug the number of days"""
+    logger = debugLog()
+    days = self.getListDays()
+    # if lenght of list of days and the delta of day they are different
+    if len(days) != self.delta:
+      # for each day
+      for i in range(1,self.delta+1):
+        # calculate the current day
+        delta = timedelta(days = i)
+        day = self.today - delta
+        day = day.strftime("%Y.%m.%d") 
+        # check if day is in the days list
+        if day not in days:
+          logger.critical("This day %s is not present on list" % day)
+    # the lenght of list of days and delta are ugual
+    else:
+      logger.info("All right!!")
+    
+  def debugMaps(self):
+    """This function is useful to debug the number of maps to download for 
+    each day"""
+    logger = debugLog()
+    days = self.getListDays()
+    for day in days:
+      self.setDirectoryIn(day)
+      listAllFiles = self.getFilesList()
+      string = day + ": " + str(len(listAllFiles)) + "\n"
+      logger.debug(string)
+      self.setDirectoryOver()   

Added: grass-addons/grass7/grass7/raster/r.modis/libmodis/parsemodis.py
===================================================================
--- grass-addons/grass7/grass7/raster/r.modis/libmodis/parsemodis.py	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.modis/libmodis/parsemodis.py	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,699 @@
+#!/usr/bin/env python
+#  class to parse modis data
+#
+#  (c) Copyright Luca Delucchi 2010
+#  Authors: Luca Delucchi
+#  Email: luca dot delucchi at iasma dot it
+#
+##################################################################
+#
+#  This MODIS Python class is licensed under the terms of GNU GPL 2.
+#  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 implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+#  See the GNU General Public License for more details.
+#
+##################################################################
+
+from datetime import *
+import string
+import os
+import sys
+import glob
+import logging
+import socket
+from ftplib import FTP
+import ftplib
+
+## lists of parameters accepted by resample MRT software
+# projections
+PROJ_LIST = ['AEA','GEO', 'HAM', 'IGH', 'ISIN', 'LA', 'LCC', 'MOL', 'PS', 
+                    'SIN','TM', 'UTM', 'MERCAT']
+# resampling
+RESAM_LIST = ['NEAREST_NEIGHBOR', 'BICUBIC', 'CUBIC_CONVOLUTION', 'NONE']
+RESAM_LIST_SWATH = ['NN', 'BI', 'CC']
+
+# datum
+DATUM_LIST = ['NODATUM', 'NAD27', 'NAD83', 'WGS66', 'WGS72', 'WGS84']
+SPHERE_LIST = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20]
+
+class parseModis:
+  """Class to parse MODIS xml files, it also can create the parameter 
+    configuration file for resampling with the MRT software
+  """
+  def __init__(self, filename):
+    """Initialization function :
+       filename = the name of MODIS hdf file
+    """
+    from xml.etree import ElementTree
+    if os.path.exists(filename):
+      # hdf name
+      self.hdfname = filename
+    else:
+      raise IOError('%s not exists' % self.hdfname)
+
+    if os.path.exists(self.hdfname + '.xml'):
+      # xml hdf name
+      self.xmlname = self.hdfname + '.xml'
+    else:
+      raise IOError('%s not exists' % self.hdfname + '.xml')
+
+    # tif name for the output file for resample MRT software
+    self.tifname = self.hdfname.replace('.hdf','.tif')
+    with open(self.xmlname) as f:
+      self.tree = ElementTree.parse(f)
+    # return the code of tile for conf file
+    self.code = os.path.split(self.hdfname)[1].split('.')[-2]
+    self.path = os.path.split(self.hdfname)[0]
+
+  def __str__(self):
+    """Print the file without xml tags"""
+    retString = ""
+    try:
+      for node in self.tree.iter():
+        if node.text.strip() != '':
+          retString = "%s = %s\n" % (node.tag,node.text) 
+    except:
+      for node in self.tree.getiterator():
+        if node.text.strip() != '':
+          retString = "%s = %s\n" % (node.tag,node.text) 
+    return retString
+
+  def getRoot(self):
+    """Set the root element"""
+    self.rootree = self.tree.getroot()
+
+  def retDTD(self):
+    """Return the DTDVersion element"""
+    self.getRoot()
+    return self.rootree.find('DTDVersion').text
+
+  def retDataCenter(self):
+    """Return the DataCenterId element"""
+    self.getRoot()
+    return self.rootree.find('DataCenterId').text
+
+  def getGranule(self):
+    """Set the GranuleURMetaData element"""
+    self.getRoot()
+    self.granule = self.rootree.find('GranuleURMetaData')
+
+  def retGranuleUR(self):
+    """Return the GranuleUR element"""
+    self.getGranule()
+    return self.granule.find('GranuleUR').text
+
+  def retDbID(self):
+    """Return the DbID element"""
+    self.getGranule()
+    return self.granule.find('DbID').text
+
+  def retInsertTime(self):
+    """Return the DbID element"""
+    self.getGranule()
+    return self.granule.find('InsertTime').text
+
+  def retLastUpdate(self):
+    """Return the DbID element"""
+    self.getGranule()
+    return self.granule.find('LastUpdate').text
+
+  def retCollectionMetaData(self):
+    """Return the CollectionMetaData element"""
+    self.getGranule()
+    collect = {}
+    for i in self.granule.find('CollectionMetaData').getiterator():
+      if i.text.strip() != '':
+        collect[i.tag] = i.text
+    return collect
+
+  def retDataFiles(self):
+    """Return the DataFiles element"""
+    self.getGranule()
+    collect = {}
+    datafiles = self.granule.find('DataFiles')
+    for i in datafiles.find('DataFileContainer').getiterator():
+      if i.text.strip() != '':
+        collect[i.tag] = i.text
+    return collect
+
+  def retDataGranule(self):
+    """Return the ECSDataGranule elements"""
+    self.getGranule()
+    datagran = {}
+    for i in self.granule.find('ECSDataGranule').getiterator():
+      if i.text.strip() != '':
+        datagran[i.tag] = i.text
+    return datagran
+
+  def retPGEVersion(self):
+    """Return the PGEVersion element"""
+    self.getGranule()
+    return self.granule.find('PGEVersionClass').find('PGEVersion').text
+
+  def retRangeTime(self):
+    """Return the RangeDateTime elements inside a dictionary with the element
+       name like dictionary key
+    """
+    self.getGranule()
+    rangeTime = {}
+    for i in self.granule.find('RangeDateTime').getiterator():
+      if i.text.strip() != '':
+        rangeTime[i.tag] = i.text
+    return rangeTime
+
+  def retBoundary(self):
+    """Return the maximum extend of the MODIS file inside a dictionary"""
+    self.getGranule()
+    self.boundary = []
+    lat = []
+    lon = []
+    spatialContainer = self.granule.find('SpatialDomainContainer')
+    horizontal = spatialContainer.find('HorizontalSpatialDomainContainer')
+    boundary = horizontal.find('GPolygon').find('Boundary')
+    for i in boundary.findall('Point'):
+      la = float(i.find('PointLongitude').text)
+      lo = float(i.find('PointLatitude').text)
+      lon.append(la)
+      lat.append(lo)
+      self.boundary.append({'lat': la, 'lon':lo})
+    extent = {'min_lat':min(lat),'max_lat':max(lat),'min_lon':min(lon),
+                'max_lon':max(lon)}
+    return extent
+
+  def retMeasure(self):
+    """Return statistics inside a dictionary"""
+    value = {}
+    self.getGranule()
+    mes = self.granule.find('MeasuredParameter')
+    mespc = mes.find('MeasuredParameterContainer')
+    value['ParameterName'] = mespc.find('ParameterName').text
+    meStat = mespc.find('QAStats')
+    qastat = {}
+    for i in meStat.getiterator():
+      if i.tag != 'QAStats':
+        qastat[i.tag] = i.text
+    value['QAStats'] = qastat
+    meFlag = mespc.find('QAFlags')
+    flagstat = {}
+    for i in meFlag.getiterator():
+      if i.tag != 'QAFlags':
+        flagstat[i.tag] = i.text
+    value['QAFlags'] = flagstat
+    return value
+
+  def retPlatform(self):
+    """Return the platform values inside a dictionary."""
+    value = {}
+    self.getGranule()
+    plat = self.granule.find('Platform')
+    value['PlatformShortName'] = plat.find('PlatformShortName').text
+    instr = plat.find('Instrument')
+    value['InstrumentShortName'] = instr.find('InstrumentShortName').text
+    sensor = instr.find('Sensor')
+    value['SensorShortName'] = sensor.find('SensorShortName').text
+    return value
+
+  def retPSA(self):
+    """Return the PSA values inside a dictionary, the PSAName is he key and
+       and PSAValue is the value
+    """
+    value = {}
+    self.getGranule()
+    psas = self.granule.find('PSAs')
+    for i in psas.findall('PSA'):
+      value[i.find('PSAName').text] = i.find('PSAValue').text
+    return value
+
+  def retInputGranule(self):
+    """Return the input files used to process the considered file"""
+    value = []
+    self.getGranule()
+    for i in self.granule.find('InputGranule').getiterator():
+      if i.tag != 'InputGranule':
+        value.append(i.text)
+    return value
+
+  def retBrowseProduct(self):
+    """Return the PGEVersion element"""
+    self.getGranule()
+    try:
+        value = self.granule.find('BrowseProduct').find('BrowseGranuleId').text
+    except:
+        value = None
+    return value    
+
+  def confResample(self, spectral, res = None, output = None, datum = 'WGS84',
+                  resampl = 'NEAREST_NEIGHBOR', projtype = 'GEO',  utm = None,
+                  projpar = '( 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 )',
+                  ):
+    """Create the parameter file to use with resample MRT software to create
+       tif file
+        spectral = the spectral subset to use, look the product table to 
+                   understand the layer that you want use. 
+                   For example: 
+                    - NDVI ( 1 1 1 0 0 0 0 0 0 0 0 0) copy only layer NDVI, EVI 
+                      and QA VI the other layers are not used
+                    - LST ( 1 1 0 0 1 1 0 0 0 0 0 0 ) copy only layer daily and
+                      nightly temperature and QA
+        res = the resolution for the output file, it must be set in the map 
+              unit of output projection system. The software will use the original
+              resolution of input file if res it isn't set
+        output = the output name, if it doesn't set will use the prefix name of 
+                 input hdf file
+        utm = the UTM zone if projection system is UTM
+        resampl = the type of resampling, the valid values are: NN (nearest 
+                  neighbor), BI (bilinear), CC (cubic convolution)
+        projtype = the output projection system, the valid values are: AEA 
+                   (Albers Equal Area), ER (Equirectangular), GEO (Geographic 
+                   Latitude/Longitude), HAM (Hammer), ISIN (Integerized Sinusoidal), 
+                   IGH (Interrupted Goode Homolosine), LA (Lambert Azimuthal), 
+                   LCC (LambertConformal Conic), MERCAT (Mercator), MOL (Mollweide), 
+                   PS (Polar Stereographic), SIN ()Sinusoidal), UTM (Universal 
+                   TransverseMercator)
+        datum = the datum to use, the valid values are: NAD27, NAD83, WGS66,
+                WGS76, WGS84, NODATUM
+        projpar = a list of projection parameters, for more info check the 
+                  "Appendix C" of MODIS reprojection tool user’s manual
+                  https://lpdaac.usgs.gov/content/download/4831/22895/file/mrt41_usermanual_032811.pdf
+
+        """
+    #check if spectral it's write with correct construct ( value )
+    if string.find(spectral, '(') == -1 or  string.find(spectral, ')') == -1:
+      raise IOError('ERROR: The spectral string should be similar to: ( 1 0 )')
+    # output name
+    if not output:
+      fileout = self.tifname
+    else:
+      fileout = output
+    # the name of the output parameters files for resample MRT software
+    filename = os.path.join(self.path,'%s_mrt_resample.conf' % self.code)
+    # if the file already exists it remove it 
+    if os.path.exists(filename):
+      os.remove(filename)
+    # open the file
+    conFile = open(filename, 'w')
+    conFile.write("INPUT_FILENAME = %s\n" % self.hdfname)
+    conFile.write("SPECTRAL_SUBSET = %s\n" % spectral)
+    conFile.write("SPATIAL_SUBSET_TYPE = INPUT_LAT_LONG\n")
+    # return the boundary from the input xml file
+    bound = self.retBoundary()
+    # Order:  UL: N W  - LR: S E
+    conFile.write("SPATIAL_SUBSET_UL_CORNER = ( %f %f )\n" % (bound['max_lat'],
+                                                              bound['min_lon']))
+    conFile.write("SPATIAL_SUBSET_LR_CORNER = ( %f %f )\n" % (bound['min_lat'],
+                                                              bound['max_lon']))
+    conFile.write("OUTPUT_FILENAME = %s\n" % fileout)
+    # if resampl is in resam_list set the parameter otherwise return an error
+    if resampl in RESAM_LIST:
+      conFile.write("RESAMPLING_TYPE = %s\n" % resampl)
+    else:
+      raise IOError('The resampling type %s is not supportet.\n' \
+                   'The resampling type supported are %s' % (resampl,RESAM_LIST))
+    # if projtype is in proj_list set the parameter otherwise return an error
+    if projtype in PROJ_LIST:
+      conFile.write("OUTPUT_PROJECTION_TYPE = %s\n" % projtype)
+    else:
+      raise IOError('The projection type %s is not supported.\n' \
+                   'The projections supported are %s' % (projtype,PROJ_LIST))
+    conFile.write("OUTPUT_PROJECTION_PARAMETERS = %s\n" % projpar)
+    # if datum is in datum_list set the parameter otherwise return an error
+    if datum in DATUM_LIST:
+      conFile.write("DATUM = %s\n" % datum)
+    else:
+      raise IOError('The datum %s is not supported.\n' \
+                   'The datum supported are %s' % (datum,DATUM_LIST))
+    # if utm is not None write the UTM_ZONE parameter in the file
+    if utm:
+      conFile.write("UTM_ZONE = %s\n" % utm)
+    # if res is not None write the OUTPUT_PIXEL_SIZE parameter in the file
+    if res:
+      conFile.write("OUTPUT_PIXEL_SIZE = %i\n" % res)
+    conFile.close()
+    return filename
+
+  def confResample_swath(self, sds, geoloc, res, output = None, 
+                  sphere = '8', resampl = 'NN', projtype = 'GEO',  utm = None,
+                  projpar = '0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0',
+                  ):
+    """Create the parameter file to use with resample MRT software to create
+       tif file
+        sds = Name of band/s (Science Data Set) to resample
+        geoloc = Name geolocation file (example MOD3, MYD3)
+        res = the resolution for the output file, it must be set in the map 
+              unit of output projection system. The software will use the original
+              resolution of input file if res it isn't set
+        output = the output name, if it doesn't set will use the prefix name of 
+                 input hdf file
+        sphere = Output sphere number. Valid options are: 
+                 0=Clarke 1866, 1=Clarke 1880, 2=Bessel, 3=International 1967, 
+                 4=International 1909, 5=WGS 72, 6=Everest, 7=WGS 66, 
+                 8=GRS1980/WGS 84, 9=Airy, 10=Modified Everest, 11=Modified Airy, 
+                 12=Walbeck, 13=Southeast Asia, 14=Australian National, 
+                 15=Krassovsky, 16=Hough, 17=Mercury1960, 18=Modified Mercury1968, 
+                 19=Sphere 19 (Radius 6370997), 20=MODIS Sphere (Radius 6371007.181)
+        resampl = the type of resampling, the valid values are: NN (nearest 
+                  neighbor), BI (bilinear), CC (cubic convolution)
+        projtype = the output projection system, the valid values are: 
+                   AEA (Albers Equal Area), ER (Equirectangular), 
+                   GEO (Geographic Latitude/Longitude), HAM (Hammer), 
+                   ISIN (Integerized Sinusoidal),IGH (Interrupted Goode Homolosine), 
+                   LA (Lambert Azimuthal), LCC (LambertConformal Conic),
+                   MERCAT (Mercator), MOL (Mollweide), PS (Polar Stereographic),
+                   SIN ()Sinusoidal), UTM (Universal TransverseMercator)
+        utm = the UTM zone if projection system is UTM
+        projpar = a list of projection parameters, for more info check the 
+                  "Appendix C" of MODIS reprojection tool user’s manual
+                  https://lpdaac.usgs.gov/content/download/4831/22895/file/mrt41_usermanual_032811.pdf
+        """
+    # output name
+    if not output:
+      fileout = self.tifname
+    else:
+      fileout = output
+    # the name of the output parameters files for resample MRT software
+    filename = os.path.join(self.path,'%s_mrt_resample.prm' % self.code)
+    # if the file already exists it remove it 
+    if os.path.exists(filename):
+      os.remove(filename)
+    # open the file
+    conFile = open(filename, 'w')
+    conFile.write("INPUT_FILENAME = %s\n" % self.hdfname)
+    conFile.write("GEOLOCATION_FILENAME = %s\n" % geoloc)
+    conFile.write("INPUT_SDS_NAME = %s\n" % sds)
+    conFile.write("OUTPUT_SPATIAL_SUBSET_TYPE = LAT_LONG\n")
+    # return the boundary from the input xml file
+    bound = self.retBoundary()
+    # Order:  UL: N W  - LR: S E
+    conFile.write("OUTPUT_SPACE_UPPER_LEFT_CORNER (LONG LAT) = %f %f\n" % (bound['max_lat'],
+                                                              bound['min_lon']))
+    conFile.write("OUTPUT_SPACE_LOWER_RIGHT_CORNER (LONG LAT) = %f %f\n" % (bound['min_lat'],
+                                                              bound['max_lon']))
+    conFile.write("OUTPUT_FILENAME = %s\n" % fileout)
+    conFile.write("OUTPUT_FILE_FORMAT = GEOTIFF_FMT\n")
+    # if resampl is in resam_list set the parameter otherwise return an error
+    if resampl in RESAM_LIST_SWATH:
+      conFile.write("KERNEL_TYPE (CC/BI/NN) = %s\n" % resampl)
+    else:
+      raise IOError('The resampling type %s is not supportet.\n' \
+                   'The resampling type supported are %s' % (resampl,RESAM_LIST_SWATH))
+    # if projtype is in proj_list set the parameter otherwise return an error
+    if projtype in PROJ_LIST:
+      conFile.write("OUTPUT_PROJECTION_NUMBER = %s\n" % projtype)
+    else:
+      raise IOError('The projection type %s is not supported.\n' \
+                   'The projections supported are %s' % (projtype,PROJ_LIST))
+    conFile.write("OUTPUT_PROJECTION_PARAMETER = %s\n" % projpar)
+    # if sphere is in sphere_list set the parameter otherwise return an error
+    if int(sphere) in SPHERE_LIST:
+      conFile.write("OUTPUT_PROJECTION_SPHERE = %s\n" % sphere)
+    else:
+      raise IOError('The sphere %s is not supported.\n' \
+                   'The spheres supported are %s' % (sphere,SPHERE_LIST))
+    # if utm is not None write the UTM_ZONE parameter in the file
+    if utm:
+      if utm < '-60' or utm > '60':
+        raise IOError('The valid UTM zone are -60 to 60')
+      else:
+        conFile.write("OUTPUT_PROJECTION_ZONE = %s\n" % utm)
+    # if res is not None write the OUTPUT_PIXEL_SIZE parameter in the file
+    if res:
+      conFile.write("OUTPUT_PIXEL_SIZE = %f\n" % res)
+    conFile.close()
+    return filename
+
+class parseModisMulti:
+  """A class to some variable for the xml file of a mosaic
+  """
+  def __init__(self,hdflist):
+    """hdflist = python list containing the hdf files"""
+    from xml.etree import ElementTree
+    self.ElementTree = ElementTree
+    self.hdflist = hdflist
+    self.parModis = []
+    self.nfiles = 0
+    # for each hdf files create a parseModis object
+    for i in hdflist:
+      self.parModis.append(parseModis(i))
+      self.nfiles += 1
+
+  def _checkval(self,vals):
+    """Internal function to return values from list"""
+    if vals.count(vals[0]) == self.nfiles:
+      return [vals[0]]
+    else:
+      outvals = []
+      for i in vals:
+        if outvals.count(i) == 0:
+          outvals.append(i)
+      return outvals
+      
+  def _checkvaldict(self,vals):
+    """Internal function to return values from dictionary"""
+    keys = vals[0].keys()
+    outvals = {}
+    for k in keys:
+      valtemp = []
+      for v in vals:
+        valtemp.append(v[k])
+      if valtemp.count(valtemp[0]) == self.nfiles:
+        outvals[k] = valtemp[0]
+      else:
+        raise IOError('Something wrong reading XML files')
+      
+    return outvals
+
+  def _minval(self, vals):
+    """Internal function to return the minimum value"""
+    outval = vals[0]
+    for i in range(1,len(vals)):
+      if outval > i:
+        outval = i
+    return outval
+    
+  def _maxval(self, vals):
+    """Internal function to return the maximum value"""
+    outval = vals[0]
+    for i in range(1,len(vals)):
+      if outval < i:
+        outval = i
+    return outval
+    
+  def _cicle_values(self, ele,values):
+    """Internal function to add values from a dictionary"""
+    for k,v in values.iteritems():
+      elem = self.ElementTree.SubElement(ele,k)
+      elem.text = v
+
+  def _addPoint(self,obj,lon,lat):
+    """Internal function to add a point in boundary xml tag"""
+    pt = self.ElementTree.SubElement(obj, 'Point')
+    ptlon = self.ElementTree.SubElement(pt, 'PointLongitude')
+    ptlon.text = str(self.boundary[lon])
+    ptlat = self.ElementTree.SubElement(pt, 'PointLatitude')
+    ptlat.text = str(self.boundary[lat])
+
+  def valDTD(self,obj):
+    """Function to add DTDVersion"""
+    values = []
+    for i in self.parModis:
+      values.append(i.retDTD())
+    for i in self._checkval(values):
+      dtd = self.ElementTree.SubElement(obj,'DTDVersion')
+      dtd.text = i
+
+  def valDataCenter(self,obj):
+    """Function to add DataCenter"""
+    values = []
+    for i in self.parModis:
+      values.append(i.retDataCenter())
+    for i in self._checkval(values):
+      dci = self.ElementTree.SubElement(obj,'DataCenterId')
+      dci.text = i
+      
+  def valGranuleUR(self,obj):
+    """Function to add GranuleUR"""
+    values = []
+    for i in self.parModis:
+      values.append(i.retGranuleUR())
+    for i in self._checkval(values):
+      gur = self.ElementTree.SubElement(obj,'GranuleUR')
+      gur.text = i
+
+  def valDbID(self,obj):
+    """Function to add DbID"""
+    values = []
+    for i in self.parModis:
+      values.append(i.retDbID())
+    for i in self._checkval(values):
+      dbid = self.ElementTree.SubElement(obj,'DbID')
+      dbid.text = i
+      
+  def valInsTime(self,obj):
+    """TODO"""
+    values = []
+    for i in self.parModis:
+      values.append(i.retInsertTime())
+    obj.text = self._minval(values)
+  
+  def valCollectionMetaData(self,obj):
+    """Function to add CollectionMetaData"""
+    values = []
+    for i in self.parModis:
+      values.append(i.retCollectionMetaData())
+    self._cicle_values(obj,self._checkvaldict(values))
+  
+  def valDataFiles(self, obj):
+    """Function to add DataFileContainer"""
+    values = []
+    for i in self.parModis:
+      values.append(i.retDataFiles())
+    for i in values:
+      dfc = self.ElementTree.SubElement(obj, 'DataFileContainer')
+      self._cicle_values(dfc,i)
+    
+  def valPGEVersion(self,obj):
+    """Function to add PGEVersion"""
+    values = []
+    for i in self.parModis:
+      values.append(i.retPGEVersion())
+    for i in self._checkval(values):
+      pge = self.ElementTree.SubElement(obj,'PGEVersion')
+      pge.text = i
+  
+  def valRangeTime(self,obj):
+    """Function to add RangeDateTime"""
+    values = []
+    for i in self.parModis:
+      values.append(i.retRangeTime())
+    self._cicle_values(obj,self._checkvaldict(values))
+  
+  def valBound(self):
+    """Function return the bounding box of mosaic"""
+    boundary = self.parModis[0].retBoundary()
+    for i in range(1,len(self.parModis)):
+      bound = self.parModis[i].retBoundary()
+      if bound['min_lat'] < boundary['min_lat']:
+        boundary['min_lat'] = bound['min_lat']
+      if bound['min_lon'] < boundary['min_lon']:
+        boundary['min_lon'] = bound['min_lon']
+      if bound['max_lat'] > boundary['max_lat']:
+        boundary['max_lat'] = bound['max_lat']
+      if bound['max_lon'] > boundary['max_lon']:
+        boundary['max_lon'] = bound['max_lon']
+    self.boundary = boundary
+  
+  def valMeasuredParameter(self,obj):
+    """Function to add ParameterName"""
+    valuesQAStats = []
+    valuesQAFlags = []
+    valuesParameter = []
+    for i in self.parModis:
+      valuesQAStats.append(i.retMeasure()['QAStats'])
+      valuesQAFlags.append(i.retMeasure()['QAFlags'])
+      valuesParameter.append(i.retMeasure()['ParameterName'])
+    for i in self._checkval(valuesParameter):
+      pn = self.ElementTree.SubElement(obj,'ParameterName')
+      pn.text = i
+  
+  def valInputPointer(self,obj):
+    """Function to add InputPointer"""
+    for i in self.parModis:
+      for v in i.retInputGranule():
+        ip = self.ElementTree.SubElement(obj,'InputPointer')
+        ip.text = v
+  
+  def valPlatform(self, obj):
+    """Function to add Platform tags"""
+    valuesSName = []
+    valuesInstr = []
+    valuesSensor = []
+    for i in self.parModis:
+        valuesSName.append(i.retPlatform()['PlatformShortName'])
+        valuesInstr.append(i.retPlatform()['InstrumentShortName'])
+        valuesSensor.append(i.retPlatform()['SensorShortName'])
+    for i in self._checkval(valuesSName):
+      pn = self.ElementTree.SubElement(obj,'PlatformShortName')
+      pn.text = i
+      
+    valInstr = self._checkval(valuesInstr)
+    valSens = self._checkval(valuesSensor)
+    
+    if len(valInstr) != len(valSens):
+      raise IOError('Something wrong reading XML files')
+    else:
+      for i in range(len(valInstr)):
+        ins = self.ElementTree.SubElement(obj,'Instrument')
+        pn = self.ElementTree.SubElement(ins,'InstrumentShortName')
+        pn.text = valInstr[i]
+        sens = self.ElementTree.SubElement(ins,'Sensor')
+        ps = self.ElementTree.SubElement(sens,'SensorShortName')
+        ps.text = valSens[i]
+
+  def writexml(self,outputname):
+    """Return a xml file for a mosaic"""
+    # the root element
+    granule = self.ElementTree.Element('GranuleMetaDataFile')
+    # add DTDVersion
+    self.valDTD(granule)
+    # add DataCenterId
+    self.valDataCenter(granule)
+    # add GranuleURMetaData
+    gurmd = self.ElementTree.SubElement(granule,'GranuleURMetaData')
+    # add GranuleUR
+    self.valGranuleUR(gurmd)
+    # add dbID
+    self.valDbID(gurmd)
+    
+    # TODO ADD InsertTime LastUpdate
+
+    # add CollectionMetaData
+    cmd = self.ElementTree.SubElement(gurmd,'CollectionMetaData')
+    self.valCollectionMetaData(cmd)
+    # add DataFiles
+    df = self.ElementTree.SubElement(gurmd,'DataFiles')
+    self.valDataFiles(df)
+    
+    # TODO ADD ECSDataGranule
+    
+    # add PGEVersionClass
+    pgevc = self.ElementTree.SubElement(gurmd,'PGEVersionClass')
+    self.valPGEVersion(pgevc)
+    # add RangeDateTime
+    rdt = self.ElementTree.SubElement(gurmd,'RangeDateTime')
+    self.valRangeTime(rdt)
+    # SpatialDomainContainer
+    sdc = self.ElementTree.SubElement(gurmd,'SpatialDomainContainer')
+    hsdc = self.ElementTree.SubElement(sdc,'HorizontalSpatialDomainContainer')
+    gp = self.ElementTree.SubElement(hsdc,'GPolygon')
+    bound = self.ElementTree.SubElement(gp,'Boundary')
+    self.valBound()
+    self._addPoint(bound,'min_lon','max_lat')
+    self._addPoint(bound,'max_lon','max_lat')
+    self._addPoint(bound,'min_lon','min_lat')
+    self._addPoint(bound,'max_lon','min_lat')
+    # add MeasuredParameter
+    mp = self.ElementTree.SubElement(gurmd,'MeasuredParameter')
+    mpc = self.ElementTree.SubElement(mp,'MeasuredParameterContainer')
+    self.valMeasuredParameter(mpc)
+    # Platform
+    pl = self.ElementTree.SubElement(gurmd,'Platform')
+    self.valPlatform(pl)
+
+    # add PSAs
+    psas = self.ElementTree.SubElement(gurmd,'PSAs')
+    # TODO ADD all PSA
+
+    # add InputGranule and InputPointer
+    ig = self.ElementTree.SubElement(gurmd,'InputGranule')
+    self.valInputPointer(ig)
+    # TODO ADD BrowseProduct
+    output = open(outputname, 'w')
+    output.write('<?xml version="1.0" encoding="UTF-8"?>')
+    output.write('<!DOCTYPE GranuleMetaDataFile SYSTEM "http://ecsinfo.gsfc.nasa.gov/ECSInfo/ecsmetadata/dtds/DPL/ECS/ScienceGranuleMetadata.dtd">')
+    output.write(self.ElementTree.tostring(granule))
+    output.close()

Added: grass-addons/grass7/grass7/raster/r.modis/libmodis/rmodislib.py
===================================================================
--- grass-addons/grass7/grass7/raster/r.modis/libmodis/rmodislib.py	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.modis/libmodis/rmodislib.py	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,347 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+############################################################################
+#
+# MODULE:	r.modis
+# AUTHOR(S):	Luca Delucchi
+# PURPOSE:	Here there are some important class to run r.modis modules
+#
+#
+# COPYRIGHT:	(C) 2011 by Luca Delucchi
+#
+#		This program is free software under the GNU General Public
+#		License (>=v2). Read the file COPYING that comes with GRASS
+#		for details.
+#
+#############################################################################
+import grass.script as grass
+# interface to g.proj -p
+def get_proj():
+    """!Returns the output from running "g.proj -p" plus towgs84 parameter (g.proj -d), 
+    as a dictionary. Example:
+
+    \code
+    >>> proj = grass.get_proj()
+    >>> (proj['name'], proj['ellps'], proj['datum'])
+    (Lat/Lon, wgs84, wgs84)
+    \endcode
+
+    @return dictionary of projection values
+    """
+    gproj = grass.read_command('g.proj',flags='p')
+    listproj = gproj.split('\n')
+    listproj.remove('-PROJ_INFO-------------------------------------------------')
+    listproj.remove('-PROJ_UNITS------------------------------------------------')
+    listproj.remove('')
+    proj = {}
+    for i in listproj:
+        ilist = i.split(':')
+        proj[ilist[0].strip()] = ilist[1].strip()
+    proj.update(grass.parse_command('g.proj',flags='j'))
+    return proj
+
+class product:
+    """Definition of MODIS product with url and path in the ftp server
+    """
+    def __init__(self,value = None):
+        # url to download products
+        urlbase = 'e4ftl01.cr.usgs.gov'
+        usrsnow = 'n4ftl01u.ecs.nasa.gov'
+        ### values of lst product:
+        lst_spec = '( 1 0 0 0 1 0 0 0 0 0 0 0 )'
+        lst_specqa = '( 1 1 0 0 1 1 0 0 0 0 0 0 )'
+        # pattern for r.bitpatter (key is the pattern option, list of values 
+        #                         contain values for patval option)
+        lst_patt = {3 : [2, 3], 128 : [81, 85], 255 : [129, 133, 145, 149]}
+        # suffix for the lst product (key is the lst map, value the QA)
+        lst1km_suff = {'.LST_Day_1km':'.QC_Day','.LST_Night_1km':'.QC_Night'}
+        lst6km_suff = {'.LST_Day_6km':'.QC_Day','.LST_Night_6km':'.QC_Night'}
+        # color for lst product
+        lst_color = ['celsius']
+        ### values of vi product:
+        vi_spec = '( 1 1 0 0 0 0 0 0 0 0 0 )'
+        vi_specqa = '( 1 1 1 0 0 0 0 0 0 0 0 )'
+        vi_patt = {3 : [2, 3], 63 : [13, 14, 15], 128 : [3], 1024 : [1], 
+        8192 : [0, 6, 7], 16384 : [1], 32768 : [1]}
+        vi_color = ['ndvi','evi']
+        vi250m_suff = {'.250m_16_days_NDVI' : '.250m_16_days_VI_Quality',
+        '.250m_16_days_EVI' : '.250m_16_days_VI_Quality'}
+        vi500m_suff = {'.500m_16_days_NDVI' : '.500m_16_days_VI_Quality',
+        '.500m_16_days_EVI' : '.500m_16_days_VI_Quality'}        
+        vi1km_suff = {'.1_km_16_days_NDVI' : '.1_km_16_days_VI_Quality',
+        '.1_km_16_days_EVI' : '.1_km_16_days_VI_Quality'}
+        ### values of snow product:
+        snow1_spec = ('( 1 )')
+        snow1_specqa = ('( 1 1 )')
+        snow1_suff = {'.Snow_Cover_Daily_Tile':'.Snow_Spatial_QA'}
+        snow1_patt = {3 : [2,3], 7 : [6, 7], 15 : [10, 11, 14, 15]}
+        
+        snow8_spec = ('( 1 1 )')
+        snow_color = ['gyr'] #TODO CREATE THE COLOR TABLE FOR MODIS_SNOW
+        snow8_suff = {'.Maximum_Snow_Extent' : None, '.Eight_Day_Snow_Cover' : None}
+        lstL2_spec = 'LST; QC; Error_LST; Emis_31; Emis_32; View_angle; View_time'
+        
+	self.prod = value
+	lst = {'lst_aqua_daily_1000' : {'url' : urlbase, 'folder' : 'MOLA/MYD11A1.005',
+                                  'res' : 1000, 'spec' : lst_spec, 'spec_qa' : lst_specqa,
+                                  'suff' : lst1km_suff, 'pattern' : lst_patt, 
+                                  'color' : lst_color
+              },
+              'lst_terra_daily_1000' : {'url' : urlbase, 'folder' : 'MOLT/MOD11A1.005',
+                                  'res' : 1000, 'spec': lst_spec,'spec_qa': lst_specqa, 
+                                  'suff' : lst1km_suff, 'pattern' : lst_patt, 
+                                  'color' : lst_color
+              }, 
+              'lst_terra_eight_1000' : {'url' : urlbase, 'folder' : 'MOLT/MOD11A2.005',
+                                  'res' : 1000, 'spec': lst_spec,'spec_qa': lst_specqa, 
+                                  'suff' : lst1km_suff, 'pattern' : lst_patt, 
+                                  'color' : lst_color
+              },
+              'lst_aqua_eight_1000' : {'url' : urlbase, 'folder' : 'MOLA/MYD11A2.005',
+                                  'res' : 1000, 'spec': lst_spec,'spec_qa': lst_specqa, 
+                                  'suff' : lst1km_suff, 'pattern' : lst_patt, 
+                                  'color' : lst_color
+              },
+              'lst_terra_daily_6000' : {'url' : urlbase, 'folder' : 'MOLT/MOD11B1.005',
+                                  'res' : 6000, 'spec': lst_spec,'spec_qa': lst_specqa, 
+                                  'suff' : lst6km_suff, 'pattern' : lst_patt, 
+                                  'color' : lst_color
+              }, 
+              'lst_aqua_daily_6000' : {'url' : urlbase, 'folder' : 'MOLA/MYD11B1.005',
+                                  'res' : 6000, 'spec': lst_spec,'spec_qa': lst_specqa, 
+                                  'suff' : lst6km_suff, 'pattern' : lst_patt, 
+                                  'color' : lst_color
+              },
+
+        }
+	vi = {'ndvi_terra_sixteen_250':{'url':urlbase, 'folder':'MOLT/MOD13Q1.005',
+                                    'res':250,'spec': vi_spec,'spec_qa': vi_specqa,
+                                    'suff' : vi250m_suff, 'pattern' : vi_patt, 
+                                    'color' : vi_color
+              },
+              'ndvi_aqua_sixteen_250':{'url':urlbase, 'folder':'MOLA/MYD13Q1.005',
+                                    'res':250,'spec': vi_spec,'spec_qa': vi_specqa,
+                                    'suff' : vi250m_suff, 'pattern' : vi_patt, 
+                                    'color' : vi_color
+              },
+              'ndvi_terra_sixteen_500':{'url':urlbase, 'folder':'MOLT/MOD13A1.005',
+                                    'res':500,'spec': vi_spec,'spec_qa': vi_specqa,
+                                    'suff' : vi1km_suff, 'pattern' : vi_patt, 
+                                    'color' : vi_color
+              },
+              'ndvi_aqua_sixteen_500':{'url':urlbase, 'folder':'MOLA/MYD13A1.005',
+                                    'res':500,'spec': vi_spec,'spec_qa': vi_specqa,
+                                    'suff' : vi500m_suff, 'pattern' : vi_patt, 
+                                    'color' : vi_color
+              },
+              'ndvi_terra_sixteen_1000':{'url':urlbase, 'folder':'MOLT/MOD13A2.005',
+                                    'res':1000,'spec': vi_spec,'spec_qa': vi_specqa,
+                                    'suff' : vi500m_suff, 'pattern' : vi_patt, 
+                                    'color' : vi_color
+              },
+              'ndvi_aqua_sixteen_1000':{'url':urlbase, 'folder':'MOLA/MYD13A2.005',
+                                    'res':1000,'spec': vi_spec,'spec_qa': vi_specqa,
+                                    'suff' : vi1km_suff, 'pattern' : vi_patt, 
+                                    'color' : vi_color
+              }
+        }
+        snow = {'snow_terra_daily_500' : {'url' : usrsnow, 'folder' : 
+				'SAN/MOST/MOD10A1.005', 'res' : 500, 'spec' : snow1_spec
+				,'spec_qa': snow1_specqa, 'color' : snow_color,
+				'suff' : snow1_suff, 'pattern' : snow1_patt
+		}, 
+		'snow_aqua_daily_500' : {'url' : usrsnow, 'folder' : 
+                                'SAN/MOSA/MYD10A1.005', 'res' : 500, 'spec' : snow1_spec
+                                ,'spec_qa': snow1_specqa, 'color' : snow_color,
+                                'suff' : snow1_suff, 'pattern' : snow1_patt
+                },
+                'snow_terra_eight_500' : {'url' : usrsnow, 'folder' : 
+                                'SAN/MOST/MOD10A2.005', 'res' : 500, 'spec' : snow8_spec
+                                ,'spec_qa': None, 'color' : snow_color,
+                                'pattern' : None, 'suff' : snow8_suff
+                }, 
+                'snow_aqua_eight_500' : {'url' : usrsnow, 'folder' : 
+                                'SAN/MOSA/MYD10A2.005', 'res' : 500, 'spec' : snow8_spec
+                                ,'spec_qa': None, 'color' : snow_color,
+                                'pattern' : None, 'suff' : snow8_suff
+                }
+	}
+	self.products = { }
+	self.products.update(lst)
+	self.products.update(vi)
+	self.products.update(snow)
+        self.products_swath = { 
+          'lst_terra_daily':{'url':urlbase,'folder':'MOLT/MOD11_L2.005',
+          'spec': lstL2_spec}, 'lst_aqua_daily':{'url':urlbase,'folder':'MOLA/MYD11_L2.005',
+          'spec': lstL2_spec}
+        }
+    def returned(self):
+        if self.products.keys().count(self.prod) == 1:
+            return self.products[self.prod]
+        elif self.products_swath.keys().count(self.prod) == 1:
+            return self.products_swath[self.prod]
+        else:
+            grass.fatal(_("The code insert is not supported yet. Consider to ask " \
+                      + "on the grass-dev mailing list for future support"))
+
+    def fromcode(self,code):
+        import string
+        for k,v in self.products.iteritems():
+          if string.find(v['folder'],code) != -1:
+            return self.products[k]
+        for k,v in self.products_swath.iteritems():
+          if string.find(v['folder'],code) != -1:
+            return self.products_swath[k]
+        grass.fatal(_("The code insert is not supported yet. Consider to ask " \
+                      "on the grass-dev mailing list for future support"))
+
+    def color(self,code = None):
+        if code:
+          return self.fromcode(code)['color']
+        else:
+          return self.returned()['color']
+
+
+    def pattern(self,code = None):
+        if code:
+          return self.fromcode(code)['pattern']
+        else:
+          return self.returned()['pattern']
+
+    def suffix(self,code = None):
+        if code:
+          return self.fromcode(code)['suff']
+        else:
+          return self.returned()['suff']
+
+    def __str__(self):
+	prod = self.returned()
+	string = "url: " + prod['url'] + ", folder: " + prod['folder']
+        if prod.keys().count('spec') == 1:
+                string += ", spectral subset: " + prod['spec']
+        if prod.keys().count('spec_qa') == 1:
+                string += ", spectral subset qa:" + prod['spec_qa']
+	return string
+
+class resampling:
+    """Return the resampling value from the code used in the modules
+    """
+    def __init__(self,value):
+        self.code = value
+        self.resampling = {'nearest': 'NEAREST_NEIGHBOR', 'bilinear': 'BILINEAR',
+        'cubic': 'CUBIC CONVOLUTION'}
+
+    def returned(self):
+        return self.resampling[self.code]
+
+class projection:
+    """Definition of projection for converting from sinusoidal projection to
+    another one. Not all projection systems are supported"""
+    def __init__(self):
+        self.proj = get_proj()
+        self.val = self.proj['proj']
+        if self.proj['datum']:
+            self.dat = self.proj['datum']
+        else:
+            self.dat = 'none'
+        self.projections = {'laea' : 'LA','ll':'GEO', 'lcc':'LCC',
+             'merc':'MERCAT', 'polar':'PS', 'utm':'UTM', 'tmerc':'TM'}
+        self.datumlist = {'none':'NONE', 'nad27':'NAD27', 'nad83':'NAD83', 
+        'wgs66':'WGS66', 'wgs72':'WGS72', 'wgs84':'WGS84', 'etrs89':'WGS84'}
+        self.datumlist_swath = {'Clarke 1866' : 0, 'Clarke 1880' : 1, 'bessel' : 2,
+            'International 1967' : 3, 'International 1909': 4, 'wgs72' : 5, 
+            'Everest' : 6, 'wgs66' : 7, 'wgs84' : 8, 'Airy' : 9, 
+            'Modified Everest' : 10, 'Modified Airy' : 11, 'Walbeck' : 12, 
+            'Southeast Asia' : 13, 'Australian National' : 14, 'Krassovsky' : 15, 
+            'Hough' : 16, 'Mercury1960' : 17, 'Modified Mercury1968' : 18, 
+            'Sphere 19 (Radius 6370997)' : 19, 'MODIS Sphere (Radius 6371007.181)' : 20}
+
+    def returned(self):
+        """Return the projection in the MRT style"""
+        if self.val not in self.projections.keys():
+            grass.fatal(_("Projection <%s> is not supported") % self.val)
+        else:
+            return self.projections[self.val]
+
+    def _par(self,key):
+        """Function use in return_params"""
+        if self.proj[key]:
+            Val = self.proj[key]
+        else:
+            Val = 0.0
+        return float(Val)
+
+    def _outpar(self, SMajor, SMinor, Val, Factor, CentMer, TrueScale, FE, FN,swath):
+        if swath:
+          return '%i %i %d %d %d %d %d %d 0.0 0.0 0.0 0.0 0.0 0.0 0.0' % ( 
+                SMajor, SMinor, Val, Factor, CentMer, TrueScale, FE, FN )
+        else:
+          return '( %i %i %d %d %d %d %d %d 0.0 0.0 0.0 0.0 0.0 0.0 0.0 )' % ( 
+                SMajor, SMinor, Val, Factor, CentMer, TrueScale, FE, FN )
+
+    def return_params(self, swath = False):
+        """ Return the 13 parameters for MRT parameter file """
+        if self.val == 'll' or self.val == 'utm':
+            return self._outpar(0, 0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, swath)
+        elif self.val == 'laea':
+            SMajor = self._par('+a')
+            try:
+                SMinor = self._par('+b')
+            except:
+                SMinor = self._par('+rf')
+            CentMer = self._par('+lon_0')
+            CentLat = self._par('+lat_0')
+            FE = self._par('+x_0')
+            FN = self._par('+y_0')
+            return self._outpar(SMajor, SMinor, 0.0, 0.0, CentMer, 
+                                CentLat, FE, FN, swath)
+        elif self.val == 'lcc':
+            SMajor = self._par('+a')
+            try:
+                SMinor = self._par('+b')
+            except:
+                SMinor = self._par('+rf')
+            STDPR1 = self._par('+lat_1')
+            STDPR2 = self._par('+lat_2')
+            CentMer = self._par('+lon_0')
+            CentLat = self._par('+lat_0')
+            FE = self._par('+x_0')
+            FN = self._par('+y_0')
+            return self._outpar(SMajor, SMinor, STDPR1, STDPR2, CentMer, 
+                                CentLat, FE, FN, swath)
+        elif self.val == 'merc' or self.val == 'polar' or self.val == 'tmerc':
+            SMajor = self._par('+a')
+            try:
+                SMinor = self._par('+b')
+            except:
+                SMinor = self._par('+rf')
+            CentMer = self._par('+lon_0')
+            if self.val == 'tmerc':
+                Factor = self._par('+k_0')
+            else:
+                Factor = 0.0
+            TrueScale = self._par('+lat_ts')
+            FE = self._par('+x_0')
+            FN = self._par('+y_0')
+            return self._outpar(SMajor, SMinor, 0.0, Factor, CentMer, 
+                                 TrueScale, FE, FN, swath)
+        else:
+            grass.fatal(_('Projection not supported, please contact the ' \
+                          'GRASS-dev mailing list'))
+
+    def datum(self):
+        """Return the datum in the MRT style"""
+        if self.dat not in self.datumlist.keys():
+            grass.fatal(_("Datum <%s> is not supported") % self.dat)
+        elif self.dat == 'etrs89':
+            grass.warning(_("Changing datum <%s> to <%s>") % (self.dat, 'wgs84'))
+        return self.datumlist[self.dat]
+
+    def datumswath(self):
+        """Return the datum in MRT style"""
+        return self.datumlist_swath[self.dat]
+
+    def utmzone(self):
+        """Return the utm zone number"""
+        return self.proj['zone']

Added: grass-addons/grass7/grass7/raster/r.modis/r.modis.download/Makefile
===================================================================
--- grass-addons/grass7/grass7/raster/r.modis/r.modis.download/Makefile	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.modis/r.modis.download/Makefile	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,13 @@
+MODULE_TOPDIR = ../../..
+
+PGM = r.modis.download
+
+include $(MODULE_TOPDIR)/include/Make/Script.make
+
+default: script
+
+# $(ETC)/r.modis/r.modis.download/%: % | $(ETC)/r.modis/r.modis.download
+# 	$(INSTALL) $< $@
+# 
+# $(ETC)/r.modis/r.modis.download:
+# 	$(MKDIR) $@
\ No newline at end of file

Added: grass-addons/grass7/grass7/raster/r.modis/r.modis.download/r.modis.download.html
===================================================================
--- grass-addons/grass7/grass7/raster/r.modis/r.modis.download/r.modis.download.html	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.modis/r.modis.download/r.modis.download.html	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,78 @@
+<h2>DESCRIPTION</h2>
+
+<em>r.modis.download</em> downloads selected MODIS products. The module
+can download several tiles at once and also multiple observation days
+for each MODIS product.
+
+<h2>NOTE</h2>
+
+The connection to the FTP data site requires a default login.
+To set the username and password options the user has to use
+the <em>setting</em> option; a file can be used (in this case the first
+line is the username, usually it is 'anonymous', in the second line
+the password is given, usually the user's e-mail address):
+<div class="code"><pre>
+  your_NASA_FTP_username
+  your_NASA_FTP_password
+</pre></div>
+As alternative, the user can pass the values from standard input.
+<p>
+
+<b>Warning</b>: The NASA policy does not permit to open more then ten
+connections in parallel with their FTP server. Hence no more than ten
+process of <em>r.modis.download</em> should run at the same time.
+<p>
+By default the downloaded files are stored in the path where the setting
+file is saved. The user can change this directory with <em>folder</em>
+option. The user has <!-- NOT?? --> to set the <em>folder</em> option if
+user and password are sent by standard input.
+<p>
+The time for the download depends on the number of requested tiles, days
+and the type of the MODIS product. For example, the NDVI product ranges 
+from 5 MB to 270 MB and the LST product ranges from 2 MB to 21 MB.
+
+<h2>EXAMPLES</h2>
+
+To download the MODIS LST product from the Terra satellite using the default
+options and setting the user and password by standard input, launch:
+<div class="code"><pre>
+r.modis.download setting=-
+</pre></div>
+
+Reading the user and password options from file:
+<div class="code"><pre>
+r.modis.download setting=/home/user/.grass7/r.modis/SETTING
+</pre></div>
+
+To download LST Terra product using the default options and changing
+the starting and ending dates to custom values:
+<div class="code"><pre>
+r.modis.download setting=/home/user/.grass7/r.modis/SETTING startday=2011-05-01 endday=2011-05-31
+</pre></div>
+
+To download another product (for example <em>Snow eight days 500 m</em>),
+with other default options:
+<div class="code"><pre>
+r.modis.download setting=/home/user/.grass7/r.modis/SETTING product=snow_terra_eight_500
+</pre></div>
+
+To use <em>r.modis.download</em> in a script with one of the other module
+the user has to set the <em>-g</em> flag to return the name of the file
+containing a list of downloaded HDF names:
+<div class="code"><pre>
+r.modis.download -g setting=/home/user/.grass7/r.modis/SETTING startday=2011-05-01 endday=2011-05-31
+</pre></div>
+
+<h2>SEE ALSO</h2>
+<em>
+<a href="r.modis.html">r.modis</a>,
+<a href="r.modis.import.html">r.modis.import</a>
+<!-- <a href="r.modis.process.html">r.modis.process</a>,-->
+</em>
+<a href="https://lpdaac.usgs.gov/lpdaac/products/modis_overview">Map of MODIS Land products' Sinusoidal grid tiling system</a> 
+
+<h2>AUTHOR</h2>
+
+Luca Delucchi, Google Summer of Code 2011
+
+<p><i>Last changed: $Date: 2011-11-08 22:56:45 +0100 (Tue, 08 Nov 2011) $</i>

Added: grass-addons/grass7/grass7/raster/r.modis/r.modis.download/r.modis.download.py
===================================================================
--- grass-addons/grass7/grass7/raster/r.modis/r.modis.download/r.modis.download.py	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.modis/r.modis.download/r.modis.download.py	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,239 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+############################################################################
+#
+# MODULE:        r.in.modis.download
+# AUTHOR(S):     Luca Delucchi
+# PURPOSE:       r.in.modis.download is an interface to pyModis for download 
+#                several tiles of MODIS produts from NASA ftp
+#
+# COPYRIGHT:        (C) 2011 by Luca Delucchi
+#
+#                This program is free software under the GNU General Public
+#                License (>=v2). Read the file COPYING that comes with GRASS
+#                for details.
+#
+#############################################################################
+
+#%module
+#% description: Download several tiles of MODIS products using pyModis
+#% keywords: raster
+#% keywords: import
+#%end
+#%flag
+#% key: d
+#% description: For debug mode, it will write more info in the log file
+#%end
+#%flag
+#% key: g
+#% description: Return the name of file containing the list of HDF tiles downloaded in shell script style
+#%end
+#%option
+#% key: settings
+#% type: string
+#% gisprompt: old,file,input
+#% label: Full path to settings file
+#% description: "-" to pass the parameter from stdin
+#% answer: -
+#% guisection: Define
+#%end
+#%option
+#% key: product
+#% type: string
+#% label: Name of MODIS product(s)
+#% multiple: yes
+#% required: no
+#% options: lst_terra_daily_1000, lst_aqua_daily_1000, lst_terra_eight_1000, lst_aqua_eight_1000, lst_terra_daily_6000, lst_aqua_daily_6000, ndvi_terra_sixteen_250, ndvi_aqua_sixteen_250, ndvi_terra_sixteen_500, ndvi_aqua_sixteen_500, snow_terra_daily_500, snow_aqua_daily_500, snow_terra_eight_500, snow_aqua_eight_500
+#% answer: lst_terra_daily_1000
+#%end
+#%option
+#% key: tiles
+#% type: string
+#% label: The name(s) of tile(s) to download (comma separated)
+#% description: e.g.: h18v04
+#% required: no
+#%end
+#%option
+#% key: startday
+#% type: string
+#% label: First date to download
+#% description: Format: YYYY-MM-DD. If not set the download starts from today and go back 10 days. If not endday the download stops 10 days after the endday
+#% required: no
+#%end
+#%option
+#% key: endday
+#% type: string
+#% label: Last date to download
+#% description: Format: YYYY-MM-DD. To use only together with startday
+#% required: no
+#%end
+#%option
+#% key: folder
+#% type: string
+#% label: Folder to store the downloaded data
+#% description: If not set, path of settings file is used
+#% required: no
+#%end
+
+# import library
+import os, sys
+from datetime import *
+import grass.script as grass
+
+# add the folder containing libraries to python path
+if os.path.isdir(os.path.join(os.getenv('GISBASE'), 'etc', 'r.modis',os.sep)):
+    libmodis = os.path.join(os.getenv('GISBASE'), 'etc', 'r.modis')
+elif os.path.isdir(os.path.join(os.getenv('GRASS_ADDON_PATH'), 'etc', 'r.modis',os.sep)):
+    libmodis = os.path.join(os.getenv('GRASS_ADDON_PATH'), 'etc', 'r.modis')
+else:
+    print "ERROR: path to libraries not found"
+    sys.exit()
+# try to import pymodis (modis) and some class for r.modis.download
+sys.path.append(libmodis)
+try:
+    from rmodislib import product
+    from downmodis import downModis
+except ImportError:
+    grass.fatal(_("modis library not imported"))
+
+def check(home):
+    """ Check if a folder it is writable by the user that launch the process
+    """
+    if os.access(home,os.W_OK):
+        return 1
+    else:
+        grass.fatal(_("Folder to write downloaded files does not" \
+        + " exist or is not writeable"))
+        return 0
+
+def checkdate(options):
+    """ Function to check the data and return the correct value to download the
+        the tiles
+    """
+    def check2day(second,first=None):
+        """Function to check two date"""
+        if not first:
+            valueDay = None
+            firstDay = date.today()
+        else:
+            valueDay = first
+            firstSplit = first.split('-')
+            firstDay = date(int(firstSplit[0]),int(firstSplit[1]),int(firstSplit[2]))
+        lastSplit = second.split('-')
+        lastDay = date(int(lastSplit[0]),int(lastSplit[1]),int(lastSplit[2]))
+        delta = firstDay-lastDay
+        valueDelta = int(delta.days)
+        return valueDay, second, valueDelta
+
+    # no set start and end day
+    if options['startday'] == '' and options['endday'] == '':
+        return None, None, 10
+    # set only end day
+    elif options['startday'] != '' and options['endday'] == '':
+        valueDelta = 10
+        valueEnd = options['startday']
+        firstSplit = valueEnd.split('-')
+        firstDay = date(int(firstSplit[0]),int(firstSplit[1]),int(firstSplit[2]))
+        delta = timedelta(10)
+        lastday = firstDay + delta
+        valueDay = lastday.strftime("%Y-%m-%d")
+    # set only start day
+    elif options['startday'] == '' and options['endday'] != '':
+        grass.fatal(_("It is not possible use <endday> option without <startday> option"))
+    # set start and end day
+    elif options['startday'] != '' and options['endday'] != '':
+        valueDay, valueEnd, valueDelta = check2day(options['startday'],options['endday'])
+    return valueDay, valueEnd, valueDelta 
+
+# main function
+def main():
+    # check if you are in GRASS
+    gisbase = os.getenv('GISBASE')
+    if not gisbase:
+        grass.fatal(_('$GISBASE not defined'))
+        return 0
+    # set username, password and folder if settings are insert by stdin
+    if options['settings'] == '-':
+        if options['folder'] != '':
+            if check(options['folder']):
+                fold = options['folder']
+            user = 'anonymous'
+            passwd = raw_input(_('Insert password (your e-mail): '))
+        else:
+            grass.fatal(_("Set folder parameter when using stdin for passing the username " \
+            + "and password"))
+            return 0
+    # set username, password and folder by file
+    else:
+        # open the file and read the the user and password:
+        # first line is username
+        # second line is password
+	if check(options['settings']):
+           filesett = open(options['settings'],'r')
+           fileread = filesett.readlines()
+           user = fileread[0].strip()
+           passwd = fileread[1].strip()
+           filesett.close()
+	else:
+	   grass.fatal(_("File <%s> not found") % options['settings'])
+        # set the folder by option folder
+        if options['folder'] != '':
+            if check(options['folder']):
+                fold = options['folder']
+        # set the folder from path where settings file is stored 
+        else:
+            path = os.path.split(options['settings'])[0]
+            if check(path):
+                fold = path
+    # check the version
+    version = grass.core.version()
+    # this is would be set automatically
+    if version['version'].find('7.') == -1:
+        grass.fatal(_('GRASS GIS version 7 required'))
+        return 0
+    # the product
+    products = options['product'].split(',')
+    # first date and delta
+    firstday, finalday, delta = checkdate(options)
+    # set tiles
+    if options['tiles'] == '':
+        tiles = None
+        grass.warning(_("Option 'tiles' not set. Downloading all available tiles"))
+    else:
+        tiles = options['tiles']
+    # set the debug
+    if flags['d']:
+        debug_opt = True
+    else:
+        debug_opt = False
+    for produ in products:
+        prod = product(produ).returned()
+        #start modis class
+      
+        modisOgg = downModis(url = prod['url'], user = user,password = passwd, 
+              destinationFolder = fold, tiles = tiles, path = prod['folder'], 
+              today = firstday, enddate = finalday, delta = delta, debug = debug_opt)
+        # connect to ftp
+        modisOgg.connectFTP()
+        if modisOgg.nconnection <= 20:
+            # download tha tiles
+            grass.message(_("Downloading MODIS product <%s>..." % produ))
+            modisOgg.downloadsAllDay()
+            filesize = int(os.path.getsize(modisOgg.filelist.name))
+            if flags['g'] and filesize != 0:
+                grass.message("filename=%s" % modisOgg.filelist.name)
+            elif flags['g'] and filesize == 0:
+                grass.message("filename=")
+            elif not flags['g'] and filesize == 0:
+                grass.message(_("All data have been previously downloaded"))
+            elif filesize != 0:
+                grass.message(_("All data have been downloaded, continue with "\
+                + "r.modis.import with the option 'files=%s'" % modisOgg.filelist.name \
+                + " and 'mrtpath=/path/to/mrt/'"))
+        else:
+            grass.fatal(_("Error during connection"))
+
+if __name__ == "__main__":
+    options, flags = grass.parser()
+    sys.exit(main())

Added: grass-addons/grass7/grass7/raster/r.modis/r.modis.html
===================================================================
--- grass-addons/grass7/grass7/raster/r.modis/r.modis.html	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.modis/r.modis.html	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,129 @@
+<h2>DESCRIPTION</h2>
+
+The <em>r.modis</em> suite is a toolset to import MODIS satellite data in GRASS GIS. 
+It uses the <a href="http://gis.cri.fmach.it/development/pyModis">pyModis</a>
+library and the <a
+href="https://lpdaac.usgs.gov/lpdaac/tools/modis_reprojection_tool"> MODIS
+Reprojection Tool</a> software to convert, mosaik and process MODIS data.
+It requires the <a
+href="https://lpdaac.usgs.gov/lpdaac/tools/modis_reprojection_tool">MODIS
+Reprojection Tool</a> to be installed while <a
+href="http://gis.cri.fmach.it/development/pyModis">pyModis</a> is
+included in the <em>r.modis</em> suite.
+The suite offers three modules as interface with MODIS data. Each modules
+is dedicated to for a specific operation. The module <em>r.modis.download</em>
+is used to download MODIS HDF products from NASA FTP. These files can then
+be imported with <em>r.modis.import</em> which supports import of Level 3 
+MODIS products as single image or daily mosaik into GRASS GIS.
+<p>
+The user can download several MODIS products, by single or multiple tiles and
+also ranges of observation days retrieving data from the related NASA FTP server.
+<!--
+The suite process Level 2 data using the <em>r.modis.process</em> module.
+-->
+It imports Level 3 (georeferenced) products either as single image or as daily mosaik.
+
+<h4>Products</h4>
+The products already supported: 
+<ul>
+  <li><b>Land Surface Temperature daily 1 Km (Terra/Aqua)</b>: product provides per-pixel temperature
+      and emissivity values in a sequence of swath-based to grid-based global products.
+      The MODIS/Terra-Aqua LST/E Daily L3 Global 1 km Grid product (MOD11A1/MYD11A1), is tile-based 
+      and gridded in the Sinusoidal projection, and produced daily at 1 km spatial resolution. </li>
+  <li><b>Land Surface Temperature daily 6 Km (Terra/Aqua)</b>: data are composed from the daily 
+      1-kilometer LST product (MOD11A1/MYD11A1) and stored on a 1-km Sinusoidal grid as the 
+      average values of clear-sky LSTs during an 8-day period.<br>
+      MOD11A2/MYD11A2 is comprised of daytime and nighttime LSTs, quality assessment, 
+      observation times, view angles, bits of clear sky days and nights, and 
+      emissivities estimated in Bands 31 and 32 from land cover types.</li>
+  <li><b>Land Surface Temperature eight day 1 Km (Terra/Aqua)</b>: products provide per-pixel 
+      temperature and emissivity values in a sequence of swath-based to grid-based 
+      global products. The MODIS/Terra-Aqua LST/E Daily L3 Global 5 Km Grid 
+      (Short name: MOD11B1/MYD11B1), is tile-based and gridded in the Sinusoidal projection, 
+      and produced daily at 5 km spatial resolution.</li>
+  <li><b>VI sixteen days 250 m (Terra/Aqua)</b>: Global MODIS vegetation indices are designed 
+      to provide consistent spatial and temporal comparisons of vegetation conditions. 
+      Blue, red, and near-infrared reflectances, centered at 469-nanometers, 
+      645-nanometers, and 858-nanometers, respectively, are used to determine 
+      the MODIS daily vegetation indices.<br>
+      The MODIS Normalized Difference Vegetation Index (NDVI) complements NOAA's 
+      Advanced Very High Resolution Radiometer (AVHRR) NDVI products and provides 
+      continuity for time series historical applications. MODIS also includes a 
+      new Enhanced Vegetation Index (EVI) that minimizes canopy background variations 
+      and maintains sensitivity over dense vegetation conditions. The EVI also 
+      uses the blue band to remove residual atmosphere contamination caused by 
+      smoke and sub-pixel thin cloud clouds. The MODIS NDVI and EVI products are 
+      computed from atmospherically corrected bi-directional surface reflectances 
+      that have been masked for water, clouds, heavy aerosols, and cloud shadows.
+      Global MOD13Q1/MYD13Q1 data are provided every 16 days at 250-meter spatial resolution 
+      as a gridded level-3 product in the Sinusoidal projection. Lacking a 250m 
+      blue band, the EVI algorithm uses the 500m blue band to correct for residual 
+      atmospheric effects, with negligible spatial artifacts.</li>
+  <li><b>VI sixteen days 500 m (Terra/Aqua)</b>: Global MODIS vegetation indices are 
+      designed to provide consistent spatial and temporal comparisons of vegetation 
+      conditions. Blue, red, and near-infrared reflectances, centered at 
+      469-nanometers, 645-nanometers, and 858-nanometers, respectively, are used 
+      to determine the MODIS daily vegetation indices.<br>
+      The MODIS Normalized Difference Vegetation Index (NDVI) complements NOAA's 
+      Advanced Very High Resolution Radiometer (AVHRR) NDVI products provide 
+      continuity for time series historical applications. MODIS also includes a 
+      new Enhanced Vegetation Index (EVI) that minimizes canopy background 
+      variations and maintains sensitivity over dense vegetation conditions. 
+      The EVI also uses the blue band to remove residual atmosphere contamination 
+      caused by smoke and sub-pixel thin cloud clouds. The MODIS NDVI and EVI 
+      products are computed from atmospherically corrected bi-directional surface 
+      reflectances that have been masked for water, clouds, heavy aerosols, and 
+      cloud shadows.<br>
+      Global MOD13A1/MYD13A1 data are provided every 16 days at 500-meter spatial 
+      resolution as a gridded level-3 product in the Sinusoidal projection. 
+      Vegetation indices are used for global monitoring of vegetation conditions 
+      and are used in products displaying land cover and land cover changes. 
+      These data may be used as input for modeling global biogeochemical and 
+      hydrologic processes and global and regional climate. These data also may 
+      be used for characterizing land surface biophysical properties and processes, 
+      including primary production and land cover conversion.</li>
+  <li><b>Snow eight days 500 m (Terra/Aqua)</b>: The MOD10A2 and MYD10A2 products 
+      are composites of eight days of snow maps in the sinusoidal grid.
+      An eight-day compositing period was chosen because that is the exact ground 
+      track repeat period of the Terra and Aqua platforms. Snow cover over eight 
+      days is mapped as maximum snow extent in one SDS and as a chronology of 
+      observations in the other SDS. Eight-day periods begin on the first day of 
+      the year and extend into the next year. The product can be produced with 
+      two to eight days of input. There may not always be eight days of input, 
+      because of various reasons, so the user should check the attributes to 
+      determine on what days observations were obtained. See the validation webpage 
+      for details on the validation and validation definitions.</li>
+  <li><b>Snow daily 500 m (Terra/Aqua)</b>: MOD10A1 and MYD10A1 are tiles of daily 
+      snow cover at 500 m spatial resolution. The daily observation selected from 
+      multiple observations in a MOD10A1 (or MYD10A1) cell is the observation 
+      acquired nearest nadir and having the greatest coverage of the grid cell.
+      The daily MOD10A1 and MYD10A1 snow products are tiles of data gridded in the 
+      sinusoidal projection. Tiles are approximately 1200 x 1200 km in area. A 
+      single scientific data set (SDS) of snow cover and a single SDS of QA data 
+      along with local and global attributes comprise the data product file. The 
+      daily level 3 snow product is the result of selecting an observation from 
+      the multiple observations mapped to a cell of the MOD10_L2G (or MYD10_L2G) 
+      product. See the validation webpage for details on the validation and 
+      validation definitions.</li>
+</ul>
+
+<h2>SEE ALSO</h2>
+
+<em>
+<a href="r.modis.import.html">r.modis.import</a>,
+<a href="r.modis.download.html">r.modis.download</a>
+<!-- <a href="r.modis.process.html">r.modis.process</a>,-->
+</em>
+<p>
+<ul>
+ <li><a href="https://lpdaac.usgs.gov/lpdaac/tools/modis_reprojection_tool">MODIS Reprojection Tool</a></li>
+ <li> <a href="http://modis-land.gsfc.nasa.gov/index.htm">MODIS Land homepage</a></li>
+ <li> <a href="http://modis-snow-ice.gsfc.nasa.gov/">MODIS Snow homepage</a></li>
+ <li> <a href="https://lpdaac.usgs.gov/lpdaac/products/modis_products_table">MODIS Land products table</a></li>
+</ul>
+ 
+<h2>AUTHOR</h2>
+
+Luca Delucchi, Google Summer of Code 2011
+
+<p><i>Last changed: $Date: 2011-11-08 22:56:45 +0100 (Tue, 08 Nov 2011) $</i>

Added: grass-addons/grass7/grass7/raster/r.modis/r.modis.import/Makefile
===================================================================
--- grass-addons/grass7/grass7/raster/r.modis/r.modis.import/Makefile	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.modis/r.modis.import/Makefile	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,13 @@
+MODULE_TOPDIR = ../../..
+
+PGM = r.modis.import
+
+include $(MODULE_TOPDIR)/include/Make/Script.make
+
+default: script
+
+# $(ETC)/r.modis/r.modis.download/%: % | $(ETC)/r.modis/r.modis.download
+# 	$(INSTALL) $< $@
+# 
+# $(ETC)/r.modis/r.modis.download:
+# 	$(MKDIR) $@
\ No newline at end of file

Added: grass-addons/grass7/grass7/raster/r.modis/r.modis.import/r.modis.import.html
===================================================================
--- grass-addons/grass7/grass7/raster/r.modis/r.modis.import/r.modis.import.html	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.modis/r.modis.import/r.modis.import.html	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,73 @@
+<h2>DESCRIPTION</h2>
+
+<em>r.modis.import</em> import into GRASS GIS Level 3 MODIS product.
+
+<h2>NOTE</h2>
+
+The input file is given as list of full paths to the MODIS HDF files,
+one per line. The input file(s) have to be inside the folder where 
+the HDF files are stored.
+<p>
+The <em>mrtpath</em> option is the path to the main folder of the
+MODIS Reprojection Tools (MRT) binaries, i.e. the folder which contains
+the bin/ and the data/ folder since these two folders are essential for
+obtaining a successful result.<br>
+It is not possible to use flag <em>--q</em> and the option <em>spectral</em>
+together.
+<p>
+
+<b>Warning</b>: 
+<ul>
+  <li>The module has currently only been tested with Lat/Long locations, but also
+   the following projection systems are supported: Lambert Azimuthal Equal Area,
+   Lambert Conformal Conic, Mercator, Polar Stereographic, Transverse Mercator,
+   Universal Transverse Mercator</li>
+</ul>
+
+<h2>EXAMPLES</h2>
+
+Import a single file with the default subset with QA layer analysis to remove bad pixels:
+<div class="code"><pre>
+r.modis.import dsn=/path/to/file mrtpath=/path/to/mrt
+</pre></div>
+
+Import more files with the default subset with QA layer:
+<div class="code"><pre>
+r.modis.import filename=/path/to/listfile mrtpath=/path/to/mrt
+</pre></div>
+
+Import more files like daily mosaic with the default subset without QA layer:
+<div class="code"><pre>
+r.modis.import filename=/path/to/listfile mrtpath=/path/to/mrt
+</pre></div>
+
+Import a single file with the default subset without QA layer analysis and without
+rescaling the pixel values:
+<div class="code"><pre>
+r.modis.import -r dsn=/path/to/file mrtpath=/path/to/mrt
+</pre></div>
+
+Import a single file with your own subset of layers (for power user):
+<div class="code"><pre>
+r.modis.import dsn=/path/to/file mrtpath=/path/to/mrt spectral="( 1 0 1 0 )"
+</pre></div>
+
+Import more files with your own subset of layers and without QA layer analysis (for power users):
+<div class="code"><pre>
+r.modis.import -q filename=/path/to/listfile mrtpath=/path/to/mrt spectral="( 1 )"
+</pre></div>
+
+<h2>SEE ALSO</h2>
+
+<em>
+<a href="r.modis.html">r.modis</a>,
+<a href="r.modis.download.html">r.modis.download</a>
+<!-- <a href="r.modis.process.html">r.modis.process</a>,-->
+</em><br>
+<a href="https://lpdaac.usgs.gov/lpdaac/tools/modis_reprojection_tool">MODIS Reprojection Tool</a>
+ 
+<h2>AUTHOR</h2>
+
+Luca Delucchi, Google Summer of Code 2011
+
+<p><i>Last changed: $Date: 2011-11-08 22:56:45 +0100 (Tue, 08 Nov 2011) $</i>

Added: grass-addons/grass7/grass7/raster/r.modis/r.modis.import/r.modis.import.py
===================================================================
--- grass-addons/grass7/grass7/raster/r.modis/r.modis.import/r.modis.import.py	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.modis/r.modis.import/r.modis.import.py	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,510 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+############################################################################
+#
+# MODULE:        r.modis.import
+# AUTHOR(S):     Luca Delucchi
+# PURPOSE:       r.modis.import is an interface to pyModis for import into GRASS
+#                GIS level 3 MODIS produts
+#
+# COPYRIGHT:        (C) 2011 by Luca Delucchi
+#
+#                This program is free software under the GNU General Public
+#                License (>=v2). Read the file COPYING that comes with GRASS
+#                for details.
+#
+#############################################################################
+#
+# REQUIREMENTS:
+#      -  MRT tools, https://lpdaac.usgs.gov/lpdaac/tools/modis_reprojection_tool
+#
+#############################################################################
+
+#%module
+#% description: Import single or multiple tiles of MODIS products using pyModis/MRT
+#% keywords: raster
+#% keywords: MODIS
+#%end
+#%flag
+#% key: m
+#% description: Create a mosaic for each day
+#%end
+#%flag
+#% key: t
+#% description: Preserve temporary files (TIF and HDF mosaic)
+#%end
+#%flag
+#% key: q
+#% description: Ignore the QA map layer, do not use with "r" flag
+#%end
+#%flag
+#% key: r
+#% description: Do not rescale the output map values to destination units
+#%end
+#%option
+#% key: mrtpath
+#% type: string
+#% key_desc: path
+#% description: Full path to MRT directory
+#% gisprompt: old,dir,input
+#% required: yes
+#%end
+#%option
+#% key: dns
+#% type: string
+#% key_desc: path
+#% description: Full path to single HDF file
+#% gisprompt: old,file,input
+#% required: no
+#%end
+#%option
+#% key: files
+#% type: string
+#% key_desc: file
+#% description: Full path to file with list of HDF files 
+#% gisprompt: old,file,input
+#% required: no
+#%end
+#%option G_OPT_R_OUTPUT
+#% required : no
+#% guisection: Import
+#%end
+#%option
+#% key: method
+#% type: string
+#% key_desc: resampling
+#% description: Code of spatial resampling method
+#% options: nearest, bilinear, cubic
+#% answer: nearest
+#% required: no
+#%end
+#%option
+#% key: spectral
+#% type: string
+#% key_desc: spectral subset
+#% description: String to choose subset of layers in HDF file for import 
+#% required: no
+#%end
+
+import os, sys, string, glob, shutil
+import grass.script as grass
+from datetime import date
+
+
+# add the folder containing libraries to python path
+if os.path.isdir(os.path.join(os.getenv('GISBASE'), 'etc', 'r.modis',os.sep)):
+    libmodis = os.path.join(os.getenv('GISBASE'), 'etc', 'r.modis')
+elif os.path.isdir(os.path.join(os.getenv('GRASS_ADDON_PATH'), 'etc', 'r.modis',os.sep)):
+    libmodis = os.path.join(os.getenv('GRASS_ADDON_PATH'), 'etc', 'r.modis')
+else:
+    print "ERROR: path to libraries not found"
+    sys.exit()
+
+sys.path.append(libmodis)
+# try to import pymodis (modis) and some classes for r.modis.download
+try:
+    from rmodislib import resampling, product, get_proj, projection
+except ImportError:
+    grass.fatal(_("rmodislib library not imported"))
+try:
+    from convertmodis  import convertModis, createMosaic
+except ImportError:
+    grass.fatal(_("convertmodis library not imported"))
+try:
+    from parsemodis import parseModis
+except ImportError:
+    grass.fatal(_("parsemodis library not imported"))    
+
+def list_files(opt, mosaik = False):
+    """If used in function single(): Return a list of HDF files from the file list
+    If used in function mosaic(): Return a dictionary with a list of HDF files for each day
+    """
+    # read the file with the list of HDF
+    if opt['files'] != '':
+        listoffile = open(opt['files'],'r')
+        basedir = os.path.split(listoffile.name)[0]
+        # if mosaic create a dictionary
+        if mosaik:
+            filelist = {}
+        # if not mosaic create a list
+        else:
+            filelist = []
+        # append hdf files
+        for line in listoffile:
+            if string.find(line,'xml') == -1 and mosaik == False:
+                filelist.append(line.strip())
+            # for mosaic create a list of hdf files for each day
+            elif string.find(line,'xml') == -1 and mosaik == True:
+                day = line.split('/')[-1].split('.')[1]
+                if filelist.has_key(day):
+                    filelist[day].append(line)
+                else:
+                    filelist[day] = [line]
+    # create a list for each file
+    elif options['dns'] != '':
+        filelist = [options['dns']]
+        basedir = os.path.split(filelist[0])[0]
+    return filelist, basedir
+
+def spectral(opts, prod, q, m = False):
+    """Return spectral string"""
+    # return the spectral set selected by the user
+    if opts['spectral'] != '':
+        spectr = opts['spectral']
+    # return the spectral by default
+    else:
+        if q:
+            if prod['spec_qa']:
+                spectr = prod['spec_qa']
+            else: 
+                spectr = prod['spec']
+        else:
+            spectr = prod['spec']
+        if m:
+            spectr = spectr.replace(' 0', '')
+    return spectr
+
+def confile(pm, opts, q, mosaik=False):
+    """Create the configuration file for MRT software"""
+    # return projection and datum 
+    projObj = projection()
+    proj = projObj.returned()
+    dat = projObj.datum()
+    if proj == 'UTM':
+        zone = projObj.utmzone()
+    else:
+        zone = None
+    cod = os.path.split(pm.hdfname)[1].split('.')[0]
+    prod = product().fromcode(cod)
+    if mosaik:
+        # if mosaic it remove all the 0 from the subset string to convert all 
+        # the right layer
+        spectr = spectral(opts, prod, q, True)
+    else:
+        spectr = spectral(opts, prod, q)
+    # out prefix
+    pref = prefix(opts)
+    # resampling
+    resampl = resampling(opts['method']).returned()
+    # projpar
+    projpar = projObj.return_params()
+    if projpar != "( 0, 0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 )":
+        dat = "NODATUM"
+    # resolution
+    if proj != 'GEO':
+        res = int(prod['res']) * int(projObj.proj['meters'])
+    else:
+        res = None
+    try:
+        conf = pm.confResample(spectr, res, pref, dat, resampl, 
+                                proj, zone, projpar)
+        return conf
+    except IOError, e:
+        grass.fatal(e)
+
+def prefix(options, name = False):
+    """Return the prefix of output file if not set return None to use default
+       value
+    """
+    if options['output']:
+        return options['output']
+    else:
+        return None  
+
+def import_tif(out, basedir, rem, write, target=None):
+    """Import TIF files"""
+    # list of tif files
+    tifiles = glob.glob1(basedir, out + "*.tif")
+    if not tifiles:
+        grass.fatal(_('Error during the conversion'))
+    # check if user is in latlong location to set flag l
+    if projection().val == 'll':
+        f = "l"
+    else:
+        f = None
+    outfile = []
+    # for each file import it
+    for t in tifiles:
+        basename = os.path.splitext(t)[0]
+        name = os.path.join(basedir,t)
+        filesize = int(os.path.getsize(name))
+        if filesize < 1000:
+            grass.warning(_('Probably some error occur during the conversion' \
+            + 'for file <%s>. Escape import' % name))
+            continue
+        try:
+            grass.run_command('r.in.gdal', input = name, output = basename,
+                              flags = f, overwrite = write, quiet = True)
+            outfile.append(basename)
+        except:
+            grass.fatal(_('Error during import'))
+        if rem:
+            os.remove(name)
+        if target: 
+            if target != basedir:
+                shutil.move(name,target)
+    return outfile
+
+def findfile(pref, suff):
+    """ Check if a file exists on mapset """
+    if grass.find_file(pref + suff)['file']:
+        return grass.find_file(pref + suff)
+    else:
+        grass.warning(_("Raster map <%s> not found") % (pref + suff))
+
+def metadata(pars, mapp, coll):
+    """ Set metadata to the imported files """
+    # metadata
+    meta = pars.metastring()
+    grass.run_command('r.support', quiet = True, map=mapp, hist=meta)
+    # timestamp
+    rangetime = pars.retRangeTime()
+    data = rangetime['RangeBeginningDate'].split('-')
+    dataobj = date(int(data[0]),int(data[1]),int(data[2]))
+    grass.run_command('r.timestamp', map=mapp, date=dataobj.strftime("%d %b %Y"),
+                      quiet = True)
+    # color
+    if string.find(mapp, 'QC') != -1 or string.find(mapp, 'Quality') != -1 or \
+    string.find(mapp, 'QA') != -1:
+        grass.run_command('r.colors', quiet = True, map=mapp, color = coll)
+    elif string.find(mapp, 'NDVI') != -1:
+        grass.run_command('r.colors', quiet = True, map=mapp, color = coll[0])
+    elif string.find(mapp, 'EVI') != -1:
+        grass.run_command('r.colors', quiet = True, map=mapp, color = coll[1])
+    elif string.find(mapp, 'LST') != -1:
+        grass.run_command('r.colors', quiet = True, map=mapp, color = coll[0])
+    elif string.find(mapp, 'Snow') != -1:
+        grass.run_command('r.colors', quiet = True, map=mapp, color = coll[0])
+
+def analyze(pref, an, cod, parse, write):
+    """ Analyze the MODIS data using QA if present """
+    prod = product().fromcode(cod)
+    if not prod['spec_qa']:
+        grass.warning(_("There is no QA layer, analysis and filtering will be skipped"))
+        an = 'noqa'
+    pat = prod['pattern']
+    suf = prod['suff']
+    col = prod['color']
+    val = []
+    qa = []
+    for v,q in suf.iteritems():
+        val.append(findfile(pref,v))
+        if q:
+            qa.append(findfile(pref,q))
+    for n in range(len(val)):
+        if val[n] == None:
+            grass.warning(_("Some error occur"))
+            continue
+        valname = val[n]['name']
+        valfull = val[n]['fullname']
+        grass.run_command('g.region', rast = valfull)
+        grass.run_command('r.null', map = valfull, setnull = 0)
+        if string.find(cod,'13Q1') >= 0 or string.find(cod,'13A2') >= 0:
+            mapc = "%s.2 = %s / 10000." % (valname, valfull)
+        elif string.find(cod,'11A1') >= 0 or string.find(cod,'11A2') >= 0 or string.find(cod,'11B1') >= 0:
+            mapc = "%s.2 = (%s * 0.0200) - 273.15" % (valname, valfull)
+        grass.mapcalc(mapc)
+        if an == 'noqa':
+            #grass.run_command('g.remove', quiet = True, rast = valfull)
+            try:
+                grass.run_command('g.rename', quiet = True, overwrite = write, 
+                                rast=(valname,valname + '.orig'))
+                grass.run_command('g.rename', quiet = True, overwrite = write, 
+                                rast= (valname + '.2', valname))
+            except:
+                pass
+            metadata(parse, valname, col)
+            metadata(parse, valname, col)
+            metadata(parse, qafull, 'byr')
+        if an == 'all':
+            if len(qa) != len(val):
+                grass.fatal(_("The number of QA and value maps is different, something is wrong"))
+            qaname = qa[n]['name']
+            qafull = qa[n]['fullname']
+            finalmap = "%s.3=if(" % valname
+            first_map = 1
+            for key,value in prod['pattern'].iteritems():
+                for v in value:
+                    outpat = "%s.%i.%i" % (qaname, key, v)
+                    grass.run_command('r.bitpattern', quiet = True, input = qafull, 
+                                    output = outpat, pattern = key, patval= v)
+                    if first_map:
+                        first_map = 0
+                        finalmap += "%s == 0 " % outpat
+                    else:
+                        finalmap += "&& %s == 0 " % outpat
+
+            if string.find(cod,'13Q1') >= 0 or string.find(cod,'13A2') >= 0:
+                    finalmap += "&& %s.2 <= 1.000" % valname
+            finalmap += ",%s.2, null() )" % valname
+            # grass.message("mapc finalmap: %s" % finalmap)
+            grass.mapcalc(finalmap)
+            #grass.run_command('g.remove', quiet = True, rast=(valname, valname + '.2'))
+            grass.run_command('g.rename', quiet = True, overwrite = write, 
+			      rast=(valname,valname + '.orig'))
+            grass.run_command('g.remove', quiet = True, rast=(valname + '.2'))
+            grass.run_command('g.mremove', flags="f", quiet = True,
+			      rast = ("%s.*" % qaname))
+            grass.run_command('g.rename', quiet = True, overwrite = write,
+                              rast=(valname + '.3', valname))
+            metadata(parse, valname, col)
+            metadata(parse, valname, col)
+            metadata(parse, qafull, 'byr')
+
+def single(options,remove,an,ow):
+    """Convert the HDF file to TIF and import it
+    """
+    listfile, basedir = list_files(options)
+    pid = str(os.getpid())
+    # for each file
+    for i in listfile:
+        # the full path to hdf file
+        hdf = os.path.join(basedir,i)
+        # create conf file fro mrt tools
+        pm = parseModis(hdf)
+        confname = confile(pm,options,an)
+        print confname
+        # create convertModis class and convert it in tif file
+        execmodis = convertModis(hdf,confname,options['mrtpath'])
+        execmodis.run()
+        output = prefix(options)
+        if not output:
+            output = os.path.split(hdf)[1].rstrip('.hdf')
+        # import tif files
+        maps_import = import_tif(output,basedir,remove,ow)
+        if an and len(maps_import) != 0:
+            grass.run_command('g.region', save = 'oldregion.%s' % pid)
+            try:
+                cod = os.path.split(pm.hdfname)[1].split('.')[0]
+                analyze(outname, an, cod, pm, ow)
+            except:
+                grass.run_command('g.region', region = 'oldregion.%s' % pid)
+                grass.run_command('g.remove',quiet = True, 
+                    region = 'oldregion.%s' % pid)
+            cod = os.path.split(pm.hdfname)[1].split('.')[0]
+            analyze(output, an, cod, pm, ow)
+        #os.remove(confname)
+
+def mosaic(options,remove,an,ow):
+    """Create a daily mosaic of HDF files convert to TIF and import it
+    """
+    dictfile, targetdir = list_files(options,True)
+    pid = str(os.getpid())
+    # for each day
+    for dat, listfiles in dictfile.iteritems():
+        # create the file with the list of name
+        tempfile = open(os.path.join(targetdir,pid),'w')
+        tempfile.writelines(listfiles)
+        tempfile.close()
+        # basedir of tempfile, where hdf files are write
+        basedir = os.path.split(tempfile.name)[0]
+        outname = "%s.%s.mosaic" % (listfiles[0].split('/')[-1].split('.')[0],
+                                    listfiles[0].split('/')[-1].split('.')[1])
+        # return the spectral subset in according mrtmosaic tool format
+        prod = product().fromcode(listfiles[0].split('/')[-1].split('.')[0])
+        spectr = spectral(options,prod,an)
+        spectr = spectr.lstrip('( ').rstrip(' )')
+        # create mosaic
+        cm = createMosaic(tempfile.name, outname, options['mrtpath'], spectr)
+        cm.run()
+        # list of hdf files
+        hdfiles = glob.glob1(basedir, outname + "*.hdf")
+        for i in hdfiles:
+            # the full path to hdf file
+            hdf = os.path.join(basedir,i)
+            # create conf file fro mrt tools
+            pm = parseModis(hdf)
+            confname = confile(pm,options,an, True)
+            # create convertModis class and convert it in tif file
+            execmodis = convertModis(hdf, confname, options['mrtpath'])
+            execmodis.run()
+            # remove hdf 
+            if remove:  
+                # import tif files
+                maps_import = import_tif(outname, basedir, remove, ow)
+                if an:
+                    grass.run_command('g.region', save = 'oldregion.%s' % pid)
+                    try:
+                        cod = os.path.split(pm.hdfname)[1].split('.')[0]
+                        analyze(outname, an, cod, pm, ow)
+                    except:
+                        grass.run_command('g.region', region = 'oldregion.%s' % pid)
+                        grass.run_command('g.remove',quiet = True,
+				    region = 'oldregion.%s' % pid)
+                os.remove(hdf)
+                os.remove(hdf + '.xml')
+            # or move the hdf and hdf.xml to the dir where are the original files
+            else:
+                # import tif files
+                import_tif(outname, basedir, remove, ow, targetdir)
+                if an and len(maps_import) != 0:
+                    grass.run_command('g.region', save = 'oldregion.%s' % pid)
+                    try:
+                        cod = os.path.split(pm.hdfname)[1].split('.')[0]
+                        analyze(outname, an, cod, pm, ow)
+                    except:
+                        grass.run_command('g.region', region = 'oldregion.%s' % pid)
+                        grass.run_command('g.remove', region = 'oldregion.%s' % pid)
+                try: 
+                    shutil.move(hdf,targetdir)
+                    shutil.move(hdf + '.xml',targetdir)
+                except:
+                    pass
+            # remove the conf file
+            os.remove(confname)
+        grass.try_remove(tempfile.name)
+        grass.try_remove(os.path.join(targetdir,'mosaic',pid))
+
+def main():
+    # check if you are in GRASS
+    gisbase = os.getenv('GISBASE')
+    if not gisbase:
+        grass.fatal(_('$GISBASE not defined'))
+        return 0
+    # return an error if q and spectral are set
+    if not flags['q'] and options['spectral'] != '':
+        grass.warning(_('If no QA layer chosen in the "spectral" option'\
+        + 'the command will report an error'))
+    # return an error if both dns and files option are set or not
+    if options['dns'] == '' and options['files'] == '':
+        grass.fatal(_('Choose one of "dns" or "files" options'))
+        return 0
+    elif options['dns'] != '' and options['files'] != '':
+        grass.fatal(_('It is not possible set "dns" and "files" options together'))
+        return 0
+    # check the version
+    version = grass.core.version()
+    # this is would be set automatically
+    if version['version'].find('7.') == -1:
+        grass.fatal(_('GRASS GIS version 7 required'))
+        return 0
+    # check if remove the files or not
+    if flags['t']:
+        remove = False
+    else:
+        remove = True
+    if grass.overwrite():
+        over = True
+    else:
+        over = False
+    # check if do check quality, rescaling and setting of colors
+    if flags['r']:
+        analyze = None
+    elif flags['q']:
+        analyze = 'noqa'
+    else:
+        analyze = 'all'
+    # check if import simple file or mosaic
+    if flags['m'] and options['dns'] != '':
+        grass.fatal(_('It is not possible to create a mosaic with a single HDF file'))
+        return 0
+    elif flags['m']:
+        mosaic(options,remove,analyze,over)
+    else:
+        single(options,remove,analyze,over)
+
+if __name__ == "__main__":
+    options, flags = grass.parser()
+    sys.exit(main())
+

Added: grass-addons/grass7/grass7/raster/r.regression.multi/Makefile
===================================================================
--- grass-addons/grass7/grass7/raster/r.regression.multi/Makefile	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.regression.multi/Makefile	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,10 @@
+MODULE_TOPDIR = ../..
+
+PGM = r.regression.multi
+
+LIBES = $(RASTERLIB) $(GISLIB) $(MATHLIB)
+DEPENDENCIES = $(RASTERDEP) $(GISDEP)
+
+include $(MODULE_TOPDIR)/include/Make/Module.make
+
+default: cmd

Added: grass-addons/grass7/grass7/raster/r.regression.multi/main.c
===================================================================
--- grass-addons/grass7/grass7/raster/r.regression.multi/main.c	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.regression.multi/main.c	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,571 @@
+
+/****************************************************************************
+ *
+ * MODULE:       r.regression.multi
+ * 
+ * AUTHOR(S):    Markus Metz
+ * 
+ * PURPOSE:      Calculates multiple linear regression from raster maps:
+ *               y = b0 + b1*x1 + b2*x2 + ... +  bn*xn + e
+ * 
+ * COPYRIGHT:    (C) 2011 by the GRASS Development Team
+ *
+ *               This program is free software under the GNU General Public
+ *               License (>=v2). Read the file COPYING that comes with GRASS
+ *               for details.
+ *
+ *****************************************************************************/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <string.h>
+#include <grass/gis.h>
+#include <grass/glocale.h>
+#include <grass/raster.h>
+
+struct MATRIX
+{
+    int n;			/* SIZE OF THIS MATRIX (N x N) */
+    double *v;
+};
+
+#define M(m,row,col) (m)->v[((row) * ((m)->n)) + (col)]
+
+static int solvemat(struct MATRIX *m, double a[], double B[])
+{
+    int i, j, i2, j2, imark;
+    double factor, temp;
+    double pivot;		/* ACTUAL VALUE OF THE LARGEST PIVOT CANDIDATE */
+
+    for (i = 0; i < m->n; i++) {
+	j = i;
+
+	/* find row with largest magnitude value for pivot value */
+
+	pivot = M(m, i, j);
+	imark = i;
+	for (i2 = i + 1; i2 < m->n; i2++) {
+	    temp = fabs(M(m, i2, j));
+	    if (temp > fabs(pivot)) {
+		pivot = M(m, i2, j);
+		imark = i2;
+	    }
+	}
+
+	/* if the pivot is very small then the points are nearly co-linear */
+	/* co-linear points result in an undefined matrix, and nearly */
+	/* co-linear points results in a solution with rounding error */
+
+	if (pivot == 0.0) {
+	    G_warning(_("Matrix is unsolvable"));
+	    return 0;
+	}
+
+	/* if row with highest pivot is not the current row, switch them */
+
+	if (imark != i) {
+	    for (j2 = 0; j2 < m->n; j2++) {
+		temp = M(m, imark, j2);
+		M(m, imark, j2) = M(m, i, j2);
+		M(m, i, j2) = temp;
+	    }
+
+	    temp = a[imark];
+	    a[imark] = a[i];
+	    a[i] = temp;
+	}
+
+	/* compute zeros above and below the pivot, and compute
+	   values for the rest of the row as well */
+
+	for (i2 = 0; i2 < m->n; i2++) {
+	    if (i2 != i) {
+		factor = M(m, i2, j) / pivot;
+		for (j2 = j; j2 < m->n; j2++)
+		    M(m, i2, j2) -= factor * M(m, i, j2);
+		a[i2] -= factor * a[i];
+	    }
+	}
+    }
+
+    /* SINCE ALL OTHER VALUES IN THE MATRIX ARE ZERO NOW, CALCULATE THE
+       COEFFICIENTS BY DIVIDING THE COLUMN VECTORS BY THE DIAGONAL VALUES. */
+
+    for (i = 0; i < m->n; i++) {
+	B[i] = a[i] / M(m, i, i);
+    }
+
+    return 1;
+}
+
+int main(int argc, char *argv[])
+{
+    unsigned int r, c, rows, cols, n_valid;	/*  totals  */
+    int *mapx_fd, mapy_fd, mapres_fd, mapest_fd;
+    int i, j, k, n_predictors;
+    double *sumX, sumY, *sumsqX, sumsqY, *sumXY;
+    double *meanX, meanY, *varX, varY, *sdX, sdY;
+    double yest, yres;       /* estimated y, residual */
+    double sumYest, *SSerr_without;
+    double SE;
+    double meanYest, meanYres, varYest, varYres, sdYest, sdYres;
+    double SStot, SSerr, SSreg;
+    double **a;
+    struct MATRIX *m, *m_all;
+    double **B, Rsq, Rsqadj, F, t, AIC, AICc, BIC;
+    unsigned int count = 0;
+    DCELL **mapx_buf, *mapy_buf, *mapx_val, mapy_val, *mapres_buf, *mapest_buf;
+    char *name;
+    struct Option *input_mapx, *input_mapy, *output_res, *output_est, *output_opt;
+    struct Flag *shell_style;
+    struct Cell_head region;
+    struct GModule *module;
+
+    G_gisinit(argv[0]);
+
+    module = G_define_module();
+    G_add_keyword(_("raster"));
+    G_add_keyword(_("statistics"));
+    module->description =
+	_("Calculates multiple linear regression from raster maps.");
+
+    /* Define the different options */
+    input_mapx = G_define_standard_option(G_OPT_R_INPUTS);
+    input_mapx->key = "mapx";
+    input_mapx->description = (_("Map for x coefficient"));
+
+    input_mapy = G_define_standard_option(G_OPT_R_INPUT);
+    input_mapy->key = "mapy";
+    input_mapy->description = (_("Map for y coefficient"));
+
+    output_res = G_define_standard_option(G_OPT_R_OUTPUT);
+    output_res->key = "residuals";
+    output_res->required = NO;
+    output_res->description = (_("Map to store residuals"));
+
+    output_est = G_define_standard_option(G_OPT_R_OUTPUT);
+    output_est->key = "estimates";
+    output_est->required = NO;
+    output_est->description = (_("Map to store estimates"));
+
+    output_opt = G_define_standard_option(G_OPT_F_OUTPUT);
+    output_opt->key = "output";
+    output_opt->required = NO;
+    output_opt->description =
+	(_("ASCII file for storing regression coefficients (output to screen if file not specified)."));
+
+    shell_style = G_define_flag();
+    shell_style->key = 'g';
+    shell_style->description = _("Print in shell script style");
+
+    if (G_parser(argc, argv))
+	exit(EXIT_FAILURE);
+
+    name = output_opt->answer;
+    if (name != NULL && strcmp(name, "-") != 0) {
+	if (NULL == freopen(name, "w", stdout)) {
+	    G_fatal_error(_("Unable to open file <%s> for writing"), name);
+	}
+    }
+
+    G_get_window(&region);
+    rows = region.rows;
+    cols = region.cols;
+
+    /* count x maps */
+    for (i = 0; input_mapx->answers[i]; i++);
+    n_predictors = i;
+    
+    /* allocate memory for x maps */
+    mapx_fd = (int *)G_malloc(n_predictors * sizeof(int));
+    sumX = (double *)G_malloc(n_predictors * sizeof(double));
+    sumsqX = (double *)G_malloc(n_predictors * sizeof(double));
+    sumXY = (double *)G_malloc(n_predictors * sizeof(double));
+    SSerr_without = (double *)G_malloc(n_predictors * sizeof(double));
+    meanX = (double *)G_malloc(n_predictors * sizeof(double));
+    varX = (double *)G_malloc(n_predictors * sizeof(double));
+    sdX = (double *)G_malloc(n_predictors * sizeof(double));
+    mapx_buf = (DCELL **)G_malloc(n_predictors * sizeof(DCELL *));
+    mapx_val = (DCELL *)G_malloc((n_predictors + 1) * sizeof(DCELL));
+    
+    /* ordinary least squares */
+    m = NULL;
+    m_all = (struct MATRIX *)G_malloc((n_predictors + 1) * sizeof(struct MATRIX));
+    a = (double **)G_malloc((n_predictors + 1) * sizeof(double *));
+    B = (double **)G_malloc((n_predictors + 1) * sizeof(double *));
+
+    m = &(m_all[0]);
+    m->n = n_predictors + 1;
+    m->v = (double *)G_malloc(m->n * m->n * sizeof(double));
+
+    a[0] = (double *)G_malloc(m->n * sizeof(double));
+    B[0] = (double *)G_malloc(m->n * sizeof(double));
+
+    for (i = 0; i < m->n; i++) {
+	for (j = i; j < m->n; j++)
+	    M(m, i, j) = 0.0;
+	a[0][i] = 0.0;
+	B[0][i] = 0.0;
+    }
+    
+    for (k = 1; k <= n_predictors; k++) {
+	m = &(m_all[k]);
+	m->n = n_predictors;
+	m->v = (double *)G_malloc(m->n * m->n * sizeof(double));
+	a[k] = (double *)G_malloc(m->n * sizeof(double));
+	B[k] = (double *)G_malloc(m->n * sizeof(double));
+
+	for (i = 0; i < m->n; i++) {
+	    for (j = i; j < m->n; j++)
+		M(m, i, j) = 0.0;
+	    a[k][i] = 0.0;
+	    B[k][i] = 0.0;
+	}
+    }
+
+    /* open maps */
+    G_debug(1, "open maps");
+    for (i = 0; i < n_predictors; i++) {
+	mapx_fd[i] = Rast_open_old(input_mapx->answers[i], "");
+    }
+    mapy_fd = Rast_open_old(input_mapy->answer, "");
+
+    for (i = 0; i < n_predictors; i++)
+	mapx_buf[i] = Rast_allocate_d_buf();
+    mapy_buf = Rast_allocate_d_buf();
+
+    for (i = 0; i < n_predictors; i++) {
+	sumX[i] = sumsqX[i] = sumXY[i] = 0.0;
+	meanX[i] = varX[i] = sdX[i] = 0.0;
+	SSerr_without[i] = 0.0;
+    }
+    sumY = sumsqY = meanY = varY = sdY = 0.0;
+    sumYest = meanYest = varYest = sdYest = 0.0;
+    meanYres = varYres = sdYres = 0.0;
+
+    /* read input maps */
+    G_message(_("First pass..."));
+    n_valid = 0;
+    mapx_val[0] = 1.0;
+    for (r = 0; r < rows; r++) {
+	G_percent(r, rows, 2);
+
+	for (i = 0; i < n_predictors; i++)
+	    Rast_get_d_row(mapx_fd[i], mapx_buf[i], r);
+
+	Rast_get_d_row(mapy_fd, mapy_buf, r);
+
+	for (c = 0; c < cols; c++) {
+	    int isnull = 0;
+
+	    for (i = 0; i < n_predictors; i++) {
+		mapx_val[i + 1] = mapx_buf[i][c];
+		if (Rast_is_d_null_value(&(mapx_val[i + 1]))) {
+		    isnull = 1;
+		    break;
+		}
+	    }
+	    if (isnull)
+		continue;
+
+	    mapy_val = mapy_buf[c];
+	    if (Rast_is_d_null_value(&mapy_val))
+		continue;
+
+	    for (i = 0; i <= n_predictors; i++) {
+		double val1 = mapx_val[i];
+
+		for (j = i; j <= n_predictors; j++) {
+		    double val2 = mapx_val[j];
+
+		    m = &(m_all[0]);
+		    M(m, i, j) += val1 * val2;
+
+		    /* linear model without predictor k */
+		    for (k = 1; k <= n_predictors; k++) {
+			if (k != i && k != j) {
+			    int i2 = k > i ? i : i - 1;
+			    int j2 = k > j ? j : j - 1;
+
+			    m = &(m_all[k]);
+			    M(m, i2, j2) += val1 * val2;
+			}
+		    }
+		}
+
+		a[0][i] += mapy_val * val1;
+		for (k = 1; k <= n_predictors; k++) {
+		    if (k != i) {
+			int i2 = k > i ? i : i - 1;
+
+			a[k][i2] += mapy_val * val1;
+		    }
+		}
+
+		if (i > 0) {
+		    sumX[i - 1] += val1;
+		    sumsqX[i - 1] += val1 * val1;
+		    sumXY[i - 1] += val1 * mapy_val;
+		}
+	    }
+
+	    sumY += mapy_val;
+	    sumsqY += mapy_val * mapy_val;
+	    count++;
+	}
+    }
+    G_percent(rows, rows, 2);
+    
+    if (count < n_predictors + 1)
+	G_fatal_error(_("Not enough valid cells available"));
+
+    for (k = 0; k <= n_predictors; k++) {
+	m = &(m_all[k]);
+
+	/* TRANSPOSE VALUES IN UPPER HALF OF M TO OTHER HALF */
+	for (i = 1; i < m->n; i++)
+	    for (j = 0; j < i; j++)
+		M(m, i, j) = M(m, j, i);
+
+	if (!solvemat(m, a[k], B[k])) {
+	    for (i = 0; i <= n_predictors; i++) {
+		fprintf(stdout, "b%d=0.0\n", i);
+	    }
+	    G_fatal_error(_("Multiple regression failed"));
+	}
+    }
+    
+    /* second pass */
+    G_message(_("Second pass..."));
+
+    /* residuals output */
+    if (output_res->answer) {
+	mapres_fd = Rast_open_new(output_res->answer, DCELL_TYPE);
+	mapres_buf = Rast_allocate_d_buf();
+    }
+    else {
+	mapres_fd = -1;
+	mapres_buf = NULL;
+    }
+
+    /* estimates output */
+    if (output_est->answer) {
+	mapest_fd = Rast_open_new(output_est->answer, DCELL_TYPE);
+	mapest_buf = Rast_allocate_d_buf();
+    }
+    else {
+	mapest_fd = -1;
+	mapest_buf = NULL;
+    }
+
+    for (i = 0; i < n_predictors; i++)
+	meanX[i] = sumX[i] / count;
+
+    meanY = sumY / count;
+    SStot = SSerr = SSreg = 0.0;
+    for (r = 0; r < rows; r++) {
+	G_percent(r, rows, 2);
+
+	for (i = 0; i < n_predictors; i++)
+	    Rast_get_d_row(mapx_fd[i], mapx_buf[i], r);
+
+	Rast_get_d_row(mapy_fd, mapy_buf, r);
+	
+	if (mapres_buf)
+	    Rast_set_d_null_value(mapres_buf, cols);
+	if (mapest_buf)
+	    Rast_set_d_null_value(mapest_buf, cols);
+
+	for (c = 0; c < cols; c++) {
+	    int isnull = 0;
+
+	    for (i = 0; i < n_predictors; i++) {
+		mapx_val[i + 1] = mapx_buf[i][c];
+		if (Rast_is_d_null_value(&(mapx_val[i + 1]))) {
+		    isnull = 1;
+		    break;
+		}
+	    }
+	    if (isnull)
+		continue;
+
+	    yest = 0.0;
+	    for (i = 0; i <= n_predictors; i++) {
+		yest += B[0][i] * mapx_val[i];
+	    }
+	    if (mapest_buf)
+		mapest_buf[c] = yest;
+
+	    mapy_val = mapy_buf[c];
+	    if (Rast_is_d_null_value(&mapy_val))
+		continue;
+
+	    yres = mapy_val - yest;
+	    if (mapres_buf)
+		mapres_buf[c] = yres;
+
+	    SStot += (mapy_val - meanY) * (mapy_val - meanY);
+	    SSreg += (yest - meanY) * (yest - meanY);
+	    SSerr += yres * yres;
+
+	    for (k = 1; k <= n_predictors; k++) {
+		double yesti = 0.0;
+		double yresi;
+
+		/* linear model without predictor k */
+		for (i = 0; i <= n_predictors; i++) {
+		    if (i != k) {
+			j = k > i ? i : i - 1;
+			yesti += B[k][j] * mapx_val[i];
+		    }
+		}
+		yresi = mapy_val - yesti;
+
+		/* linear model without predictor k */
+		SSerr_without[k - 1] += yresi * yresi;
+
+		varX[k - 1] = (mapx_val[k] - meanX[k - 1]) * (mapx_val[k] - meanX[k - 1]);
+	    }
+	}
+
+	if (mapres_buf)
+	    Rast_put_d_row(mapres_fd, mapres_buf);
+	if (mapest_buf)
+	    Rast_put_d_row(mapest_fd, mapest_buf);
+    }
+    G_percent(rows, rows, 2);
+
+    fprintf(stdout, "n=%d\n", count);
+    /* coefficient of determination aka R squared */
+    Rsq = 1 - (SSerr / SStot);
+    fprintf(stdout, "Rsq=%f\n", Rsq);
+    /* adjusted coefficient of determination */
+    Rsqadj = 1 - ((SSerr * (count - 1)) / (SStot * (count - n_predictors - 1)));
+    fprintf(stdout, "Rsqadj=%f\n", Rsqadj);
+    /* F statistic */
+    /* F = ((SStot - SSerr) / (n_predictors)) / (SSerr / (count - n_predictors));
+     * , or: */
+    F = ((SStot - SSerr) * (count - n_predictors - 1)) / (SSerr * (n_predictors));
+    fprintf(stdout, "F=%f\n", F);
+
+    i = 0;
+    /* constant aka estimate for intercept in R */
+    fprintf(stdout, "b%d=%f\n", i, B[0][i]);
+    /* t score for R squared of the full model, unused */
+    t = sqrt(Rsq) * sqrt((count - 2) / (1 - Rsq));
+    /*
+    fprintf(stdout, "t%d=%f\n", i, t);
+    */
+
+    /* AIC, corrected AIC, and BIC information criteria for the full model */
+    AIC = count * log(SSerr / count) + 2 * (n_predictors + 1);
+    fprintf(stdout, "AIC=%f\n", AIC);
+    AICc = AIC + (2 * n_predictors * (n_predictors + 1)) / (count - n_predictors - 1);
+    fprintf(stdout, "AICc=%f\n", AICc);
+    BIC = count * log(SSerr / count) + log(count) * (n_predictors + 1);
+    fprintf(stdout, "BIC=%f\n", BIC);
+
+    /* error variance of the model, identical to R */
+    SE = SSerr / (count - n_predictors - 1);
+    /*
+    fprintf(stdout, "SE=%f\n", SE);
+    fprintf(stdout, "SSerr=%f\n", SSerr);
+    */
+
+    for (i = 0; i < n_predictors; i++) {
+
+	fprintf(stdout, "\nb%d=%f\n", i + 1, B[0][i + 1]);
+	if (n_predictors > 1) {
+	    double Rsqi, SEi, sumsqX_corr;
+
+	    /* corrected sum of squares for predictor [i] */
+	    sumsqX_corr = sumsqX[i] - sumX[i] * sumX[i] / (count - n_predictors - 1);
+
+	    /* standard error SE for predictor [i] */
+
+	    /* SE[i] with only one predictor: sqrt(SE / sumsqX_corr)
+	     * this does not work with more than one predictor */
+	    /* in R, SEi is sqrt(diag(R) * resvar) with
+	     * R = ???
+	     * resvar = rss / rdf = SE global
+	     * rss = sum of squares of the residuals
+	     * rdf = residual degrees of freedom = count - n_predictors - 1 */
+	    SEi = sqrt(SE / (Rsq * sumsqX_corr));
+	    /*
+	    fprintf(stdout, "SE%d=%f\n", i + 1, SEi);
+	    */
+
+	    /* Sum of squares for predictor [i] */
+	    /*
+	    fprintf(stdout, "SSerr%d=%f\n", i + 1, SSerr_without[i] - SSerr);
+	    */
+
+	    /* R squared of the model without predictor [i] */
+	    /* Rsqi = 1 - SSerr_without[i] / SStot; */
+	    /* the additional amount of variance explained
+	     * when including predictor [i] :
+	     * Rsq - Rsqi */
+	    Rsqi = (SSerr_without[i] - SSerr) / SStot;
+	    fprintf(stdout, "Rsq%d=%f\n", i + 1, Rsqi);
+
+	    /* t score for Student's t distribution, unused */
+	    t = (B[0][i + 1]) / SEi;
+	    /*
+	    fprintf(stdout, "t%d=%f\n", i + 1, t);
+	    */
+
+	    /* F score for Fisher's F distribution
+	     * here: F score to test if including predictor [i]
+	     * yields a significant improvement
+	     * after Lothar Sachs, Angewandte Statistik:
+	     * F = (Rsq - Rsqi) * (count - n_predictors - 1) / (1 - Rsq) */
+	    /* same like Sumsq / SE */
+	    /* same like (SSerr_without[i] / SSerr - 1) * (count - n_predictors - 1) */
+	    /* same like R-stats when entered in R-stats as last predictor */
+	    F = (SSerr_without[i] / SSerr - 1) * (count - n_predictors - 1);
+	    fprintf(stdout, "F%d=%f\n", i + 1, F);
+
+	    /* AIC, corrected AIC, and BIC information criteria for
+	     * the model without predictor [i] */
+	    AIC = count * log(SSerr_without[i] / count) + 2 * (n_predictors);
+	    fprintf(stdout, "AIC%d=%f\n", i + 1, AIC);
+	    AICc = AIC + (2 * (n_predictors - 1) * n_predictors) / (count - n_predictors - 2);
+	    fprintf(stdout, "AICc%d=%f\n", i + 1, AICc);
+	    BIC = count * log(SSerr_without[i] / count) + (n_predictors - 1) * log(count);
+	    fprintf(stdout, "BIC%d=%f\n", i + 1, BIC);
+	}
+    }
+    
+
+    for (i = 0; i < n_predictors; i++) {
+	Rast_close(mapx_fd[i]);
+	G_free(mapx_buf[i]);
+    }
+    Rast_close(mapy_fd);
+    G_free(mapy_buf);
+    
+    if (mapres_fd > -1) {
+	struct History history;
+
+	Rast_close(mapres_fd);
+	G_free(mapres_buf);
+
+	Rast_short_history(output_res->answer, "raster", &history);
+	Rast_command_history(&history);
+	Rast_write_history(output_res->answer, &history);
+    }
+
+    if (mapest_fd > -1) {
+	struct History history;
+
+	Rast_close(mapest_fd);
+	G_free(mapest_buf);
+
+	Rast_short_history(output_est->answer, "raster", &history);
+	Rast_command_history(&history);
+	Rast_write_history(output_est->answer, &history);
+    }
+
+    exit(EXIT_SUCCESS);
+}

Added: grass-addons/grass7/grass7/raster/r.regression.multi/r.regression.multi.html
===================================================================
--- grass-addons/grass7/grass7/raster/r.regression.multi/r.regression.multi.html	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.regression.multi/r.regression.multi.html	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,82 @@
+<h2>DESCRIPTION</h2>
+
+<em>r.regression.multi</em> calculates a multiple linear regression from
+raster maps, according to the formula
+<div class="code"><pre>
+Y = b0 + sum(bi*Xi) + E
+</pre></div>
+where
+<div class="code"><pre>
+X = {X1, X2, ..., Xm}
+m = number of explaining variables
+Y = {y1, y2, ..., yn}
+Xi = {xi1, xi2, ..., xin}
+E = {e1, e2, ..., en}
+n = number of observations (cases)
+</pre></div>
+
+In R notation:
+<div class="code"><pre>
+Y ~ sum(bi*Xi)
+b0 is the intercept, X0 is set to 1
+</pre></div>
+
+<p>
+<em>r.regression.multi</em> is designed for large datasets that can not
+be processed in R. A p value is therefore not provided, because even
+very small, meaningless effects will become significant with a large
+number of cells. Instead it is recommended to judge by the estimator b,
+the amount of variance explained (R squared for a given variable) and
+the gain in AIC (AIC without a given variable minus AIC global must be
+positive) whether the inclusion of a given explaining variable in the
+model is justified.
+
+<h4>The global model</h4>
+The <em>b</em> coefficients (b0 is offset), R squared or coefficient of
+determination (Rsq) and F are identical to the ones obtained from
+R-stats's lm() function and R-stats's anova() function. The AIC value
+is identical to the one obtained from R-stats's stepAIC() function
+(in case of backwards stepping, identical to the Start value). The
+AIC value corrected for the number of explaining variables and the BIC
+(Bayesian Information Criterion) value follow the logic of AIC.
+
+<h4>The explaining variables</h4>
+R squared for each explaining variable represents the additional amount
+of explained variance when including this variable compared to when
+excluding this variable, that is, this amount of variance is explained
+by the current explaining variable after taking into consideration all
+the other explaining variables.
+<p>
+The F score for each explaining variable allows to test if the inclusion
+of this variable significantly increases the explaining power of the
+model, relative to the global model excluding this explaining variable.
+That means that the F value for a given explaining variable is only
+identical to the F value of the R-function <em>summary.aov</em> if the
+given explaining variable is the last variable in the R-formula. While
+R successively includes one variable after another in the order
+specified by the formula and at each step calculates the F value
+expressing the gain by including the current variable in addition to the
+previous variables, <em>r.regression.multi</em> calculates the F-value
+expressing the gain by including the current variable in addition to all
+other variables, not only the previous variables.
+<p>
+The AIC value is identical to the one obtained from the R-function
+stepAIC() when excluding this variable from the full model. The AIC
+value corrected for the number of explaining variables and the BIC value
+(Bayesian Information Criterion) value follow the logic of AIC. BIC is
+identical to the R-function stepAIC with k = log(n). AICc is not
+available through the R-function stepAIC.
+
+<h2>EXAMPLE</h2>
+
+North Carolina dataset:
+<div class="code"><pre>
+g.region rast=soils_Kfactor
+r.regression.multi mapx=elevation,aspect,slope mapy=soils_Kfactor
+</pre></div>
+
+<h2>AUTHOR</h2>
+
+Markus Metz
+
+<p><i>Last changed: $Date: 2011-11-16 07:54:16 +0100 (Wed, 16 Nov 2011) $</i>

Added: grass-addons/grass7/grass7/raster/r.regression.series/Makefile
===================================================================
--- grass-addons/grass7/grass7/raster/r.regression.series/Makefile	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.regression.series/Makefile	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,10 @@
+MODULE_TOPDIR = ../..
+
+PGM = r.regression.series
+
+LIBES = $(STATSLIB) $(RASTERLIB) $(GISLIB)
+DEPENDENCIES = $(STATSDEP) $(RASTERDEP) $(GISDEP)
+
+include $(MODULE_TOPDIR)/include/Make/Module.make
+
+default: cmd

Added: grass-addons/grass7/grass7/raster/r.regression.series/main.c
===================================================================
--- grass-addons/grass7/grass7/raster/r.regression.series/main.c	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.regression.series/main.c	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,351 @@
+
+/****************************************************************************
+ *
+ * MODULE:       r.series
+ * 
+ * AUTHOR(S):    Markus Metz
+ *               based on r.series by
+ *               Glynn Clements <glynn gclements.plus.com> (original contributor)
+ *               Hamish Bowman <hamish_b yahoo.com>, Jachym Cepicky <jachym les-ejk.cz>,
+ *               Martin Wegmann <wegmann biozentrum.uni-wuerzburg.de>
+ * 
+ * PURPOSE:      regression between two time series
+ * 
+ * COPYRIGHT:    (C) 2011 by the GRASS Development Team
+ *
+ *               This program is free software under the GNU General Public
+ *               License (>=v2). Read the file COPYING that comes with GRASS
+ *               for details.
+ *
+ *****************************************************************************/
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <math.h>
+
+#include <grass/gis.h>
+#include <grass/raster.h>
+#include <grass/glocale.h>
+
+/* TODO: use more stable two pass algorithm */
+
+#define SLOPE		0
+#define OFFSET		1
+#define CORCOEFF	2
+#define RSQUARE		3
+#define RSQUARE_ADJ	4
+#define F_VALUE		5
+#define T_VALUE		6
+
+struct reg_stats
+{
+    DCELL sumX, sumY, sumsqX, sumsqY, sumXY;
+    DCELL meanX, meanY;
+    DCELL A, B, R, R2;
+    int count;
+};
+
+static void reg(DCELL *result, struct reg_stats rs, int which)
+{
+    switch (which) {
+    case SLOPE:
+	*result = rs.B;
+	break;
+    case OFFSET:
+	*result = rs.meanY - rs.B * rs.meanX;
+	break;
+    case CORCOEFF:
+	*result = rs.R;
+	break;
+    case RSQUARE:
+	*result = rs.R2;
+	break;
+    case RSQUARE_ADJ:
+	*result = 1 - (1 - rs.R2) * ((rs.count - 1) / (rs.count - 2));
+	break;
+    case F_VALUE:
+	/* *result = rs.R2 / ((1 - rs.R2) / (rs.count - 2)); */
+	*result = rs.R2 * (rs.count - 2) / (1 - rs.R2);
+	break;
+    case T_VALUE:
+	*result = fabs(rs.R) * sqrt((rs.count - 2) / (1 - rs.R2));
+	break;
+    default:
+	Rast_set_d_null_value(result, 1);
+	break;
+    }
+
+    /* Check for NaN */
+    if (*result != *result)
+	Rast_set_d_null_value(result, 1);
+}
+
+struct menu
+{
+    int method;		        /* routine to compute new value */
+    char *name;			/* method name */
+    char *text;			/* menu display - full description */
+} menu[] = {
+    {SLOPE,         "slope",       "Linear regression slope"},
+    {OFFSET,        "offset",      "Linear regression offset"},
+    {CORCOEFF,      "corcoef",     "Correlation coefficient R"},
+    {RSQUARE,       "rsq",    	   "R squared (coefficient of determination)"},
+    {RSQUARE_ADJ,   "adjrsq",      "Adjusted R squared"},
+    {F_VALUE,       "f",           "F statistic"},
+    {T_VALUE,       "t",           "T statistic"},
+    {-1,         NULL,          NULL}
+};
+
+struct input
+{
+    const char *name;
+    int fd;
+    DCELL *buf;
+};
+
+struct output
+{
+    const char *name;
+    int fd;
+    DCELL *buf;
+    int method;
+};
+
+static char *build_method_list(void)
+{
+    char *buf = G_malloc(1024);
+    char *p = buf;
+    int i;
+
+    for (i = 0; menu[i].name; i++) {
+	char *q;
+
+	if (i)
+	    *p++ = ',';
+	for (q = menu[i].name; *q; p++, q++)
+	    *p = *q;
+    }
+    *p = '\0';
+
+    return buf;
+}
+
+static int find_method(const char *method_name)
+{
+    int i;
+
+    for (i = 0; menu[i].name; i++)
+	if (strcmp(menu[i].name, method_name) == 0)
+	    return i;
+
+    G_fatal_error(_("Unknown method <%s>"), method_name);
+
+    return -1;
+}
+
+int main(int argc, char *argv[])
+{
+    struct GModule *module;
+    struct
+    {
+	struct Option *xinput, *yinput, *output, *method;
+    } parm;
+    struct
+    {
+	struct Flag *nulls;
+    } flag;
+    int i;
+    int num_inputs;
+    struct input *xinputs, *yinputs;
+    int num_outputs;
+    struct output *outputs;
+    struct reg_stats rs;
+    struct History history;
+    int nrows, ncols;
+    int row, col;
+
+    G_gisinit(argv[0]);
+
+    module = G_define_module();
+    G_add_keyword(_("raster"));
+    G_add_keyword(_("series"));
+    module->description =
+	_("Makes each output cell value a "
+	  "function of the values assigned to the corresponding cells "
+	  "in the input raster map layers.");
+
+    parm.xinput = G_define_standard_option(G_OPT_R_INPUTS);
+    parm.xinput->key = "xseries";
+
+    parm.yinput = G_define_standard_option(G_OPT_R_INPUTS);
+    parm.yinput->key = "yseries";
+
+    parm.output = G_define_standard_option(G_OPT_R_OUTPUT);
+    parm.output->multiple = YES;
+
+    parm.method = G_define_option();
+    parm.method->key = "method";
+    parm.method->type = TYPE_STRING;
+    parm.method->required = YES;
+    parm.method->options = build_method_list();
+    parm.method->description = _("Regression parameters");
+    parm.method->multiple = YES;
+
+    flag.nulls = G_define_flag();
+    flag.nulls->key = 'n';
+    flag.nulls->description = _("Propagate NULLs");
+
+    if (G_parser(argc, argv))
+	exit(EXIT_FAILURE);
+
+    /* process the input maps */
+    for (i = 0; parm.xinput->answers[i]; i++)
+	;
+    num_inputs = i;
+
+    for (i = 0; parm.yinput->answers[i]; i++)
+	;
+    if (num_inputs != i)
+	G_fatal_error(_("The number of '%s' and '%s' maps must be identical"),
+		      parm.xinput->key, parm.yinput->key);
+
+    if (num_inputs < 3)
+	G_fatal_error(_("Regression parameters can not be calculated for less than 3 maps per series"));
+
+    if (num_inputs < 7)
+	G_warning(_("Regression parameters are dubious for less than 7 maps per series"));
+
+    xinputs = G_malloc(num_inputs * sizeof(struct input));
+    yinputs = G_malloc(num_inputs * sizeof(struct input));
+
+    for (i = 0; i < num_inputs; i++) {
+	struct input *px = &xinputs[i];
+	struct input *py = &yinputs[i];
+
+	px->name = parm.xinput->answers[i];
+	G_message(_("Reading raster map <%s>..."), px->name);
+	px->fd = Rast_open_old(px->name, "");
+	px->buf = Rast_allocate_d_buf();
+
+	py->name = parm.yinput->answers[i];
+	G_message(_("Reading raster map <%s>..."), py->name);
+	py->fd = Rast_open_old(py->name, "");
+	py->buf = Rast_allocate_d_buf();
+    }
+
+    /* process the output maps */
+    for (i = 0; parm.output->answers[i]; i++)
+	;
+    num_outputs = i;
+
+    for (i = 0; parm.method->answers[i]; i++)
+	;
+    if (num_outputs != i)
+	G_fatal_error(_("output= and method= must have the same number of values"));
+
+    outputs = G_calloc(num_outputs, sizeof(struct output));
+
+    for (i = 0; i < num_outputs; i++) {
+	struct output *out = &outputs[i];
+	const char *output_name = parm.output->answers[i];
+	const char *method_name = parm.method->answers[i];
+	int method = find_method(method_name);
+
+	out->name = output_name;
+	out->method = menu[method].method;
+	out->buf = Rast_allocate_d_buf();
+	out->fd = Rast_open_new(output_name, DCELL_TYPE);
+    }
+
+    /* initialise variables */
+
+    nrows = Rast_window_rows();
+    ncols = Rast_window_cols();
+
+    /* process the data */
+    G_verbose_message(_("Percent complete..."));
+
+    for (row = 0; row < nrows; row++) {
+	G_percent(row, nrows, 2);
+
+	for (i = 0; i < num_inputs; i++) {
+	    Rast_get_d_row(xinputs[i].fd, xinputs[i].buf, row);
+	    Rast_get_d_row(yinputs[i].fd, yinputs[i].buf, row);
+	}
+
+	for (col = 0; col < ncols; col++) {
+	    int null = 0;
+
+	    rs.sumX = rs.sumY = rs.sumsqX = rs.sumsqY = rs.sumXY = 0.0;
+	    rs.meanX = rs.meanY = 0.0;
+	    rs.count = 0;
+
+	    for (i = 0; i < num_inputs; i++) {
+		DCELL x = xinputs[i].buf[col];
+		DCELL y = yinputs[i].buf[col];
+
+		if (Rast_is_d_null_value(&x) || Rast_is_d_null_value(&y))
+		    null = 1;
+		else {
+		    rs.sumX += x;
+		    rs.sumY += y;
+		    rs.sumsqX += x * x;
+		    rs.sumsqY += y * y;
+		    rs.sumXY += x * y;
+		    rs.count++;
+		}
+	    }
+	    if (rs.count > 1) {
+		DCELL tmp1 = rs.count * rs.sumXY - rs.sumX * rs.sumY;
+		DCELL tmp2 = rs.count * rs.sumsqX - rs.sumX * rs.sumX;
+
+		/* slope */
+		rs.B = tmp1 / tmp2;
+		/* correlation coefficient */
+		rs.R = tmp1 / sqrt((tmp2) * (rs.count * rs.sumsqY - rs.sumY * rs.sumY));
+		/* coefficient of determination aka R squared */
+		rs.R2 = rs.R * rs.R;
+
+		rs.meanX = rs.sumX / rs.count;
+
+		rs.meanY = rs.sumY / rs.count;
+	    }
+	    else {
+		rs.R = rs.R2 = rs.B = 0;
+	    }
+
+	    for (i = 0; i < num_outputs; i++) {
+		struct output *out = &outputs[i];
+
+		if (rs.count < 2 || (null && flag.nulls->answer))
+		    Rast_set_d_null_value(&out->buf[col], 1);
+		else {
+		    reg(&out->buf[col], rs, out->method);
+		}
+	    }
+	}
+
+	for (i = 0; i < num_outputs; i++)
+	    Rast_put_d_row(outputs[i].fd, outputs[i].buf);
+    }
+
+    G_percent(row, nrows, 2);
+
+    /* close maps */
+    for (i = 0; i < num_outputs; i++) {
+	struct output *out = &outputs[i];
+
+	Rast_close(out->fd);
+
+	Rast_short_history(out->name, "raster", &history);
+	Rast_command_history(&history);
+	Rast_write_history(out->name, &history);
+    }
+
+    for (i = 0; i < num_inputs; i++) {
+	Rast_close(xinputs[i].fd);
+	Rast_close(yinputs[i].fd);
+    }
+
+    exit(EXIT_SUCCESS);
+}

Added: grass-addons/grass7/grass7/raster/r.regression.series/r.regression.series.html
===================================================================
--- grass-addons/grass7/grass7/raster/r.regression.series/r.regression.series.html	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.regression.series/r.regression.series.html	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,113 @@
+<h2>DESCRIPTION</h2>
+
+<em>r.regression.series</em> is a module to calculate linear
+regression parameters between two time series, e.g. NDVI and
+precipitation.
+<p>
+The module makes each output cell value a function of the values
+assigned to the corresponding cells in the two input raster map series.
+Following methods are available:
+
+<ul> 
+ <li>offset: Linear regression offset
+ <li>slope: Linear regression slope
+ <li>corcoef: Correlation Coefficent R
+ <li>rsq: Coefficient of determination = R squared
+ <li>adjrsq: Adjusted coefficient of determination
+ <li>f: F statistic
+ <li>t: T statistic
+ </ul> 
+
+<h2>DESCRIPTION</h2>
+
+The module assumes a simple linear regression of the form
+<div class="code"><pre>
+    y = a + b * x
+</pre></div>
+<p>
+<em>offset</em> is equivalent to <em>a</em> in the above equation, also 
+referred to as constant or intercept.
+<p>
+<em>slope</em> is equivalent to <em>b</em> in the above equation.
+<p>
+<em>corcoef</em> is the correlation coefficient R with a theoretical 
+range of -1,1.
+<p>
+<em>rsq</em> is the coefficient of determination, equivalent to 
+the squared correlation coefficient R<sup>2</sup>.
+<p>
+<em>adjrsq</em> is the coefficient of determination adjusted for the 
+number of samples, i.e. number of input maps per series.
+<p>
+<em>f</em> is the value of the F statistic.
+<p>
+<em>t</em> is the value of the T statistic.
+
+<h2>NOTES</h2>
+
+The number of maps in <em>xseries</em> and <em>yseries</em> must be 
+identical.
+<p>
+With <em>-n</em> flag, any cell for which any of the corresponding input cells are
+NULL is automatically set to NULL (NULL propagation). The aggregate function is not
+called, so all methods behave this way with respect to the <em>-n</em> flag.
+<p>
+Without <em>-n</em> flag, the complete list of inputs for each cell 
+(including NULLs) is passed to the function. Individual functions can
+handle data as they choose. Mostly, they just compute the parameter
+over the non-NULL values, producing a NULL result only if all inputs
+are NULL.
+<p>
+Linear regression (slope, offset, coefficient of determination) requires 
+an equal number of <em>xseries</em> and <em>yseries</em> maps.
+If the different time series have irregular time intervals, NULL raster 
+maps can be inserted into time series to make time intervals equal (see example).
+<p>
+The maximum number of raster maps to be processed is limited by the
+operating system. For example, both the hard and soft limits are
+typically 1024. The soft limit can be changed with e.g. <tt>ulimit -n
+1500</tt> (UNIX-based operating systems) but not higher than the hard
+limit. If it is too low, you can as superuser add an entry in
+
+<div class="code"><pre>
+/etc/security/limits.conf
+# <domain>      <type>  <item>         <value>
+your_username  hard    nofile          1500
+</pre></div>
+
+This would raise the hard limit to 1500 file. Be warned that more
+files open need more RAM.
+
+<h2>EXAMPLES</h2>
+
+Using <em>r.regression.series</em> with wildcards:
+<br>
+<div class="code"><pre>
+r.regression.series xseries="`g.mlist pattern='insitu_data.*' sep=,`" \
+	 yseries="`g.mlist pattern='invivo_data.*' sep=,`" \
+         output=insitu_data.rsquared method=rsq
+</pre></div>
+<p>
+Note the <em>g.mlist</em> module also supports regular expressions for
+selecting map names.
+
+<p>
+Example for multiple parameters to be computed in one run (3 resulting 
+parameters from 8 input maps, 4 maps per time series):
+<div class="code"><pre>
+r.regression.series x=xone,xtwo,xthree,xfour y=yone,ytwo,ythree,yfour \
+    out=res_offset,res_slope,res_adjrsq meth=offset,slope,adjrsq
+</pre></div>
+
+<h2>SEE ALSO</h2>
+
+<em><a href="r.series.html">r.series</a></em>,
+<em><a href="r.regression.line.html">r.regression.line</a></em>,
+<em><a href="g.mlist.html">g.mlist</a></em>,
+<em><a href="g.region.html">g.region</a></em>
+
+<h2>AUTHOR</h2>
+
+Markus Metz
+
+<p><i>Last changed: $Date: 2012-07-05 21:39:53 +0200 (Thu, 05 Jul 2012) $</i>

Added: grass-addons/grass7/grass7/raster/r.stream.basins/Makefile
===================================================================
--- grass-addons/grass7/grass7/raster/r.stream.basins/Makefile	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.stream.basins/Makefile	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,14 @@
+MODULE_TOPDIR = ../..
+
+PGM = r.stream.basins
+
+LIBES = $(GISLIB) $(RASTERLIB) $(SEGMENTLIB) $(VECTORLIB) $(DBMILIB)
+DEPENDENCIES = $(GISDEP) $(RASTERDEP) $(SEGMENTDEP) $(VECTORDEP) $(DBMIDEP)
+
+EXTRA_INC = $(VECT_INC)
+EXTRA_CFLAGS = $(VECT_CFLAGS)
+
+include $(MODULE_TOPDIR)/include/Make/Module.make
+
+default: cmd
+

Added: grass-addons/grass7/grass7/raster/r.stream.basins/basins_fill.c
===================================================================
--- grass-addons/grass7/grass7/raster/r.stream.basins/basins_fill.c	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.stream.basins/basins_fill.c	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,180 @@
+/* 
+   Link: a channel between junction
+   Ooutlet: is final cell of every segment
+   Segment: a channel which order remains unchanged in spite it pass through junction or not
+   Number of outlets shall be equal the number of segments
+   Number of junction shall be less than number of links
+ */
+
+/*
+   find outlets create table of outlets point, with r, c and value. depending of flag:
+   if flag -l is as anly last points of segment is added to table and uses the value is the category as value for whole basins
+   if flag -l = flase (default) last points of every link is added to table and uses the value is the category as value for subbasin
+   In both cases if flag -c is used it add out_num+1 value as value of point. That structure is next used in reset_catchments and fill_catchments fuctions
+ */
+
+/* fifo functions */
+/* insertion point: tail -> tail must always be unused */
+/* removal point: head + 1 */
+/* head == tail if last point removed or if only one free slot left */
+
+#include "local_proto.h"
+static int tail, head, fifo_count;
+
+int fifo_insert(POINT point)
+{
+    if (fifo_count == fifo_max)
+	G_fatal_error("fifo queue: circular buffer too small");
+
+    fifo_points[tail++] = point;
+    if (tail > fifo_max) {
+	G_debug(1, "tail > fifo_max");
+	tail = 0;
+    }
+    fifo_count++;
+    return 0;
+}
+
+POINT fifo_return_del(void)
+{
+    if (head >= fifo_max) {
+	G_debug(1, "head >= fifo_max");
+	head = -1;
+    }
+    fifo_count--;
+
+    return fifo_points[++head];
+}
+
+/*
+   this function adds points from outlet structure 
+   The lines below from function fill_catchments makes that 
+   outlet is not added do fifo
+   queue and basin is limited by next outlet
+
+   if (catchments[NR(i)][NR(i)]>0)
+   continue; 
+
+   It is simple trick but allow gives module its real funcionality
+
+   Buffer is an correction wchich allow to delinate basins even if vector point 
+   or coordinates do not lie exactly on stream. In that case a small one pixel buffer
+   is created. This is little risk functionality and must be used carefully.
+ */
+
+int ram_add_outlets(CELL **basins, int outlets_num)
+{
+    int i;
+
+    for (i = 0; i < outlets_num; ++i)
+	basins[outlets[i].r][outlets[i].c] = outlets[i].val;
+
+    return 0;
+}
+
+int seg_add_outlets(SEGMENT *basins, int outlets_num)
+{
+
+    int i;
+    int *basins_cell;
+
+    for (i = 0; i < outlets_num; ++i) {
+	basins_cell = &outlets[i].val;
+	segment_put(basins, basins_cell, outlets[i].r, outlets[i].c);
+    }
+    return 0;
+}
+
+/*
+   algorithm uses fifo queue for determining basins area. 
+ */
+
+int ram_fill_basins(OUTLET outlet, CELL **basins, CELL **dirs)
+{
+    int next_r, next_c;
+    int r, c, val, i, j;
+    POINT n_cell;
+
+    tail = 0;
+    head = -1;
+    fifo_count = 0;
+    r = outlet.r;
+    c = outlet.c;
+    val = outlet.val;
+
+    G_debug(1, "processing outlet at row %d col %d", r, c);
+
+    basins[r][c] = val;
+
+    while (tail != head) {
+	for (i = 1; i < 9; i++) {
+	    next_r = NR(i);
+	    next_c = NC(i);
+
+	    if (NOT_IN_REGION(i))
+		continue;
+	    j = DIAG(i);
+
+	    /* countributing cell, not yet assigned to a basin */
+	    if (dirs[next_r][next_c] == j && basins[next_r][next_c] == 0) {
+		basins[next_r][next_c] = val;
+		n_cell.r = next_r;
+		n_cell.c = next_c;
+		fifo_insert(n_cell);
+	    }
+	}			/* end for i... */
+
+	n_cell = fifo_return_del();
+	r = n_cell.r;
+	c = n_cell.c;
+    }				/* end while */
+    return 0;
+}
+
+int seg_fill_basins(OUTLET outlet, SEGMENT *basins, SEGMENT *dirs)
+{
+    int next_r, next_c;
+    int r, c, val, i, j;
+    POINT n_cell;
+    int dirs_cell, basins_cell;
+
+    tail = 0;
+    head = -1;
+    fifo_count = 0;
+    r = outlet.r;
+    c = outlet.c;
+    val = outlet.val;
+
+    G_debug(1, "processing outlet at row %d col %d", r, c);
+
+    segment_put(basins, &val, r, c);
+
+    while (tail != head) {
+	for (i = 1; i < 9; i++) {
+	    next_r = NR(i);
+	    next_c = NC(i);
+
+	    if (NOT_IN_REGION(i))
+		continue;
+	    j = DIAG(i);
+
+	    /* countributing cell, not yet assigned to a basin */
+	    segment_get(basins, &basins_cell, next_r, next_c);
+	    segment_get(dirs, &dirs_cell, next_r, next_c);
+
+	    if (dirs_cell == j && basins_cell == 0) {
+		segment_put(basins, &val, next_r, next_c);
+		n_cell.r = next_r;
+		n_cell.c = next_c;
+		fifo_insert(n_cell);
+	    }
+	}			/* end for i... */
+
+	n_cell = fifo_return_del();
+	r = n_cell.r;
+	c = n_cell.c;
+
+    }				/* end while */
+
+    return 0;
+}

Added: grass-addons/grass7/grass7/raster/r.stream.basins/basins_inputs.c
===================================================================
--- grass-addons/grass7/grass7/raster/r.stream.basins/basins_inputs.c	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.stream.basins/basins_inputs.c	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,274 @@
+#include <grass/gis.h>
+#include <grass/vector.h>
+#include <grass/glocale.h>
+
+#include "local_proto.h"
+
+int process_coors(char **answers)
+{
+
+    int n, outlets_num;
+    double X, Y;
+    struct Cell_head window;
+
+    if (!answers)
+	G_fatal_error(_("At least one pair of coordinates must pe send"));
+
+    G_get_window(&window);
+
+    for (n = 0, outlets_num = 0; answers[n] != NULL; n += 2, outlets_num++) ;
+
+    outlets = (OUTLET *) G_malloc(outlets_num * sizeof(OUTLET));
+
+    for (n = 0, outlets_num = 0; answers[n] != NULL; n += 2, outlets_num++) {
+
+	if (!G_scan_easting(answers[n], &X, G_projection()))
+	    G_fatal_error("Wrong coordinate <%s>", answers[n]);
+
+	if (!answers[n + 1])
+	    G_fatal_error("Missing north coordinate for east %g", X);
+
+	if (!G_scan_northing(answers[n + 1], &Y, G_projection()))
+	    G_fatal_error("Wrong coordinate <%s>", answers[n + 1]);
+
+	if (X < window.west || X > window.east ||
+	    Y < window.south || Y > window.north)
+	    G_fatal_error("Coordinates outside window");
+
+	outlets[outlets_num].r = (window.north - Y) / window.ns_res;
+	outlets[outlets_num].c = (X - window.west) / window.ew_res;
+	outlets[outlets_num].val = outlets_num + 1;
+    }
+
+    return outlets_num;
+}
+
+int process_vector(char *in_point)
+{
+    char *mapset;
+    struct Cell_head window;
+    struct Map_info Map;
+    struct bound_box box;
+    int num_point = 0;
+    int type, i, cat;
+    struct line_pnts *sites;
+    struct line_cats *cats;
+
+    sites = Vect_new_line_struct();
+    cats = Vect_new_cats_struct();
+
+    mapset = G_find_vector2(in_point, "");
+    if (mapset == NULL)
+	G_fatal_error(_("Vector map <%s> not found"), in_point);
+
+    if (Vect_open_old(&Map, in_point, mapset) < 0)
+	G_fatal_error("Cannot open vector map <%s>", in_point);
+
+    G_get_window(&window);
+    Vect_region_box(&window, &box);
+
+    while ((type = Vect_read_next_line(&Map, sites, cats)) > -1) {
+	if (type != GV_POINT)
+	    continue;
+	if (Vect_point_in_box(sites->x[0], sites->y[0], sites->z[0], &box)) {
+	    num_point++;
+	}
+    }
+
+    outlets = (OUTLET *) G_malloc(num_point * sizeof(OUTLET));
+
+    Vect_rewind(&Map);
+    i = 0;
+    while ((type = Vect_read_next_line(&Map, sites, cats)) > -1) {
+	if (type != GV_POINT)
+	    continue;
+
+	if (!Vect_point_in_box(sites->x[0], sites->y[0], sites->z[0], &box))
+	    continue;
+
+	Vect_cat_get(cats, 1, &cat);
+
+	outlets[i].r = (int)Rast_northing_to_row(sites->y[0], &window);
+	outlets[i].c = (int)Rast_easting_to_col(sites->x[0], &window);
+	outlets[i].val = cat;
+	i++;
+    }
+
+    return num_point;
+}
+
+int ram_process_streams(char **cat_list, CELL **streams,
+			int number_of_streams, CELL **dirs, int lasts,
+			int cats)
+{
+    int i, cat;
+    int r, c, d;		/* d: direction */
+    int outlets_num = 0;
+    int next_stream = -1, cur_stream;
+    int out_max = ncols + nrows;
+
+    categories = NULL;
+
+    if (cat_list) {		/* only if there are at least one category */
+	categories = G_malloc((number_of_streams) * sizeof(int));
+	memset(categories, -1, (number_of_streams) * sizeof(int));
+
+	for (i = 0; cat_list[i] != NULL; ++i) {
+	    cat = atoi(cat_list[i]);
+	    if (cat < 1 || cat > number_of_streams)
+		G_fatal_error(_("Stream categories must be > 0 and < maximum stream category"));
+	    categories[cat] = cat;
+	}
+    }
+
+    G_message("Finding nodes...");
+    outlets = (OUTLET *) G_malloc((out_max) * sizeof(OUTLET));
+
+    for (r = 0; r < nrows; ++r)
+	for (c = 0; c < ncols; ++c)
+	    if (streams[r][c] > 0) {
+		if (outlets_num > 6 * (out_max - 1))
+		    G_fatal_error(_("Stream and direction maps probably do not match"));
+
+		if (outlets_num > (out_max - 1))
+		    outlets =
+			(OUTLET *) G_realloc(outlets,
+					     out_max * 6 * sizeof(OUTLET));
+
+		d = abs(dirs[r][c]);	/* r.watershed */
+
+		if (NOT_IN_REGION(d))
+		    next_stream = -1;	/* border */
+		else
+		    next_stream = (streams[NR(d)][NC(d)] > 0) ?
+			streams[NR(d)][NC(d)] : -1;
+
+		if (d == 0)
+		    next_stream = -1;
+
+		cur_stream = streams[r][c];
+
+		if (lasts) {
+		    if (next_stream < 0) {	/* is outlet! */
+
+			if (categories)
+			    if (categories[cur_stream] == -1)	/* but not in list */
+				continue;
+
+			outlets[outlets_num].r = r;
+			outlets[outlets_num].c = c;
+			outlets[outlets_num].val =
+			    (cats) ? outlets_num + 1 : streams[r][c];
+			outlets_num++;
+		    }
+		}
+		else {		/* not lasts */
+
+		    if (cur_stream != next_stream) {	/* is node or outlet! */
+
+			if (categories)
+			    if (categories[cur_stream] == -1)	/* but not in list */
+				continue;
+
+			outlets[outlets_num].r = r;
+			outlets[outlets_num].c = c;
+			outlets[outlets_num].val =
+			    (cats) ? outlets_num + 1 : streams[r][c];
+			outlets_num++;
+		    }
+		}		/* end if else lasts */
+	    }			/* end if streams */
+
+    return outlets_num;
+}
+
+int seg_process_streams(char **cat_list, SEGMENT *streams,
+			int number_of_streams, SEGMENT *dirs, int lasts,
+			int cats)
+{
+    int i, cat;
+    int r, c, d;		/* d: direction */
+    int outlets_num;
+    int next_stream = -1, cur_stream;
+    int streams_cell, dirs_cell, streams_next_cell;
+    int out_max = ncols + nrows;
+
+    categories = NULL;
+
+    if (cat_list) {
+	categories = G_malloc((number_of_streams) * sizeof(int));
+	memset(categories, -1, (number_of_streams) * sizeof(int));
+
+	for (i = 0; cat_list[i] != NULL; ++i) {
+	    cat = atoi(cat_list[i]);
+	    if (cat < 1 || cat > number_of_streams)
+		G_fatal_error(_("Stream categories must be > 0 and < maximum stream category"));
+	    categories[cat] = cat;
+	}
+    }
+    G_message("Finding nodes...");
+    outlets = (OUTLET *) G_malloc((out_max) * sizeof(OUTLET));
+    outlets_num = 0;
+
+    for (r = 0; r < nrows; ++r)
+	for (c = 0; c < ncols; ++c) {
+
+	    segment_get(streams, &streams_cell, r, c);
+	    if (streams_cell > 0) {
+		if (outlets_num > 6 * (out_max - 1))
+		    G_fatal_error
+			("Stream and direction maps probably do not match");
+
+		if (outlets_num > (out_max - 1))
+		    outlets =
+			(OUTLET *) G_realloc(outlets,
+					     out_max * 6 * sizeof(OUTLET));
+
+		segment_get(dirs, &dirs_cell, r, c);
+		d = abs(dirs_cell);	/* abs */
+
+		if (NOT_IN_REGION(d))
+		    next_stream = -1;	/* border */
+		else {
+		    segment_get(streams, &streams_next_cell, NR(d), NC(d));
+		    next_stream =
+			(streams_next_cell > 0) ? streams_next_cell : -1;
+		}
+
+		if (d == 0)
+		    next_stream = -1;
+
+		cur_stream = streams_cell;
+
+		if (lasts) {
+
+		    if (next_stream < 0) {	/* is outlet! */
+			if (categories)
+			    if (categories[cur_stream] == -1)	/* but not in list */
+				continue;
+
+			outlets[outlets_num].r = r;
+			outlets[outlets_num].c = c;
+			outlets[outlets_num].val =
+			    (cats) ? outlets_num + 1 : cur_stream;
+			outlets_num++;
+		    }
+		}
+		else {		/* not lasts */
+
+		    if (cur_stream != next_stream) {	/* is outlet or node! */
+			if (categories)
+			    if (categories[cur_stream] == -1)	/* but not in list */
+				continue;
+
+			outlets[outlets_num].r = r;
+			outlets[outlets_num].c = c;
+			outlets[outlets_num].val =
+			    (cats) ? outlets_num + 1 : cur_stream;
+			outlets_num++;
+		    }
+		}		/* end if else lasts */
+	    }			/* end if streams */
+	}			/* end for */
+    return outlets_num;
+}

Added: grass-addons/grass7/grass7/raster/r.stream.basins/io.c
===================================================================
--- grass-addons/grass7/grass7/raster/r.stream.basins/io.c	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.stream.basins/io.c	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,564 @@
+#include "io.h"
+/* all in ram functions section */
+
+int ram_create_map(MAP * map, RASTER_MAP_TYPE data_type)
+{
+
+    /* 
+     * allocates 0 filled nrows*ncols map of type void;
+     * map parameters are stored in structure;
+     * map: map to be created;
+     * map type to be created must be CELL, FCELL, DCELL;
+     * */
+
+    int r;
+
+    if (data_type < 0 || data_type > 2)
+	G_fatal_error(_("ram_creat: Cannot create map of unrecognised type"));
+
+    map->data_type = data_type;
+    map->map_name = NULL;
+    map->nrows = Rast_window_rows();
+    map->ncols = Rast_window_cols();
+    map->data_size = Rast_cell_size(data_type);
+
+    /* preparing internal map */
+    switch (map->data_type) {
+    case CELL_TYPE:
+	map->map = G_calloc(map->nrows, sizeof(CELL *));
+	break;
+
+    case FCELL_TYPE:
+	map->map = G_calloc(map->nrows, sizeof(FCELL *));
+	break;
+
+    case DCELL_TYPE:
+	map->map = G_calloc(map->nrows, sizeof(DCELL *));
+	break;
+    }
+
+    for (r = 0; r < map->nrows; ++r)
+	(map->map)[r] = G_calloc(map->ncols, map->data_size);
+
+    return 0;
+}
+
+int ram_read_map(MAP * map, char *input_map_name, int check_res,
+		 RASTER_MAP_TYPE check_data_type)
+{
+    /*
+     * Funciton read external map and put it in MAP structure (created with create_map)
+     * map: map to be read can be of any data type, read map is converted to target map if neccesary.
+     * input_map_name: name of the map to be read;
+     * map pointer to map stucture (created with create_map);
+     * check_res: [1]: check res correspondence between region and map [0 no check];
+     * check_data_type [CELL, FCELL, DCELL] check if reading map is of particular type, [-1] no check;
+     */
+
+    int r, c;
+    char *mapset;
+    struct Cell_head cellhd, this_window;
+    char *maptypes[] = { "CELL", "FCELL", "DCELL" };
+    int input_map_fd;
+    RASTER_MAP_TYPE input_data_type;
+    size_t input_data_size;
+    void *input_buffer = NULL;
+    void *input_pointer;
+
+    /* checking if map exist */
+    mapset = (char *)G_find_raster2(input_map_name, "");
+    if (mapset == NULL)
+	G_fatal_error(_("Raster map <%s> not found"), input_map_name);
+
+    /* checking if region and input are the same */
+    G_get_window(&this_window);
+    Rast_get_cellhd(input_map_name, mapset, &cellhd);
+    if (check_res)
+	if (this_window.ew_res != cellhd.ew_res ||
+	    this_window.ns_res != cellhd.ns_res)
+	    G_fatal_error(_("Region resolution and map %s resolution differs. \
+		Run g.region rast=%s to set proper region resolution"),
+			  input_map_name, input_map_name);
+
+    /* checking if input map is of required type */
+    if (check_data_type != map->data_type)
+	G_debug(1,
+		"ram_open:required map type and internal map type differs: conversion forced!");
+    input_data_type = Rast_map_type(input_map_name, mapset);
+    if (check_data_type != -1)
+	if (input_data_type != check_data_type)
+	    G_fatal_error(_("<%s> is not of type %s"),
+			  input_map_name, maptypes[check_data_type]);
+
+    input_map_fd = Rast_open_old(input_map_name, mapset);
+    input_data_size = Rast_cell_size(input_data_type);
+
+    {				/* reading range */
+	struct Range map_range;
+	struct FPRange map_fp_range;
+	int min, max;
+
+	if (input_data_type == CELL_TYPE) {
+	    Rast_init_range(&map_range);
+	    Rast_read_range(input_map_name, mapset, &map_range);
+	    Rast_get_range_min_max(&map_range, &min, &max);
+	    map->min = (double)min;
+	    map->max = (double)max;
+	}
+	else {
+	    Rast_init_fp_range(&map_fp_range);
+	    Rast_read_fp_range(input_map_name, mapset, &map_fp_range);
+	    Rast_get_fp_range_min_max(&map_fp_range, &(map->min),
+				      &(map->max));
+	}
+    }
+    /* end opening and checking */
+
+    input_buffer = Rast_allocate_buf(input_data_type);
+
+    /* start reading */
+    G_message(_("Reading map <%s>"), input_map_name);
+
+    for (r = 0; r < map->nrows; ++r) {
+	G_percent(r, map->nrows, 2);
+
+	Rast_get_row(input_map_fd, input_buffer, r, input_data_type);
+	input_pointer = input_buffer;
+
+	for (c = 0; c < map->ncols; ++c)
+	    if (!Rast_is_null_value
+		(input_pointer + c * input_data_size, input_data_type))
+		switch (map->data_type) {
+		case CELL_TYPE:
+		    ((CELL **) map->map)[r][c] =
+			Rast_get_c_value(input_pointer + c * input_data_size,
+					 input_data_type);
+		    break;
+		case FCELL_TYPE:
+		    ((FCELL **) map->map)[r][c] =
+			Rast_get_f_value(input_pointer + c * input_data_size,
+					 input_data_type);
+		    break;
+		case DCELL_TYPE:
+		    ((DCELL **) map->map)[r][c] =
+			Rast_get_d_value(input_pointer + c * input_data_size,
+					 input_data_type);
+		    break;
+		default:
+		    G_fatal_error(_("ram_open:Wrong internal data type"));
+		    break;
+		}
+    }				/*end for r */
+
+    G_free(input_buffer);
+    G_percent(r, map->nrows, 2);
+    Rast_close(input_map_fd);
+    return 0;
+}				/* end create floating point map */
+
+int ram_reset_map(MAP * map, int value)
+{
+    /*
+     * set all cells in the map to value
+     */
+    int r;
+
+    for (r = 0; r < map->nrows; ++r)
+	memset((map->map)[r], value, map->ncols * map->data_size);
+    return 0;
+}
+
+int ram_write_map(MAP * map, char *output_map_name,
+		  RASTER_MAP_TYPE output_data_type, int convert_to_null,
+		  double value)
+{
+    /* 
+     * write map to disk with output_map_name and output_data_type [CELL, FCELL, DCELL];
+     * if output_data_type = -1 than internal map type is used for output;
+     * if output map != -1 and types differ data_type, conversion is forced
+     * convert to null: check if convert to null a particular value in dataset;
+     */
+
+    int r, c;
+    int output_fd = 0;
+    struct History history;
+    void *row;
+
+    /* check for output format */
+    if (output_data_type == -1)
+	output_data_type = map->data_type;
+
+    if (output_data_type != map->data_type)
+	G_debug(1,
+		"ram_write:required map type and internal map type differs: conversion forced!");
+
+    G_message(_("Writing map <%s>"), output_map_name);
+    output_fd = Rast_open_new(output_map_name, output_data_type);
+
+    /* writing */
+    for (r = 0; r < map->nrows; ++r) {
+	G_percent(r, map->nrows, 2);
+
+	if (convert_to_null) {
+	    row = map->map[r];
+	    switch (map->data_type) {
+	    case CELL_TYPE:
+		for (c = 0; c < map->ncols; ++c)
+		    if (((CELL *) row)[c] == (CELL) value)
+			Rast_set_c_null_value(row + c * (map->data_size), 1);
+		break;
+	    case FCELL_TYPE:
+		for (c = 0; c < map->ncols; ++c)
+		    if (((FCELL *) row)[c] == (FCELL) value)
+			Rast_set_f_null_value(row + c * (map->data_size), 1);
+		break;
+	    case DCELL_TYPE:
+		for (c = 0; c < map->ncols; ++c)
+		    if (((DCELL *) row)[c] == (DCELL) value)
+			Rast_set_d_null_value(row + c * (map->data_size), 1);
+		break;
+	    default:
+		G_debug(1, "ram_null:Cannot convert to null at: %d %d", r, c);
+	    }
+	}
+
+	Rast_put_row(output_fd, (map->map)[r], output_data_type);
+    }
+    G_percent(r, map->nrows, 2);
+    Rast_close(output_fd);
+    Rast_short_history(output_map_name, "raster", &history);
+    Rast_command_history(&history);
+    Rast_write_history(output_map_name, &history);
+    G_message(_("<%s> Done"), output_map_name);
+    return 0;
+}
+
+int ram_release_map(MAP *map)
+{
+    /* 
+     * free memory allocated for map, set pointer to null;
+     */
+    int r;
+
+    for (r = 0; r < map->nrows; ++r)
+	G_free((map->map)[r]);
+    G_free(map->map);
+    map = NULL;
+    return 0;
+}
+
+
+/* memory swap functions section */
+
+
+int seg_create_map(SEG * seg, int srows, int scols, int number_of_segs,
+		   RASTER_MAP_TYPE data_type)
+{
+    /* create segment  and returns pointer to it;
+     * seg must be declared first;
+     * parameters are stored in structure;
+     * seg: segment to be created;
+     * srows, scols segment size
+     * number of segs max number of segs stored in memory
+     * data_type to be created must be CELL, FCELL, DCELL;
+     */
+
+    char *filename;
+    int fd;
+    int local_number_of_segs;
+
+    seg->fd = -1;
+    seg->filename = NULL;
+    seg->map_name = NULL;
+    seg->mapset = NULL;
+    seg->data_type = data_type;
+    seg->nrows = Rast_window_rows();
+    seg->ncols = Rast_window_cols();
+
+    local_number_of_segs =
+	(seg->nrows / srows + 1) * (seg->ncols / scols + 1);
+    number_of_segs =
+	(number_of_segs >
+	 local_number_of_segs) ? local_number_of_segs : number_of_segs;
+
+    G_debug(3, "seg_creat:number of segments %d", number_of_segs);
+
+    switch (seg->data_type) {
+    case CELL_TYPE:
+	seg->data_size = sizeof(CELL);
+	break;
+    case FCELL_TYPE:
+	seg->data_size = sizeof(FCELL);
+	break;
+    case DCELL_TYPE:
+	seg->data_size = sizeof(DCELL);
+	break;
+    default:
+	G_fatal_error(_("seg_create: unrecognisabe data type"));
+    }
+
+    filename = G_tempfile();
+    fd = creat(filename, 0666);
+
+    if (0 >
+	segment_format(fd, seg->nrows, seg->ncols, srows, scols,
+		       seg->data_size)) {
+	close(fd);
+	unlink(filename);
+	G_fatal_error(_("seg_create: cannot format segment"));
+    }
+
+    close(fd);
+    if (0 > (fd = open(filename, 2))) {
+	unlink(filename);
+	G_fatal_error(_("seg_create: cannot re-open file"));
+    }
+
+    if (0 > (fd = segment_init(&(seg->seg), fd, number_of_segs))) {
+	unlink(filename);
+	G_fatal_error(_("seg_create: cannot init segment file or out of memory"));
+    }
+
+    seg->filename = G_store(filename);
+    seg->fd = fd;
+    return 0;
+}
+
+int seg_read_map(SEG * seg, char *input_map_name, int check_res,
+		 RASTER_MAP_TYPE check_data_type)
+{
+
+    /*
+     * Funciton read external map and put it in SEG structure (created with seg_create_map)
+     * map to be read can be of any data type, read map is converted if neccesary.
+     * input_map_name: name of the map to be read;
+     * seg: pointer to map stucture (created with create_map);
+     * check_res: [1]: check res correspondence between region and map [0 no check];
+     * check_data_type [CELL, FCELL, DCELL] check if reading map is of particular type, [-1] no check;
+     */
+
+    int input_fd;
+    int r, c;
+    char *mapset;
+    struct Cell_head cellhd, this_window;
+    char *maptypes[] = { "CELL", "FCELL", "DCELL" };
+    RASTER_MAP_TYPE input_data_type;
+    size_t input_data_size;
+    void *input_buffer = NULL;
+    void *target_buffer = NULL;
+    void *input_pointer = NULL;
+
+    /* checking if map exist */
+    mapset = (char *)G_find_raster2(input_map_name, "");
+    if (mapset == NULL)
+	G_fatal_error(_("seg_read:Raster map <%s> not found"),
+		      input_map_name);
+    seg->mapset = mapset;
+
+    /* checking if region and input are the same */
+    G_get_window(&this_window);
+    Rast_get_cellhd(input_map_name, mapset, &cellhd);
+
+    /* check resolution equal anyinteger check;  equal 0 no check */
+    if (check_res)
+	if (this_window.ew_res != cellhd.ew_res ||
+	    this_window.ns_res != cellhd.ns_res)
+	    G_fatal_error(_("Region resolution and map %s resolution differs. \
+		Run g.region rast=%s to set proper region resolution"),
+			  input_map_name, input_map_name);
+
+    if (check_data_type != seg->data_type)
+	G_debug(1,
+		"ram_open:required map type and internal map type differs: conversion forced!");
+    input_data_type = Rast_map_type(input_map_name, mapset);
+    if (check_data_type != -1)
+	if (input_data_type != check_data_type)
+	    G_fatal_error(_("<%s> is not of type %s"),
+			  input_map_name, maptypes[check_data_type]);
+
+    input_fd = Rast_open_old(input_map_name, mapset);
+    input_data_size = Rast_cell_size(input_data_type);
+
+    {				/* reading range */
+	struct Range map_range;
+	struct FPRange map_fp_range;
+	int min, max;
+
+	if (input_data_type == CELL_TYPE) {
+	    Rast_init_range(&map_range);
+	    Rast_read_range(input_map_name, mapset, &map_range);
+	    Rast_get_range_min_max(&map_range, &min, &max);
+	    seg->min = (double)min;
+	    seg->max = (double)max;
+	}
+	else {
+	    Rast_init_fp_range(&map_fp_range);
+	    Rast_read_fp_range(input_map_name, mapset, &map_fp_range);
+	    Rast_get_fp_range_min_max(&map_fp_range, &(seg->min),
+				      &(seg->max));
+	}
+    }
+
+    /* end opening and checking */
+
+    G_message(_("Reading map <%s>"), input_map_name);
+    input_buffer = Rast_allocate_buf(input_data_type);
+
+    target_buffer = Rast_allocate_buf(seg->data_type);
+
+    for (r = 0; r < seg->nrows; ++r) {
+	G_percent(r, seg->nrows, 2);
+	Rast_get_row(input_fd, input_buffer, r, input_data_type);
+	input_pointer = input_buffer;
+	memset(target_buffer, 0, seg->ncols * seg->data_size);
+
+	for (c = 0; c < seg->ncols; ++c)
+	    if (!Rast_is_null_value
+		(input_pointer + c * input_data_size, input_data_type)) {
+		switch (seg->data_type) {
+		case CELL_TYPE:
+		    ((CELL *) target_buffer)[c] =
+			Rast_get_c_value(input_pointer + c * input_data_size,
+					 input_data_type);
+		    break;
+		case FCELL_TYPE:
+		    ((FCELL *) target_buffer)[c] =
+			Rast_get_f_value(input_pointer + c * input_data_size,
+					 input_data_type);
+		    break;
+		case DCELL_TYPE:
+		    ((DCELL *) target_buffer)[c] =
+			Rast_get_d_value(input_pointer + c * input_data_size,
+					 input_data_type);
+		    break;
+		default:
+		    G_fatal_error(_("Wrong internal data type"));
+		    break;
+		}
+	    }
+
+	if (0 > segment_put_row(&(seg->seg), target_buffer, r)) {
+	    G_free(input_buffer);
+	    G_free(target_buffer);
+	    Rast_close(input_fd);
+	    G_fatal_error(_("seg_read: Cannot segment put row %d for map %s"),
+			  r, input_map_name);
+	}
+    }				/* end for row */
+
+    G_percent(r, seg->nrows, 2);
+    Rast_close(input_fd);
+    G_free(input_buffer);
+    G_free(target_buffer);
+
+    seg->map_name = G_store(input_map_name);
+    seg->mapset = G_store(mapset);
+
+    return 0;
+}
+
+int seg_reset_map(SEG * seg, int value)
+{
+    /*
+     * set all cells in the map to value
+     */
+    int r, c;
+
+    for (r = 0; r < seg->nrows; ++r)
+	for (c = 0; c < seg->ncols; ++c)
+	    segment_put(&(seg->seg), &value, r, c);
+
+    return 0;
+}
+
+int seg_write_map(SEG * seg, char *output_map_name,
+		  RASTER_MAP_TYPE output_data_type, int convert_to_null,
+		  double value)
+{
+    /* 
+     * write seg to disk with output_map_name and output_data_type [CELL, FCELL, DCELL];
+     * if output_data_type = -1 than internal map type is used for output;
+     * if output map != -1 and types differ data_type, conversion is forced
+     * convert to null: check if convert to null a particular value in dataset;
+     */
+    int output_fd;
+    int r, c;
+    void *output_buffer;
+    void *row;
+    struct History history;
+
+    /* check for output format */
+    if (output_data_type == -1)
+	output_data_type = seg->data_type;
+
+    if (output_data_type != seg->data_type)
+	G_debug(1,
+		"ram_write:required map type and internal map type differs: conversion forced!");
+
+    G_message(_("Writing map <%s>"), output_map_name);
+    output_fd = Rast_open_new(output_map_name, output_data_type);
+    output_buffer = Rast_allocate_buf(output_data_type);
+    segment_flush(&(seg->seg));
+
+    /* writing */
+    for (r = 0; r < seg->nrows; ++r) {
+
+	G_percent(r, seg->nrows, 2);
+	if (0 > segment_get_row(&(seg->seg), output_buffer, r))
+	    G_warning(_("seg_write: Cannot segment read row %d for map %s"),
+		      r, output_map_name);
+
+	if (convert_to_null) {
+
+	    row = output_buffer;
+	    switch (seg->data_type) {
+	    case CELL_TYPE:
+		for (c = 0; c < seg->ncols; ++c)
+		    if (((CELL *) output_buffer)[c] == (CELL) value)
+			Rast_set_c_null_value(row + c * (seg->data_size), 1);
+		break;
+	    case FCELL_TYPE:
+		for (c = 0; c < seg->ncols; ++c)
+		    if (((FCELL *) output_buffer)[c] == (FCELL) value)
+			Rast_set_f_null_value(row + c * (seg->data_size), 1);
+		break;
+	    case DCELL_TYPE:
+		for (c = 0; c < seg->ncols; ++c)
+		    if (((DCELL *) output_buffer)[c] == (DCELL) value)
+			Rast_set_d_null_value(row + c * (seg->data_size), 1);
+		break;
+	    default:
+		G_warning(_("ram_null:Cannot convert to null at: %d %d"), r,
+			  c);
+	    }
+	}
+	Rast_put_row(output_fd, output_buffer, output_data_type);
+    }
+
+    G_percent(r, seg->nrows, 2);
+    G_free(output_buffer);
+    Rast_close(output_fd);
+    Rast_short_history(output_map_name, "raster", &history);
+    Rast_command_history(&history);
+    Rast_write_history(output_map_name, &history);
+    G_message(_("%s Done"), output_map_name);
+
+    return 0;
+}
+
+int seg_release_map(SEG * seg)
+{
+    /* 
+     * release segment close files, set pointers to null;
+     */
+    segment_release(&(seg->seg));
+    close(seg->fd);
+    unlink(seg->filename);
+
+    if (seg->map_name)
+	G_free(seg->map_name);
+    if (seg->mapset)
+	G_free(seg->mapset);
+
+    return 0;
+}

Added: grass-addons/grass7/grass7/raster/r.stream.basins/io.h
===================================================================
--- grass-addons/grass7/grass7/raster/r.stream.basins/io.h	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.stream.basins/io.h	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,59 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <string.h>
+#include <math.h>
+#include <grass/glocale.h>
+#include <grass/gis.h>
+#include <grass/raster.h>
+#include <grass/segment.h>
+
+#define NOT_IN_REGION(x) (r + nextr[(x)] < 0 || r + nextr[(x)] > (nrows - 1) || \
+                          c + nextc[(x)] < 0 || c + nextc[(x)] > (ncols - 1))
+#define NR(x) (r + nextr[(x)])
+#define NC(x) (c + nextc[(x)])
+#define INDEX(r,c) ((r) * ncols + (c))
+#define DIAG(x) (((x) + 4) > 8 ? ((x) - 4) : ((x) + 4))
+
+#define SROWS 256
+#define SCOLS 256
+
+typedef struct {
+	void **map; /* matrix of data */
+	double min, max; /* data range : may requre casting */
+	int nrows, ncols;
+	char *map_name; /* map name, unused */
+	RASTER_MAP_TYPE data_type; /* type of data */
+	size_t data_size; /* type of data */
+} MAP;
+
+typedef struct {
+	SEGMENT seg;		/* segmented data store */
+	int fd;					/* segment temporary file name descriptor */
+	char *filename; /* segment temporary file name */
+	char *map_name; /* map name converted to segment */
+	char *mapset;
+	int nrows, ncols; /* store nrows and rcols */
+	RASTER_MAP_TYPE data_type; /* data type of the map */
+	size_t data_size; /* size of cell returned by sizeof */
+	double min, max; /* data range */
+} SEG;
+
+
+/* all in ram functions */
+int ram_create_map(MAP *, RASTER_MAP_TYPE);
+int ram_read_map(MAP *, char *, int, RASTER_MAP_TYPE);
+int ram_reset_map(MAP *, int);
+int ram_write_map(MAP *, char *, RASTER_MAP_TYPE, int, double);
+int ram_release_map(MAP *);
+int ram_destory_map(MAP *);
+
+/* memory swap functions */
+int seg_create_map(SEG *, int, int, int, RASTER_MAP_TYPE);
+int seg_read_map(SEG *, char *, int, RASTER_MAP_TYPE);
+int seg_reset_map (SEG *, int);
+int seg_write_map(SEG *, char *, RASTER_MAP_TYPE, int, double);
+int seg_release_map(SEG *);
+

Added: grass-addons/grass7/grass7/raster/r.stream.basins/local_proto.h
===================================================================
--- grass-addons/grass7/grass7/raster/r.stream.basins/local_proto.h	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.stream.basins/local_proto.h	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,17 @@
+#include "io.h"
+#include "local_vars.h"
+
+int process_coors(char **answers);
+int process_vector(char *in_point);
+
+int ram_fill_basins(OUTLET outlet, CELL **basins, CELL **dirs);
+int ram_add_outlets(CELL **basins, int outlets_num);
+int ram_process_streams(char **cat_list, CELL **streams,
+			int number_of_streams, CELL **dirs, int lasts,
+			int cats);
+
+int seg_fill_basins(OUTLET outlet, SEGMENT *basins, SEGMENT *dirs);
+int seg_add_outlets(SEGMENT *basins, int outlets_num);
+int seg_process_streams(char **cat_list, SEGMENT *streams,
+			int number_of_streams, SEGMENT *dirs, int lasts,
+			int cats);

Added: grass-addons/grass7/grass7/raster/r.stream.basins/local_vars.h
===================================================================
--- grass-addons/grass7/grass7/raster/r.stream.basins/local_vars.h	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.stream.basins/local_vars.h	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,40 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include <grass/glocale.h>
+#include <grass/gis.h>
+#include <grass/raster.h>
+#include <grass/vector.h>
+#include <grass/dbmi.h>
+
+#ifdef MAIN
+#  define GLOBAL
+#else
+#  define GLOBAL extern
+#endif
+
+typedef struct {
+	int r,c;
+	int val;
+} OUTLET;
+
+typedef struct {
+	int r,c;
+	} POINT;
+
+GLOBAL int nextr[9];
+GLOBAL int nextc[9];
+
+GLOBAL OUTLET* outlets;
+GLOBAL OUTLET* border_outlets;
+GLOBAL int* categories;
+GLOBAL int nrows, ncols;
+GLOBAL int fifo_max;
+GLOBAL POINT* fifo_points;
+
+
+
+
+
+

Added: grass-addons/grass7/grass7/raster/r.stream.basins/main.c
===================================================================
--- grass-addons/grass7/grass7/raster/r.stream.basins/main.c	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.stream.basins/main.c	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,253 @@
+
+/****************************************************************************
+ *
+ * MODULE:       r.stream.basins
+ * AUTHOR(S):    Jarek Jasiewicz jarekj amu.edu.pl
+ *               
+ * PURPOSE:      Calculate basins according user' input data.
+ *               It uses multiple type of inputs:
+ * 							 r.stream.order, r.stream.extract or r.watershed stream  map 
+ *               list of categoires to create basins (require stream map);
+ *               vector file containing outputs;
+ *               list of coordinates;
+ *               with analogous  direction map;
+ *
+ * COPYRIGHT:    (C) 2002,2010 by the GRASS Development Team
+ *
+ *               This program is free software under the GNU General Public
+ *   	    	 	  License (>=v2). Read the file COPYING that comes with GRASS
+ *   	    	 	  for details.
+ *
+ *****************************************************************************/
+#define MAIN
+#include <grass/glocale.h>
+#include "local_proto.h"
+
+int nextr[9] = { 0, -1, -1, -1, 0, 1, 1, 1, 0 };
+int nextc[9] = { 0, 1, 0, -1, -1, -1, 0, 1, 1 };
+
+int main(int argc, char *argv[])
+{
+
+    struct GModule *module;
+    struct Option *in_dir_opt,
+	*in_coor_opt,
+	*in_stm_opt,
+	*in_stm_cat_opt, *in_point_opt, *opt_basins, *opt_swapsize;
+
+    struct Flag *flag_zerofill, *flag_cats, *flag_lasts, *flag_segmentation;
+
+    int b_test = 0;		/* test which option have been choosed: like chmod */
+    int segmentation, zerofill, lasts, cats;
+    int i, outlets_num = 0;
+    int max_number_of_streams;
+
+    G_gisinit(argv[0]);
+
+    module = G_define_module();
+    module->description = _("Delineate basins according user' input. \
+	Input can be stream network, point file with outlets or outlet coordinates");
+    G_add_keyword("basins creation");
+
+    in_dir_opt = G_define_standard_option(G_OPT_R_INPUT);	/* input directon file */
+    in_dir_opt->key = "dirs";
+    in_dir_opt->description = _("Name of flow direction input map");
+
+    in_coor_opt = G_define_option();	/* input coordinates de outlet */
+    in_coor_opt->key = "coors";
+    in_coor_opt->type = TYPE_STRING;
+    in_coor_opt->key_desc = "x,y";
+    in_coor_opt->answers = NULL;
+    in_coor_opt->required = NO;
+    in_coor_opt->multiple = YES;
+    in_coor_opt->description = _("Basin's outlet's coordinates: E,N");
+
+    in_stm_opt = G_define_standard_option(G_OPT_R_INPUT);	/* input stream file file */
+    in_stm_opt->key = "streams";
+    in_stm_opt->required = NO;
+    in_stm_opt->description = _("Name of stream mask input map");
+
+    in_stm_cat_opt = G_define_option();	/* input stream category - optional */
+    in_stm_cat_opt->key = "cats";
+    in_stm_cat_opt->type = TYPE_STRING;
+    in_stm_cat_opt->required = NO;
+    in_stm_cat_opt->description =
+	_("Create basins only for these categories:");
+
+    in_point_opt = G_define_standard_option(G_OPT_V_INPUT);	/* input point outputs - optional */
+    in_point_opt->key = "points";
+    in_point_opt->required = NO;
+    in_point_opt->description = _("Name of vector points map");
+
+    opt_swapsize = G_define_option();
+    opt_swapsize->key = "memory";
+    opt_swapsize->type = TYPE_INTEGER;
+    opt_swapsize->answer = "300";
+    opt_swapsize->description = _("Max memory used in memory swap mode (MB)");
+    opt_swapsize->guisection = _("Optional");
+
+    opt_basins = G_define_standard_option(G_OPT_R_OUTPUT);
+    opt_basins->key = "basins";
+    opt_basins->description = _("Output basin map");
+
+    /*flags */
+    flag_zerofill = G_define_flag();
+    flag_zerofill->key = 'z';
+    flag_zerofill->description =
+	_("Create zero-value background instead of NULL");
+
+    flag_cats = G_define_flag();
+    flag_cats->key = 'c';
+    flag_cats->description =
+	_("Use unique category sequence instead of input streams");
+
+    flag_lasts = G_define_flag();
+    flag_lasts->key = 'l';
+    flag_lasts->description = _("Create basins only for last stream links");
+
+    flag_segmentation = G_define_flag();
+    flag_segmentation->key = 'm';
+    flag_segmentation->description = _("Use memory swap (operation is slow)");
+
+    if (G_parser(argc, argv))	/* parser */
+	exit(EXIT_FAILURE);
+
+    zerofill = (flag_zerofill->answer == 0);
+    cats = (flag_cats->answer != 0);
+    lasts = (flag_lasts->answer != 0);
+    segmentation = (flag_segmentation->answer != 0);
+
+    if (!in_coor_opt->answers && !in_stm_opt->answer && !in_point_opt->answer)
+	G_fatal_error(_("One basin's outlet definition is required"));
+
+    if (in_stm_cat_opt->answers && !in_stm_opt->answer)
+	G_fatal_error(_("If cats stream file is required"));
+
+    if (in_coor_opt->answers)
+	b_test += 1;
+    if (in_stm_opt->answer)
+	b_test += 2;
+    if (in_point_opt->answer)
+	b_test += 4;
+
+    if (b_test != 1 && b_test != 2 && b_test != 4)
+	G_fatal_error("Only one outlet definition is allowed");
+
+    nrows = Rast_window_rows();
+    ncols = Rast_window_cols();
+
+    if (G_legal_filename(opt_basins->answer) < 0)
+	G_fatal_error(_("<%s> is an illegal basin name"), opt_basins->answer);
+
+
+    /* ALL IN RAM VERSION */
+    if (!segmentation) {
+	MAP map_dirs, map_streams, map_basins;
+	CELL **streams = NULL, **dirs, **basins;
+
+	G_message("ALL IN RAM CALCULATION");
+
+	ram_create_map(&map_dirs, CELL_TYPE);
+	ram_read_map(&map_dirs, in_dir_opt->answer, 1, CELL_TYPE);
+	dirs = (CELL **) map_dirs.map;
+
+
+	switch (b_test) {
+	case 1:
+	    G_message("Calculate basins using coordinates...");
+	    outlets_num = process_coors(in_coor_opt->answers);
+	    break;
+
+	case 2:
+	    G_message("Calculate basins using streams...");
+	    ram_create_map(&map_streams, CELL_TYPE);
+	    ram_read_map(&map_streams, in_stm_opt->answer, 1, CELL_TYPE);
+	    streams = (CELL **) map_streams.map;
+	    max_number_of_streams = (int)map_streams.max + 1;
+	    outlets_num = ram_process_streams(in_stm_cat_opt->answers,
+					      streams, max_number_of_streams,
+					      dirs, lasts, cats);
+	    ram_release_map(&map_streams);
+	    break;
+
+	case 4:
+	    G_message("Calculate basins using point file...");
+	    outlets_num = process_vector(in_point_opt->answer);
+	    break;
+	}
+
+	ram_create_map(&map_basins, CELL_TYPE);
+	basins = (CELL **) map_basins.map;
+	ram_add_outlets(basins, outlets_num);
+	fifo_max = 4 * (nrows + ncols);
+	fifo_points = (POINT *) G_malloc((fifo_max + 1) * sizeof(POINT));
+
+	for (i = 0; i < outlets_num; ++i)
+	    ram_fill_basins(outlets[i], basins, dirs);
+
+	G_free(fifo_points);
+	ram_write_map(&map_basins, opt_basins->answer, CELL_TYPE, zerofill,
+		      0);
+	ram_release_map(&map_dirs);
+	ram_release_map(&map_basins);
+
+    }				/* end ram */
+
+    /* SEGMENT VERSION */
+
+    if (segmentation) {
+	SEG map_dirs, map_streams, map_basins;
+	SEGMENT *streams = NULL, *dirs, *basins;
+	int number_of_segs;
+
+	G_message("MEMORY SWAP CALCULATION: MAY TAKE SOME TIME!");
+
+	number_of_segs = (int)atof(opt_swapsize->answer);
+	number_of_segs = number_of_segs < 32 ? (int)(32 / 0.12) : number_of_segs / 0.12;
+
+	seg_create_map(&map_dirs, SROWS, SCOLS, number_of_segs, CELL_TYPE);
+	seg_read_map(&map_dirs, in_dir_opt->answer, 1, CELL_TYPE);
+	dirs = &map_dirs.seg;
+
+	switch (b_test) {
+	case 1:
+	    G_message("Calculate basins using coordinates...");
+	    outlets_num = process_coors(in_coor_opt->answers);
+	    break;
+
+	case 2:
+	    G_message("Calculate basins using streams...");
+	    seg_create_map(&map_streams, SROWS, SCOLS, number_of_segs,
+			   CELL_TYPE);
+	    seg_read_map(&map_streams, in_stm_opt->answer, 1, CELL_TYPE);
+	    streams = &map_streams.seg;
+	    max_number_of_streams = (int)map_streams.max + 1;
+	    outlets_num = seg_process_streams(in_stm_cat_opt->answers,
+					      streams, max_number_of_streams,
+					      dirs, lasts, cats);
+	    seg_release_map(&map_streams);
+	    break;
+
+	case 4:
+	    G_message("Calculate basins using point file...");
+	    outlets_num = process_vector(in_point_opt->answer);
+	    break;
+	}
+
+	seg_create_map(&map_basins, SROWS, SCOLS, number_of_segs, CELL_TYPE);
+	basins = &map_basins.seg;
+	seg_add_outlets(basins, outlets_num);
+	fifo_max = 4 * (nrows + ncols);
+	fifo_points = (POINT *) G_malloc((fifo_max + 1) * sizeof(POINT));
+
+	for (i = 0; i < outlets_num; ++i)
+	    seg_fill_basins(outlets[i], basins, dirs);
+	G_free(fifo_points);
+	seg_write_map(&map_basins, opt_basins->answer, CELL_TYPE, zerofill,
+		      0);
+	seg_release_map(&map_dirs);
+	seg_release_map(&map_basins);
+    }
+
+    exit(EXIT_SUCCESS);
+}

Added: grass-addons/grass7/grass7/raster/r.stream.basins/r.stream.basins.html
===================================================================
--- grass-addons/grass7/grass7/raster/r.stream.basins/r.stream.basins.html	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.stream.basins/r.stream.basins.html	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,191 @@
+<h2>OPTIONS</h2>
+<dl>
+<dt><b>-z</b></dt>
+<dd>Creates zero-value background instead of NULL. For some reason (like map
+algebra calculation) zero-valued background may be required. This flag produces
+zero-filled background instead of null (default).</dd>
+<dt><b>-c</b></dt>
+<dd>By default r.stream.basins uses streams category as basin category. In some
+cases - for example if stream map is product of map algebra and separete streams
+may not have unique values this option will create new category sequence for
+each basin (do not work in vector point mode)
+</dd>
+<dt><b>-l</b></dt>
+<dd>By default r.stream.basins create basins for all unique streams. This option
+delinate basins only for last streams ignoring upstreams (do not work in vector
+point mode).
+</dd>
+
+<dt><b>dirs</b></dt>
+<dd>Flow direction: name of input direction map produced by r.watershed or
+r.stream.extract. If r.stream.extract output map is used, it only has non-NULL
+values in places where streams occur. NULL (nodata) cells are ignored, zero and
+negative values are valid direction data if they vary from -8 to 8 (CCW from
+East in steps of 45 degrees). Direction map shall be of type CELL values. Region
+resolution and map resoultion must be the same. 
+Also <em>stream</em> network map (if used) and direction map must have the same
+resolution. It is checked by default. If resolutions differ the module informs
+about it and stops. Region boundary and maps boundary may be differ but it may
+lead to unexpected results.</dd>
+
+<dt><b>coors</b></dt>
+<dd>East and north coordinates for basin outlet. It can delinate only one basin
+using that option. This option simply copies funcionality of <a
+href="r.water.outlet.html">r.water.outlet</a>.
+</dd>
+<dt><b>streams</b></dt>
+<dd>Stream network: name of input stream map on which ordering will be performed
+produced by r.watershed or r.stream.extract. Because streams network produced by
+r.watershed and r.stream.extract may slighty differ in detail it is required to
+use both stream and direction map produced by the same module. Stream background
+shall have NULL value or zero value. Background values of NULL are by default
+produced by r.watershed and r.stream.extract. If not 0 or NULL use <a
+href="r.mapcalc.html">r.mapcalc</a> to set background values to null.  
+</dd>
+
+<dt><b>cats</b></dt>
+<dd>Stream categories to delineate basins for: All categories which are not in
+stream map are ignored. It can be used with stream network created by
+r.watershed, r.stream.extract or r.stream.order. For r.stream.order use category
+of order for which basins must be created. For example to delineate only basins
+for order two use cats=2. If you need unique category for every basin use -c
+flag.
+</dd>
+
+<dt><b>points</b></dt>
+<dd>Vector file containing basins outlet as vector points. Only point's
+categories are used to prepare basins. Table attached to it is ignored. Every
+point shall have his own unique category. In that mode flags -l and -c are
+ignored
+</dd>
+</dl>
+
+
+<h2>OUTPUTS</h2>
+<p>The module produces one raster map with basins acording user's rules</p>
+
+
+<h2>DESCRIPTION</h2>
+
+Module r.stream.basins is prepared to delineate basins and subasins with
+different input data. Module is prepared to delineate unrestricted number of
+basins in one step. It can delineate basins with three methods:
+<ul>
+<li>Using coordinates: his option simply copies funcionality of <a
+href="r.water.outlet.html">r.water.outlet</a>.
+<li>Using vector points: it allow to mannually point outlets with any method
+<li>Using streams (most advanced) it allow on lots of modifications. See
+examples for more details.
+</ul>
+Only one method can be used at once. Methods cannot be mixed.
+<p>
+The most recommended method require two maps: direction and streams. In spite of
+in stream map we can store information required to proper delineation, we can
+also enumarate stream categories for which basins are to be created (cats
+option). Module is prepared to work with output data of <em>r.watershed,
+r.stream.extract, r.stream.order</em> also with modification done by
+<em>r.recalss</em> and <em>r.mapcalc</em>. r.stream.basin can delineate basins
+according outlets marked by raster streams, and polygons, vector points and
+numerical coordinates. If outlets are marked by points or coordinates it
+delineate basins which cells contribute to that points, if outlets are marked by
+streams it delineate cells which contribute to the last (downstream) cell of the
+every stream. If outlets are marked by polygon it delineate cells contributing
+to most downstream cell of the polygon. If polygon covers more outlets than of
+one basins it will create collective basin for all outlets  with common
+category.
+
+
+<h2>NOTES</h2>
+<p>
+To receive good results outlets markers created by user shall overlapping with
+streams. On the other way basins could results with very small area. Input maps
+must be in CELL format (default output of r.watershed, r.stream.order  and
+r.stream.extract)<p>
+Module can work only if direction map, stream map and region map has same
+settings. It is also required that stream map and direction map come from the
+same source. For lots of reason this limitation probably cannot be omitted.  
+this means if stream map comes from r.stream.extract also direction map from
+r.stream.extract must be used. If stream network was generated with MFD method
+also MFD direction map must be used. Nowadays f direction map comes from
+r.stream.extract  must be patched by direction map from r.watershed. (with
+r.patch). 
+
+<h2>EXAMPLES</h2>
+<p>
+To delineate all basins with categories of streams:
+<p>
+<code>r.stream.basins dir=dirs stream=streams basins=bas_basins_elem</code>
+<p>
+To determine major and minor basins in area, definied by outlets, ignoring
+subbasins use  - l flag. That flag ignores all nodes and uses only real outlets
+(in most cases that on map border):
+<p>
+<code>r.stream.basins -l dir=dirs stream=streams basins=bas_basins_last</code>
+
+<p>
+<code>r.stream.basins dir=dirs coors=639936.623832,216939.836449</code>
+
+<p>
+To delineate one or more particular basins defined by given streams, add simply
+stream categories:
+<div class="code"><pre>
+r.stream.basins -lc dirs=dirs streams=streams cats=2,7,184 basins=bas_basin
+</pre></div>
+
+<p>
+Do delineate basins of particular order we must use the following procedure: 
+
+<div class="code"><pre>
+r.stream.basins -lc dirs=dirs streams=strahler cats=2
+basins=bas_basin_strahler_2
+</pre></div>
+
+<p>
+The usage of polygons as outlets markers is very useful when exact stream course
+cannot be cleary determined before running analysis, but the area of its
+occurrence can be determined (mostly in iterative simulations) Example uses
+r.circle but can be substituted by any polygon created for example  with
+v.digit:
+<div class="code"><pre>
+r.circle -b output=circle coordinate=639936.623832,216939.836449 max=200
+r.stream.basins -c dirs=dirs streams=circle basins=bas_simul
+</pre></div>
+<p>
+To determine areas of contribution to streams of particular order  use as
+streams the result of ordering:
+<p>
+<div class="code"><pre>
+r.stream.basins dirs=dirs streams=ord_strahler basins=bas_basin_strahler
+</pre></div>
+<p>
+Determination of areas of potential source of pollution. The example will be
+done for lake marked with FULL_HYDR 8056 in North Carolina sample dataset. The
+lake shall be extracted and converted to binary raster map.
+
+<div class="code"><pre>
+v.extract -d input=lakes at PERMANENT output=lake8056 type=area layer=1
+'where=FULL_HYDRO = 8056' new=-1 
+v.to.rast input=lake8056 output=lake8056 use=val type=area layer=1 value=1
+r.stream.basins dirs=dirs streams=lake8056 basins=bas_basin_lake
+</pre></div>
+<p>
+See also tutorial: <a href="http://grass.OSGeo.org/wiki/R.stream.*">http://grass.OSGeo.org/wiki/R.stream.*</a>
+
+<h2>SEE ALSO</h2>
+
+<em>
+<a href="r.watershed.html">r.watershed</a>,
+<a href="r.stream.extract.html">r.stream.extract</a>,
+<a href="r.stream.order.html">r.stream.order</a>,
+<a href="r.stream.stats.html">r.stream.stats</a>,
+<a href="r.mapcalc.html">r.mapcalc</a>,
+<a href="r.reclass.html">r.reclass</a>,
+<a href="r.patch.html">r.patch</a>
+</em>
+
+<h2>AUTHOR</h2>
+Jarek Jasiewicz, Adam Mickiewicz University, Geoecology and Geoinformation
+Institute.
+
+<p><i>Last changed: $Date: 2011-11-08 22:56:45 +0100 (Tue, 08 Nov 2011) $</i>
+

Added: grass-addons/grass7/grass7/raster/r.stream.channel/Makefile
===================================================================
--- grass-addons/grass7/grass7/raster/r.stream.channel/Makefile	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.stream.channel/Makefile	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,11 @@
+MODULE_TOPDIR = ../..
+
+PGM = r.stream.channel
+
+LIBES = $(GISLIB) $(RASTERLIB) $(SEGMENTLIB)
+DEPENDENCIES = $(GISDEP) $(RASTERDEP) $(SEGMENTDEP)
+
+include $(MODULE_TOPDIR)/include/Make/Module.make
+
+default: cmd
+

Added: grass-addons/grass7/grass7/raster/r.stream.channel/io.c
===================================================================
--- grass-addons/grass7/grass7/raster/r.stream.channel/io.c	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.stream.channel/io.c	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,564 @@
+#include "io.h"
+/* all in ram functions section */
+
+int ram_create_map(MAP * map, RASTER_MAP_TYPE data_type)
+{
+
+    /* 
+     * allocates 0 filled nrows*ncols map of type void;
+     * map parameters are stored in structure;
+     * map: map to be created;
+     * map type to be created must be CELL, FCELL, DCELL;
+     * */
+
+    int r;
+
+    if (data_type < 0 || data_type > 2)
+	G_fatal_error(_("ram_creat: Cannot create map of unrecognised type"));
+
+    map->data_type = data_type;
+    map->map_name = NULL;
+    map->nrows = Rast_window_rows();
+    map->ncols = Rast_window_cols();
+    map->data_size = Rast_cell_size(data_type);
+
+    /* preparing internal map */
+    switch (map->data_type) {
+    case CELL_TYPE:
+	map->map = G_calloc(map->nrows, sizeof(CELL *));
+	break;
+
+    case FCELL_TYPE:
+	map->map = G_calloc(map->nrows, sizeof(FCELL *));
+	break;
+
+    case DCELL_TYPE:
+	map->map = G_calloc(map->nrows, sizeof(DCELL *));
+	break;
+    }
+
+    for (r = 0; r < map->nrows; ++r)
+	(map->map)[r] = G_calloc(map->ncols, map->data_size);
+
+    return 0;
+}
+
+int ram_read_map(MAP * map, char *input_map_name, int check_res,
+		 RASTER_MAP_TYPE check_data_type)
+{
+    /*
+     * Funciton read external map and put it in MAP structure (created with create_map)
+     * map: map to be read can be of any data type, read map is converted to target map if neccesary.
+     * input_map_name: name of the map to be read;
+     * map pointer to map stucture (created with create_map);
+     * check_res: [1]: check res correspondence between region and map [0 no check];
+     * check_data_type [CELL, FCELL, DCELL] check if reading map is of particular type, [-1] no check;
+     */
+
+    int r, c;
+    char *mapset;
+    struct Cell_head cellhd, this_window;
+    char *maptypes[] = { "CELL", "FCELL", "DCELL" };
+    int input_map_fd;
+    RASTER_MAP_TYPE input_data_type;
+    size_t input_data_size;
+    void *input_buffer = NULL;
+    void *input_pointer;
+
+    /* checking if map exist */
+    mapset = (char *)G_find_raster2(input_map_name, "");
+    if (mapset == NULL)
+	G_fatal_error(_("Raster map <%s> not found"), input_map_name);
+
+    /* checking if region and input are the same */
+    G_get_window(&this_window);
+    Rast_get_cellhd(input_map_name, mapset, &cellhd);
+    if (check_res)
+	if (this_window.ew_res != cellhd.ew_res ||
+	    this_window.ns_res != cellhd.ns_res)
+	    G_fatal_error(_("Region resolution and map %s resolution differs. \
+		Run g.region rast=%s to set proper region resolution"),
+			  input_map_name, input_map_name);
+
+    /* checking if input map is of required type */
+    if (check_data_type != map->data_type)
+	G_debug(1,
+		"ram_open:required map type and internal map type differs: conversion forced!");
+    input_data_type = Rast_map_type(input_map_name, mapset);
+    if (check_data_type != -1)
+	if (input_data_type != check_data_type)
+	    G_fatal_error(_("<%s> is not of type %s"),
+			  input_map_name, maptypes[check_data_type]);
+
+    input_map_fd = Rast_open_old(input_map_name, mapset);
+    input_data_size = Rast_cell_size(input_data_type);
+
+    {				/* reading range */
+	struct Range map_range;
+	struct FPRange map_fp_range;
+	int min, max;
+
+	if (input_data_type == CELL_TYPE) {
+	    Rast_init_range(&map_range);
+	    Rast_read_range(input_map_name, mapset, &map_range);
+	    Rast_get_range_min_max(&map_range, &min, &max);
+	    map->min = (double)min;
+	    map->max = (double)max;
+	}
+	else {
+	    Rast_init_fp_range(&map_fp_range);
+	    Rast_read_fp_range(input_map_name, mapset, &map_fp_range);
+	    Rast_get_fp_range_min_max(&map_fp_range, &(map->min),
+				      &(map->max));
+	}
+    }
+    /* end opening and checking */
+
+    input_buffer = Rast_allocate_buf(input_data_type);
+
+    /* start reading */
+    G_message(_("Reading map <%s>"), input_map_name);
+
+    for (r = 0; r < map->nrows; ++r) {
+	G_percent(r, map->nrows, 2);
+
+	Rast_get_row(input_map_fd, input_buffer, r, input_data_type);
+	input_pointer = input_buffer;
+
+	for (c = 0; c < map->ncols; ++c)
+	    if (!Rast_is_null_value
+		(input_pointer + c * input_data_size, input_data_type))
+		switch (map->data_type) {
+		case CELL_TYPE:
+		    ((CELL **) map->map)[r][c] =
+			Rast_get_c_value(input_pointer + c * input_data_size,
+					 input_data_type);
+		    break;
+		case FCELL_TYPE:
+		    ((FCELL **) map->map)[r][c] =
+			Rast_get_f_value(input_pointer + c * input_data_size,
+					 input_data_type);
+		    break;
+		case DCELL_TYPE:
+		    ((DCELL **) map->map)[r][c] =
+			Rast_get_d_value(input_pointer + c * input_data_size,
+					 input_data_type);
+		    break;
+		default:
+		    G_fatal_error(_("ram_open:Wrong internal data type"));
+		    break;
+		}
+    }				/*end for r */
+
+    G_free(input_buffer);
+    G_percent(r, map->nrows, 2);
+    Rast_close(input_map_fd);
+    return 0;
+}				/* end create floating point map */
+
+int ram_reset_map(MAP * map, int value)
+{
+    /*
+     * set all cells in the map to value
+     */
+    int r;
+
+    for (r = 0; r < map->nrows; ++r)
+	memset((map->map)[r], value, map->ncols * map->data_size);
+    return 0;
+}
+
+int ram_write_map(MAP * map, char *output_map_name,
+		  RASTER_MAP_TYPE output_data_type, int convert_to_null,
+		  double value)
+{
+    /* 
+     * write map to disk with output_map_name and output_data_type [CELL, FCELL, DCELL];
+     * if output_data_type = -1 than internal map type is used for output;
+     * if output map != -1 and types differ data_type, conversion is forced
+     * convert to null: check if convert to null a particular value in dataset;
+     */
+
+    int r, c;
+    int output_fd = 0;
+    struct History history;
+    void *row;
+
+    /* check for output format */
+    if (output_data_type == -1)
+	output_data_type = map->data_type;
+
+    if (output_data_type != map->data_type)
+	G_debug(1,
+		"ram_write:required map type and internal map type differs: conversion forced!");
+
+    G_message(_("Writing map <%s>"), output_map_name);
+    output_fd = Rast_open_new(output_map_name, output_data_type);
+
+    /* writing */
+    for (r = 0; r < map->nrows; ++r) {
+	G_percent(r, map->nrows, 2);
+
+	if (convert_to_null) {
+	    row = map->map[r];
+	    switch (map->data_type) {
+	    case CELL_TYPE:
+		for (c = 0; c < map->ncols; ++c)
+		    if (((CELL *) row)[c] == (CELL) value)
+			Rast_set_c_null_value(row + c * (map->data_size), 1);
+		break;
+	    case FCELL_TYPE:
+		for (c = 0; c < map->ncols; ++c)
+		    if (((FCELL *) row)[c] == (FCELL) value)
+			Rast_set_f_null_value(row + c * (map->data_size), 1);
+		break;
+	    case DCELL_TYPE:
+		for (c = 0; c < map->ncols; ++c)
+		    if (((DCELL *) row)[c] == (DCELL) value)
+			Rast_set_d_null_value(row + c * (map->data_size), 1);
+		break;
+	    default:
+		G_debug(1, "ram_null:Cannot convert to null at: %d %d", r, c);
+	    }
+	}
+
+	Rast_put_row(output_fd, (map->map)[r], output_data_type);
+    }
+    G_percent(r, map->nrows, 2);
+    Rast_close(output_fd);
+    Rast_short_history(output_map_name, "raster", &history);
+    Rast_command_history(&history);
+    Rast_write_history(output_map_name, &history);
+    G_message(_("<%s> Done"), output_map_name);
+    return 0;
+}
+
+int ram_release_map(MAP *map)
+{
+    /* 
+     * free memory allocated for map, set pointer to null;
+     */
+    int r;
+
+    for (r = 0; r < map->nrows; ++r)
+	G_free((map->map)[r]);
+    G_free(map->map);
+    map = NULL;
+    return 0;
+}
+
+
+/* memory swap functions section */
+
+
+int seg_create_map(SEG * seg, int srows, int scols, int number_of_segs,
+		   RASTER_MAP_TYPE data_type)
+{
+    /* create segment  and returns pointer to it;
+     * seg must be declared first;
+     * parameters are stored in structure;
+     * seg: segment to be created;
+     * srows, scols segment size
+     * number of segs max number of segs stored in memory
+     * data_type to be created must be CELL, FCELL, DCELL;
+     */
+
+    char *filename;
+    int fd;
+    int local_number_of_segs;
+
+    seg->fd = -1;
+    seg->filename = NULL;
+    seg->map_name = NULL;
+    seg->mapset = NULL;
+    seg->data_type = data_type;
+    seg->nrows = Rast_window_rows();
+    seg->ncols = Rast_window_cols();
+
+    local_number_of_segs =
+	(seg->nrows / srows + 1) * (seg->ncols / scols + 1);
+    number_of_segs =
+	(number_of_segs >
+	 local_number_of_segs) ? local_number_of_segs : number_of_segs;
+
+    G_debug(3, "seg_creat:number of segments %d", number_of_segs);
+
+    switch (seg->data_type) {
+    case CELL_TYPE:
+	seg->data_size = sizeof(CELL);
+	break;
+    case FCELL_TYPE:
+	seg->data_size = sizeof(FCELL);
+	break;
+    case DCELL_TYPE:
+	seg->data_size = sizeof(DCELL);
+	break;
+    default:
+	G_fatal_error(_("seg_create: unrecognisabe data type"));
+    }
+
+    filename = G_tempfile();
+    fd = creat(filename, 0666);
+
+    if (0 >
+	segment_format(fd, seg->nrows, seg->ncols, srows, scols,
+		       seg->data_size)) {
+	close(fd);
+	unlink(filename);
+	G_fatal_error(_("seg_create: cannot format segment"));
+    }
+
+    close(fd);
+    if (0 > (fd = open(filename, 2))) {
+	unlink(filename);
+	G_fatal_error(_("seg_create: cannot re-open file"));
+    }
+
+    if (0 > (fd = segment_init(&(seg->seg), fd, number_of_segs))) {
+	unlink(filename);
+	G_fatal_error(_("seg_create: cannot init segment file or out of memory"));
+    }
+
+    seg->filename = G_store(filename);
+    seg->fd = fd;
+    return 0;
+}
+
+int seg_read_map(SEG * seg, char *input_map_name, int check_res,
+		 RASTER_MAP_TYPE check_data_type)
+{
+
+    /*
+     * Funciton read external map and put it in SEG structure (created with seg_create_map)
+     * map to be read can be of any data type, read map is converted if neccesary.
+     * input_map_name: name of the map to be read;
+     * seg: pointer to map stucture (created with create_map);
+     * check_res: [1]: check res correspondence between region and map [0 no check];
+     * check_data_type [CELL, FCELL, DCELL] check if reading map is of particular type, [-1] no check;
+     */
+
+    int input_fd;
+    int r, c;
+    char *mapset;
+    struct Cell_head cellhd, this_window;
+    char *maptypes[] = { "CELL", "FCELL", "DCELL" };
+    RASTER_MAP_TYPE input_data_type;
+    size_t input_data_size;
+    void *input_buffer = NULL;
+    void *target_buffer = NULL;
+    void *input_pointer = NULL;
+
+    /* checking if map exist */
+    mapset = (char *)G_find_raster2(input_map_name, "");
+    if (mapset == NULL)
+	G_fatal_error(_("seg_read:Raster map <%s> not found"),
+		      input_map_name);
+    seg->mapset = mapset;
+
+    /* checking if region and input are the same */
+    G_get_window(&this_window);
+    Rast_get_cellhd(input_map_name, mapset, &cellhd);
+
+    /* check resolution equal anyinteger check;  equal 0 no check */
+    if (check_res)
+	if (this_window.ew_res != cellhd.ew_res ||
+	    this_window.ns_res != cellhd.ns_res)
+	    G_fatal_error(_("Region resolution and map %s resolution differs. \
+		Run g.region rast=%s to set proper region resolution"),
+			  input_map_name, input_map_name);
+
+    if (check_data_type != seg->data_type)
+	G_debug(1,
+		"ram_open:required map type and internal map type differs: conversion forced!");
+    input_data_type = Rast_map_type(input_map_name, mapset);
+    if (check_data_type != -1)
+	if (input_data_type != check_data_type)
+	    G_fatal_error(_("<%s> is not of type %s"),
+			  input_map_name, maptypes[check_data_type]);
+
+    input_fd = Rast_open_old(input_map_name, mapset);
+    input_data_size = Rast_cell_size(input_data_type);
+
+    {				/* reading range */
+	struct Range map_range;
+	struct FPRange map_fp_range;
+	int min, max;
+
+	if (input_data_type == CELL_TYPE) {
+	    Rast_init_range(&map_range);
+	    Rast_read_range(input_map_name, mapset, &map_range);
+	    Rast_get_range_min_max(&map_range, &min, &max);
+	    seg->min = (double)min;
+	    seg->max = (double)max;
+	}
+	else {
+	    Rast_init_fp_range(&map_fp_range);
+	    Rast_read_fp_range(input_map_name, mapset, &map_fp_range);
+	    Rast_get_fp_range_min_max(&map_fp_range, &(seg->min),
+				      &(seg->max));
+	}
+    }
+
+    /* end opening and checking */
+
+    G_message(_("Reading map <%s>"), input_map_name);
+    input_buffer = Rast_allocate_buf(input_data_type);
+
+    target_buffer = Rast_allocate_buf(seg->data_type);
+
+    for (r = 0; r < seg->nrows; ++r) {
+	G_percent(r, seg->nrows, 2);
+	Rast_get_row(input_fd, input_buffer, r, input_data_type);
+	input_pointer = input_buffer;
+	memset(target_buffer, 0, seg->ncols * seg->data_size);
+
+	for (c = 0; c < seg->ncols; ++c)
+	    if (!Rast_is_null_value
+		(input_pointer + c * input_data_size, input_data_type)) {
+		switch (seg->data_type) {
+		case CELL_TYPE:
+		    ((CELL *) target_buffer)[c] =
+			Rast_get_c_value(input_pointer + c * input_data_size,
+					 input_data_type);
+		    break;
+		case FCELL_TYPE:
+		    ((FCELL *) target_buffer)[c] =
+			Rast_get_f_value(input_pointer + c * input_data_size,
+					 input_data_type);
+		    break;
+		case DCELL_TYPE:
+		    ((DCELL *) target_buffer)[c] =
+			Rast_get_d_value(input_pointer + c * input_data_size,
+					 input_data_type);
+		    break;
+		default:
+		    G_fatal_error(_("Wrong internal data type"));
+		    break;
+		}
+	    }
+
+	if (0 > segment_put_row(&(seg->seg), target_buffer, r)) {
+	    G_free(input_buffer);
+	    G_free(target_buffer);
+	    Rast_close(input_fd);
+	    G_fatal_error(_("seg_read: Cannot segment put row %d for map %s"),
+			  r, input_map_name);
+	}
+    }				/* end for row */
+
+    G_percent(r, seg->nrows, 2);
+    Rast_close(input_fd);
+    G_free(input_buffer);
+    G_free(target_buffer);
+
+    seg->map_name = G_store(input_map_name);
+    seg->mapset = G_store(mapset);
+
+    return 0;
+}
+
+int seg_reset_map(SEG * seg, int value)
+{
+    /*
+     * set all cells in the map to value
+     */
+    int r, c;
+
+    for (r = 0; r < seg->nrows; ++r)
+	for (c = 0; c < seg->ncols; ++c)
+	    segment_put(&(seg->seg), &value, r, c);
+
+    return 0;
+}
+
+int seg_write_map(SEG * seg, char *output_map_name,
+		  RASTER_MAP_TYPE output_data_type, int convert_to_null,
+		  double value)
+{
+    /* 
+     * write seg to disk with output_map_name and output_data_type [CELL, FCELL, DCELL];
+     * if output_data_type = -1 than internal map type is used for output;
+     * if output map != -1 and types differ data_type, conversion is forced
+     * convert to null: check if convert to null a particular value in dataset;
+     */
+    int output_fd;
+    int r, c;
+    void *output_buffer;
+    void *row;
+    struct History history;
+
+    /* check for output format */
+    if (output_data_type == -1)
+	output_data_type = seg->data_type;
+
+    if (output_data_type != seg->data_type)
+	G_debug(1,
+		"ram_write:required map type and internal map type differs: conversion forced!");
+
+    G_message(_("Writing map <%s>"), output_map_name);
+    output_fd = Rast_open_new(output_map_name, output_data_type);
+    output_buffer = Rast_allocate_buf(output_data_type);
+    segment_flush(&(seg->seg));
+
+    /* writing */
+    for (r = 0; r < seg->nrows; ++r) {
+
+	G_percent(r, seg->nrows, 2);
+	if (0 > segment_get_row(&(seg->seg), output_buffer, r))
+	    G_warning(_("seg_write: Cannot segment read row %d for map %s"),
+		      r, output_map_name);
+
+	if (convert_to_null) {
+
+	    row = output_buffer;
+	    switch (seg->data_type) {
+	    case CELL_TYPE:
+		for (c = 0; c < seg->ncols; ++c)
+		    if (((CELL *) output_buffer)[c] == (CELL) value)
+			Rast_set_c_null_value(row + c * (seg->data_size), 1);
+		break;
+	    case FCELL_TYPE:
+		for (c = 0; c < seg->ncols; ++c)
+		    if (((FCELL *) output_buffer)[c] == (FCELL) value)
+			Rast_set_f_null_value(row + c * (seg->data_size), 1);
+		break;
+	    case DCELL_TYPE:
+		for (c = 0; c < seg->ncols; ++c)
+		    if (((DCELL *) output_buffer)[c] == (DCELL) value)
+			Rast_set_d_null_value(row + c * (seg->data_size), 1);
+		break;
+	    default:
+		G_warning(_("ram_null:Cannot convert to null at: %d %d"), r,
+			  c);
+	    }
+	}
+	Rast_put_row(output_fd, output_buffer, output_data_type);
+    }
+
+    G_percent(r, seg->nrows, 2);
+    G_free(output_buffer);
+    Rast_close(output_fd);
+    Rast_short_history(output_map_name, "raster", &history);
+    Rast_command_history(&history);
+    Rast_write_history(output_map_name, &history);
+    G_message(_("%s Done"), output_map_name);
+
+    return 0;
+}
+
+int seg_release_map(SEG * seg)
+{
+    /* 
+     * release segment close files, set pointers to null;
+     */
+    segment_release(&(seg->seg));
+    close(seg->fd);
+    unlink(seg->filename);
+
+    if (seg->map_name)
+	G_free(seg->map_name);
+    if (seg->mapset)
+	G_free(seg->mapset);
+
+    return 0;
+}

Added: grass-addons/grass7/grass7/raster/r.stream.channel/io.h
===================================================================
--- grass-addons/grass7/grass7/raster/r.stream.channel/io.h	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.stream.channel/io.h	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,59 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <string.h>
+#include <math.h>
+#include <grass/glocale.h>
+#include <grass/gis.h>
+#include <grass/raster.h>
+#include <grass/segment.h>
+
+#define NOT_IN_REGION(x) (r + nextr[(x)] < 0 || r + nextr[(x)] > (nrows - 1) || \
+                          c + nextc[(x)] < 0 || c + nextc[(x)] > (ncols - 1))
+#define NR(x) (r + nextr[(x)])
+#define NC(x) (c + nextc[(x)])
+#define INDEX(r,c) ((r) * ncols + (c))
+#define DIAG(x) (((x) + 4) > 8 ? ((x) - 4) : ((x) + 4))
+
+#define SROWS 256
+#define SCOLS 256
+
+typedef struct {
+	void **map; /* matrix of data */
+	double min, max; /* data range : may requre casting */
+	int nrows, ncols;
+	char *map_name; /* map name, unused */
+	RASTER_MAP_TYPE data_type; /* type of data */
+	size_t data_size; /* type of data */
+} MAP;
+
+typedef struct {
+	SEGMENT seg;		/* segmented data store */
+	int fd;					/* segment temporary file name descriptor */
+	char *filename; /* segment temporary file name */
+	char *map_name; /* map name converted to segment */
+	char *mapset;
+	int nrows, ncols; /* store nrows and rcols */
+	RASTER_MAP_TYPE data_type; /* data type of the map */
+	size_t data_size; /* size of cell returned by sizeof */
+	double min, max; /* data range */
+} SEG;
+
+
+/* all in ram functions */
+int ram_create_map(MAP *, RASTER_MAP_TYPE);
+int ram_read_map(MAP *, char *, int, RASTER_MAP_TYPE);
+int ram_reset_map(MAP *, int);
+int ram_write_map(MAP *, char *, RASTER_MAP_TYPE, int, double);
+int ram_release_map(MAP *);
+int ram_destory_map(MAP *);
+
+/* memory swap functions */
+int seg_create_map(SEG *, int, int, int, RASTER_MAP_TYPE);
+int seg_read_map(SEG *, char *, int, RASTER_MAP_TYPE);
+int seg_reset_map (SEG *, int);
+int seg_write_map(SEG *, char *, RASTER_MAP_TYPE, int, double);
+int seg_release_map(SEG *);
+

Added: grass-addons/grass7/grass7/raster/r.stream.channel/local_proto.h
===================================================================
--- grass-addons/grass7/grass7/raster/r.stream.channel/local_proto.h	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.stream.channel/local_proto.h	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,57 @@
+#include "io.h"
+#include "local_vars.h"
+
+int free_attributes(int number_of_streams);
+
+
+int ram_build_streamlines(CELL **streams, CELL **dirs, FCELL **elevation,
+			  int number_of_streams);
+int ram_number_of_streams(CELL **streams, CELL **dirs);
+int ram_find_contributing_cell(int r, int c, CELL **dirs, FCELL **elevation);
+
+int ram_set_null_output(DCELL **output);
+int ram_calculate_identifiers(CELL **identifier, int number_of_streams,
+			      int downstream);
+int ram_calculate_difference(DCELL **output, int number_of_streams,
+			     int downstream);
+int ram_calculate_drop(DCELL **output, int number_of_streams, int downstream);
+int ram_calculate_local_distance(DCELL **output, int number_of_streams,
+				 int downstream);
+int ram_calculate_distance(DCELL **output, int number_of_streams,
+			   int downstream);
+int ram_calculate_cell(DCELL **output, int number_of_streams, int downstream);
+int ram_calculate_local_gradient(DCELL **output, int number_of_streams,
+				 int downstream);
+int ram_calculate_gradient(DCELL **output, int number_of_streams,
+			   int downstream);
+int ram_calculate_curvature(DCELL **output, int number_of_streams,
+			    int downstream);
+
+
+
+int seg_build_streamlines(SEGMENT *streams, SEGMENT *dirs,
+			  SEGMENT *elevation, int number_of_streams);
+int seg_number_of_streams(SEGMENT *streams, SEGMENT *dirs);
+
+int seg_find_contributing_cell(int r, int c, SEGMENT *dirs,
+			       SEGMENT *elevation);
+
+int seg_set_null_output(SEGMENT *output);
+int seg_calculate_identifiers(SEGMENT *identifier, int number_of_streams,
+			      int downstream);
+int seg_calculate_difference(SEGMENT *output, int number_of_streams,
+			     int downstream);
+int seg_calculate_drop(SEGMENT *output, int number_of_streams,
+		       int downstream);
+int seg_calculate_local_distance(SEGMENT *output, int number_of_streams,
+				 int downstream);
+int seg_calculate_distance(SEGMENT *output, int number_of_streams,
+			   int downstream);
+int seg_calculate_cell(SEGMENT *output, int number_of_streams,
+		       int downstream);
+int seg_calculate_local_gradient(SEGMENT *output, int number_of_streams,
+				 int downstream);
+int seg_calculate_gradient(SEGMENT *output, int number_of_streams,
+			   int downstream);
+int seg_calculate_curvature(SEGMENT *output, int number_of_streams,
+			    int downstream);

Added: grass-addons/grass7/grass7/raster/r.stream.channel/local_vars.h
===================================================================
--- grass-addons/grass7/grass7/raster/r.stream.channel/local_vars.h	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.stream.channel/local_vars.h	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,39 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include <grass/glocale.h>
+#include <grass/gis.h>
+#include <grass/raster.h>
+
+#define SQRT2 1.414214
+	
+
+	
+typedef struct {
+	int stream_num;
+	int number_of_cells;
+	int order;
+	unsigned long int * points;
+	float * elevation;
+	double * distance;
+	unsigned int init_r;
+	unsigned int init_c;
+} STREAM;	
+
+
+#ifdef MAIN
+#	define GLOBAL
+#else
+#	define GLOBAL extern
+#endif
+
+GLOBAL int nextr[9];
+GLOBAL int nextc[9];
+
+GLOBAL int nrows, ncols; 
+GLOBAL STREAM* stream_attributes;
+
+GLOBAL struct Cell_head window;
+
+

Added: grass-addons/grass7/grass7/raster/r.stream.channel/main.c
===================================================================
--- grass-addons/grass7/grass7/raster/r.stream.channel/main.c	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.stream.channel/main.c	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,340 @@
+
+/****************************************************************************
+ *
+ * MODULE:       r.stream.channel
+ * AUTHOR(S):    Jarek Jasiewicz jarekj amu.edu.pl
+ *               
+ * PURPOSE:      Program calculate some channel properities:
+ * 							 local elevation change, curvature along stream,
+ * 							 distance to channel init/join, elevation below channel init, 
+ * 							 optionally distance to outlet, elevation above outlet;
+        
+ * COPYRIGHT:    (C) 2002,2010 by the GRASS Development Team
+ *
+ *               This program is free software under the GNU General Public
+ *   	    	 	  License (>=v2). Read the file COPYING that comes with GRASS
+ *   	    	 	  for details.
+ *
+ *****************************************************************************/
+#define MAIN
+#include <grass/glocale.h>
+#include "local_proto.h"
+
+int nextr[9] = { 0, -1, -1, -1, 0, 1, 1, 1, 0 };
+int nextc[9] = { 0, 1, 0, -1, -1, -1, 0, 1, 1 };
+
+
+int main(int argc, char *argv[])
+{
+
+    /*
+       IO output[] = {
+       {"local_diff",NO,"Local elevation difference"},
+       {"out_dist",NO,"Upstream distance form init"},
+     */
+
+    struct GModule *module;
+    struct Option *in_dir_opt,	/* options */
+     *in_stm_opt,
+	*in_elev_opt,
+	*out_identifier_opt,
+	*out_distance_opt,
+	*out_difference_opt,
+	*out_gradient_opt, *out_curvature_opt, *opt_swapsize;
+
+    struct Flag *flag_segmentation,
+	*flag_local, *flag_cells, *flag_downstream;
+
+    char *method_name[] = { "UPSTREAM", "DOWNSTREAM" };
+    int number_of_segs;
+    int number_of_streams;
+    int segmentation, downstream, local, cells;	/*flags */
+
+    /* initialize GIS environment */
+    G_gisinit(argv[0]);
+
+    /* initialize module */
+    module = G_define_module();
+    G_add_keyword("Horton statisctics");
+    module->description =
+	_("Calculate local parameters for individual streams");
+    G_add_keyword("Stream parameters");
+    G_add_keyword("Stream gradient");
+    G_add_keyword("Stream curvature");
+
+    in_stm_opt = G_define_standard_option(G_OPT_R_INPUT);
+    in_stm_opt->key = "streams";
+    in_stm_opt->description = "Name of streams mask input map";
+
+    in_dir_opt = G_define_standard_option(G_OPT_R_INPUT);
+    in_dir_opt->key = "dirs";
+    in_dir_opt->description = "Name of flow direction input map";
+
+    in_elev_opt = G_define_standard_option(G_OPT_R_INPUT);
+    in_elev_opt->key = "elevation";
+    in_elev_opt->description = "Name of elevation map";
+
+    out_identifier_opt = G_define_standard_option(G_OPT_R_OUTPUT);
+    out_identifier_opt->key = "identifier";
+    out_identifier_opt->required = NO;
+    out_identifier_opt->description = "Unique identifier for stream";
+
+    out_distance_opt = G_define_standard_option(G_OPT_R_OUTPUT);
+    out_distance_opt->key = "distance";
+    out_distance_opt->required = NO;
+    out_distance_opt->description = "Distance from init/join/outlet";
+
+    out_difference_opt = G_define_standard_option(G_OPT_R_OUTPUT);
+    out_difference_opt->key = "difference";
+    out_difference_opt->required = NO;
+    out_difference_opt->description =
+	"Elevation differecne from init/join/outlet";
+
+    out_gradient_opt = G_define_standard_option(G_OPT_R_OUTPUT);
+    out_gradient_opt->key = "gradient";
+    out_gradient_opt->required = NO;
+    out_gradient_opt->description =
+	"Mean gradient of stream from init/join/outlet";
+
+    out_curvature_opt = G_define_standard_option(G_OPT_R_OUTPUT);
+    out_curvature_opt->key = "curvature";
+    out_curvature_opt->required = NO;
+    out_curvature_opt->description = "Local stream curvature";
+
+    opt_swapsize = G_define_option();
+    opt_swapsize->key = "memory";
+    opt_swapsize->type = TYPE_INTEGER;
+    opt_swapsize->answer = "300";
+    opt_swapsize->description = _("Max memory used in memory swap mode (MB)");
+    opt_swapsize->guisection = _("Optional");
+
+    flag_downstream = G_define_flag();
+    flag_downstream->key = 'd';
+    flag_downstream->description =
+	_("Calculate parameters from outlet (downstream values)");
+
+    flag_local = G_define_flag();
+    flag_local->key = 'l';
+    flag_local->description = _("Calculate local values (for current cell)");
+
+    flag_cells = G_define_flag();
+    flag_cells->key = 'c';
+    flag_cells->description = _("Calculate distance in cell (ignored local)");
+
+    flag_segmentation = G_define_flag();
+    flag_segmentation->key = 'm';
+    flag_segmentation->description = _("Use memory swap (operation is slow)");
+
+    if (G_parser(argc, argv))	/* parser */
+	exit(EXIT_FAILURE);
+
+    segmentation = (flag_segmentation->answer != 0);
+    downstream = (flag_downstream->answer != 0);
+
+    if (!out_identifier_opt->answer &&
+	!out_distance_opt->answer &&
+	!out_difference_opt->answer &&
+	!out_gradient_opt->answer && !out_curvature_opt->answer)
+	G_fatal_error(_("You must select at least one output maps"));
+
+    local = (flag_local->answer != 0);
+    cells = (flag_cells->answer != 0);
+    nrows = Rast_window_rows();
+    ncols = Rast_window_cols();
+    G_get_window(&window);
+    G_begin_distance_calculations();
+
+    if (out_identifier_opt->answer)
+	if (G_legal_filename(out_identifier_opt->answer) < 0)
+	    G_fatal_error(_("<%s> is an illegal difference map name"),
+			  out_identifier_opt->answer);
+
+    if (out_difference_opt->answer)
+	if (G_legal_filename(out_difference_opt->answer) < 0)
+	    G_fatal_error(_("<%s> is an illegal difference map name"),
+			  out_difference_opt->answer);
+
+    if (out_distance_opt->answer)
+	if (G_legal_filename(out_distance_opt->answer) < 0)
+	    G_fatal_error(_("<%s> is an illegal distance map name"),
+			  out_distance_opt->answer);
+
+    if (out_gradient_opt->answer)
+	if (G_legal_filename(out_gradient_opt->answer) < 0)
+	    G_fatal_error(_("<%s> is an illegal gradient map name"),
+			  out_gradient_opt->answer);
+
+    if (out_curvature_opt->answer)
+	if (G_legal_filename(out_curvature_opt->answer) < 0)
+	    G_fatal_error(_("<%s> is an illegal gradient map name"),
+			  out_curvature_opt->answer);
+
+    if (!segmentation) {
+	MAP map_dirs, map_streams, map_elevation, map_output, map_identifier;
+	CELL **streams, **dirs, **identifier = NULL;
+	FCELL **elevation;
+	DCELL **output;
+
+	G_message(_("ALL IN RAM CALCULATION - DIRECTION: %s"),
+		  method_name[downstream]);
+	ram_create_map(&map_streams, CELL_TYPE);
+	ram_read_map(&map_streams, in_stm_opt->answer, 1, CELL_TYPE);
+	ram_create_map(&map_dirs, CELL_TYPE);
+	ram_read_map(&map_dirs, in_dir_opt->answer, 1, CELL_TYPE);
+	ram_create_map(&map_elevation, FCELL_TYPE);
+	ram_read_map(&map_elevation, in_elev_opt->answer, 0, -1);
+
+	streams = (CELL **) map_streams.map;
+	dirs = (CELL **) map_dirs.map;
+	elevation = (FCELL **) map_elevation.map;
+
+	number_of_streams = ram_number_of_streams(streams, dirs) + 1;
+	ram_build_streamlines(streams, dirs, elevation, number_of_streams);
+	ram_release_map(&map_streams);
+	ram_release_map(&map_dirs);
+	ram_create_map(&map_output, DCELL_TYPE);
+	output = (DCELL **) map_output.map;	/* one output for all maps */
+
+	if (out_identifier_opt->answer) {
+	    ram_create_map(&map_identifier, CELL_TYPE);
+	    identifier = (CELL **) map_identifier.map;
+	    ram_calculate_identifiers(identifier, number_of_streams,
+				      downstream);
+	    ram_write_map(&map_identifier, out_identifier_opt->answer,
+			  CELL_TYPE, 1, 0);
+	    ram_release_map(&map_identifier);
+	}
+
+	if (out_difference_opt->answer) {
+	    ram_set_null_output(output);
+	    if (local)
+		ram_calculate_difference(output, number_of_streams,
+					 downstream);
+	    else
+		ram_calculate_drop(output, number_of_streams, downstream);
+	    ram_write_map(&map_output, out_difference_opt->answer, DCELL_TYPE,
+			  0, 0);
+	}
+
+	if (out_distance_opt->answer) {
+	    ram_set_null_output(output);
+	    if (local && !cells)
+		ram_calculate_local_distance(output, number_of_streams,
+					     downstream);
+	    if (!local && !cells)
+		ram_calculate_distance(output, number_of_streams, downstream);
+	    if (cells)
+		ram_calculate_cell(output, number_of_streams, downstream);
+	    ram_write_map(&map_output, out_distance_opt->answer, DCELL_TYPE,
+			  0, 0);
+	}
+
+	if (out_gradient_opt->answer) {
+	    ram_set_null_output(output);
+	    if (local)
+		ram_calculate_local_gradient(output, number_of_streams,
+					     downstream);
+	    else
+		ram_calculate_gradient(output, number_of_streams, downstream);
+	    ram_write_map(&map_output, out_gradient_opt->answer, DCELL_TYPE,
+			  0, 0);
+	}
+
+	if (out_curvature_opt->answer) {
+	    ram_set_null_output(output);
+	    ram_calculate_curvature(output, number_of_streams, downstream);
+	    ram_write_map(&map_output, out_curvature_opt->answer, DCELL_TYPE,
+			  0, 0);
+	}
+
+	ram_release_map(&map_output);
+    }
+
+
+    if (segmentation) {
+	SEG map_dirs, map_streams, map_elevation, map_output, map_identifier;
+	SEGMENT *streams, *dirs, *elevation, *output, *identifier;
+
+	G_message(_("SEGMENT CALCULATION: MAY TAKE SOME TIME- DIRECTION: %s"),
+		  method_name[downstream]);
+
+	number_of_segs = (int)atof(opt_swapsize->answer);
+	number_of_segs = number_of_segs < 32 ? (int)(32 / 0.18) : number_of_segs / 0.18;
+
+	seg_create_map(&map_streams, SROWS, SCOLS, number_of_segs, CELL_TYPE);
+	seg_read_map(&map_streams, in_stm_opt->answer, 1, CELL_TYPE);
+	seg_create_map(&map_dirs, SROWS, SCOLS, number_of_segs, CELL_TYPE);
+	seg_read_map(&map_dirs, in_dir_opt->answer, 1, CELL_TYPE);
+	seg_create_map(&map_elevation, SROWS, SCOLS, number_of_segs,
+		       FCELL_TYPE);
+	seg_read_map(&map_elevation, in_elev_opt->answer, 0, -1);
+
+	streams = &map_streams.seg;
+	dirs = &map_dirs.seg;
+	elevation = &map_elevation.seg;
+
+	number_of_streams = seg_number_of_streams(streams, dirs) + 1;
+	seg_build_streamlines(streams, dirs, elevation, number_of_streams);
+	seg_release_map(&map_streams);
+	seg_release_map(&map_dirs);
+	seg_create_map(&map_output, SROWS, SCOLS, number_of_segs, DCELL_TYPE);
+	output = &map_output.seg;	/* one output for all maps */
+
+	if (out_identifier_opt->answer) {
+	    seg_create_map(&map_identifier, SROWS, SCOLS, number_of_segs,
+			   CELL_TYPE);
+	    identifier = &map_identifier.seg;
+	    seg_calculate_identifiers(identifier, number_of_streams,
+				      downstream);
+	    seg_write_map(&map_identifier, out_identifier_opt->answer,
+			  CELL_TYPE, 1, 0);
+	    seg_release_map(&map_identifier);
+	}
+
+	if (out_difference_opt->answer) {
+	    seg_set_null_output(output);
+	    if (local)
+		seg_calculate_difference(output, number_of_streams,
+					 downstream);
+	    else
+		seg_calculate_drop(output, number_of_streams, downstream);
+	    seg_write_map(&map_output, out_difference_opt->answer, DCELL_TYPE,
+			  0, 0);
+	}
+
+	if (out_distance_opt->answer) {
+	    seg_set_null_output(output);
+	    if (local && !cells)
+		seg_calculate_local_distance(output, number_of_streams,
+					     downstream);
+	    if (!local && !cells)
+		seg_calculate_distance(output, number_of_streams, downstream);
+	    if (cells)
+		seg_calculate_cell(output, number_of_streams, downstream);
+	    seg_write_map(&map_output, out_distance_opt->answer, DCELL_TYPE,
+			  0, 0);
+	}
+
+	if (out_gradient_opt->answer) {
+	    seg_set_null_output(output);
+	    if (local)
+		seg_calculate_local_gradient(output, number_of_streams,
+					     downstream);
+	    else
+		seg_calculate_gradient(output, number_of_streams, downstream);
+	    seg_write_map(&map_output, out_gradient_opt->answer, DCELL_TYPE,
+			  0, 0);
+	}
+
+	if (out_curvature_opt->answer) {
+	    seg_set_null_output(output);
+	    seg_calculate_curvature(output, number_of_streams, downstream);
+	    seg_write_map(&map_output, out_curvature_opt->answer, DCELL_TYPE,
+			  0, 0);
+	}
+
+	seg_release_map(&map_output);
+    }
+    free_attributes(number_of_streams);
+    exit(EXIT_SUCCESS);
+}

Added: grass-addons/grass7/grass7/raster/r.stream.channel/r.stream.channel.html
===================================================================
--- grass-addons/grass7/grass7/raster/r.stream.channel/r.stream.channel.html	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.stream.channel/r.stream.channel.html	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,136 @@
+<h2>OPTIONS</h2>
+<dl>
+<dt><b>-l</b></dt>
+<dd>Calculate local values. See output for detials.</dd>
+<dt><b>-c</b></dt>
+<dd>Calculate distance in cells instead of meters. See output for detials.</dd>
+<dt><b>-d</b></dt>
+<dd>Calculate downstream distance (from current cell DOWNSTREAM to outlet/join).
+Default is upstream (from current cell upstream to init/join.</dd>
+<dt><b>-m</b></dt>
+<dd>Only for very large data sets. Use segment library to optimize memory
+consumption during analysis</dd>
+<dt><b>stream</b></dt>
+<dd>Stream network: name of input stream map. Map may be ordered according one
+of the r.stream.order ordering system as well as unordered (with origilan stream
+identifiers)  Because streams network produced by r.watershed and
+r.stream.extract may slighty differ in detail it is required to use both stream
+and direction map produced by the same module. Stream background shall have NULL
+value or zero value. Background values of NULL are by default produced by
+r.watershed and r.stream.extract. If not 0 or NULL use <a
+href="r.mapcalc.html">r.mapcalc</a> to set background values to null.  
+</dd>
+<dt><b>dir</b></dt>
+<dd>Flow direction: name of input direction map produced by r.watershed or
+r.stream.extract. If r.stream.extract output map is used, it only has non-NULL
+values in places where streams occur. NULL (nodata) cells are ignored, zero and
+negative values are valid direction data if they vary from -8 to 8 (CCW from
+East in steps of 45 degrees). Direction map shall be of type CELL values. Region
+resolution and map resoultion must be the same. 
+Also <em>stream</em> network map must have the same resolution. It is checked by
+default. If resolutions differ the module informs about it and stops. Region
+boundary and maps boundary may be differ but it may lead to unexpected
+results.</dd>
+<dt><b>elevation</b></dt>
+<dd>Elevation: name of input elevation map. Map can be of type CELL, FCELL or
+DCELL. It is not restricted to resolution of region settings as streams and
+dirs.</dd>
+</dl>
+<h2>OUTPUTS</h2>
+<dl>
+<dt><b>distance</b></dt>
+<dd>Upstream distance of current cell to the init/join. Flag modifications: <br>
+<b>d:</b> downstream distance of current cell to the join/outlet;<br>
+<b>l:</b> local distance between current cell and next cell. In most cases cell
+resolution and sqrt2 of cell resolution. usefull when projection is LL or NS and
+WE resolutions differs. Flag d ignored<br>
+<b>c:</b> distance in cells. Map is written as double. Use mapcalc to convetrt
+to integer. Flags l and d ignored.<br>
+</dd>
+<dt><b>difference</b></dt>
+<dd>Upstream elevation difference between current cell to the init/join. It we
+need to calculate parameters different than elevation. If we need to calculate
+different parameters than elevation along streams (for example precipitation or
+so) use neccesary map as elevation. Flag modifications: <br>
+<b>d:</b> downstream difference of current cell to the join/outlet;<br>
+<b>l:</b> local difference between current cell and next cell. With flag
+calculates difference between previous cell and current cell<br>
+<b>c:</b> Ignored.
+</dd>
+<dt><b>gradient</b></dt>
+<dd>Upstream mean gradient between current cell and the init/join.  Flag
+modifications: <br>
+<b>d:</b> downstream mean gradient between current cell and the the
+join/outlet;<br>
+<b>l:</b> local gradient between current cell and next cell. Flag d ignored<br>
+<b>c:</b> Ignored.
+</dd>
+<dt><b>curvature</b></dt>
+<dd>Local stream course curvature  of current cell. Calculated according
+formula: <i>first_derivative/(1-second_derivative<sup>2</sup>)<sup>3/2</sup></i>
+Flag modifications: <br>
+<b>d:</b> ignored;<br>
+<b>l:</b> Ignored.<br>
+<b>c:</b> Ignored.
+</dd>
+<dt><b>identifier</b></dt>
+<dd> Integer map: In ordered stream network there are more than one segment
+(segment: a part of the network where order ramains unchanged) with the same
+order. To identify particular segments (for further analysis) every segment
+recive his unique identifier.</dd>
+</dl>
+
+<h2>DESCRIPTION</h2>
+<p>
+Module r.stream.channel is prepared to calculate some local properties of the
+stream network. It is suplementary module for r.stream.order, and
+r.stream.distance to investigate channel subsystem. For slope subsystem
+parameters is r.stream.slope. It may use ordered or unordered network. It
+calculate parameters for every segment between it init to outlet/join to the
+next stream. it also may calculate parameters between outlet and segment's init.
+It can calculate parameters for every orders but best results are for these
+orders where order remains unchanged from stream init to natural outlet (Hack
+and Horton ordering).
+<p>
+
+<h2>EXAMPLE</h2>
+
+This example shows how to visualise the change of gradient map along the main
+stream of the catchment:
+
+<div class="code"><pre>
+r.watershed elevation=elevation.10m treshold=1000 stream=streams drainage=dirs
+r.stream.order streams=streams dirs=dirs hack=hack
+r.stream.channel streams=hack dirs=dirs elevation=elevation.10m
+identifier=stream_identifier gradient=stream_gradient distance=stream_distance
+#495 is a stream identifier. May be different in different situaltion
+r.mapcalc stgrad=if(stream_identifier==495,float(stream_gradient),null())
+r.mapcalc stdist=if(stream_identifier==495,float(stream_distance),null())
+
+#the rest data processing in R
+R
+library(spgrass6)
+r=readRAST6(c("stdist","stgrad"),NODATA=-9999)
+p=subset(r at data,!is.na(r at data$dist))
+sorted=p[order(p$stdist),]
+plot(sorted,stdist~stgrad,type="l")
+</pre></div>
+
+<h2>SEE ALSO</h2>
+
+<em>
+<a href="r.watershed.html">r.watershed</a>,
+<a href="r.stream.extract.html">r.stream.extract</a>,
+<a href="r.stream.order.html">r.stream.order</a>,
+<a href="r.stream.basins.html">r.stream.basins</a>,
+<a href="r.stream.slope.html">r.stream.slope</a>,
+<a href="r.stream.stats.html">r.stream.stats</a>,
+<a href="r.mapcalc.html">r.mapcalc</a>,
+</em>
+
+<h2>AUTHOR</h2>
+Jarek Jasiewicz, Adam Mickiewicz University, Geoecology and Geoinformation
+Institute.
+
+<p><i>Last changed: $Date: 2011-11-08 22:56:45 +0100 (Tue, 08 Nov 2011) $</i>
+

Added: grass-addons/grass7/grass7/raster/r.stream.channel/stream_topology.c
===================================================================
--- grass-addons/grass7/grass7/raster/r.stream.channel/stream_topology.c	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.stream.channel/stream_topology.c	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,424 @@
+#include "local_proto.h"
+double get_distance(int r, int c, int d)
+{
+    double northing, easting, next_northing, next_easting;
+    int next_r, next_c;
+
+    next_r = NR(d);
+    next_c = NC(d);
+    northing = window.north - (r + .5) * window.ns_res;
+    easting = window.west + (c + .5) * window.ew_res;
+    next_northing = window.north - (next_r + .5) * window.ns_res;
+    next_easting = window.west + (next_c + .5) * window.ew_res;
+    return G_distance(easting, northing, next_easting, next_northing);
+}
+
+int ram_trib_nums(int r, int c, CELL ** streams, CELL ** dirs)
+{				/* calculate number of tributuaries */
+
+    int trib_num = 0;
+    int i, j;
+    int next_r, next_c;
+
+    for (i = 1; i < 9; ++i) {
+	if (NOT_IN_REGION(i))
+	    continue;
+
+	j = DIAG(i);
+	next_r = NR(i);
+	next_c = NC(i);
+
+	if (streams[next_r][next_c] > 0 && dirs[next_r][next_c] == j)
+	    trib_num++;
+    }
+
+    if (trib_num > 1)
+	for (i = 1; i < 9; ++i) {
+	    if (NOT_IN_REGION(i))
+		continue;
+
+	    j = DIAG(i);
+	    next_r = NR(i);
+	    next_c = NC(i);
+
+	    if (streams[next_r][next_c] == streams[r][c] &&
+		dirs[next_r][next_c] == j)
+		trib_num--;
+	}
+
+    if (trib_num > 5)
+	G_fatal_error(_("Error finding inits. Stream and direction maps probably do not match..."));
+    if (trib_num > 3)
+	G_warning(_("Stream network may be too dense..."));
+
+    return trib_num;
+}				/* end trib_num */
+
+
+
+int ram_number_of_streams(CELL **streams, CELL **dirs)
+{
+    int r, c;
+    int stream_num = 0;
+
+    for (r = 0; r < nrows; ++r)
+	for (c = 0; c < ncols; ++c)
+	    if (streams[r][c] > 0)
+		if (ram_trib_nums(r, c, streams, dirs) != 1)
+		    stream_num++;
+    return stream_num;
+}
+
+int ram_build_streamlines(CELL **streams, CELL **dirs, FCELL **elevation,
+			  int number_of_streams)
+{
+    int r, c, i;
+    int d, next_d;
+    int prev_r, prev_c;
+    int stream_num = 1, cell_num = 0;
+    int contrib_cell;
+    STREAM *SA;
+
+    stream_num = 1;
+
+    Rast_get_window(&window);
+
+    stream_attributes =
+	(STREAM *) G_malloc(number_of_streams * sizeof(STREAM));
+    G_message("Finding inits...");
+    SA = stream_attributes;
+
+    for (r = 0; r < nrows; ++r)
+	for (c = 0; c < ncols; ++c)
+	    if (streams[r][c])
+		if (ram_trib_nums(r, c, streams, dirs) != 1) {	/* adding inits */
+		    if (stream_num > number_of_streams)
+			G_fatal_error(_("Error finding inits. Stream and direction maps probably do not match..."));
+
+		    SA[stream_num].stream_num = stream_num;
+		    SA[stream_num].init_r = r;
+		    SA[stream_num++].init_c = c;
+		}
+
+    for (i = 1; i < stream_num; ++i) {
+
+	r = SA[i].init_r;
+	c = SA[i].init_c;
+	SA[i].order = streams[r][c];
+	SA[i].number_of_cells = 0;
+	do {
+
+	    SA[i].number_of_cells++;
+	    d = abs(dirs[r][c]);
+	    if (NOT_IN_REGION(d) || d == 0)
+		break;
+	    r = NR(d);
+	    c = NC(d);
+	} while (streams[r][c] == SA[i].order);
+
+	SA[i].number_of_cells += 2;	/* add two extra points for init+ and outlet+ */
+    }
+
+    for (i = 1; i < number_of_streams; ++i) {
+
+	SA[i].points = (unsigned long int *)
+	    G_malloc((SA[i].number_of_cells) * sizeof(unsigned long int));
+	SA[i].elevation = (float *)
+	    G_malloc((SA[i].number_of_cells) * sizeof(float));
+	SA[i].distance = (double *)
+	    G_malloc((SA[i].number_of_cells) * sizeof(double));
+
+	r = SA[i].init_r;
+	c = SA[i].init_c;
+	contrib_cell = ram_find_contributing_cell(r, c, dirs, elevation);
+	prev_r = NR(contrib_cell);
+	prev_c = NC(contrib_cell);
+
+	/* add one point contributing to init to calculate parameters */
+	/* what to do if there is no contributing points? */
+	SA[i].points[0] = (contrib_cell == 0) ? -1 : INDEX(prev_r, prev_c);
+	SA[i].elevation[0] = (contrib_cell == 0) ? -99999 :
+	    elevation[prev_r][prev_c];
+	d = (contrib_cell == 0) ? dirs[r][c] : dirs[prev_r][prev_c];
+	SA[i].distance[0] = (contrib_cell == 0) ? get_distance(r, c, d) :
+	    get_distance(prev_r, prev_c, d);
+
+	SA[i].points[1] = INDEX(r, c);
+	SA[i].elevation[1] = elevation[r][c];
+	d = abs(dirs[r][c]);
+	SA[i].distance[1] = get_distance(r, c, d);
+
+	cell_num = 2;
+	do {
+	    d = abs(dirs[r][c]);
+
+	    if (NOT_IN_REGION(d) || d == 0) {
+		SA[i].points[cell_num] = -1;
+		SA[i].distance[cell_num] = SA[i].distance[cell_num - 1];
+		SA[i].elevation[cell_num] =
+		    2 * SA[i].elevation[cell_num - 1] -
+		    SA[i].elevation[cell_num - 2];
+		break;
+	    }
+	    r = NR(d);
+	    c = NC(d);
+	    SA[i].points[cell_num] = INDEX(r, c);
+	    SA[i].elevation[cell_num] = elevation[r][c];
+	    next_d = (abs(dirs[r][c]) == 0) ? d : abs(dirs[r][c]);
+	    SA[i].distance[cell_num] = get_distance(r, c, next_d);
+	    cell_num++;
+	    if (cell_num > SA[i].number_of_cells)
+		G_fatal_error(_("To much points in stream line..."));
+	} while (streams[r][c] == SA[i].order);
+
+	if (SA[i].elevation[0] == -99999)
+	    SA[i].elevation[0] = 2 * SA[i].elevation[1] - SA[i].elevation[2];
+    }
+
+    return 0;
+}
+
+int ram_find_contributing_cell(int r, int c, CELL **dirs, FCELL **elevation)
+{
+    int i, j = 0;
+    int next_r, next_c;
+    float elev_min = 9999;
+
+    for (i = 1; i < 9; ++i) {
+	if (NOT_IN_REGION(i))
+	    continue;
+	next_r = NR(i);
+	next_c = NC(i);
+	if (dirs[next_r][next_c] == DIAG(i) &&
+	    elevation[next_r][next_c] < elev_min) {
+	    elev_min = elevation[next_r][next_c];
+	    j = i;
+	}
+    }
+
+    return j;
+}
+
+int seg_trib_nums(int r, int c, SEGMENT * streams, SEGMENT * dirs)
+{				/* calculate number of tributuaries */
+
+    int trib_num = 0;
+    int i, j;
+    int next_r, next_c;
+    int streams_cell, streams_next_cell, dirs_next_cell;
+
+    segment_get(streams, &streams_cell, r, c);
+    for (i = 1; i < 9; ++i) {
+	if (NOT_IN_REGION(i))
+	    continue;
+
+	j = DIAG(i);
+	next_r = NR(i);
+	next_c = NC(i);
+	segment_get(streams, &streams_next_cell, next_r, next_c);
+	segment_get(dirs, &dirs_next_cell, next_r, next_c);
+	if (streams_next_cell > 0 && dirs_next_cell == j)
+	    trib_num++;
+    }
+
+    if (trib_num > 1)
+	for (i = 1; i < 9; ++i) {
+	    if (NOT_IN_REGION(i))
+		continue;
+
+	    j = DIAG(i);
+	    next_r = NR(i);
+	    next_c = NC(i);
+	    segment_get(streams, &streams_next_cell, next_r, next_c);
+	    segment_get(dirs, &dirs_next_cell, next_r, next_c);
+	    if (streams_next_cell == streams_cell && dirs_next_cell == j)
+		trib_num--;
+	}
+
+    if (trib_num > 5)
+	G_fatal_error(_("Error finding inits. Stream and direction maps probably do not match..."));
+    if (trib_num > 3)
+	G_warning(_("Stream network may be too dense..."));
+
+    return trib_num;
+}				/* end trib_num */
+
+int seg_number_of_streams(SEGMENT *streams, SEGMENT *dirs)
+{
+    int r, c;
+    int stream_num = 0;
+    int streams_cell;
+
+    for (r = 0; r < nrows; ++r)
+	for (c = 0; c < ncols; ++c) {
+	    segment_get(streams, &streams_cell, r, c);
+	    if (streams_cell > 0)
+		if (seg_trib_nums(r, c, streams, dirs) != 1)
+		    stream_num++;
+	}
+    G_message("%d", stream_num);
+    return stream_num;
+}
+
+int seg_build_streamlines(SEGMENT *streams, SEGMENT *dirs,
+			  SEGMENT *elevation, int number_of_streams)
+{
+    int r, c, i;
+    int d, next_d;
+    int prev_r, prev_c;
+    int streams_cell, dirs_cell;
+    float elevation_prev_cell;
+    int stream_num = 1, cell_num = 0;
+    int contrib_cell;
+    STREAM *SA;
+
+    stream_num = 1;
+
+
+    stream_attributes =
+	(STREAM *) G_malloc(number_of_streams * sizeof(STREAM));
+    G_message("Finding inits...");
+    SA = stream_attributes;
+
+    for (r = 0; r < nrows; ++r)
+	for (c = 0; c < ncols; ++c) {
+	    segment_get(streams, &streams_cell, r, c);
+	    if (streams_cell)
+		if (seg_trib_nums(r, c, streams, dirs) != 1) {	/* adding inits */
+		    if (stream_num > number_of_streams)
+			G_fatal_error(_("Error finding inits. Stream and direction maps probably do not match..."));
+
+		    SA[stream_num].stream_num = stream_num;
+		    SA[stream_num].init_r = r;
+		    SA[stream_num++].init_c = c;
+		}
+	}
+
+    for (i = 1; i < stream_num; ++i) {
+
+	r = SA[i].init_r;
+	c = SA[i].init_c;
+	segment_get(streams, &(SA[i].order), r, c);
+	//segment_get(streams,&streams_cell,r,c);
+	SA[i].number_of_cells = 0;
+	do {
+
+	    SA[i].number_of_cells++;
+	    segment_get(dirs, &dirs_cell, r, c);
+	    d = abs(dirs_cell);
+	    if (NOT_IN_REGION(d) || d == 0)
+		break;
+	    r = NR(d);
+	    c = NC(d);
+	    segment_get(streams, &streams_cell, r, c);
+	} while (streams_cell == SA[i].order);
+
+	SA[i].number_of_cells += 2;	/* add two extra points for init+ and outlet+ */
+    }
+
+    for (i = 1; i < number_of_streams; ++i) {
+
+	SA[i].points = (unsigned long int *)
+	    G_malloc((SA[i].number_of_cells) * sizeof(unsigned long int));
+	SA[i].elevation = (float *)
+	    G_malloc((SA[i].number_of_cells) * sizeof(float));
+	SA[i].distance = (double *)
+	    G_malloc((SA[i].number_of_cells) * sizeof(double));
+
+	r = SA[i].init_r;
+	c = SA[i].init_c;
+	contrib_cell =
+	    seg_find_contributing_cell(r, c, dirs, elevation);
+	prev_r = NR(contrib_cell);
+	prev_c = NC(contrib_cell);
+
+	/* add one point contributing to init to calculate parameters */
+	/* what to do if there is no contributing points? */
+	SA[i].points[0] = (contrib_cell == 0) ? -1 : INDEX(prev_r, prev_c);
+
+	segment_get(elevation, &elevation_prev_cell, prev_r, prev_c);
+	SA[i].elevation[0] = (contrib_cell == 0) ? -99999 :
+	    elevation_prev_cell;
+
+	if (contrib_cell == 0)
+	    segment_get(dirs, &d, r, c);
+	else
+	    segment_get(dirs, &d, prev_r, prev_c);
+	SA[i].distance[0] = (contrib_cell == 0) ? get_distance(r, c, d) :
+	    get_distance(prev_r, prev_c, d);
+
+	SA[i].points[1] = INDEX(r, c);
+	segment_get(elevation, &(SA[i].elevation[1]), r, c);
+	segment_get(dirs, &d, r, c);
+	SA[i].distance[1] = get_distance(r, c, d);
+
+	cell_num = 2;
+	do {
+	    segment_get(dirs, &dirs_cell, r, c);
+	    d = abs(dirs_cell);
+	    if (NOT_IN_REGION(d) || d == 0) {
+		SA[i].points[cell_num] = -1;
+		SA[i].distance[cell_num] = SA[i].distance[cell_num - 1];
+		SA[i].elevation[cell_num] =
+		    2 * SA[i].elevation[cell_num - 1] -
+		    SA[i].elevation[cell_num - 2];
+		break;
+	    }
+	    r = NR(d);
+	    c = NC(d);
+	    SA[i].points[cell_num] = INDEX(r, c);
+	    segment_get(elevation, &(SA[i].elevation[cell_num]), r, c);
+	    segment_get(dirs, &next_d, r, c);
+	    next_d = (abs(next_d) == 0) ? d : abs(next_d);
+	    SA[i].distance[cell_num] = get_distance(r, c, next_d);
+	    cell_num++;
+	    segment_get(streams, &streams_cell, r, c);
+	    if (cell_num > SA[i].number_of_cells)
+		G_fatal_error(_("To much points in stream line..."));
+	} while (streams_cell == SA[i].order);
+
+	if (SA[i].elevation[0] == -99999)
+	    SA[i].elevation[0] = 2 * SA[i].elevation[1] - SA[i].elevation[2];
+    }
+    return 0;
+}
+
+int seg_find_contributing_cell(int r, int c, SEGMENT *dirs,
+			       SEGMENT *elevation)
+{
+    int i, j = 0;
+    int next_r, next_c;
+    float elev_min = 9999;
+    int dirs_next_cell;
+    float elevation_next_cell;
+
+    for (i = 1; i < 9; ++i) {
+	if (NOT_IN_REGION(i))
+	    continue;
+	next_r = NR(i);
+	next_c = NC(i);
+	segment_get(dirs, &dirs_next_cell, next_r, next_c);
+	segment_get(elevation, &elevation_next_cell, next_r, next_c);
+	if (dirs_next_cell == DIAG(i) && elevation_next_cell < elev_min) {
+	    elev_min = elevation_next_cell;
+	    j = i;
+	}
+    }
+    return j;
+}
+
+int free_attributes(int number_of_streams)
+{
+    int i;
+    STREAM *SA;
+
+    SA = stream_attributes;
+
+    for (i = 1; i < number_of_streams; ++i) {
+	G_free(SA[i].points);
+	G_free(SA[i].elevation);
+	G_free(SA[i].distance);
+    }
+    G_free(stream_attributes);
+    return 0;
+}

Added: grass-addons/grass7/grass7/raster/r.stream.channel/stream_write.c
===================================================================
--- grass-addons/grass7/grass7/raster/r.stream.channel/stream_write.c	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.stream.channel/stream_write.c	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,505 @@
+#include "local_proto.h"
+int ram_set_null_output(DCELL **output)
+{
+
+    int r;
+
+    for (r = 0; r < nrows; ++r)
+	Rast_set_d_null_value(output[r], ncols);
+    return 0;
+}
+
+int seg_set_null_output(SEGMENT *output)
+{
+
+    int r, c;
+    double output_cell;
+
+    for (r = 0; r < nrows; ++r)
+	for (c = 0; c < ncols; ++c) {
+	    Rast_set_d_null_value(&output_cell, 1);
+	    segment_put(output, &output_cell, r, c);
+	}
+    return 0;
+}
+
+int ram_calculate_identifiers(CELL **identifier, int number_of_streams,
+			      int downstream)
+{
+    int r, c;
+    int i, j;
+    STREAM *SA;
+
+    SA = stream_attributes;
+
+    for (i = 1; i < number_of_streams; ++i) {
+	for (j = 1; j < SA[i].number_of_cells - 1; ++j) {
+	    r = (int)SA[i].points[j] / ncols;
+	    c = (int)SA[i].points[j] % ncols;
+	    identifier[r][c] = SA[i].stream_num;
+	}
+    }
+    return 0;
+}
+
+int seg_calculate_identifiers(SEGMENT *identifier, int number_of_streams,
+			      int downstream)
+{
+    int r, c;
+    int i, j;
+    STREAM *SA;
+
+    SA = stream_attributes;
+
+    for (i = 1; i < number_of_streams; ++i) {
+	for (j = 1; j < SA[i].number_of_cells - 1; ++j) {
+	    r = (int)SA[i].points[j] / ncols;
+	    c = (int)SA[i].points[j] % ncols;
+	    segment_put(identifier, &(SA[i].stream_num), r, c);
+	}
+    }
+    return 0;
+}
+
+
+int ram_calculate_distance(DCELL **output, int number_of_streams,
+			   int downstream)
+{
+    int r, c;
+    double cum_length;
+    int i, j;
+    STREAM *SA;
+
+    SA = stream_attributes;
+
+    for (i = 1; i < number_of_streams; ++i) {
+	cum_length = 0;
+	if (!downstream)
+	    for (j = 1; j < SA[i].number_of_cells - 1; ++j) {
+		cum_length += SA[i].distance[j];
+		r = (int)SA[i].points[j] / ncols;
+		c = (int)SA[i].points[j] % ncols;
+		output[r][c] = cum_length;
+	    }
+	else
+	    for (j = SA[i].number_of_cells - 2; j > 0; --j) {
+		cum_length += SA[i].distance[j];
+		r = (int)SA[i].points[j] / ncols;
+		c = (int)SA[i].points[j] % ncols;
+		output[r][c] = cum_length;
+	    }
+    }
+    return 0;
+}
+
+int seg_calculate_distance(SEGMENT *output, int number_of_streams,
+			   int downstream)
+{
+    int r, c;
+    double cum_length;
+    int i, j;
+    STREAM *SA;
+
+    SA = stream_attributes;
+
+    for (i = 1; i < number_of_streams; ++i) {
+	cum_length = 0;
+	if (!downstream)
+	    for (j = 1; j < SA[i].number_of_cells - 1; ++j) {
+		cum_length += SA[i].distance[j];
+		r = (int)SA[i].points[j] / ncols;
+		c = (int)SA[i].points[j] % ncols;
+		segment_put(output, &cum_length, r, c);
+	    }
+	else
+	    for (j = SA[i].number_of_cells - 2; j > 0; --j) {
+		cum_length += SA[i].distance[j];
+		r = (int)SA[i].points[j] / ncols;
+		c = (int)SA[i].points[j] % ncols;
+		segment_put(output, &cum_length, r, c);
+	    }
+    }
+    return 0;
+}
+
+int ram_calculate_cell(DCELL **output, int number_of_streams, int downstream)
+{
+    int r, c;
+    int i, j, k;
+    STREAM *SA;
+
+    SA = stream_attributes;
+
+    for (i = 1; i < number_of_streams; ++i) {
+
+	k = SA[i].number_of_cells - 2;
+	for (j = 1; j < SA[i].number_of_cells - 1; ++j, --k) {
+	    r = (int)SA[i].points[j] / ncols;
+	    c = (int)SA[i].points[j] % ncols;
+	    output[r][c] = downstream ? k : j;
+	}
+    }
+    return 0;
+}
+
+int seg_calculate_cell(SEGMENT *output, int number_of_streams,
+		       int downstream)
+{
+    int r, c;
+    int i, j, k;
+    double output_cell;
+    STREAM *SA;
+
+    SA = stream_attributes;
+
+    for (i = 1; i < number_of_streams; ++i) {
+
+	k = SA[i].number_of_cells - 2;
+	for (j = 1; j < SA[i].number_of_cells - 1; ++j, --k) {
+	    r = (int)SA[i].points[j] / ncols;
+	    c = (int)SA[i].points[j] % ncols;
+	    output_cell = downstream ? k : j;
+	    segment_put(output, &output_cell, r, c);
+	}
+    }
+    return 0;
+}
+
+int ram_calculate_difference(DCELL **output, int number_of_streams,
+			     int downstream)
+{
+    int r, c;
+    int i, j;
+    double result;
+    STREAM *SA;
+
+    SA = stream_attributes;
+
+    for (i = 1; i < number_of_streams; ++i) {
+
+	for (j = 1; j < SA[i].number_of_cells - 1; ++j) {
+	    result = downstream ?
+		SA[i].elevation[j - 1] - SA[i].elevation[j] :
+		SA[i].elevation[j] - SA[i].elevation[j + 1];
+	    r = (int)SA[i].points[j] / ncols;
+	    c = (int)SA[i].points[j] % ncols;
+	    output[r][c] = result;
+	}
+    }
+    return 0;
+}
+
+int seg_calculate_difference(SEGMENT *output, int number_of_streams,
+			     int downstream)
+{
+    int r, c;
+    int i, j;
+    double output_cell;
+    STREAM *SA;
+
+    SA = stream_attributes;
+
+    for (i = 1; i < number_of_streams; ++i) {
+
+	for (j = 1; j < SA[i].number_of_cells - 1; ++j) {
+	    output_cell = downstream ?
+		SA[i].elevation[j - 1] - SA[i].elevation[j] :
+		SA[i].elevation[j] - SA[i].elevation[j + 1];
+	    r = (int)SA[i].points[j] / ncols;
+	    c = (int)SA[i].points[j] % ncols;
+	    segment_put(output, &output_cell, r, c);
+	}
+    }
+    return 0;
+}
+
+int ram_calculate_drop(DCELL **output, int number_of_streams, int downstream)
+{
+    int r, c;
+    int i, j;
+    double init;
+    STREAM *SA;
+
+    SA = stream_attributes;
+
+    for (i = 1; i < number_of_streams; ++i) {
+	if (!downstream) {
+	    init = SA[i].elevation[1];
+	    for (j = 1; j < SA[i].number_of_cells - 1; ++j) {
+		r = (int)SA[i].points[j] / ncols;
+		c = (int)SA[i].points[j] % ncols;
+		output[r][c] = init - SA[i].elevation[j];
+	    }
+	}
+	else {
+	    init = SA[i].elevation[SA[i].number_of_cells - 2];
+	    for (j = SA[i].number_of_cells - 2; j > 0; --j) {
+		r = (int)SA[i].points[j] / ncols;
+		c = (int)SA[i].points[j] % ncols;
+		output[r][c] = SA[i].elevation[j] - init;
+	    }
+	}
+    }
+    return 0;
+}
+
+int seg_calculate_drop(SEGMENT *output, int number_of_streams,
+		       int downstream)
+{
+    int r, c;
+    int i, j;
+    double init;
+    double output_cell;
+    STREAM *SA;
+
+    SA = stream_attributes;
+
+    for (i = 1; i < number_of_streams; ++i) {
+	if (!downstream) {
+	    init = SA[i].elevation[1];
+	    for (j = 1; j < SA[i].number_of_cells - 1; ++j) {
+		r = (int)SA[i].points[j] / ncols;
+		c = (int)SA[i].points[j] % ncols;
+		output_cell = init - SA[i].elevation[j];
+		segment_put(output, &output_cell, r, c);
+	    }
+	}
+	else {
+	    init = SA[i].elevation[SA[i].number_of_cells - 2];
+	    for (j = SA[i].number_of_cells - 2; j > 0; --j) {
+		r = (int)SA[i].points[j] / ncols;
+		c = (int)SA[i].points[j] % ncols;
+		output_cell = SA[i].elevation[j] - init;
+		segment_put(output, &output_cell, r, c);
+	    }
+	}
+    }
+    return 0;
+}
+
+int ram_calculate_gradient(DCELL **output, int number_of_streams,
+			   int downstream)
+{
+    int r, c;
+    int i, j;
+    double init;
+    double cum_length;
+    STREAM *SA;
+
+    SA = stream_attributes;
+
+    for (i = 1; i < number_of_streams; ++i) {
+	cum_length = 0;
+	if (!downstream) {
+	    init = SA[i].elevation[0];
+	    for (j = 1; j < SA[i].number_of_cells - 1; ++j) {
+		cum_length += SA[i].distance[j];
+		r = (int)SA[i].points[j] / ncols;
+		c = (int)SA[i].points[j] % ncols;
+		output[r][c] = (init - SA[i].elevation[j]) / cum_length;
+	    }
+	}
+	else {
+	    init = SA[i].elevation[SA[i].number_of_cells - 1];
+	    for (j = SA[i].number_of_cells - 2; j > 0; --j) {
+		cum_length += SA[i].distance[j];
+		r = (int)SA[i].points[j] / ncols;
+		c = (int)SA[i].points[j] % ncols;
+		output[r][c] = (SA[i].elevation[j] - init) / cum_length;
+	    }
+	}
+    }
+    return 0;
+}
+
+int seg_calculate_gradient(SEGMENT *output, int number_of_streams,
+			   int downstream)
+{
+    int r, c;
+    int i, j;
+    double init;
+    double output_cell;
+    double cum_length;
+    STREAM *SA;
+
+    SA = stream_attributes;
+
+    for (i = 1; i < number_of_streams; ++i) {
+	cum_length = 0;
+	if (!downstream) {
+	    init = SA[i].elevation[1];
+	    for (j = 1; j < SA[i].number_of_cells - 1; ++j) {
+		cum_length += SA[i].distance[j];
+		r = (int)SA[i].points[j] / ncols;
+		c = (int)SA[i].points[j] % ncols;
+		output_cell = (init - SA[i].elevation[j]) / cum_length;
+		segment_put(output, &output_cell, r, c);
+
+	    }
+	}
+	else {
+	    init = SA[i].elevation[SA[i].number_of_cells - 2];
+	    for (j = SA[i].number_of_cells - 2; j > 0; --j) {
+		cum_length += SA[i].distance[j];
+		r = (int)SA[i].points[j] / ncols;
+		c = (int)SA[i].points[j] % ncols;
+		output_cell = (SA[i].elevation[j] - init) / cum_length;
+		segment_put(output, &output_cell, r, c);
+	    }
+	}
+    }
+    return 0;
+}
+
+int ram_calculate_local_gradient(DCELL **output, int number_of_streams,
+				 int downstream)
+{
+    int r, c;
+    int i, j;
+    double elev_diff;
+    STREAM *SA;
+
+    SA = stream_attributes;
+
+    for (i = 1; i < number_of_streams; ++i) {
+	for (j = 1; j < SA[i].number_of_cells - 1; ++j) {
+	    r = (int)SA[i].points[j] / ncols;
+	    c = (int)SA[i].points[j] % ncols;
+	    elev_diff =
+		(SA[i].elevation[j] - SA[i].elevation[j + 1]) <
+		0 ? 0 : (SA[i].elevation[j] - SA[i].elevation[j + 1]);
+	    output[r][c] = elev_diff / SA[i].distance[j];
+	}
+    }
+    return 0;
+}
+
+int seg_calculate_local_gradient(SEGMENT *output, int number_of_streams,
+				 int downstream)
+{
+    int r, c;
+    int i, j;
+    double elev_diff;
+    double output_cell;
+    STREAM *SA;
+
+    SA = stream_attributes;
+
+    for (i = 1; i < number_of_streams; ++i) {
+	for (j = 1; j < SA[i].number_of_cells - 1; ++j) {
+	    r = (int)SA[i].points[j] / ncols;
+	    c = (int)SA[i].points[j] % ncols;
+	    elev_diff =
+		(SA[i].elevation[j] - SA[i].elevation[j + 1]) <
+		0 ? 0 : (SA[i].elevation[j] - SA[i].elevation[j + 1]);
+	    output_cell = elev_diff / SA[i].distance[j];
+	    segment_put(output, &output_cell, r, c);
+	}
+    }
+    return 0;
+}
+
+
+int ram_calculate_local_distance(DCELL **output, int number_of_streams,
+				 int downstream)
+{
+    int r, c;
+    int i, j;
+    STREAM *SA;
+
+    SA = stream_attributes;
+
+    for (i = 1; i < number_of_streams; ++i) {
+	for (j = 1; j < SA[i].number_of_cells - 1; ++j) {
+	    r = (int)SA[i].points[j] / ncols;
+	    c = (int)SA[i].points[j] % ncols;
+	    output[r][c] = SA[i].distance[j];
+	}
+    }
+    return 0;
+}
+
+int seg_calculate_local_distance(SEGMENT *output, int number_of_streams,
+				 int downstream)
+{
+    int r, c;
+    int i, j;
+    double output_cell;
+    STREAM *SA;
+
+    SA = stream_attributes;
+
+    for (i = 1; i < number_of_streams; ++i) {
+	for (j = 1; j < SA[i].number_of_cells - 1; ++j) {
+	    r = (int)SA[i].points[j] / ncols;
+	    c = (int)SA[i].points[j] % ncols;
+	    output_cell = SA[i].distance[j];
+	    segment_put(output, &output_cell, r, c);
+	}
+    }
+    return 0;
+}
+
+int ram_calculate_curvature(DCELL **output, int number_of_streams,
+			    int downstream)
+{
+    int r, c;
+    int i, j;
+    STREAM *SA;
+    double first_derivative, second_derivative;
+
+    SA = stream_attributes;
+
+    for (i = 1; i < number_of_streams; ++i) {
+	for (j = 1; j < SA[i].number_of_cells - 1; ++j) {
+	    r = (int)SA[i].points[j] / ncols;
+	    c = (int)SA[i].points[j] % ncols;
+	    first_derivative =
+		(SA[i].elevation[j - 1] -
+		 SA[i].elevation[j + 1]) / (SA[i].distance[j - 1] +
+					    SA[i].distance[j]);
+	    second_derivative =
+		((SA[i].elevation[j - 1] - SA[i].elevation[j]) -
+		 (SA[i].elevation[j] -
+		  SA[i].elevation[j + 1])) / (SA[i].distance[j - 1] +
+					      SA[i].distance[j]);
+	    output[r][c] =
+		first_derivative /
+		pow((1 + second_derivative * second_derivative), 1.5);
+	}
+    }
+    return 0;
+}
+
+int seg_calculate_curvature(SEGMENT *output, int number_of_streams,
+			    int downstream)
+{
+    int r, c;
+    int i, j;
+    double output_cell;
+    STREAM *SA;
+    double first_derivative, second_derivative;
+
+    SA = stream_attributes;
+
+    for (i = 1; i < number_of_streams; ++i) {
+	for (j = 1; j < SA[i].number_of_cells - 1; ++j) {
+	    r = (int)SA[i].points[j] / ncols;
+	    c = (int)SA[i].points[j] % ncols;
+	    first_derivative =
+		(SA[i].elevation[j - 1] -
+		 SA[i].elevation[j + 1]) / (SA[i].distance[j - 1] +
+					    SA[i].distance[j]);
+	    second_derivative =
+		((SA[i].elevation[j - 1] - SA[i].elevation[j]) -
+		 (SA[i].elevation[j] -
+		  SA[i].elevation[j + 1])) / (SA[i].distance[j - 1] +
+					      SA[i].distance[j]);
+	    output_cell =
+		first_derivative /
+		pow((1 + second_derivative * second_derivative), 1.5);
+	    segment_put(output, &output_cell, r, c);
+	}
+    }
+    return 0;
+}

Added: grass-addons/grass7/grass7/raster/r.stream.distance/Makefile
===================================================================
--- grass-addons/grass7/grass7/raster/r.stream.distance/Makefile	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.stream.distance/Makefile	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,11 @@
+MODULE_TOPDIR = ../..
+
+PGM = r.stream.distance
+
+LIBES = $(GISLIB) $(RASTERLIB) $(SEGMENTLIB)
+DEPENDENCIES = $(GISDEP) $(RASTERDEP) $(SEGMENTDEP)
+
+include $(MODULE_TOPDIR)/include/Make/Module.make
+
+default: cmd
+

Added: grass-addons/grass7/grass7/raster/r.stream.distance/distance_calc.c
===================================================================
--- grass-addons/grass7/grass7/raster/r.stream.distance/distance_calc.c	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.stream.distance/distance_calc.c	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,628 @@
+#include "local_proto.h"
+static int tail, head, fifo_count;
+
+int fifo_insert(POINT point)
+{
+    if (fifo_count == fifo_max)
+	G_fatal_error("fifo queue: circular buffer too small");
+
+    fifo_points[tail++] = point;
+    if (tail > fifo_max) {
+	G_debug(1, "tail > fifo_max");
+	tail = 0;
+    }
+    fifo_count++;
+    return 0;
+}
+
+POINT fifo_return_del(void)
+{
+    if (head >= fifo_max) {
+	G_debug(1, "head >= fifo_max");
+	head = -1;
+    }
+    fifo_count--;
+
+    return fifo_points[++head];
+}
+
+
+int ram_calculate_downstream(CELL ** dirs, FCELL ** distance,
+			     FCELL ** elevation, OUTLET outlet, int outs)
+{
+
+    int r, c, i, j;
+    int next_r, next_c;
+    POINT n_cell;
+    float cur_dist = 0;
+    float tmp_dist = 0;
+    float target_elev;		/* eleavation at stream or outlet */
+    float easting, northing;
+    float cell_easting, cell_northing;
+    struct Cell_head window;
+
+    Rast_get_window(&window);
+
+    tail = 0;
+    head = -1;
+    r = outlet.r;
+    c = outlet.c;
+
+    if (elevation) {
+	target_elev = elevation[r][c];
+	elevation[r][c] = 0.;
+    }
+
+    while (tail != head) {
+	easting = window.west + (c + .5) * window.ew_res;
+	northing = window.north - (r + .5) * window.ns_res;
+
+	for (i = 1; i < 9; ++i) {
+
+	    if (NOT_IN_REGION(i))
+		continue;	/* border */
+
+	    j = DIAG(i);
+	    next_r = NR(i);
+	    next_c = NC(i);
+	    if (dirs[NR(i)][NC(i)] == j) {	/* countributing cell, reset distance and elevation */
+
+		if (outs) {	/* outlet mode */
+
+		    if (distance[NR(i)][NC(i)] == 0)
+			continue;	/* continue loop, point is not added to the queue! */
+		    else {
+			cell_northing =
+			    window.north - (next_r + .5) * window.ns_res;
+			cell_easting =
+			    window.west + (next_c + .5) * window.ew_res;
+			cur_dist =
+			    tmp_dist + G_distance(easting, northing,
+						  cell_easting,
+						  cell_northing);
+			distance[NR(i)][NC(i)] = cur_dist;
+		    }
+
+		}
+		else {		/* stream mode */
+
+		    if (distance[next_r][next_c] == 0) {
+			cur_dist = 0;
+			if (elevation)
+			    target_elev = elevation[next_r][next_c];
+		    }
+		    else {
+			cell_northing =
+			    window.north - (next_r + .5) * window.ns_res;
+			cell_easting =
+			    window.west + (next_c + .5) * window.ew_res;
+			cur_dist =
+			    tmp_dist + G_distance(easting, northing,
+						  cell_easting,
+						  cell_northing);
+			distance[NR(i)][NC(i)] = cur_dist;
+		    }
+		}		/* end stream mode */
+
+		if (elevation) {
+		    elevation[next_r][next_c] =
+			elevation[next_r][next_c] - target_elev;
+		    n_cell.target_elev = target_elev;
+		}
+
+		n_cell.r = next_r;
+		n_cell.c = next_c;
+		n_cell.cur_dist = cur_dist;
+		fifo_insert(n_cell);
+	    }
+	}			/* end for i... */
+
+	n_cell = fifo_return_del();
+	r = n_cell.r;
+	c = n_cell.c;
+	tmp_dist = n_cell.cur_dist;
+	target_elev = n_cell.target_elev;
+
+    }				/* end while */
+    return 0;
+}
+
+int seg_calculate_downstream(SEGMENT *dirs, SEGMENT * distance,
+			     SEGMENT *elevation, OUTLET outlet, int outs)
+{
+
+    int r, c, i, j;
+    int next_r, next_c;
+    POINT n_cell;
+    float cur_dist = 0;
+    float tmp_dist = 0;
+    float target_elev;		/* eleavation at stream or outlet */
+    float easting, northing;
+    float cell_easting, cell_northing;
+    CELL dirs_cell;
+    FCELL distance_cell, elevation_cell;
+    FCELL zero_cell = 0;
+    struct Cell_head window;
+
+    Rast_get_window(&window);
+
+    tail = 0;
+    head = -1;
+    r = outlet.r;
+    c = outlet.c;
+
+    if (elevation) {
+	segment_get(elevation, &target_elev, r, c);
+	segment_put(elevation, &zero_cell, r, c);
+    }
+
+    while (tail != head) {
+	easting = window.west + (c + .5) * window.ew_res;
+	northing = window.north - (r + .5) * window.ns_res;
+
+	for (i = 1; i < 9; ++i) {
+
+	    if (NOT_IN_REGION(i))
+		continue;	/* border */
+
+	    j = DIAG(i);
+	    next_r = NR(i);
+	    next_c = NC(i);
+
+	    segment_get(dirs, &dirs_cell, next_r, next_c);
+	    if (dirs_cell == j) {	/* countributing cell, reset distance and elevation */
+
+		if (outs) {	/* outlet mode */
+		    segment_get(distance, &distance_cell, next_r, next_c);
+		    if (distance_cell == 0)
+			continue;	/* continue loop, point is not added to the queue! */
+		    else {
+			cell_northing =
+			    window.north - (next_r + .5) * window.ns_res;
+			cell_easting =
+			    window.west + (next_c + .5) * window.ew_res;
+			cur_dist =
+			    tmp_dist + G_distance(easting, northing,
+						  cell_easting,
+						  cell_northing);
+			segment_put(distance, &cur_dist, next_r, next_c);
+
+		    }
+
+		}
+		else {		/* stream mode */
+		    segment_get(distance, &distance_cell, next_r, next_c);
+		    if (distance_cell == 0) {
+			cur_dist = 0;
+			if (elevation)
+			    segment_get(elevation, &target_elev, next_r,
+					next_c);
+		    }
+		    else {
+			cell_northing =
+			    window.north - (next_r + .5) * window.ns_res;
+			cell_easting =
+			    window.west + (next_c + .5) * window.ew_res;
+			cur_dist =
+			    tmp_dist + G_distance(easting, northing,
+						  cell_easting,
+						  cell_northing);
+			segment_put(distance, &cur_dist, next_r, next_c);
+		    }
+		}		/* end stream mode */
+
+		if (elevation) {
+		    segment_get(elevation, &elevation_cell, next_r, next_c);
+		    elevation_cell -= target_elev;
+		    segment_put(elevation, &elevation_cell, next_r, next_c);
+		    n_cell.target_elev = target_elev;
+		}
+
+		n_cell.r = next_r;
+		n_cell.c = next_c;
+		n_cell.cur_dist = cur_dist;
+		fifo_insert(n_cell);
+	    }
+	}			/* end for i... */
+
+	n_cell = fifo_return_del();
+	r = n_cell.r;
+	c = n_cell.c;
+	tmp_dist = n_cell.cur_dist;
+	target_elev = n_cell.target_elev;
+
+    }				/* end while */
+    return 0;
+}
+
+int ram_fill_basins(OUTLET outlet, FCELL ** distance, CELL ** dirs)
+{
+    /* fill empty spaces with zeros but leave -1 as a markers of NULL */
+    int r, c, i, j;
+    int next_r, next_c;
+    float stop, val;
+    POINT n_cell;
+
+    tail = 0;
+    head = -1;
+    r = outlet.r;
+    c = outlet.c;
+    val = 1;
+    stop = 0;
+
+    distance[r][c] = stop;
+
+    while (tail != head) {
+	for (i = 1; i < 9; ++i) {
+	    if (NOT_IN_REGION(i))
+		continue;	/* out of border */
+
+	    j = DIAG(i);
+	    next_r = NR(i);
+	    next_c = NC(i);
+
+	    if (dirs[next_r][next_c] == j) {	/* countributing cell */
+
+		distance[next_r][next_c] =
+		    (distance[next_r][next_c] == stop) ? stop : val;
+		n_cell.r = next_r;
+		n_cell.c = next_c;
+		fifo_insert(n_cell);
+	    }
+
+	}			/* end for i... */
+
+	n_cell = fifo_return_del();
+	r = n_cell.r;
+	c = n_cell.c;
+    }
+
+    return 0;
+}
+
+int seg_fill_basins(OUTLET outlet, SEGMENT * distance, SEGMENT * dirs)
+{
+    /* fill empty spaces with zeros but leave -1 as a markers of NULL */
+    int r, c, i, j;
+    int next_r, next_c;
+    float stop, val;
+    POINT n_cell;
+    CELL dirs_cell;
+    FCELL distance_cell;
+
+    tail = 0;
+    head = -1;
+    r = outlet.r;
+    c = outlet.c;
+    val = 1;
+    stop = 0;
+
+    segment_put(distance, &stop, r, c);
+
+    while (tail != head) {
+
+	for (i = 1; i < 9; ++i) {
+	    if (NOT_IN_REGION(i))
+		continue;	/* out of border */
+
+	    j = DIAG(i);
+	    next_r = NR(i);
+	    next_c = NC(i);
+
+	    segment_get(dirs, &dirs_cell, next_r, next_c);
+
+	    if (dirs_cell == j) {	/* countributing cell */
+
+		segment_get(distance, &distance_cell, next_r, next_c);
+		distance_cell = (distance_cell == stop) ? stop : val;
+		segment_put(distance, &distance_cell, next_r, next_c);
+		n_cell.r = next_r;
+		n_cell.c = next_c;
+		fifo_insert(n_cell);
+
+	    }
+	}			/* end for i... */
+
+	n_cell = fifo_return_del();
+	r = n_cell.r;
+	c = n_cell.c;
+    }
+
+    return 0;
+}
+
+int ram_calculate_upstream(FCELL ** distance, CELL ** dirs,
+			   FCELL ** elevation, FCELL ** tmp_elevation,
+			   int near)
+{
+    int r, c;
+    int next_r, next_c;
+    float easting, northing;
+    float cell_easting, cell_northing;
+    int i, j, k, d;
+    int done;
+    int counter;
+    int n_inits = 0;
+    float cur_dist;
+    POINT *d_inits;
+    float tmp_dist = 0;
+    float target_elev = 0;
+    size_t elevation_data_size;
+    struct Cell_head window;
+
+    Rast_get_window(&window);
+
+    if (elevation) {
+	elevation_data_size = Rast_cell_size(FCELL_TYPE);
+	for (r = 0; r < nrows; ++r)
+	    memcpy(tmp_elevation[r], elevation[r],
+		   ncols * elevation_data_size);
+    }
+
+    for (r = 0; r < nrows; ++r)
+	for (c = 0; c < ncols; ++c) {
+
+	    for (i = 1; i < 9; ++i) {
+		if (NOT_IN_REGION(i))
+		    continue;	/* out of border */
+
+		j = DIAG(i);
+		next_r = NR(i);
+		next_c = NC(i);
+		if (dirs[next_r][next_c] == j && distance[r][c] != 0) {	/* is contributing cell */
+		    distance[r][c] = -1;
+		    break;
+		}
+	    }
+	    if (distance[r][c] == 1 && dirs[r][c] > 0)
+		n_inits++;
+	    else if (dirs[r][c] > 0)
+		distance[r][c] = -1;
+	}
+
+    d_inits = (POINT *) G_malloc(n_inits * sizeof(POINT));
+
+    k = 0;
+    for (r = 0; r < nrows; ++r)
+	for (c = 0; c < ncols; ++c) {
+
+	    if (distance[r][c] == 1) {
+
+		distance[r][c] = 0;
+		if (elevation)
+		    elevation[r][c] = 0;
+
+		d = dirs[r][c];
+
+		if (dirs[NR(d)][NC(d)] < 0)
+		    continue;
+
+		d_inits[k].r = r;
+		d_inits[k].c = c;
+		d_inits[k].cur_dist = 0;
+
+
+		if (elevation)
+		    d_inits[k].target_elev = tmp_elevation[r][c];
+
+		k++;
+	    }
+	}
+
+    counter = n_inits = k;
+    //return 0; // do usunięcia
+    G_message("Calculate upstream parameters...");
+    while (n_inits > 0) {
+	k = 0;
+	G_percent((counter - n_inits), counter, 10);
+	for (i = 0; i < n_inits; ++i) {
+	    r = d_inits[i].r;
+	    c = d_inits[i].c;
+	    d = dirs[r][c];
+	    next_r = NR(d);
+	    next_c = NC(d);
+	    tmp_dist = d_inits[i].cur_dist;
+
+	    if (elevation)
+		target_elev = d_inits[i].target_elev;
+
+	    easting = window.west + (c + 0.5) * window.ew_res;
+	    northing = window.north - (r + 0.5) * window.ns_res;
+	    cell_easting = window.west + (next_c + 0.5) * window.ew_res;
+	    cell_northing = window.north - (next_r + 0.5) * window.ns_res;
+
+	    cur_dist = tmp_dist +
+		G_distance(easting, northing, cell_easting, cell_northing);
+
+	    if (near)
+		done = (distance[next_r][next_c] > cur_dist ||
+			distance[next_r][next_c] <= 0) ? 1 : 0;
+	    else
+		done = (distance[next_r][next_c] < cur_dist ||
+			distance[next_r][next_c] <= 0) ? 1 : 0;
+
+	    if (done) {
+		distance[next_r][next_c] = cur_dist;
+		if (elevation) {
+		    elevation[next_r][next_c] =
+			target_elev - tmp_elevation[next_r][next_c];
+		}
+		if (dirs[NR(d)][NC(d)] < 1)
+		    continue;
+
+		d_inits[k].r = next_r;
+		d_inits[k].c = next_c;
+		d_inits[k].cur_dist = cur_dist;
+
+		if (elevation)
+		    d_inits[k].target_elev = target_elev;
+		k++;
+	    }			/* end of if done */
+	}
+	n_inits = k;
+    }
+    G_percent((counter - n_inits), counter, 10);
+    return 0;
+}
+
+
+int seg_calculate_upstream(SEGMENT * distance, SEGMENT * dirs,
+			   SEGMENT * elevation, SEGMENT * tmp_elevation,
+			   int near)
+{
+    int r, c;
+    int next_r, next_c;
+    float easting, northing;
+    float cell_easting, cell_northing;
+    int i, j, k, d, d_next;
+    FCELL minus_one_cell = -1;
+    FCELL zero_cell = 0;
+    int done;
+    int counter;
+    int n_inits = 0;
+    float cur_dist;
+    POINT *d_inits;
+    float tmp_dist = 0;
+    float target_elev = 0;
+    CELL dirs_cell;
+    FCELL distance_cell, elevation_cell, tmp_elevation_cell;
+    size_t elevation_data_size;
+    struct Cell_head window;
+
+    Rast_get_window(&window);
+
+    if (elevation) {
+	elevation_data_size = Rast_cell_size(FCELL_TYPE);
+	for (r = 0; r < nrows; ++r)
+	    for (c = 0; c < ncols; ++c) {
+		segment_get(elevation, &elevation_cell, r, c);
+		segment_put(tmp_elevation, &elevation_cell, r, c);
+	    }
+    }
+
+    for (r = 0; r < nrows; ++r)
+	for (c = 0; c < ncols; ++c) {
+
+	    segment_get(distance, &distance_cell, r, c);
+
+	    for (i = 1; i < 9; ++i) {
+		if (NOT_IN_REGION(i))
+		    continue;	/* out of border */
+
+		j = DIAG(i);
+		next_r = NR(i);
+		next_c = NC(i);
+
+		segment_get(dirs, &dirs_cell, next_r, next_c);
+
+		if (dirs_cell == j && distance_cell != 0) {	/* is contributing cell */
+		    segment_put(distance, &minus_one_cell, r, c);
+		    break;
+		}
+	    }			/* end for i */
+
+	    segment_get(distance, &distance_cell, r, c);
+	    segment_get(dirs, &dirs_cell, r, c);
+	    if (distance_cell == 1) {
+		if (distance_cell == 1 && dirs_cell > 0)
+		    n_inits++;
+		else if (dirs_cell > 0)
+		    segment_put(distance, &minus_one_cell, r, c);
+	    }
+
+	}
+
+    d_inits = (POINT *) G_malloc(n_inits * sizeof(POINT));
+
+    k = 0;
+    for (r = 0; r < nrows; ++r)
+	for (c = 0; c < ncols; ++c) {
+
+	    segment_get(distance, &distance_cell, r, c);
+	    if (distance_cell == 1) {
+
+		segment_put(distance, &zero_cell, r, c);
+		if (elevation)
+		    segment_put(elevation, &zero_cell, r, c);
+
+		segment_get(dirs, &d, r, c);
+		segment_get(dirs, &d_next, NR(d), NR(d));
+
+		if (d_next < 0)
+		    continue;
+
+		d_inits[k].r = r;
+		d_inits[k].c = c;
+		d_inits[k].cur_dist = 0;
+
+		if (elevation)
+		    segment_get(tmp_elevation, &(d_inits[k].target_elev), r,
+				c);
+		k++;
+	    }
+	}
+
+    counter = n_inits = k;
+
+    G_message("Calculate upstream parameters...");
+    while (n_inits > 0) {
+	k = 0;
+	G_percent((counter - n_inits), counter, 10);
+
+	for (i = 0; i < n_inits; ++i) {
+	    r = d_inits[i].r;
+	    c = d_inits[i].c;
+
+	    segment_get(dirs, &d, r, c);
+	    next_r = NR(d);
+	    next_c = NC(d);
+	    tmp_dist = d_inits[i].cur_dist;
+
+	    if (elevation)
+		target_elev = d_inits[i].target_elev;
+
+	    easting = window.west + (c + 0.5) * window.ew_res;
+	    northing = window.north - (r + 0.5) * window.ns_res;
+	    cell_easting = window.west + (next_c + 0.5) * window.ew_res;
+	    cell_northing = window.north - (next_r + 0.5) * window.ns_res;
+
+	    cur_dist = tmp_dist +
+		G_distance(easting, northing, cell_easting, cell_northing);
+
+	    segment_get(distance, &distance_cell, next_r, next_c);
+
+	    if (near)
+		done = (distance_cell > cur_dist ||
+			distance_cell <= 0) ? 1 : 0;
+	    else
+		done = (distance_cell < cur_dist ||
+			distance_cell <= 0) ? 1 : 0;
+
+	    if (done) {
+		segment_put(distance, &cur_dist, next_r, next_c);
+		if (elevation) {
+		    segment_get(tmp_elevation, &tmp_elevation_cell, next_r,
+				next_c);
+		    tmp_elevation_cell = target_elev - tmp_elevation_cell;
+		    segment_put(elevation, &tmp_elevation_cell, next_r,
+				next_c);
+		}
+
+		segment_get(dirs, &dirs_cell, NR(d), NC(d));
+		if (dirs_cell < 1)
+		    continue;
+
+		d_inits[k].r = next_r;
+		d_inits[k].c = next_c;
+		d_inits[k].cur_dist = cur_dist;
+
+		if (elevation)
+		    d_inits[k].target_elev = target_elev;
+		k++;
+	    }			/* end of if done */
+	}
+	n_inits = k;
+    }
+    G_percent((counter - n_inits), counter, 10);
+    return 0;
+}

Added: grass-addons/grass7/grass7/raster/r.stream.distance/distance_init.c
===================================================================
--- grass-addons/grass7/grass7/raster/r.stream.distance/distance_init.c	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.stream.distance/distance_init.c	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,208 @@
+#include "local_proto.h"
+
+int ram_find_outlets(CELL ** streams, int number_of_streams, CELL ** dirs,
+		     int subs, int outs)
+{
+    int d;			/* d: direction */
+    int r, c;
+    int next_stream = -1, cur_stream;
+    int out_max = ncols + nrows;
+    int outlets_num;
+
+    G_message(_("Finding nodes..."));
+    outlets = (OUTLET *) G_malloc((out_max) * sizeof(OUTLET));
+
+    outlets_num = 0;
+
+    for (r = 0; r < nrows; ++r)
+	for (c = 0; c < ncols; ++c)
+	    if (streams[r][c] > 0) {
+		if (outlets_num > (out_max - 1)) {
+		    if (outlets_num > 4 * (out_max - 1))
+			G_fatal_error
+			    ("Stream and direction maps probably do not match");
+		    out_max *= 4;
+		    outlets =
+			(OUTLET *) G_realloc(outlets,
+					     (out_max) * sizeof(OUTLET));
+		}
+
+		d = abs(dirs[r][c]);	/* r.watershed */
+
+		if (NOT_IN_REGION(d)) {
+		    next_stream = -1;
+		}
+		else {
+		    next_stream = streams[NR(d)][NC(d)];
+		    if (next_stream < 1)
+			next_stream = -1;
+		}
+
+		if (d == 0)
+		    next_stream = -1;
+
+		cur_stream = streams[r][c];
+
+		if (subs && outs) {	/* in stream mode subs is ignored */
+		    if (cur_stream != next_stream) {	/* is outlet or node! */
+			outlets[outlets_num].r = r;
+			outlets[outlets_num++].c = c;
+		    }
+		}
+		else {
+		    if (next_stream < 0) {	/* is outlet! */
+			outlets[outlets_num].r = r;
+			outlets[outlets_num++].c = c;
+		    }
+		}		/* end lasts */
+	    }			/* end if streams */
+
+    return outlets_num;
+}
+
+
+int seg_find_outlets(SEGMENT * streams, int number_of_streams, SEGMENT * dirs,
+		     int subs, int outs)
+{
+    int d;			/* d: direction */
+    int r, c;
+    int next_stream = -1;
+    int out_max = ncols + nrows;
+    int outlets_num;
+    CELL streams_cell;
+    CELL dirs_cell;
+
+    G_message(_("Finding nodes..."));
+    outlets = (OUTLET *) G_malloc((out_max) * sizeof(OUTLET));
+
+    outlets_num = 0;
+
+    for (r = 0; r < nrows; ++r)
+	for (c = 0; c < ncols; ++c) {
+	    segment_get(streams, &streams_cell, r, c);
+
+	    if (streams_cell > 0) {
+		if (outlets_num > (out_max - 1)) {
+		    if (outlets_num > 4 * (out_max - 1))
+			G_fatal_error
+			    ("Stream and direction maps probably do not match");
+		    out_max *= 4;
+		    outlets =
+			(OUTLET *) G_realloc(outlets,
+					     (out_max) * sizeof(OUTLET));
+		}
+
+		segment_get(dirs, &dirs_cell, r, c);
+		d = abs(dirs_cell);	/* r.watershed */
+
+		if (NOT_IN_REGION(d)) {
+		    next_stream = -1;
+		}
+		else {
+		    segment_get(streams, &next_stream, NR(d), NC(d));
+		    if (next_stream < 1)
+			next_stream = -1;
+		}
+
+		if (d == 0)
+		    next_stream = -1;
+
+		if (subs && outs) {	/* in stream mode subs is ignored */
+		    if (streams_cell != next_stream) {	/* is outlet or node! */
+			outlets[outlets_num].r = r;
+			outlets[outlets_num++].c = c;
+		    }
+		}
+		else {
+		    if (next_stream < 0) {	/* is outlet! */
+			outlets[outlets_num].r = r;
+			outlets[outlets_num++].c = c;
+		    }
+		}		/* end lasts */
+	    }			/* end if streams */
+	}			/* end for c */
+    return outlets_num;
+}
+
+int ram_init_distance(CELL ** streams, FCELL ** distance, int outlets_num,
+		      int outs)
+{
+    int r, c, i;
+    size_t data_size;
+
+    data_size = Rast_cell_size(FCELL_TYPE);
+
+    if (!outs) {		/* stream mode */
+	for (r = 0; r < nrows; ++r)
+	    for (c = 0; c < ncols; ++c)
+		distance[r][c] = (streams[r][c]) ? 0 : -1;
+    }
+    else {			/* outlets mode */
+	for (r = 0; r < nrows; ++r)
+	    for (c = 0; c < ncols; ++c)
+		distance[r][c] = -1;
+
+	for (i = 0; i < outlets_num; ++i)
+	    distance[outlets[i].r][outlets[i].c] = 0;
+    }
+
+    return 0;
+}
+
+int seg_init_distance(SEGMENT * streams, SEGMENT * distance, int outlets_num,
+		      int outs)
+{
+    int r, c, i;
+    CELL streams_cell;
+    FCELL distance_cell;
+    FCELL minus_one_cell = -1;
+    FCELL zero_cell = 0;
+
+    if (!outs) {		/* stream mode */
+	for (r = 0; r < nrows; ++r)
+	    for (c = 0; c < ncols; ++c) {
+		segment_get(streams, &streams_cell, r, c);
+		distance_cell = (streams_cell) ? 0 : -1;
+		segment_put(distance, &distance_cell, r, c);
+	    }
+    }
+    else {			/* outlets mode */
+	for (r = 0; r < nrows; ++r)
+	    for (c = 0; c < ncols; ++c)
+		segment_put(distance, &minus_one_cell, r, c);
+
+	for (i = 0; i < outlets_num; ++i)
+	    segment_put(distance, &zero_cell, outlets[i].r, outlets[i].c);
+    }
+    return 0;
+}
+
+int ram_prep_null_elevation(FCELL ** distance, FCELL ** elevation)
+{
+
+    int r, c;
+
+    for (r = 0; r < nrows; ++r)
+	for (c = 0; c < ncols; ++c)
+	    if (distance[r][c] == -1) {
+		elevation[r][c] = -1;
+	    }
+
+    return 0;
+}
+
+
+int seg_prep_null_elevation(SEGMENT * distance, SEGMENT * elevation)
+{
+    int r, c;
+    FCELL distance_cell;
+
+    for (r = 0; r < nrows; ++r)
+	for (c = 0; c < ncols; ++c) {
+	    segment_get(distance, &distance_cell, r, c);
+	    if (distance_cell == -1)
+		segment_put(elevation, &distance_cell, r, c);
+	}
+
+    return 0;
+}

Added: grass-addons/grass7/grass7/raster/r.stream.distance/io.c
===================================================================
--- grass-addons/grass7/grass7/raster/r.stream.distance/io.c	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.stream.distance/io.c	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,564 @@
+#include "io.h"
+/* all in ram functions section */
+
+int ram_create_map(MAP * map, RASTER_MAP_TYPE data_type)
+{
+
+    /* 
+     * allocates 0 filled nrows*ncols map of type void;
+     * map parameters are stored in structure;
+     * map: map to be created;
+     * map type to be created must be CELL, FCELL, DCELL;
+     * */
+
+    int r;
+
+    if (data_type < 0 || data_type > 2)
+	G_fatal_error(_("ram_creat: Cannot create map of unrecognised type"));
+
+    map->data_type = data_type;
+    map->map_name = NULL;
+    map->nrows = Rast_window_rows();
+    map->ncols = Rast_window_cols();
+    map->data_size = Rast_cell_size(data_type);
+
+    /* preparing internal map */
+    switch (map->data_type) {
+    case CELL_TYPE:
+	map->map = G_calloc(map->nrows, sizeof(CELL *));
+	break;
+
+    case FCELL_TYPE:
+	map->map = G_calloc(map->nrows, sizeof(FCELL *));
+	break;
+
+    case DCELL_TYPE:
+	map->map = G_calloc(map->nrows, sizeof(DCELL *));
+	break;
+    }
+
+    for (r = 0; r < map->nrows; ++r)
+	(map->map)[r] = G_calloc(map->ncols, map->data_size);
+
+    return 0;
+}
+
+int ram_read_map(MAP * map, char *input_map_name, int check_res,
+		 RASTER_MAP_TYPE check_data_type)
+{
+    /*
+     * Funciton read external map and put it in MAP structure (created with create_map)
+     * map: map to be read can be of any data type, read map is converted to target map if neccesary.
+     * input_map_name: name of the map to be read;
+     * map pointer to map stucture (created with create_map);
+     * check_res: [1]: check res correspondence between region and map [0 no check];
+     * check_data_type [CELL, FCELL, DCELL] check if reading map is of particular type, [-1] no check;
+     */
+
+    int r, c;
+    char *mapset;
+    struct Cell_head cellhd, this_window;
+    char *maptypes[] = { "CELL", "FCELL", "DCELL" };
+    int input_map_fd;
+    RASTER_MAP_TYPE input_data_type;
+    size_t input_data_size;
+    void *input_buffer = NULL;
+    void *input_pointer;
+
+    /* checking if map exist */
+    mapset = (char *)G_find_raster2(input_map_name, "");
+    if (mapset == NULL)
+	G_fatal_error(_("Raster map <%s> not found"), input_map_name);
+
+    /* checking if region and input are the same */
+    G_get_window(&this_window);
+    Rast_get_cellhd(input_map_name, mapset, &cellhd);
+    if (check_res)
+	if (this_window.ew_res != cellhd.ew_res ||
+	    this_window.ns_res != cellhd.ns_res)
+	    G_fatal_error(_("Region resolution and map %s resolution differs. \
+		Run g.region rast=%s to set proper region resolution"),
+			  input_map_name, input_map_name);
+
+    /* checking if input map is of required type */
+    if (check_data_type != map->data_type)
+	G_debug(1,
+		"ram_open:required map type and internal map type differs: conversion forced!");
+    input_data_type = Rast_map_type(input_map_name, mapset);
+    if (check_data_type != -1)
+	if (input_data_type != check_data_type)
+	    G_fatal_error(_("<%s> is not of type %s"),
+			  input_map_name, maptypes[check_data_type]);
+
+    input_map_fd = Rast_open_old(input_map_name, mapset);
+    input_data_size = Rast_cell_size(input_data_type);
+
+    {				/* reading range */
+	struct Range map_range;
+	struct FPRange map_fp_range;
+	int min, max;
+
+	if (input_data_type == CELL_TYPE) {
+	    Rast_init_range(&map_range);
+	    Rast_read_range(input_map_name, mapset, &map_range);
+	    Rast_get_range_min_max(&map_range, &min, &max);
+	    map->min = (double)min;
+	    map->max = (double)max;
+	}
+	else {
+	    Rast_init_fp_range(&map_fp_range);
+	    Rast_read_fp_range(input_map_name, mapset, &map_fp_range);
+	    Rast_get_fp_range_min_max(&map_fp_range, &(map->min),
+				      &(map->max));
+	}
+    }
+    /* end opening and checking */
+
+    input_buffer = Rast_allocate_buf(input_data_type);
+
+    /* start reading */
+    G_message(_("Reading map <%s>"), input_map_name);
+
+    for (r = 0; r < map->nrows; ++r) {
+	G_percent(r, map->nrows, 2);
+
+	Rast_get_row(input_map_fd, input_buffer, r, input_data_type);
+	input_pointer = input_buffer;
+
+	for (c = 0; c < map->ncols; ++c)
+	    if (!Rast_is_null_value
+		(input_pointer + c * input_data_size, input_data_type))
+		switch (map->data_type) {
+		case CELL_TYPE:
+		    ((CELL **) map->map)[r][c] =
+			Rast_get_c_value(input_pointer + c * input_data_size,
+					 input_data_type);
+		    break;
+		case FCELL_TYPE:
+		    ((FCELL **) map->map)[r][c] =
+			Rast_get_f_value(input_pointer + c * input_data_size,
+					 input_data_type);
+		    break;
+		case DCELL_TYPE:
+		    ((DCELL **) map->map)[r][c] =
+			Rast_get_d_value(input_pointer + c * input_data_size,
+					 input_data_type);
+		    break;
+		default:
+		    G_fatal_error(_("ram_open:Wrong internal data type"));
+		    break;
+		}
+    }				/*end for r */
+
+    G_free(input_buffer);
+    G_percent(r, map->nrows, 2);
+    Rast_close(input_map_fd);
+    return 0;
+}				/* end create floating point map */
+
+int ram_reset_map(MAP * map, int value)
+{
+    /*
+     * set all cells in the map to value
+     */
+    int r;
+
+    for (r = 0; r < map->nrows; ++r)
+	memset((map->map)[r], value, map->ncols * map->data_size);
+    return 0;
+}
+
+int ram_write_map(MAP * map, char *output_map_name,
+		  RASTER_MAP_TYPE output_data_type, int convert_to_null,
+		  double value)
+{
+    /* 
+     * write map to disk with output_map_name and output_data_type [CELL, FCELL, DCELL];
+     * if output_data_type = -1 than internal map type is used for output;
+     * if output map != -1 and types differ data_type, conversion is forced
+     * convert to null: check if convert to null a particular value in dataset;
+     */
+
+    int r, c;
+    int output_fd = 0;
+    struct History history;
+    void *row;
+
+    /* check for output format */
+    if (output_data_type == -1)
+	output_data_type = map->data_type;
+
+    if (output_data_type != map->data_type)
+	G_debug(1,
+		"ram_write:required map type and internal map type differs: conversion forced!");
+
+    G_message(_("Writing map <%s>"), output_map_name);
+    output_fd = Rast_open_new(output_map_name, output_data_type);
+
+    /* writing */
+    for (r = 0; r < map->nrows; ++r) {
+	G_percent(r, map->nrows, 2);
+
+	if (convert_to_null) {
+	    row = map->map[r];
+	    switch (map->data_type) {
+	    case CELL_TYPE:
+		for (c = 0; c < map->ncols; ++c)
+		    if (((CELL *) row)[c] == (CELL) value)
+			Rast_set_c_null_value(row + c * (map->data_size), 1);
+		break;
+	    case FCELL_TYPE:
+		for (c = 0; c < map->ncols; ++c)
+		    if (((FCELL *) row)[c] == (FCELL) value)
+			Rast_set_f_null_value(row + c * (map->data_size), 1);
+		break;
+	    case DCELL_TYPE:
+		for (c = 0; c < map->ncols; ++c)
+		    if (((DCELL *) row)[c] == (DCELL) value)
+			Rast_set_d_null_value(row + c * (map->data_size), 1);
+		break;
+	    default:
+		G_debug(1, "ram_null:Cannot convert to null at: %d %d", r, c);
+	    }
+	}
+
+	Rast_put_row(output_fd, (map->map)[r], output_data_type);
+    }
+    G_percent(r, map->nrows, 2);
+    Rast_close(output_fd);
+    Rast_short_history(output_map_name, "raster", &history);
+    Rast_command_history(&history);
+    Rast_write_history(output_map_name, &history);
+    G_message(_("<%s> Done"), output_map_name);
+    return 0;
+}
+
+int ram_release_map(MAP *map)
+{
+    /* 
+     * free memory allocated for map, set pointer to null;
+     */
+    int r;
+
+    for (r = 0; r < map->nrows; ++r)
+	G_free((map->map)[r]);
+    G_free(map->map);
+    map = NULL;
+    return 0;
+}
+
+
+/* memory swap functions section */
+
+
+int seg_create_map(SEG * seg, int srows, int scols, int number_of_segs,
+		   RASTER_MAP_TYPE data_type)
+{
+    /* create segment  and returns pointer to it;
+     * seg must be declared first;
+     * parameters are stored in structure;
+     * seg: segment to be created;
+     * srows, scols segment size
+     * number of segs max number of segs stored in memory
+     * data_type to be created must be CELL, FCELL, DCELL;
+     */
+
+    char *filename;
+    int fd;
+    int local_number_of_segs;
+
+    seg->fd = -1;
+    seg->filename = NULL;
+    seg->map_name = NULL;
+    seg->mapset = NULL;
+    seg->data_type = data_type;
+    seg->nrows = Rast_window_rows();
+    seg->ncols = Rast_window_cols();
+
+    local_number_of_segs =
+	(seg->nrows / srows + 1) * (seg->ncols / scols + 1);
+    number_of_segs =
+	(number_of_segs >
+	 local_number_of_segs) ? local_number_of_segs : number_of_segs;
+
+    G_debug(3, "seg_creat:number of segments %d", number_of_segs);
+
+    switch (seg->data_type) {
+    case CELL_TYPE:
+	seg->data_size = sizeof(CELL);
+	break;
+    case FCELL_TYPE:
+	seg->data_size = sizeof(FCELL);
+	break;
+    case DCELL_TYPE:
+	seg->data_size = sizeof(DCELL);
+	break;
+    default:
+	G_fatal_error(_("seg_create: unrecognisabe data type"));
+    }
+
+    filename = G_tempfile();
+    fd = creat(filename, 0666);
+
+    if (0 >
+	segment_format(fd, seg->nrows, seg->ncols, srows, scols,
+		       seg->data_size)) {
+	close(fd);
+	unlink(filename);
+	G_fatal_error(_("seg_create: cannot format segment"));
+    }
+
+    close(fd);
+    if (0 > (fd = open(filename, 2))) {
+	unlink(filename);
+	G_fatal_error(_("seg_create: cannot re-open file"));
+    }
+
+    if (0 > (fd = segment_init(&(seg->seg), fd, number_of_segs))) {
+	unlink(filename);
+	G_fatal_error(_("seg_create: cannot init segment file or out of memory"));
+    }
+
+    seg->filename = G_store(filename);
+    seg->fd = fd;
+    return 0;
+}
+
+int seg_read_map(SEG * seg, char *input_map_name, int check_res,
+		 RASTER_MAP_TYPE check_data_type)
+{
+
+    /*
+     * Funciton read external map and put it in SEG structure (created with seg_create_map)
+     * map to be read can be of any data type, read map is converted if neccesary.
+     * input_map_name: name of the map to be read;
+     * seg: pointer to map stucture (created with create_map);
+     * check_res: [1]: check res correspondence between region and map [0 no check];
+     * check_data_type [CELL, FCELL, DCELL] check if reading map is of particular type, [-1] no check;
+     */
+
+    int input_fd;
+    int r, c;
+    char *mapset;
+    struct Cell_head cellhd, this_window;
+    char *maptypes[] = { "CELL", "FCELL", "DCELL" };
+    RASTER_MAP_TYPE input_data_type;
+    size_t input_data_size;
+    void *input_buffer = NULL;
+    void *target_buffer = NULL;
+    void *input_pointer = NULL;
+
+    /* checking if map exist */
+    mapset = (char *)G_find_raster2(input_map_name, "");
+    if (mapset == NULL)
+	G_fatal_error(_("seg_read:Raster map <%s> not found"),
+		      input_map_name);
+    seg->mapset = mapset;
+
+    /* checking if region and input are the same */
+    G_get_window(&this_window);
+    Rast_get_cellhd(input_map_name, mapset, &cellhd);
+
+    /* check resolution equal anyinteger check;  equal 0 no check */
+    if (check_res)
+	if (this_window.ew_res != cellhd.ew_res ||
+	    this_window.ns_res != cellhd.ns_res)
+	    G_fatal_error(_("Region resolution and map %s resolution differs. \
+		Run g.region rast=%s to set proper region resolution"),
+			  input_map_name, input_map_name);
+
+    if (check_data_type != seg->data_type)
+	G_debug(1,
+		"ram_open:required map type and internal map type differs: conversion forced!");
+    input_data_type = Rast_map_type(input_map_name, mapset);
+    if (check_data_type != -1)
+	if (input_data_type != check_data_type)
+	    G_fatal_error(_("<%s> is not of type %s"),
+			  input_map_name, maptypes[check_data_type]);
+
+    input_fd = Rast_open_old(input_map_name, mapset);
+    input_data_size = Rast_cell_size(input_data_type);
+
+    {				/* reading range */
+	struct Range map_range;
+	struct FPRange map_fp_range;
+	int min, max;
+
+	if (input_data_type == CELL_TYPE) {
+	    Rast_init_range(&map_range);
+	    Rast_read_range(input_map_name, mapset, &map_range);
+	    Rast_get_range_min_max(&map_range, &min, &max);
+	    seg->min = (double)min;
+	    seg->max = (double)max;
+	}
+	else {
+	    Rast_init_fp_range(&map_fp_range);
+	    Rast_read_fp_range(input_map_name, mapset, &map_fp_range);
+	    Rast_get_fp_range_min_max(&map_fp_range, &(seg->min),
+				      &(seg->max));
+	}
+    }
+
+    /* end opening and checking */
+
+    G_message(_("Reading map <%s>"), input_map_name);
+    input_buffer = Rast_allocate_buf(input_data_type);
+
+    target_buffer = Rast_allocate_buf(seg->data_type);
+
+    for (r = 0; r < seg->nrows; ++r) {
+	G_percent(r, seg->nrows, 2);
+	Rast_get_row(input_fd, input_buffer, r, input_data_type);
+	input_pointer = input_buffer;
+	memset(target_buffer, 0, seg->ncols * seg->data_size);
+
+	for (c = 0; c < seg->ncols; ++c)
+	    if (!Rast_is_null_value
+		(input_pointer + c * input_data_size, input_data_type)) {
+		switch (seg->data_type) {
+		case CELL_TYPE:
+		    ((CELL *) target_buffer)[c] =
+			Rast_get_c_value(input_pointer + c * input_data_size,
+					 input_data_type);
+		    break;
+		case FCELL_TYPE:
+		    ((FCELL *) target_buffer)[c] =
+			Rast_get_f_value(input_pointer + c * input_data_size,
+					 input_data_type);
+		    break;
+		case DCELL_TYPE:
+		    ((DCELL *) target_buffer)[c] =
+			Rast_get_d_value(input_pointer + c * input_data_size,
+					 input_data_type);
+		    break;
+		default:
+		    G_fatal_error(_("Wrong internal data type"));
+		    break;
+		}
+	    }
+
+	if (0 > segment_put_row(&(seg->seg), target_buffer, r)) {
+	    G_free(input_buffer);
+	    G_free(target_buffer);
+	    Rast_close(input_fd);
+	    G_fatal_error(_("seg_read: Cannot segment put row %d for map %s"),
+			  r, input_map_name);
+	}
+    }				/* end for row */
+
+    G_percent(r, seg->nrows, 2);
+    Rast_close(input_fd);
+    G_free(input_buffer);
+    G_free(target_buffer);
+
+    seg->map_name = G_store(input_map_name);
+    seg->mapset = G_store(mapset);
+
+    return 0;
+}
+
+int seg_reset_map(SEG * seg, int value)
+{
+    /*
+     * set all cells in the map to value
+     */
+    int r, c;
+
+    for (r = 0; r < seg->nrows; ++r)
+	for (c = 0; c < seg->ncols; ++c)
+	    segment_put(&(seg->seg), &value, r, c);
+
+    return 0;
+}
+
+int seg_write_map(SEG * seg, char *output_map_name,
+		  RASTER_MAP_TYPE output_data_type, int convert_to_null,
+		  double value)
+{
+    /* 
+     * write seg to disk with output_map_name and output_data_type [CELL, FCELL, DCELL];
+     * if output_data_type = -1 than internal map type is used for output;
+     * if output map != -1 and types differ data_type, conversion is forced
+     * convert to null: check if convert to null a particular value in dataset;
+     */
+    int output_fd;
+    int r, c;
+    void *output_buffer;
+    void *row;
+    struct History history;
+
+    /* check for output format */
+    if (output_data_type == -1)
+	output_data_type = seg->data_type;
+
+    if (output_data_type != seg->data_type)
+	G_debug(1,
+		"ram_write:required map type and internal map type differs: conversion forced!");
+
+    G_message(_("Writing map <%s>"), output_map_name);
+    output_fd = Rast_open_new(output_map_name, output_data_type);
+    output_buffer = Rast_allocate_buf(output_data_type);
+    segment_flush(&(seg->seg));
+
+    /* writing */
+    for (r = 0; r < seg->nrows; ++r) {
+
+	G_percent(r, seg->nrows, 2);
+	if (0 > segment_get_row(&(seg->seg), output_buffer, r))
+	    G_warning(_("seg_write: Cannot segment read row %d for map %s"),
+		      r, output_map_name);
+
+	if (convert_to_null) {
+
+	    row = output_buffer;
+	    switch (seg->data_type) {
+	    case CELL_TYPE:
+		for (c = 0; c < seg->ncols; ++c)
+		    if (((CELL *) output_buffer)[c] == (CELL) value)
+			Rast_set_c_null_value(row + c * (seg->data_size), 1);
+		break;
+	    case FCELL_TYPE:
+		for (c = 0; c < seg->ncols; ++c)
+		    if (((FCELL *) output_buffer)[c] == (FCELL) value)
+			Rast_set_f_null_value(row + c * (seg->data_size), 1);
+		break;
+	    case DCELL_TYPE:
+		for (c = 0; c < seg->ncols; ++c)
+		    if (((DCELL *) output_buffer)[c] == (DCELL) value)
+			Rast_set_d_null_value(row + c * (seg->data_size), 1);
+		break;
+	    default:
+		G_warning(_("ram_null:Cannot convert to null at: %d %d"), r,
+			  c);
+	    }
+	}
+	Rast_put_row(output_fd, output_buffer, output_data_type);
+    }
+
+    G_percent(r, seg->nrows, 2);
+    G_free(output_buffer);
+    Rast_close(output_fd);
+    Rast_short_history(output_map_name, "raster", &history);
+    Rast_command_history(&history);
+    Rast_write_history(output_map_name, &history);
+    G_message(_("%s Done"), output_map_name);
+
+    return 0;
+}
+
+int seg_release_map(SEG * seg)
+{
+    /* 
+     * release segment close files, set pointers to null;
+     */
+    segment_release(&(seg->seg));
+    close(seg->fd);
+    unlink(seg->filename);
+
+    if (seg->map_name)
+	G_free(seg->map_name);
+    if (seg->mapset)
+	G_free(seg->mapset);
+
+    return 0;
+}

Added: grass-addons/grass7/grass7/raster/r.stream.distance/io.h
===================================================================
--- grass-addons/grass7/grass7/raster/r.stream.distance/io.h	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.stream.distance/io.h	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,59 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <string.h>
+#include <math.h>
+#include <grass/glocale.h>
+#include <grass/gis.h>
+#include <grass/raster.h>
+#include <grass/segment.h>
+
+#define NOT_IN_REGION(x) (r + nextr[(x)] < 0 || r + nextr[(x)] > (nrows - 1) || \
+                          c + nextc[(x)] < 0 || c + nextc[(x)] > (ncols - 1))
+#define NR(x) (r + nextr[(x)])
+#define NC(x) (c + nextc[(x)])
+#define INDEX(r,c) ((r) * ncols + (c))
+#define DIAG(x) (((x) + 4) > 8 ? ((x) - 4) : ((x) + 4))
+
+#define SROWS 256
+#define SCOLS 256
+
+typedef struct {
+	void **map; /* matrix of data */
+	double min, max; /* data range : may requre casting */
+	int nrows, ncols;
+	char *map_name; /* map name, unused */
+	RASTER_MAP_TYPE data_type; /* type of data */
+	size_t data_size; /* type of data */
+} MAP;
+
+typedef struct {
+	SEGMENT seg;		/* segmented data store */
+	int fd;					/* segment temporary file name descriptor */
+	char *filename; /* segment temporary file name */
+	char *map_name; /* map name converted to segment */
+	char *mapset;
+	int nrows, ncols; /* store nrows and rcols */
+	RASTER_MAP_TYPE data_type; /* data type of the map */
+	size_t data_size; /* size of cell returned by sizeof */
+	double min, max; /* data range */
+} SEG;
+
+
+/* all in ram functions */
+int ram_create_map(MAP *, RASTER_MAP_TYPE);
+int ram_read_map(MAP *, char *, int, RASTER_MAP_TYPE);
+int ram_reset_map(MAP *, int);
+int ram_write_map(MAP *, char *, RASTER_MAP_TYPE, int, double);
+int ram_release_map(MAP *);
+int ram_destory_map(MAP *);
+
+/* memory swap functions */
+int seg_create_map(SEG *, int, int, int, RASTER_MAP_TYPE);
+int seg_read_map(SEG *, char *, int, RASTER_MAP_TYPE);
+int seg_reset_map (SEG *, int);
+int seg_write_map(SEG *, char *, RASTER_MAP_TYPE, int, double);
+int seg_release_map(SEG *);
+

Added: grass-addons/grass7/grass7/raster/r.stream.distance/local_proto.h
===================================================================
--- grass-addons/grass7/grass7/raster/r.stream.distance/local_proto.h	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.stream.distance/local_proto.h	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,22 @@
+#include "io.h"
+#include "local_vars.h"
+
+/* inits */
+int ram_find_outlets(CELL **streams, int number_of_streams, CELL **dirs, int subs, int outs);
+int ram_init_distance(CELL **streams, FCELL **distance, int outlets_num, int outs);
+int ram_prep_null_elevation(FCELL **distance, FCELL **elevation);
+
+int seg_find_outlets(SEGMENT *streams, int number_of_streams, SEGMENT *dirs, int subs, int outs);
+int seg_prep_null_elevation(SEGMENT *distance, SEGMENT *elevation);
+int seg_init_distance(SEGMENT *streams, SEGMENT *distance, int outlets_num, int outs);
+
+/* calculate */
+int ram_calculate_downstream(CELL **dirs, FCELL **distance, FCELL **elevation, OUTLET outlet, int outs);
+int ram_fill_basins(OUTLET outlet, FCELL **distance, CELL **dirs);
+int ram_calculate_upstream(FCELL **distance, CELL **dirs, FCELL **elevation, FCELL **tmp_elevation, int near);
+
+int seg_calculate_downstream (SEGMENT *dirs, SEGMENT *distance, SEGMENT *elevation, OUTLET outlet, int outs);
+int seg_fill_basins(OUTLET outlet, SEGMENT *distance, SEGMENT *dirs);
+int seg_calculate_upstream(SEGMENT *distance, SEGMENT *dirs, SEGMENT *elevation, SEGMENT *tmp_elevation, int near);
+
+

Added: grass-addons/grass7/grass7/raster/r.stream.distance/local_vars.h
===================================================================
--- grass-addons/grass7/grass7/raster/r.stream.distance/local_vars.h	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.stream.distance/local_vars.h	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,42 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include <grass/glocale.h>
+#include <grass/gis.h>
+#include <grass/raster.h>
+
+#ifdef MAIN
+#  define GLOBAL
+#else
+#  define GLOBAL extern
+#endif
+
+#define SQRT2 1.414214
+#define UPSTREAM 0
+#define DOWNSTREAM 1
+
+typedef struct {
+	int r,c;
+} OUTLET;
+
+typedef struct {
+	int r,c;
+  float cur_dist;
+  float target_elev;
+} POINT;
+
+GLOBAL int nextr[9];
+GLOBAL int nextc[9];
+
+GLOBAL OUTLET* outlets;
+GLOBAL int nrows, ncols;
+GLOBAL int fifo_max;
+GLOBAL POINT* fifo_points;
+GLOBAL int accum;
+
+
+
+
+
+

Added: grass-addons/grass7/grass7/raster/r.stream.distance/main.c
===================================================================
--- grass-addons/grass7/grass7/raster/r.stream.distance/main.c	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.stream.distance/main.c	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,316 @@
+
+/****************************************************************************
+ *
+ * MODULE:       r.stream.distance
+ * AUTHOR(S):    Jarek Jasiewicz jarekj amu.edu.pl
+ *               
+ * PURPOSE:      Calculate distance and elevation over the streams and outlets 
+ *               according user's input data. The elevation and distance is calculated
+ *               along watercourses
+ *               It uses any stream map  and r.watershed or .stream.extreact direction map.
+ *               Stram input map shall contains streams or points outlets with or
+ *               without unique categories
+ *
+ * COPYRIGHT:    (C) 2002,2009 by the GRASS Development Team
+ *
+ *               This program is free software under the GNU General Public
+ *   	    	 	  License (>=v2). Read the file COPYING that comes with GRASS
+ *   	    	 	  for details.
+ *
+ *****************************************************************************/
+#define MAIN
+#include <grass/glocale.h>
+#include "local_proto.h"
+
+int nextr[9] = { 0, -1, -1, -1, 0, 1, 1, 1, 0 };
+int nextc[9] = { 0, 1, 0, -1, -1, -1, 0, 1, 1 };
+
+int process_cat(char **cat_list);
+int main(int argc, char *argv[])
+{
+
+    struct GModule *module;
+    struct Option *in_dir_opt,
+	*in_stm_opt,
+	*in_elev_opt,
+	*in_method_opt, *opt_swapsize, *out_dist_opt, *out_diff_opt;
+    struct Flag *flag_outs, *flag_sub, *flag_near, *flag_segmentation;
+    char *method_name[] = { "UPSTREAM", "DOWNSTREAM" };
+    int method;
+    int number_of_segs;
+    int outlets_num;
+    int number_of_streams;
+    int outs, subs, near, segmentation;	/*flags */
+    int j;
+
+    G_gisinit(argv[0]);
+
+    module = G_define_module();
+    module->description =
+	_("Calculate distance to and alavation above streams \
+    and outlets according user' input. It can work in stream mode where target are streams and outlets mode \
+    where targets are outlets");
+
+    G_add_keyword("watercourse distance");
+    G_add_keyword("relative elevation");
+
+    in_stm_opt = G_define_standard_option(G_OPT_R_INPUT);
+    in_stm_opt->key = "stream";
+    in_stm_opt->description = "Name of streams (outlets) mask input map";
+
+    in_dir_opt = G_define_standard_option(G_OPT_R_INPUT);
+    in_dir_opt->key = "dirs";
+    in_dir_opt->description = "Name of flow direction input map";
+
+    in_elev_opt = G_define_standard_option(G_OPT_R_INPUT);
+    in_elev_opt->key = "elevation";
+    in_elev_opt->required = NO;
+    in_elev_opt->description = "Name of elevation map";
+
+    in_method_opt = G_define_option();
+    in_method_opt->key = "method";
+    in_method_opt->description = "Calculation method";
+    in_method_opt->type = TYPE_STRING;
+    in_method_opt->required = YES;
+    in_method_opt->options = "upstream,downstream";
+    in_method_opt->answer = "downstream";
+
+    opt_swapsize = G_define_option();
+    opt_swapsize->key = "memory";
+    opt_swapsize->type = TYPE_INTEGER;
+    opt_swapsize->answer = "300";
+    opt_swapsize->description = _("Max memory used in memory swap mode (MB)");
+    opt_swapsize->guisection = _("Optional");
+
+    out_dist_opt = G_define_standard_option(G_OPT_R_OUTPUT);
+    out_dist_opt->key = "distance";
+    out_dist_opt->required = NO;
+    out_dist_opt->description = "Output distance/accumulation map";
+
+    out_diff_opt = G_define_standard_option(G_OPT_R_OUTPUT);
+    out_diff_opt->key = "difference";
+    out_diff_opt->required = NO;
+    out_diff_opt->description = "Output elevation difference map";
+
+    flag_outs = G_define_flag();
+    flag_outs->key = 'o';
+    flag_outs->description =
+	_("Calculate parameters for outlets (outlet mode) instead of (default) streams");
+
+    flag_sub = G_define_flag();
+    flag_sub->key = 's';
+    flag_sub->description =
+	_("Calculate parameters for subbasins (ignored in stream mode)");
+
+    flag_near = G_define_flag();
+    flag_near->key = 'n';
+    flag_near->description =
+	_("Calculate nearest local maximum (ignored in downstream calculation)");
+
+    flag_segmentation = G_define_flag();
+    flag_segmentation->key = 'm';
+    flag_segmentation->description = _("Use memory swap (operation is slow)");
+
+    if (G_parser(argc, argv))
+	exit(EXIT_FAILURE);
+
+    if (!out_diff_opt->answer && !out_dist_opt->answer)
+	G_fatal_error(_("You must select at least one output maps: distance and (or) elevation"));
+    if (out_diff_opt->answer && !in_elev_opt->answer)
+	G_fatal_error(_("If you select elevation output, elevation is required"));
+
+    if (out_dist_opt->answer)
+	if (G_legal_filename(out_dist_opt->answer) < 0)
+	    G_fatal_error(_("<%s> is an illegal distance name"),
+			  out_dist_opt->answer);
+
+    if (out_diff_opt->answer)
+	if (G_legal_filename(out_diff_opt->answer) < 0)
+	    G_fatal_error(_("<%s> is an illegal elevation difference name"),
+			  out_diff_opt->answer);
+
+    if (!strcmp(in_method_opt->answer, "upstream"))
+	method = UPSTREAM;
+    else if (!strcmp(in_method_opt->answer, "downstream"))
+	method = DOWNSTREAM;
+
+    outs = (flag_outs->answer != 0);
+    subs = (flag_sub->answer != 0);
+    near = (flag_near->answer != 0);
+    segmentation = (flag_segmentation->answer != 0);
+
+    nrows = Rast_window_rows();
+    ncols = Rast_window_cols();
+    G_begin_distance_calculations();
+
+    fifo_max = 4 * nrows * ncols;
+    fifo_points = (POINT *) G_malloc((fifo_max + 1) * sizeof(POINT));
+
+    if (!segmentation) {
+	G_message(_("ALL IN RAM CALCULATION - METHOD: %s"),
+		  method_name[method]);
+	MAP map_dirs, map_streams, map_distance, map_elevation,
+	    map_tmp_elevation;
+	CELL **streams, **dirs;
+	FCELL **distance;
+	FCELL **elevation = NULL;
+	FCELL **tmp_elevation = NULL;
+
+	ram_create_map(&map_streams, CELL_TYPE);
+	ram_read_map(&map_streams, in_stm_opt->answer, 1, CELL_TYPE);
+	ram_create_map(&map_dirs, CELL_TYPE);
+	ram_read_map(&map_dirs, in_dir_opt->answer, 1, CELL_TYPE);
+	ram_create_map(&map_distance, FCELL_TYPE);
+
+	streams = (CELL **) map_streams.map;
+	dirs = (CELL **) map_dirs.map;
+	distance = (FCELL **) map_distance.map;
+	number_of_streams = (int)map_streams.max + 1;
+
+	outlets_num =
+	    ram_find_outlets(streams, number_of_streams, dirs, subs, outs);
+	ram_init_distance(streams, distance, outlets_num, outs);
+	ram_release_map(&map_streams);
+
+	if (in_elev_opt->answer) {
+	    ram_create_map(&map_elevation, FCELL_TYPE);
+	    ram_read_map(&map_elevation, in_elev_opt->answer, 0, -1);
+	    elevation = (FCELL **) map_elevation.map;
+	}			/* map elevation will be replaced by elevation difference map */
+
+
+	if (method == DOWNSTREAM) {
+	    G_message(_("Calculate downstream parameters..."));
+	    for (j = 0; j < outlets_num; ++j) {
+		G_percent(j, outlets_num, 1);
+		ram_calculate_downstream(dirs, distance, elevation,
+					 outlets[j], outs);
+	    }
+	    G_percent(j, outlets_num, 1);
+
+	}
+	else if (method == UPSTREAM) {
+
+	    if (out_diff_opt->answer) {
+		ram_create_map(&map_tmp_elevation, FCELL_TYPE);
+		tmp_elevation = (FCELL **) map_tmp_elevation.map;
+	    }
+
+	    for (j = 0; j < outlets_num; ++j)
+		ram_fill_basins(outlets[j], distance, dirs);
+	    ram_calculate_upstream(distance, dirs, elevation, tmp_elevation,
+				   near);
+
+	}
+	else {
+	    G_fatal_error(_("Unrecognised method of processing"));
+	}			/* end methods */
+
+	if (out_diff_opt->answer) {
+	    ram_prep_null_elevation(distance, elevation);
+	    ram_write_map(&map_elevation, out_diff_opt->answer, FCELL_TYPE, 1,
+			  -1);
+	}
+
+	if (out_dist_opt->answer)
+	    ram_write_map(&map_distance, out_dist_opt->answer, FCELL_TYPE, 1,
+			  -1);
+
+	ram_release_map(&map_dirs);
+	ram_release_map(&map_distance);
+
+	if (in_elev_opt->answer)
+	    ram_release_map(&map_elevation);
+	if (in_elev_opt->answer && method == UPSTREAM)
+	    ram_release_map(&map_tmp_elevation);
+    }
+
+    if (segmentation) {
+	G_message(_("MEMORY SWAP CALCULATION - METHOD: %s MAY TAKE SOME TIME"),
+		  method_name[method]);
+	SEG map_dirs, map_streams, map_distance, map_elevation,
+	    map_tmp_elevation;
+	SEGMENT *streams, *dirs, *distance;
+	SEGMENT *elevation = NULL;
+	SEGMENT *tmp_elevation = NULL;
+
+	number_of_segs = (int)atof(opt_swapsize->answer);
+	if (method == DOWNSTREAM)
+	    number_of_segs = number_of_segs < 32 ? (int)(32 / 0.18) : number_of_segs / 0.18;
+	else			/* two elevation maps */
+	    number_of_segs = number_of_segs < 32 ? (int)(32 / 0.24) : number_of_segs / 0.24;
+
+	seg_create_map(&map_streams, SROWS, SCOLS, number_of_segs, CELL_TYPE);
+	seg_read_map(&map_streams, in_stm_opt->answer, 1, CELL_TYPE);
+	seg_create_map(&map_dirs, SROWS, SCOLS, number_of_segs, CELL_TYPE);
+	seg_read_map(&map_dirs, in_dir_opt->answer, 1, CELL_TYPE);
+	seg_create_map(&map_distance, SROWS, SCOLS, number_of_segs,
+		       FCELL_TYPE);
+
+	streams = &map_streams.seg;
+	dirs = &map_dirs.seg;
+	distance = &map_distance.seg;
+	number_of_streams = (int)map_streams.max + 1;
+
+	outlets_num =
+	    seg_find_outlets(streams, number_of_streams, dirs, subs, outs);
+	seg_init_distance(streams, distance, outlets_num, outs);
+	seg_release_map(&map_streams);
+
+	if (in_elev_opt->answer) {
+	    seg_create_map(&map_elevation, SROWS, SCOLS, number_of_segs,
+			   FCELL_TYPE);
+	    seg_read_map(&map_elevation, in_elev_opt->answer, 0, -1);
+	    elevation = &map_elevation.seg;
+	}			/* map elevation will be replaced by elevation difference map */
+
+	if (method == DOWNSTREAM) {
+	    G_message(_("Calculate downstream parameters..."));
+	    for (j = 0; j < outlets_num; ++j) {
+		G_percent(j, outlets_num, 1);
+		seg_calculate_downstream(dirs, distance, elevation,
+					 outlets[j], outs);
+	    }
+	    G_percent(j, outlets_num, 1);
+
+	}
+	else if (method == UPSTREAM) {
+
+	    if (out_diff_opt->answer) {
+		seg_create_map(&map_tmp_elevation, SROWS, SCOLS,
+			       number_of_segs, FCELL_TYPE);
+		tmp_elevation = &map_tmp_elevation.seg;
+	    }
+
+	    for (j = 0; j < outlets_num; ++j)
+		seg_fill_basins(outlets[j], distance, dirs);
+	    seg_calculate_upstream(distance, dirs, elevation, tmp_elevation,
+				   near);
+
+	}
+	else {
+	    G_fatal_error(_("Unrecognised method of processing"));
+	}			/* end methods */
+
+	if (out_dist_opt->answer)
+	    seg_write_map(&map_distance, out_dist_opt->answer, FCELL_TYPE, 1,
+			  -1);
+
+	if (out_diff_opt->answer) {
+	    seg_prep_null_elevation(distance, elevation);
+	    seg_write_map(&map_elevation, out_diff_opt->answer, FCELL_TYPE, 1,
+			  -1);
+	}
+
+	seg_release_map(&map_dirs);
+	seg_release_map(&map_distance);
+
+	if (in_elev_opt->answer)
+	    seg_release_map(&map_elevation);
+	if (in_elev_opt->answer && method == UPSTREAM)
+	    seg_release_map(&map_tmp_elevation);
+    }
+
+    G_free(fifo_points);
+    exit(EXIT_SUCCESS);
+}

Added: grass-addons/grass7/grass7/raster/r.stream.distance/r.stream.distance.html
===================================================================
--- grass-addons/grass7/grass7/raster/r.stream.distance/r.stream.distance.html	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.stream.distance/r.stream.distance.html	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,125 @@
+<h2>OPTIONS</h2>
+<dl>
+<dt><b>-o</b></dt>
+<dd>Outlets. Downstream method only. Calculate distance and relative  elevation
+to basin outlets instead of streams. It choose only last outlets in the network
+ignoring nodes.</dd>
+<dt><b>-s</b></dt>
+<dd>Subbasins. Downstream method only. Calculate distance and elevation to
+stream nodes instead of streams. It create distance and elevation parameters not
+for whole basins but for all elementary subbasins.</dd>
+<dt><b>-n</b></dt>
+<dd>Near. For upstream method only. Calculate distance and elevation to the
+nearest local maximum/divide. With the default option distance/elevation is
+calculated to the farthest possible maximum/divide
+</dd>
+<dt><b>streams</b></dt>
+<dd>Stream network: name of input stream map on which ordering will be performed
+produced by r.watershed or r.stream.extract. Because streams network produced by
+r.watershed and r.stream.extract may slighty differ in detail it is required to
+use both stream and direction map produced by the same module. Stream background
+shall have NULL value or zero value. Background values of NULL are by default
+produced by r.watershed and r.stream.extract. If not 0 or NULL use <a
+href="r.mapcalc.html">r.mapcalc</a> to set background values to null.  
+</dd>
+<dt><b>dirs</b></dt>
+<dd>Flow direction: name of input direction map produced by r.watershed or
+r.stream.extract. If r.stream.extract output map is used, it only has non-NULL
+values in places where streams occur. NULL (nodata) cells are ignored, zero and
+negative values are valid direction data if they vary from -8 to 8 (CCW from
+East in steps of 45 degrees). Direction map shall be of type CELL values. Region
+resolution and map resoultion must be the same. Also <em>stream</em> network map
+must have the same resolution. It is checked by default. If resolutions differ
+the module informs about it and stops. Region boundary and maps boundary may be
+differ but it may lead to unexpected results.</dd>
+<dt><b>elevation</b></dt>
+<dd>Elevation: name of input elevation map. Map can be of type CELL, FCELL or
+DCELL. It is not restricted to resolution of region settings as stream and
+dir.</dd>
+<dt><b>method</b></dt>
+<dd>It is possible to calculate distance with two method: <b>downstream</b> from
+any raster cell to the nearest stream cell/ junction cell or outlet or
+<b>upstream</b> from any cell upstream to the nearest maximum or divide</dd>
+</dl>
+
+<h2>OUTPUTS</h2>
+<dl>
+<dt><b>difference</b></dt>
+<dd>Returns elevation difference to the targer (outlet, node, stream, divide,
+maximum) along watercoures. The map is of FCELL type</dd>
+<dt><b>distance</b></dt>
+<dd>Returns distance to the targer (outlet, node, stream, divide, maximum) along
+watercoures. The map is of FCELL type</dd>
+</dl>
+
+<h2>DESCRIPTION</h2>
+<p>
+Module r.stream.distance may calculate distance using two methods: downstream
+and upstream.
+<p>
+The default is downstream method when it  calculate distance to streams and
+outlets and relative elevation to streams and outlets. The distance and
+elevation is calculated along watercourses. In outlets mode it can also
+calculate parameters for subbasins.
+<p>
+In streams mode (default) it calculates that parameters downstream to streams
+which are added as stream mask. In outlets mode there are some additional
+possibilities. If subbasin is off it calculate parameters only for last point of
+last (downstream) CELL. In subbasin mode it calculates parameters for every
+subbasin separately. Subbasin mode acts similar to subbasin mask. Streams file
+prepared to create basins and subbasins with r.stream.basins can use to to
+calculate distance and elevation parameters.
+<p>
+With upstream method it calculate distance to the local maximum or divide.
+Opposite to downstream method, where every cell has one and only one downstream
+cell in upstream method every cell has usually more than one upstream cell. So
+it is impossible to determine interchangeable path from any cell. The upstream
+method offers two alternative modes switched with -n flag: nearest local
+maximum/divide:  means the shortest path to local maximum and default option
+farthest maximum/divide means the longest path. In hydrological sense nearest
+mode means the shortest path which particle of water must run from divide to
+reach particular cell, while farthest mode means the possible longest path.
+
+<h2>NOTES</h2>
+<p>
+If there are more than one point or one stream networks and some separate points
+or separate streams networks are in catchment area defined by others it will
+results as in subbasin mode.  In stream mode subbasin options is ommited. Input
+maps must be in CELL format (default output of r.watershed, r.stream.order  and
+r.stream.extract).
+The distance are calculated in meters both for planimeters and
+Latitude-Longitude projections. The distance is calculated for flat areas not
+corrected by topography. Distance correction by topography may be done with
+following mapcalc formula:
+<p>
+<code>echo 'dist_corrected = sqrt(distance^2 + elevation ^2)'|r.mapcalc</code>
+<p>
+Module can work only if direction map, stream map and region has same settings.
+It is also required that stream map and direction map come from the same source.
+For lots of reason this limitation probably cannot be omitted.   this means if
+stream map comes from r.stream.extract also direction map from r.stream.extract
+must be used. If stream network was generated with MFD method also MFD direction
+map must be used.
+<p>
+Probably one of the most imortant features of r.stream.extract is the ability to
+calculate distnace not only for streams generated with r.stream.order, but also
+to any CELL map with resoultion coresponding to dirs map. It can be a lake,
+swamp, depression and lake boundaries even divided into smaller fragments each
+with its own category.
+
+<h2>SEE ALSO</h2>
+<em>
+<a href="r.watershed.html">r.watershed</a>,
+<a href="r.stream.extract.html">r.stream.extract</a>,
+<a href="r.stream.order.html">r.stream.order</a>,
+<a href="r.stream.basins.html">r.stream.basins</a>,
+<a href="r.mapcalc.html">r.mapcalc</a>,
+<a href="r.reclass.html">r.reclass</a>,
+</em>
+
+<h2>AUTHOR</h2>
+Jarek Jasiewicz, Adam Mickiewicz University, Geoecology and Geoinformation
+Institute.
+
+<p><i>Last changed: $Date: 2011-11-08 22:56:45 +0100 (Tue, 08 Nov 2011) $</i>
+

Added: grass-addons/grass7/grass7/raster/r.stream.extract/Makefile
===================================================================
--- grass-addons/grass7/grass7/raster/r.stream.extract/Makefile	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.stream.extract/Makefile	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,12 @@
+MODULE_TOPDIR = ../..
+
+PGM = r.stream.extract
+
+LIBES     = $(SEGMENTLIB) $(RASTERLIB) $(VECTORLIB) $(DBMILIB) $(GISLIB)
+DEPENDENCIES = $(SEGMENTDEP) $(RASTERDEP) $(VECTORDEP) $(DBMIDEP) $(GISDEP)
+EXTRA_INC = $(VECT_INC)
+EXTRA_CFLAGS = $(VECT_CFLAGS)
+
+include $(MODULE_TOPDIR)/include/Make/Module.make
+
+default: cmd

Added: grass-addons/grass7/grass7/raster/r.stream.extract/bseg.c
===================================================================
--- grass-addons/grass7/grass7/raster/r.stream.extract/bseg.c	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.stream.extract/bseg.c	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,159 @@
+#include <unistd.h>
+#include <fcntl.h>
+#include <grass/glocale.h>
+#include "seg.h"
+
+int bseg_open(BSEG *bseg, int srows, int scols, int nsegs_in_memory)
+{
+    char *filename;
+    int errflag;
+    int fd;
+
+    bseg->filename = NULL;
+    bseg->fd = -1;
+    bseg->name = NULL;
+    bseg->mapset = NULL;
+
+    filename = G_tempfile();
+    if (-1 == (fd = creat(filename, 0666))) {
+	G_warning(_("bseg_open(): unable to create segment file"));
+	return -2;
+    }
+    if (0 > (errflag = segment_format(fd, Rast_window_rows(),
+				      Rast_window_cols(), srows, scols,
+				      sizeof(char)))) {
+	close(fd);
+	unlink(filename);
+	if (errflag == -1) {
+	    G_warning(_("bseg_open(): could not write segment file"));
+	    return -1;
+	}
+	else {
+	    G_warning(_("bseg_open(): illegal configuration parameter(s)"));
+	    return -3;
+	}
+    }
+    close(fd);
+    if (-1 == (fd = open(filename, 2))) {
+	unlink(filename);
+	G_warning(_("bseg_open(): unable to re-open segment file"));
+	return -4;
+    }
+    if (0 > (errflag = segment_init(&(bseg->seg), fd, nsegs_in_memory))) {
+	close(fd);
+	unlink(filename);
+	if (errflag == -1) {
+	    G_warning(_("bseg_open(): could not read segment file"));
+	    return -5;
+	}
+	else {
+	    G_warning(_("bseg_open(): out of memory"));
+	    return -6;
+	}
+    }
+    bseg->filename = filename;
+    bseg->fd = fd;
+    return 0;
+}
+
+int bseg_close(BSEG *bseg)
+{
+    segment_release(&(bseg->seg));
+    close(bseg->fd);
+    unlink(bseg->filename);
+    if (bseg->name) {
+	G_free(bseg->name);
+	bseg->name = NULL;
+    }
+    if (bseg->mapset) {
+	G_free(bseg->mapset);
+	bseg->mapset = NULL;
+    }
+    return 0;
+}
+
+int bseg_put(BSEG *bseg, char *value, int row, int col)
+{
+    if (segment_put(&(bseg->seg), value, row, col) < 0) {
+	G_warning(_("bseg_put(): could not write segment file"));
+	return -1;
+    }
+    return 0;
+}
+
+int bseg_put_row(BSEG *bseg, char *value, int row)
+{
+    if (segment_put_row(&(bseg->seg), value, row) < 0) {
+	G_warning(_("bseg_put_row(): could not write segment file"));
+	return -1;
+    }
+    return 0;
+}
+
+int bseg_get(BSEG *bseg, char *value, int row, int col)
+{
+    if (segment_get(&(bseg->seg), value, row, col) < 0) {
+	G_warning(_("bseg_get(): could not read segment file"));
+	return -1;
+    }
+    return 0;
+}
+
+
+int bseg_read_raster(BSEG *bseg, char *map_name, char *mapset)
+{
+    int row, nrows;
+    int col, ncols;
+    int map_fd;
+    CELL *buffer;
+    char cbuf;
+
+    bseg->name = NULL;
+    bseg->mapset = NULL;
+
+    map_fd = Rast_open_old(map_name, mapset);
+    nrows = Rast_window_rows();
+    ncols = Rast_window_cols();
+    buffer = Rast_allocate_c_buf();
+    for (row = 0; row < nrows; row++) {
+	Rast_get_c_row(map_fd, buffer, row);
+	for (col = ncols; col >= 0; col--) {
+	    cbuf = (char) buffer[col];
+	    bseg_put(bseg, &cbuf, row, col);
+	}
+    }
+
+    Rast_close(map_fd);
+    G_free(buffer);
+
+    bseg->name = G_store(map_name);
+    bseg->mapset = G_store(mapset);
+
+    return 0;
+}
+
+int bseg_write_raster(BSEG *bseg, char *map_name)
+{
+    int map_fd;
+    int row, nrows;
+    int col, ncols;
+    CELL *buffer;
+    char value;
+
+    map_fd = Rast_open_c_new(map_name);
+    nrows = Rast_window_rows();
+    ncols = Rast_window_cols();
+    buffer = Rast_allocate_c_buf();
+    for (row = 0; row < nrows; row++) {
+	G_percent(row, nrows, 1);
+	for (col = 0; col < ncols; col++) {
+	    bseg_get(bseg, &value, row, col);
+	    buffer[col] = value;
+	}
+	Rast_put_row(map_fd, buffer, CELL_TYPE);
+    }
+    G_percent(row, nrows, 1);    /* finish it */
+    G_free(buffer);
+    Rast_close(map_fd);
+    return 0;
+}

Added: grass-addons/grass7/grass7/raster/r.stream.extract/close.c
===================================================================
--- grass-addons/grass7/grass7/raster/r.stream.extract/close.c	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.stream.extract/close.c	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,322 @@
+#include <grass/raster.h>
+#include <grass/glocale.h>
+#include <grass/vector.h>
+#include <grass/dbmi.h>
+#include "local_proto.h"
+
+int close_streamvect(char *stream_vect)
+{
+    int i, r, c, r_nbr, c_nbr, done;
+    CELL stream_id, stream_nbr;
+    char aspect;
+    int next_node;
+    struct sstack
+    {
+	int stream_id;
+	int next_trib;
+    } *nodestack;
+    int top = 0, stack_step = 1000;
+    int asp_r[9] = { 0, -1, -1, -1, 0, 1, 1, 1, 0 };
+    int asp_c[9] = { 0, 1, 0, -1, -1, -1, 0, 1, 1 };
+    struct Map_info Out;
+    static struct line_pnts *Points;
+    struct line_cats *Cats;
+    dbDriver *driver;
+    dbHandle handle;
+    dbString table_name, dbsql, valstr;
+    struct field_info *Fi;
+    char *cat_col_name = "cat", buf[2000];
+    struct Cell_head window;
+    double north_offset, west_offset, ns_res, ew_res;
+    int next_cat;
+
+    G_message(_("Writing vector map <%s>..."), stream_vect);
+
+    if (0 > Vect_open_new(&Out, stream_vect, 0)) {
+	G_fatal_error(_("Unable to create vector map <%s>"), stream_vect);
+    }
+
+    nodestack = (struct sstack *)G_malloc(stack_step * sizeof(struct sstack));
+
+    Points = Vect_new_line_struct();
+    Cats = Vect_new_cats_struct();
+
+    G_get_set_window(&window);
+    ns_res = window.ns_res;
+    ew_res = window.ew_res;
+    north_offset = window.north - 0.5 * ns_res;
+    west_offset = window.west + 0.5 * ew_res;
+
+    next_cat = n_stream_nodes + 1;
+
+    for (i = 0; i < n_outlets; i++, next_cat++) {
+	G_percent(i, n_outlets, 2);
+	r = outlets[i].r;
+	c = outlets[i].c;
+	cseg_get(&stream, &stream_id, r, c);
+
+	if (!stream_id)
+	    continue;
+
+	Vect_reset_line(Points);
+	Vect_reset_cats(Cats);
+
+	/* outlet */
+	Vect_cat_set(Cats, 1, stream_id);
+	Vect_cat_set(Cats, 2, 2);
+	Vect_append_point(Points, west_offset + c * ew_res,
+			  north_offset - r * ns_res, 0);
+	Vect_write_line(&Out, GV_POINT, Points, Cats);
+
+	/* add root node to stack */
+	G_debug(3, "add root node");
+	top = 0;
+	nodestack[top].stream_id = stream_id;
+	nodestack[top].next_trib = 0;
+
+	/* depth first post order traversal */
+	G_debug(3, "traverse");
+	while (top >= 0) {
+
+	    done = 1;
+	    stream_id = nodestack[top].stream_id;
+	    G_debug(3, "stream_id %d", stream_id);
+	    if (nodestack[top].next_trib < stream_node[stream_id].n_trib) {
+		/* add to stack */
+		next_node =
+		    stream_node[stream_id].trib[nodestack[top].next_trib];
+		G_debug(3, "add to stack: next %d, trib %d, n trib %d",
+			next_node, nodestack[top].next_trib,
+			stream_node[stream_id].n_trib);
+		nodestack[top].next_trib++;
+		top++;
+		if (top >= stack_step) {
+		    /* need more space */
+		    stack_step += 1000;
+		    nodestack =
+			(struct sstack *)G_realloc(nodestack,
+						   stack_step *
+						   sizeof(struct sstack));
+		}
+		nodestack[top].next_trib = 0;
+		nodestack[top].stream_id = next_node;
+		done = 0;
+		G_debug(3, "go further down");
+	    }
+	    if (done) {
+		G_debug(3, "write stream segment");
+
+		Vect_reset_line(Points);
+		Vect_reset_cats(Cats);
+
+		r_nbr = stream_node[stream_id].r;
+		c_nbr = stream_node[stream_id].c;
+
+		cseg_get(&stream, &stream_nbr, r_nbr, c_nbr);
+		if (stream_nbr <= 0)
+		    G_fatal_error("stream id %d not set, top is %d, parent is %d", stream_id, top, nodestack[top - 1].stream_id);
+
+		Vect_cat_set(Cats, 1, stream_id);
+		if (stream_node[stream_id].n_trib == 0)
+		    Vect_cat_set(Cats, 2, 0);
+		else
+		    Vect_cat_set(Cats, 2, 1);
+
+		Vect_append_point(Points, west_offset + c_nbr * ew_res,
+				  north_offset - r_nbr * ns_res, 0);
+
+		Vect_write_line(&Out, GV_POINT, Points, Cats);
+
+		bseg_get(&asp, &aspect, r_nbr, c_nbr);
+		while (aspect > 0) {
+		    r_nbr = r_nbr + asp_r[(int)aspect];
+		    c_nbr = c_nbr + asp_c[(int)aspect];
+		    
+		    cseg_get(&stream, &stream_nbr, r_nbr, c_nbr);
+		    if (stream_nbr <= 0)
+			G_fatal_error("stream id not set while tracing");
+
+		    Vect_append_point(Points, west_offset + c_nbr * ew_res,
+				      north_offset - r_nbr * ns_res, 0);
+		    if (stream_nbr != stream_id) {
+			/* first point of parent stream */
+			break;
+		    }
+		    bseg_get(&asp, &aspect, r_nbr, c_nbr);
+		}
+
+		Vect_write_line(&Out, GV_LINE, Points, Cats);
+
+		top--;
+	    }
+	}
+    }
+    G_percent(n_outlets, n_outlets, 1);	/* finish it */
+
+    G_message(_("Writing vector attribute table"));
+
+    /* Prepeare strings for use in db_* calls */
+    db_init_string(&dbsql);
+    db_init_string(&valstr);
+    db_init_string(&table_name);
+    db_init_handle(&handle);
+
+    /* Preparing database for use */
+    /* Create database for new vector map */
+    Fi = Vect_default_field_info(&Out, 1, NULL, GV_1TABLE);
+    driver = db_start_driver_open_database(Fi->driver,
+					   Vect_subst_var(Fi->database,
+							          &Out));
+    if (driver == NULL) {
+	G_fatal_error(_("Unable to start driver <%s>"), Fi->driver);
+    }
+
+    G_debug(1, "table: %s", Fi->table);
+    G_debug(1, "driver: %s", Fi->driver);
+    G_debug(1, "database: %s", Fi->database);
+
+    sprintf(buf,
+	    "create table %s (%s integer, stream_type varchar(20), type_code integer)",
+	    Fi->table, cat_col_name);
+    db_set_string(&dbsql, buf);
+
+    if (db_execute_immediate(driver, &dbsql) != DB_OK) {
+	db_close_database(driver);
+	db_shutdown_driver(driver);
+	G_fatal_error(_("Cannot create table: %s"), db_get_string(&dbsql));
+    }
+
+    if (db_create_index2(driver, Fi->table, cat_col_name) != DB_OK)
+	G_warning(_("Cannot create index"));
+
+    if (db_grant_on_table(driver, Fi->table, DB_PRIV_SELECT,
+			  DB_GROUP | DB_PUBLIC) != DB_OK)
+	G_fatal_error(_("Cannot grant privileges on table %s"), Fi->table);
+
+    db_begin_transaction(driver);
+
+    /* stream nodes */
+    for (i = 1; i <= n_stream_nodes; i++) {
+
+	sprintf(buf, "insert into %s values ( %d, \'%s\', %d )",
+		Fi->table, i,
+		(stream_node[i].n_trib > 0 ? "intermediate" : "start"),
+		(stream_node[i].n_trib > 0));
+
+	db_set_string(&dbsql, buf);
+
+	if (db_execute_immediate(driver, &dbsql) != DB_OK) {
+	    db_close_database(driver);
+	    db_shutdown_driver(driver);
+	    G_fatal_error(_("Cannot insert new row: %s"),
+			  db_get_string(&dbsql));
+	}
+    }
+
+    db_commit_transaction(driver);
+    db_close_database_shutdown_driver(driver);
+
+    Vect_map_add_dblink(&Out, 1, NULL, Fi->table,
+			cat_col_name, Fi->database, Fi->driver);
+
+    G_debug(1, "close vector");
+
+    Vect_hist_command(&Out);
+    Vect_build(&Out);
+    Vect_close(&Out);
+
+    G_free(nodestack);
+
+    return 1;
+}
+
+
+int close_maps(char *stream_rast, char *stream_vect, char *dir_rast)
+{
+    int stream_fd, dir_fd, r, c, i;
+    CELL *cell_buf1, *cell_buf2;
+    struct History history;
+    char flag_value;
+    CELL stream_id;
+    char aspect;
+
+    /* cheating... */
+    stream_fd = dir_fd = -1;
+    cell_buf1 = cell_buf2 = NULL;
+
+    G_message(_("Writing raster %s"),
+              (stream_rast != NULL) + (dir_rast != NULL) > 1 ? _("maps") : _("map"));
+
+    /* write requested output rasters */
+    if (stream_rast) {
+	stream_fd = Rast_open_new(stream_rast, CELL_TYPE);
+	cell_buf1 = Rast_allocate_c_buf();
+    }
+    if (dir_rast) {
+	dir_fd = Rast_open_new(dir_rast, CELL_TYPE);
+	cell_buf2 = Rast_allocate_c_buf();
+    }
+
+    for (r = 0; r < nrows; r++) {
+	G_percent(r, nrows, 2);
+	if (stream_rast)
+	    Rast_set_c_null_value(cell_buf1, ncols);	/* reset row to all NULL */
+	if (dir_rast)
+	    Rast_set_c_null_value(cell_buf2, ncols);	/* reset row to all NULL */
+
+	for (c = 0; c < ncols; c++) {
+	    if (stream_rast) {
+		cseg_get(&stream, &stream_id, r, c);
+		if (stream_id)
+		    cell_buf1[c] = stream_id;
+	    }
+	    if (dir_rast) {
+		bseg_get(&bitflags, &flag_value, r, c);
+		if (!FLAG_GET(flag_value, NULLFLAG)) {
+		    bseg_get(&asp, &aspect, r, c);
+		    cell_buf2[c] = aspect;
+		}
+	    }
+	    
+	}
+	if (stream_rast)
+	    Rast_put_row(stream_fd, cell_buf1, CELL_TYPE);
+	if (dir_rast)
+	    Rast_put_row(dir_fd, cell_buf2, CELL_TYPE);
+    }
+    G_percent(nrows, nrows, 2);	/* finish it */
+
+    if (stream_rast) {
+	Rast_close(stream_fd);
+	G_free(cell_buf1);
+	Rast_short_history(stream_rast, "raster", &history);
+	Rast_command_history(&history);
+	Rast_write_history(stream_rast, &history);
+    }
+    if (dir_rast) {
+	Rast_close(dir_fd);
+	G_free(cell_buf2);
+	Rast_short_history(dir_rast, "raster", &history);
+	Rast_command_history(&history);
+	Rast_write_history(dir_rast, &history);
+    }
+
+    /* close stream vector */
+    if (stream_vect) {
+	if (close_streamvect(stream_vect) < 0)
+	    G_fatal_error(_("Unable to write vector map <%s>"), stream_vect);
+    }
+
+    /* rearranging desk chairs on the Titanic... */
+    G_free(outlets);
+
+    /* free stream nodes */
+    for (i = 1; i <= n_stream_nodes; i++) {
+	if (stream_node[i].n_alloc > 0) {
+	    G_free(stream_node[i].trib);
+	}
+    }
+    G_free(stream_node);
+
+    return 1;
+}

Added: grass-addons/grass7/grass7/raster/r.stream.extract/cseg.c
===================================================================
--- grass-addons/grass7/grass7/raster/r.stream.extract/cseg.c	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.stream.extract/cseg.c	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,154 @@
+#include <unistd.h>
+#include <fcntl.h>
+#include <grass/glocale.h>
+#include "seg.h"
+
+int cseg_open(CSEG *cseg, int srows, int scols, int nsegs_in_memory)
+{
+    char *filename;
+    int errflag;
+    int fd;
+
+    cseg->filename = NULL;
+    cseg->fd = -1;
+    cseg->name = NULL;
+    cseg->mapset = NULL;
+
+    filename = G_tempfile();
+    if (-1 == (fd = creat(filename, 0666))) {
+	G_warning(_("cseg_open(): unable to create segment file"));
+	return -2;
+    }
+    if (0 >
+	(errflag =
+	 segment_format(fd, Rast_window_rows(), Rast_window_cols(), srows, scols,
+			sizeof(CELL)))) {
+	close(fd);
+	unlink(filename);
+	if (errflag == -1) {
+	    G_warning(_("cseg_open(): could not write segment file"));
+	    return -1;
+	}
+	else {
+	    G_warning(_("cseg_open(): illegal configuration parameter(s)"));
+	    return -3;
+	}
+    }
+    close(fd);
+    if (-1 == (fd = open(filename, 2))) {
+	unlink(filename);
+	G_warning(_("cseg_open(): unable to re-open segment file"));
+	return -4;
+    }
+    if (0 > (errflag = segment_init(&(cseg->seg), fd, nsegs_in_memory))) {
+	close(fd);
+	unlink(filename);
+	if (errflag == -1) {
+	    G_warning(_("cseg_open(): could not read segment file"));
+	    return -5;
+	}
+	else {
+	    G_warning(_("cseg_open(): out of memory"));
+	    return -6;
+	}
+    }
+    cseg->filename = filename;
+    cseg->fd = fd;
+    return 0;
+}
+
+int cseg_close(CSEG *cseg)
+{
+    segment_release(&(cseg->seg));
+    close(cseg->fd);
+    unlink(cseg->filename);
+    if (cseg->name) {
+	G_free(cseg->name);
+	cseg->name = NULL;
+    }
+    if (cseg->mapset) {
+	G_free(cseg->mapset);
+	cseg->mapset = NULL;
+    }
+    return 0;
+}
+
+int cseg_put(CSEG *cseg, CELL *value, int row, int col)
+{
+    if (segment_put(&(cseg->seg), value, row, col) < 0) {
+	G_warning(_("cseg_put(): could not write segment file"));
+	return -1;
+    }
+    return 0;
+}
+
+int cseg_put_row(CSEG *cseg, CELL *value, int row)
+{
+    if (segment_put_row(&(cseg->seg), value, row) < 0) {
+	G_warning(_("cseg_put_row(): could not write segment file"));
+	return -1;
+    }
+    return 0;
+}
+
+int cseg_get(CSEG *cseg, CELL *value, int row, int col)
+{
+    if (segment_get(&(cseg->seg), value, row, col) < 0) {
+	G_warning(_("cseg_get(): could not read segment file"));
+	return -1;
+    }
+    return 0;
+}
+
+int cseg_read_raster(CSEG *cseg, char *map_name, char *mapset)
+{
+    int row, nrows;
+    int map_fd;
+    CELL *buffer;
+
+    cseg->name = NULL;
+    cseg->mapset = NULL;
+
+    map_fd = Rast_open_old(map_name, mapset);
+    nrows = Rast_window_rows();
+    buffer = Rast_allocate_c_buf();
+    for (row = 0; row < nrows; row++) {
+	Rast_get_c_row(map_fd, buffer, row);
+	if (segment_put_row(&(cseg->seg), buffer, row) < 0) {
+	    G_free(buffer);
+	    Rast_close(map_fd);
+	    G_warning(_("cseg_read_cell(): unable to segment put row for <%s> in <%s>"),
+		    map_name, mapset);
+	    return (-1);
+	}
+    }
+
+    Rast_close(map_fd);
+    G_free(buffer);
+
+    cseg->name = G_store(map_name);
+    cseg->mapset = G_store(mapset);
+
+    return 0;
+}
+
+int cseg_write_raster(CSEG *cseg, char *map_name)
+{
+    int map_fd;
+    int row, nrows;
+    CELL *buffer;
+
+    map_fd = Rast_open_c_new(map_name);
+    nrows = Rast_window_rows();
+    buffer = Rast_allocate_c_buf();
+    segment_flush(&(cseg->seg));
+    for (row = 0; row < nrows; row++) {
+	G_percent(row, nrows, 1);
+	segment_get_row(&(cseg->seg), buffer, row);
+	Rast_put_row(map_fd, buffer, CELL_TYPE);
+    }
+    G_percent(row, nrows, 1);    /* finish it */
+    G_free(buffer);
+    Rast_close(map_fd);
+    return 0;
+}

Added: grass-addons/grass7/grass7/raster/r.stream.extract/del_streams.c
===================================================================
--- grass-addons/grass7/grass7/raster/r.stream.extract/del_streams.c	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.stream.extract/del_streams.c	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,194 @@
+#include <stdlib.h>
+#include <math.h>
+#include <grass/raster.h>
+#include <grass/glocale.h>
+#include "local_proto.h"
+
+/* get stream segment length */
+int seg_length(CELL stream_id, CELL *next_stream_id)
+{
+    int r, c, r_nbr, c_nbr;
+    int slength = 1;
+    CELL curr_stream;
+    int asp_r[9] = { 0, -1, -1, -1, 0, 1, 1, 1, 0 };
+    int asp_c[9] = { 0, 1, 0, -1, -1, -1, 0, 1, 1 };
+    char aspect;
+
+    r = stream_node[stream_id].r;
+    c = stream_node[stream_id].c;
+    if (next_stream_id)
+	*next_stream_id = stream_id;
+
+    /* get next downstream point */
+    bseg_get(&asp, &aspect, r, c);
+    while (aspect > 0) {
+	r_nbr = r + asp_r[(int)aspect];
+	c_nbr = c + asp_c[(int)aspect];
+
+	/* user-defined depression */
+	if (r_nbr == r && c_nbr == c)
+	    break;
+	/* outside region */
+	if (r_nbr < 0 || r_nbr >= nrows || c_nbr < 0 || c_nbr >= ncols)
+	    break;
+	/* next stream */
+	cseg_get(&stream, &curr_stream, r_nbr, c_nbr);
+	if (next_stream_id)
+	    *next_stream_id = curr_stream;
+	if (curr_stream != stream_id)
+	    break;
+	slength++;
+	r = r_nbr;
+	c = c_nbr;
+	bseg_get(&asp, &aspect, r, c);
+    }
+
+    return slength;
+}
+
+/* change downstream id: update or remove */
+int update_stream_id(CELL stream_id, CELL new_stream_id)
+{
+    int i, r, c, r_nbr, c_nbr;
+    CELL new_stream = new_stream_id;
+    CELL curr_stream;
+    int asp_r[9] = { 0, -1, -1, -1, 0, 1, 1, 1, 0 };
+    int asp_c[9] = { 0, 1, 0, -1, -1, -1, 0, 1, 1 };
+    char aspect;
+
+    r = stream_node[stream_id].r;
+    c = stream_node[stream_id].c;
+    cseg_get(&stream, &curr_stream, r, c);
+    if (curr_stream != stream_id)
+	G_fatal_error("update downstream id: curr_stream != stream_id");
+    cseg_put(&stream, &new_stream, r, c);
+    curr_stream = stream_id;
+
+    /* get next downstream point */
+    bseg_get(&asp, &aspect, r, c);
+    while (aspect > 0) {
+	r_nbr = r + asp_r[(int)aspect];
+	c_nbr = c + asp_c[(int)aspect];
+
+	/* user-defined depression */
+	if (r_nbr == r && c_nbr == c)
+	    break;
+	/* outside region */
+	if (r_nbr < 0 || r_nbr >= nrows || c_nbr < 0 || c_nbr >= ncols)
+	    break;
+	/* next stream */
+	cseg_get(&stream, &curr_stream, r_nbr, c_nbr);
+	if (curr_stream != stream_id)
+	    break;
+	r = r_nbr;
+	c = c_nbr;
+	cseg_put(&stream, &new_stream, r, c);
+	bseg_get(&asp, &aspect, r, c);
+    }
+    
+    if (curr_stream <= 0)
+	return curr_stream;
+
+    /* update tributaries */
+    if (curr_stream != stream_id) {
+	int last_i = -1;
+	
+	for (i = 0; i < stream_node[curr_stream].n_trib; i++) {
+	    if (stream_node[curr_stream].trib[i] == stream_id) {
+		if (new_stream_id) {
+		    stream_node[curr_stream].trib[i] = new_stream_id;
+		}
+		else {
+		    stream_node[curr_stream].n_trib--;
+		    stream_node[curr_stream].trib[i] = stream_node[curr_stream].trib[stream_node[curr_stream].n_trib];
+		    stream_node[curr_stream].trib[stream_node[curr_stream].n_trib] = 0;
+		}
+		last_i = i;
+		break;
+	    }
+	}
+	for (i = 0; i < stream_node[curr_stream].n_trib; i++) {
+	    if (stream_node[curr_stream].trib[i] == stream_id) {
+		G_warning("last_i %d, i %d", last_i, i);
+		G_warning("failed updating stream %d at node %d", stream_id, curr_stream);
+	    }
+	}
+    }
+
+    return curr_stream;
+}
+
+/* delete stream segments shorter than threshold */
+int del_streams(int min_length)
+{
+    int i;
+    int n_deleted = 0;
+    CELL curr_stream, stream_id;
+    int other_trib, tmp_trib;
+    int slength;
+
+    G_message(_("Deleting stream segments shorter than %d cells..."), min_length);
+
+    /* TODO: proceed from stream heads to outlets
+     *       -> use depth first post order traversal */
+
+    /* go through all nodes */
+    for (i = 1; i <= n_stream_nodes; i++) {
+	G_percent(i, n_stream_nodes, 2);
+
+	/* not a stream head */
+	if (stream_node[i].n_trib > 0)
+	    continue;
+
+	/* already deleted */
+	cseg_get(&stream, &curr_stream, stream_node[i].r, stream_node[i].c);
+	if (curr_stream == 0)
+	    continue;
+
+	/* get length counted as n cells */
+	if ((slength = seg_length(i, &curr_stream)) >= min_length)
+	    continue;
+
+	stream_id = i;
+	
+	/* check n sibling tributaries */
+	if (curr_stream != stream_id) {
+	    /* only one sibling tributary */
+	    if (stream_node[curr_stream].n_trib == 2) {
+		if (stream_node[curr_stream].trib[0] != stream_id)
+		    other_trib = stream_node[curr_stream].trib[0];
+		else
+		    other_trib = stream_node[curr_stream].trib[1];
+
+		/* other trib is also stream head */
+		if (stream_node[other_trib].n_trib == 0) {
+		    /* use shorter one */
+		    if (seg_length(other_trib, NULL) < slength) {
+			tmp_trib = stream_id;
+			stream_id = other_trib;
+			other_trib = tmp_trib;
+		    }
+		}
+		update_stream_id(stream_id, 0);
+		n_deleted++;
+		
+		/* update downstream IDs */
+		update_stream_id(curr_stream, other_trib);
+	    }
+	    /* more than one other tributary */
+	    else {
+		update_stream_id(stream_id, 0);
+		n_deleted++;
+	    }
+	}
+	/* stream head is also outlet */
+	else {
+	    update_stream_id(stream_id, 0);
+	    n_deleted++;
+	}
+    }
+
+    G_verbose_message(_("%d stream segments deleted"), n_deleted);
+
+    return n_deleted;
+}

Added: grass-addons/grass7/grass7/raster/r.stream.extract/do_astar.c
===================================================================
--- grass-addons/grass7/grass7/raster/r.stream.extract/do_astar.c	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.stream.extract/do_astar.c	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,291 @@
+#include <stdlib.h>
+#include <math.h>
+#include <grass/raster.h>
+#include <grass/glocale.h>
+#include "local_proto.h"
+
+#define GET_PARENT(c) ((((c) - 2) >> 3) + 1)
+#define GET_CHILD(p) (((p) << 3) - 6)
+
+HEAP_PNT heap_drop(void);
+int sift_up(GW_LARGE_INT, HEAP_PNT);
+double get_slope(CELL, CELL, double);
+
+int do_astar(void)
+{
+    int r, c, r_nbr, c_nbr, ct_dir;
+    GW_LARGE_INT first_cum, count;
+    int nextdr[8] = { 1, -1, 0, 0, -1, 1, 1, -1 };
+    int nextdc[8] = { 0, 0, -1, 1, 1, -1, 1, -1 };
+    CELL ele_val, ele_up, ele_nbr[8];
+    WAT_ALT wa;
+    char asp_val;
+    char flag_value, is_in_list, is_worked;
+    HEAP_PNT heap_p;
+    /* sides
+     * |7|1|4|
+     * |2| |3|
+     * |5|0|6|
+     */
+    int nbr_ew[8] = { 0, 1, 2, 3, 1, 0, 0, 1 };
+    int nbr_ns[8] = { 0, 1, 2, 3, 3, 2, 3, 2 };
+    double dx, dy, dist_to_nbr[8], ew_res, ns_res;
+    double slope[8];
+    struct Cell_head window;
+    int skip_me;
+
+    count = 0;
+
+    first_cum = n_points;
+
+    G_message(_("A* Search..."));
+
+    Rast_get_window(&window);
+
+    for (ct_dir = 0; ct_dir < sides; ct_dir++) {
+	/* get r, c (r_nbr, c_nbr) for neighbours */
+	r_nbr = nextdr[ct_dir];
+	c_nbr = nextdc[ct_dir];
+	/* account for rare cases when ns_res != ew_res */
+	dy = abs(r_nbr) * window.ns_res;
+	dx = abs(c_nbr) * window.ew_res;
+	if (ct_dir < 4)
+	    dist_to_nbr[ct_dir] = dx + dy;
+	else
+	    dist_to_nbr[ct_dir] = sqrt(dx * dx + dy * dy);
+    }
+    ew_res = window.ew_res;
+    ns_res = window.ns_res;
+    
+    while (heap_size > 0) {
+	G_percent(count++, n_points, 1);
+	if (count > n_points)
+	    G_fatal_error(_("BUG in A* Search: %lld surplus points"),
+	                  heap_size);
+
+	if (heap_size > n_points)
+	    G_fatal_error
+		(_("BUG in A* Search: too many points in heap %lld, should be %lld"),
+		 heap_size, n_points);
+
+	heap_p = heap_drop();
+
+	r = heap_p.pnt.r;
+	c = heap_p.pnt.c;
+
+	ele_val = heap_p.ele;
+
+	for (ct_dir = 0; ct_dir < sides; ct_dir++) {
+	    /* get r, c (r_nbr, c_nbr) for neighbours */
+	    r_nbr = r + nextdr[ct_dir];
+	    c_nbr = c + nextdc[ct_dir];
+	    slope[ct_dir] = ele_nbr[ct_dir] = 0;
+	    skip_me = 0;
+
+	    /* check that neighbour is within region */
+	    if (r_nbr < 0 || r_nbr >= nrows || c_nbr < 0 || c_nbr >= ncols)
+		continue;
+
+	    bseg_get(&bitflags, &flag_value, r_nbr, c_nbr);
+	    is_in_list = FLAG_GET(flag_value, INLISTFLAG);
+	    is_worked = FLAG_GET(flag_value, WORKEDFLAG);
+	    if (!is_worked) {
+		seg_get(&watalt, (char *)&wa, r_nbr, c_nbr);
+		ele_nbr[ct_dir] = wa.ele;
+		slope[ct_dir] = get_slope(ele_val, ele_nbr[ct_dir],
+			                  dist_to_nbr[ct_dir]);
+	    }
+	    /* avoid diagonal flow direction bias */
+	    if (!is_in_list) {
+		if (ct_dir > 3 && slope[ct_dir] > 0) {
+		    if (slope[nbr_ew[ct_dir]] > 0) {
+			/* slope to ew nbr > slope to center */
+			if (slope[ct_dir] <
+			    get_slope(ele_nbr[nbr_ew[ct_dir]],
+				       ele_nbr[ct_dir], ew_res))
+			    skip_me = 1;
+		    }
+		    if (!skip_me && slope[nbr_ns[ct_dir]] > 0) {
+			/* slope to ns nbr > slope to center */
+			if (slope[ct_dir] <
+			    get_slope(ele_nbr[nbr_ns[ct_dir]],
+				       ele_nbr[ct_dir], ns_res))
+			    skip_me = 1;
+		    }
+		}
+	    }
+
+	    if (is_in_list == 0 && skip_me == 0) {
+		ele_up = ele_nbr[ct_dir];
+		asp_val = drain[r_nbr - r + 1][c_nbr - c + 1];
+		bseg_put(&asp, &asp_val, r_nbr, c_nbr);
+		heap_add(r_nbr, c_nbr, ele_up);
+		FLAG_SET(flag_value, INLISTFLAG);
+		bseg_put(&bitflags, &flag_value, r_nbr, c_nbr);
+	    }
+	    else if (is_in_list && is_worked == 0) {
+		if (FLAG_GET(flag_value, EDGEFLAG)) {
+		    /* neighbour is edge in list, not yet worked */
+		    bseg_get(&asp, &asp_val, r_nbr, c_nbr);
+		    if (asp_val < 0) {
+			/* adjust flow direction for edge cell */
+			asp_val = drain[r_nbr - r + 1][c_nbr - c + 1];
+			bseg_put(&asp, &asp_val, r_nbr, c_nbr);
+		    }
+		}
+		else if (FLAG_GET(flag_value, DEPRFLAG)) {
+		    G_debug(3, "real depression");
+		    /* neighbour is inside real depression, not yet worked */
+		    bseg_get(&asp, &asp_val, r_nbr, c_nbr);
+		    if (asp_val == 0 && ele_val <= ele_nbr[ct_dir]) {
+			asp_val = drain[r_nbr - r + 1][c_nbr - c + 1];
+			bseg_put(&asp, &asp_val, r_nbr, c_nbr);
+			FLAG_UNSET(flag_value, DEPRFLAG);
+			bseg_put(&bitflags, &flag_value, r_nbr, c_nbr);
+		    }
+		}
+	    }
+	}    /* end neighbours */
+	/* add astar points to sorted list for flow accumulation and stream extraction */
+	first_cum--;
+	seg_put(&astar_pts, (char *)&heap_p.pnt, 0, first_cum);
+	bseg_get(&bitflags, &flag_value, r, c);
+	FLAG_SET(flag_value, WORKEDFLAG);
+	bseg_put(&bitflags, &flag_value, r, c);
+    }    /* end A* search */
+
+    G_percent(n_points, n_points, 1);	/* finish it */
+
+    return 1;
+}
+
+/*
+ * compare function for heap
+ * returns 1 if point1 < point2 else 0
+ */
+int heap_cmp(HEAP_PNT *a, HEAP_PNT *b)
+{
+    if (a->ele < b->ele)
+	return 1;
+    else if (a->ele == b->ele) {
+	if (a->added < b->added)
+	    return 1;
+    }
+    return 0;
+}
+
+int sift_up(GW_LARGE_INT start, HEAP_PNT child_p)
+{
+    GW_LARGE_INT parent, child;
+    HEAP_PNT heap_p;
+
+    child = start;
+
+    while (child > 1) {
+	parent = GET_PARENT(child);
+	seg_get(&search_heap, (char *)&heap_p, 0, parent);
+
+	/* push parent point down if child is smaller */
+	if (heap_cmp(&child_p, &heap_p)) {
+	    seg_put(&search_heap, (char *)&heap_p, 0, child);
+	    child = parent;
+	}
+	else
+	    /* no more sifting up, found slot for child */
+	    break;
+    }
+
+    /* add child to heap */
+    seg_put(&search_heap, (char *)&child_p, 0, child);
+
+    return 0;
+}
+
+/*
+ * add item to heap
+ * returns heap_size
+ */
+GW_LARGE_INT heap_add(int r, int c, CELL ele)
+{
+    HEAP_PNT heap_p;
+    
+    /* add point to next free position */
+
+    heap_size++;
+
+    heap_p.added = nxt_avail_pt;
+    heap_p.ele = ele;
+    heap_p.pnt.r = r;
+    heap_p.pnt.c = c;
+
+    nxt_avail_pt++;
+
+    /* sift up: move new point towards top of heap */
+    sift_up(heap_size, heap_p);
+
+    return heap_size;
+}
+
+/*
+ * drop item from heap
+ * returns heap size
+ */
+HEAP_PNT heap_drop(void)
+{
+    GW_LARGE_INT child, childr, parent;
+    GW_LARGE_INT i;
+    HEAP_PNT child_p, childr_p, last_p, root_p;
+
+    seg_get(&search_heap, (char *)&last_p, 0, heap_size);
+    seg_get(&search_heap, (char *)&root_p, 0, 1);
+
+    if (heap_size == 1) {
+	heap_size = 0;
+	return root_p;
+    }
+
+    parent = 1;
+    while ((child = GET_CHILD(parent)) < heap_size) {
+
+	seg_get(&search_heap, (char *)&child_p, 0, child);
+
+	if (child < heap_size) {
+	    childr = child + 1;
+	    i = child + 8;
+	    while (childr < heap_size && childr < i) {
+		seg_get(&search_heap, (char *)&childr_p, 0, childr);
+		if (heap_cmp(&childr_p, &child_p)) {
+		    child = childr;
+		    child_p = childr_p;
+		}
+		childr++;
+	    }
+	}
+
+	if (heap_cmp(&last_p, &child_p)) {
+	    break;
+	}
+
+	/* move hole down */
+	seg_put(&search_heap, (char *)&child_p, 0, parent);
+	parent = child;
+    }
+
+    /* fill hole */
+    if (parent < heap_size) {
+	seg_put(&search_heap, (char *)&last_p, 0, parent);
+    }
+
+    /* the actual drop */
+    heap_size--;
+
+    return root_p;
+}
+
+double get_slope(CELL ele, CELL up_ele, double dist)
+{
+    if (ele >= up_ele)
+	return 0.0;
+    else
+	return (double)(up_ele - ele) / dist;
+}

Added: grass-addons/grass7/grass7/raster/r.stream.extract/dseg.c
===================================================================
--- grass-addons/grass7/grass7/raster/r.stream.extract/dseg.c	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.stream.extract/dseg.c	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,156 @@
+#include <unistd.h>
+#include <fcntl.h>
+#include <grass/glocale.h>
+#include "seg.h"
+
+int dseg_open(DSEG *dseg, int srows, int scols, int nsegs_in_memory)
+{
+    char *filename;
+    int errflag;
+    int fd;
+
+    dseg->filename = NULL;
+    dseg->fd = -1;
+    dseg->name = NULL;
+    dseg->mapset = NULL;
+
+    filename = G_tempfile();
+    if (-1 == (fd = creat(filename, 0666))) {
+	G_warning(_("dseg_open(): unable to create segment file"));
+	return -2;
+    }
+    if (0 >
+	(errflag =
+	 segment_format(fd, Rast_window_rows(), Rast_window_cols(), srows, scols,
+			sizeof(DCELL)))) {
+	close(fd);
+	unlink(filename);
+	if (errflag == -1) {
+	    G_warning(_("dseg_open(): could not write segment file"));
+	    return -1;
+	}
+	else {
+	    G_warning(_("dseg_open(): illegal configuration parameter(s)"));
+	    return -3;
+	}
+    }
+    close(fd);
+    if (-1 == (fd = open(filename, 2))) {
+	unlink(filename);
+	G_warning(_("dseg_open(): unable to re-open segment file"));
+	return -4;
+    }
+    if (0 > (errflag = segment_init(&(dseg->seg), fd, nsegs_in_memory))) {
+	close(fd);
+	unlink(filename);
+	if (errflag == -1) {
+	    G_warning(_("dseg_open(): could not read segment file"));
+	    return -5;
+	}
+	else {
+	    G_warning(_("dseg_open(): out of memory"));
+	    return -6;
+	}
+    }
+    dseg->filename = filename;
+    dseg->fd = fd;
+    return 0;
+}
+
+int dseg_close(DSEG *dseg)
+{
+    segment_release(&(dseg->seg));
+    close(dseg->fd);
+    unlink(dseg->filename);
+    if (dseg->name) {
+	G_free(dseg->name);
+	dseg->name = NULL;
+    }
+    if (dseg->mapset) {
+	G_free(dseg->mapset);
+	dseg->mapset = NULL;
+    }
+    return 0;
+}
+
+int dseg_put(DSEG *dseg, DCELL *value, int row, int col)
+{
+    if (segment_put(&(dseg->seg), (DCELL *) value, row, col) < 0) {
+	G_warning(_("dseg_put(): could not write segment file"));
+	return -1;
+    }
+    return 0;
+}
+
+int dseg_put_row(DSEG *dseg, DCELL *value, int row)
+{
+    if (segment_put_row(&(dseg->seg), (DCELL *) value, row) < 0) {
+	G_warning(_("dseg_put(): could not write segment file"));
+	return -1;
+    }
+    return 0;
+}
+
+int dseg_get(DSEG *dseg, DCELL *value, int row, int col)
+{
+    if (segment_get(&(dseg->seg), (DCELL *) value, row, col) < 0) {
+	G_warning(_("dseg_get(): could not read segment file"));
+	return -1;
+    }
+    return 0;
+}
+
+int dseg_read_raster(DSEG *dseg, char *map_name, char *mapset)
+{
+    int row, nrows, ncols;
+    int map_fd;
+    DCELL *dbuffer;
+
+    dseg->name = NULL;
+    dseg->mapset = NULL;
+
+    map_fd = Rast_open_old(map_name, mapset);
+    nrows = Rast_window_rows();
+    ncols = Rast_window_cols();
+    dbuffer = Rast_allocate_d_buf();
+    for (row = 0; row < nrows; row++) {
+	Rast_get_d_row(map_fd, dbuffer, row);
+	if (segment_put_row(&(dseg->seg), (DCELL *) dbuffer, row) < 0) {
+	    G_free(dbuffer);
+	    Rast_close(map_fd);
+	    G_warning(_("dseg_read_raster(): unable to segment put row for <%s> in <%s>"),
+		    map_name, mapset);
+	    return (-1);
+	}
+    }
+
+    Rast_close(map_fd);
+    G_free(dbuffer);
+
+    dseg->name = G_store(map_name);
+    dseg->mapset = G_store(mapset);
+
+    return 0;
+}
+
+int dseg_write_cellfile(DSEG *dseg, char *map_name)
+{
+    int map_fd;
+    int row, nrows, ncols;
+    DCELL *dbuffer;
+
+    map_fd = Rast_open_new(map_name, DCELL_TYPE);
+    nrows = Rast_window_rows();
+    ncols = Rast_window_cols();
+    dbuffer = Rast_allocate_d_buf();
+    segment_flush(&(dseg->seg));
+    for (row = 0; row < nrows; row++) {
+	G_percent(row, nrows, 1);
+	segment_get_row(&(dseg->seg), (DCELL *) dbuffer, row);
+	Rast_put_row(map_fd, dbuffer, DCELL_TYPE);
+    }
+    G_percent(row, nrows, 1);    /* finish it */
+    G_free(dbuffer);
+    Rast_close(map_fd);
+    return 0;
+}

Added: grass-addons/grass7/grass7/raster/r.stream.extract/flag.h
===================================================================
--- grass-addons/grass7/grass7/raster/r.stream.extract/flag.h	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.stream.extract/flag.h	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,36 @@
+#ifndef __FLAG_H__
+#define __FLAG_H__
+
+/* a set of routines that allow the programmer to "flag" cells in a
+ * raster map. A flag is of type unsigned char, i.e. 8 bits can be set. 
+ *
+ * int flag_set(flag, bitno)
+ *     sets the flag at position bitno to one.
+ *
+ * int flag_unset(flag, bitno)
+ *     sets the flag at position bitno to zero.
+ *
+ * int flag_get(flag, bitno)
+ *     checks if the flag is set at postion bitno.
+ *
+ * Examples:
+ * set flag at position 0: FLAG_SET(flag, 0)
+ * unset (clear) flag at position 7: FLAG_UNSET(flag, 7)
+ * check flag at position 5: is_set_at_5 = FLAG_GET(flag, 5)
+ */
+
+/* flag positions */
+#define NULLFLAG         0      /* elevation is NULL */
+#define EDGEFLAG         1      /* edge cell */
+#define INLISTFLAG       2      /* in open A* list */
+#define WORKEDFLAG       3      /* in closed A* list/ accumulation done */
+#define STREAMFLAG       4      /* stream */
+#define DEPRFLAG         5      /* real depression */
+#define WORKED2FLAG      6      /* extraction done */
+/* last bit is unused */
+
+#define FLAG_SET(flag,bitno) ((flag) |= (1 << (bitno)))
+#define FLAG_UNSET(flag,bitno) ((flag) &= ~(1 << (bitno)))
+#define FLAG_GET(flag,bitno) ((flag) & (1 << (bitno)))
+
+#endif /* __FLAG_H__ */

Added: grass-addons/grass7/grass7/raster/r.stream.extract/init_search.c
===================================================================
--- grass-addons/grass7/grass7/raster/r.stream.extract/init_search.c	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.stream.extract/init_search.c	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,122 @@
+#include <grass/raster.h>
+#include <grass/glocale.h>
+#include "local_proto.h"
+
+int init_search(int depr_fd)
+{
+    int r, c, r_nbr, c_nbr, ct_dir;
+    CELL *depr_buf, ele_value;
+    int nextdr[8] = { 1, -1, 0, 0, -1, 1, 1, -1 };
+    int nextdc[8] = { 0, 0, -1, 1, 1, -1, 1, -1 };
+    char flag_value, flag_value_nbr, is_null;
+    WAT_ALT wa;
+    char asp_value;
+    GW_LARGE_INT n_depr_cells = 0;
+
+    nxt_avail_pt = heap_size = 0;
+
+    /* load edge cells and real depressions to A* heap */
+    if (depr_fd >= 0)
+	depr_buf = Rast_allocate_buf(CELL_TYPE);
+    else
+	depr_buf = NULL;
+
+    G_message(_("Initializing A* Search..."));
+    for (r = 0; r < nrows; r++) {
+	G_percent(r, nrows, 2);
+
+	if (depr_fd >= 0) {
+	    Rast_get_row(depr_fd, depr_buf, r, CELL_TYPE);
+	}
+
+	for (c = 0; c < ncols; c++) {
+
+	    bseg_get(&bitflags, &flag_value, r, c);
+	    is_null = FLAG_GET(flag_value, NULLFLAG);
+
+	    if (is_null)
+		continue;
+
+	    asp_value = 0;
+	    if (r == 0 || r == nrows - 1 || c == 0 || c == ncols - 1) {
+
+		if (r == 0 && c == 0)
+		    asp_value = -7;
+		else if (r == 0 && c == ncols - 1)
+		    asp_value = -5;
+		else if (r == nrows - 1 && c == 0)
+		    asp_value = -1;
+		else if (r == nrows - 1 && c == ncols - 1)
+		    asp_value = -3;
+		else if (r == 0)
+		    asp_value = -2;
+		else if (c == 0)
+		    asp_value = -4;
+		else if (r == nrows - 1)
+		    asp_value = -6;
+		else if (c == ncols - 1)
+		    asp_value = -8;
+
+		seg_get(&watalt, (char *)&wa, r, c);
+		ele_value = wa.ele;
+		heap_add(r, c, ele_value);
+		FLAG_SET(flag_value, INLISTFLAG);
+		FLAG_SET(flag_value, EDGEFLAG);
+		bseg_put(&bitflags, &flag_value, r, c);
+		bseg_put(&asp, &asp_value, r, c);
+		continue;
+	    }
+
+	    /* any neighbour NULL ? */
+	    for (ct_dir = 0; ct_dir < sides; ct_dir++) {
+		/* get r, c (r_nbr, c_nbr) for neighbours */
+		r_nbr = r + nextdr[ct_dir];
+		c_nbr = c + nextdc[ct_dir];
+
+		bseg_get(&bitflags, &flag_value_nbr, r_nbr, c_nbr);
+		is_null = FLAG_GET(flag_value_nbr, NULLFLAG);
+
+		if (is_null) {
+		    asp_value = -1 * drain[r - r_nbr + 1][c - c_nbr + 1];
+		    seg_get(&watalt, (char *)&wa, r, c);
+		    ele_value = wa.ele;
+		    heap_add(r, c, ele_value);
+		    FLAG_SET(flag_value, INLISTFLAG);
+		    FLAG_SET(flag_value, EDGEFLAG);
+		    bseg_put(&bitflags, &flag_value, r, c);
+		    bseg_put(&asp, &asp_value, r, c);
+
+		    break;
+		}
+	    }
+	    if (asp_value) /* some neighbour was NULL, point added to list */
+		continue;
+	    
+	    /* real depression ? */
+	    if (depr_fd >= 0) {
+		if (!Rast_is_c_null_value(&depr_buf[c]) && depr_buf[c] != 0) {
+		    seg_get(&watalt, (char *)&wa, r, c);
+		    ele_value = wa.ele;
+		    heap_add(r, c, ele_value);
+		    FLAG_SET(flag_value, INLISTFLAG);
+		    FLAG_SET(flag_value, DEPRFLAG);
+		    bseg_put(&bitflags, &flag_value, r, c);
+		    bseg_put(&asp, &asp_value, r, c);
+		    n_depr_cells++;
+		}
+	    }
+	}
+    }
+    G_percent(nrows, nrows, 2);	/* finish it */
+
+    if (depr_fd >= 0) {
+	Rast_close(depr_fd);
+	G_free(depr_buf);
+    }
+
+    G_debug(1, "%lld edge cells", heap_size - n_depr_cells);
+    if (n_depr_cells)
+	G_debug(1, "%lld cells in depressions", n_depr_cells);
+
+    return 1;
+}

Added: grass-addons/grass7/grass7/raster/r.stream.extract/load.c
===================================================================
--- grass-addons/grass7/grass7/raster/r.stream.extract/load.c	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.stream.extract/load.c	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,168 @@
+#include <grass/raster.h>
+#include <grass/glocale.h>
+#include "local_proto.h"
+
+/* need elevation map, do A* search on elevation like for r.watershed */
+
+int ele_round(double x)
+{
+    if (x >= 0.0)
+	return x + .5;
+    else
+	return x - .5;
+}
+
+/*
+ * loads elevation and optional flow accumulation map to memory and
+ * gets start points for A* Search
+ * start points are edges
+ */
+int load_maps(int ele_fd, int acc_fd)
+{
+    int r, c;
+    void *ele_buf, *ptr, *acc_buf = NULL, *acc_ptr = NULL;
+    CELL ele_value, *stream_id;
+    DCELL dvalue, acc_value;
+    size_t ele_size, acc_size = 0;
+    int ele_map_type, acc_map_type = 0;
+    WAT_ALT *wabuf;
+    char *flag_value_buf, *aspect;
+
+    if (acc_fd < 0)
+	G_message(_("Loading elevation map..."));
+    else
+	G_message(_("Loading input maps..."));
+
+    n_search_points = n_points = 0;
+
+    G_debug(1, "get buffers");
+    ele_map_type = Rast_get_map_type(ele_fd);
+    ele_size = Rast_cell_size(ele_map_type);
+    ele_buf = Rast_allocate_buf(ele_map_type);
+
+    if (ele_buf == NULL) {
+	G_warning(_("Could not allocate memory"));
+	return -1;
+    }
+
+    if (acc_fd >= 0) {
+	acc_map_type = Rast_get_map_type(acc_fd);
+	acc_size = Rast_cell_size(acc_map_type);
+	acc_buf = Rast_allocate_buf(acc_map_type);
+	if (acc_buf == NULL) {
+	    G_warning(_("Could not allocate memory"));
+	    return -1;
+	}
+    }
+
+    ele_scale = 1;
+    if (ele_map_type == FCELL_TYPE || ele_map_type == DCELL_TYPE)
+	ele_scale = 1000;	/* should be enough to do the trick */
+
+    wabuf = G_malloc(ncols * sizeof(WAT_ALT));
+    flag_value_buf = G_malloc(ncols * sizeof(char));
+    stream_id = G_malloc(ncols * sizeof(CELL));
+    aspect = G_malloc(ncols * sizeof(char));
+
+    G_debug(1, "start loading %d rows, %d cols", nrows, ncols);
+    for (r = 0; r < nrows; r++) {
+
+	G_percent(r, nrows, 2);
+
+	Rast_get_row(ele_fd, ele_buf, r, ele_map_type);
+	ptr = ele_buf;
+
+	if (acc_fd >= 0) {
+	    Rast_get_row(acc_fd, acc_buf, r, acc_map_type);
+	    acc_ptr = acc_buf;
+	}
+
+	for (c = 0; c < ncols; c++) {
+
+	    flag_value_buf[c] = 0;
+	    aspect[c] = 0;
+	    stream_id[c] = 0;
+
+	    /* check for masked and NULL cells */
+	    if (Rast_is_null_value(ptr, ele_map_type)) {
+		FLAG_SET(flag_value_buf[c], NULLFLAG);
+		FLAG_SET(flag_value_buf[c], INLISTFLAG);
+		FLAG_SET(flag_value_buf[c], WORKEDFLAG);
+		FLAG_SET(flag_value_buf[c], WORKED2FLAG);
+		Rast_set_c_null_value(&ele_value, 1);
+		/* flow accumulation */
+		if (acc_fd >= 0) {
+		    if (!Rast_is_null_value(acc_ptr, acc_map_type))
+			G_fatal_error(_("Elevation map is NULL but accumulation map is not NULL!"));
+		}
+		Rast_set_d_null_value(&acc_value, 1);
+	    }
+	    else {
+		switch (ele_map_type) {
+		case CELL_TYPE:
+		    ele_value = *((CELL *) ptr);
+		    break;
+		case FCELL_TYPE:
+		    dvalue = *((FCELL *) ptr);
+		    dvalue *= ele_scale;
+		    ele_value = ele_round(dvalue);
+		    break;
+		case DCELL_TYPE:
+		    dvalue = *((DCELL *) ptr);
+		    dvalue *= ele_scale;
+		    ele_value = ele_round(dvalue);
+		    break;
+		}
+		if (acc_fd < 0)
+		    acc_value = 1;
+		else {
+		    if (Rast_is_null_value(acc_ptr, acc_map_type)) {
+			/* can this be ok after weighing ? */
+			G_fatal_error(_("Accumulation map is NULL but elevation map is not NULL!"));
+		    }
+
+		    switch (acc_map_type) {
+		    case CELL_TYPE:
+			acc_value = *((CELL *) acc_ptr);
+			break;
+		    case FCELL_TYPE:
+			acc_value = *((FCELL *) acc_ptr);
+			break;
+		    case DCELL_TYPE:
+			acc_value = *((DCELL *) acc_ptr);
+			break;
+		    }
+		}
+
+		n_points++;
+	    }
+
+	    wabuf[c].wat = acc_value;
+	    wabuf[c].ele = ele_value;
+	    ptr = G_incr_void_ptr(ptr, ele_size);
+	    if (acc_fd >= 0)
+		acc_ptr = G_incr_void_ptr(acc_ptr, acc_size);
+	}
+	seg_put_row(&watalt, (char *) wabuf, r);
+	bseg_put_row(&asp, aspect, r);
+	cseg_put_row(&stream, stream_id, r);
+	bseg_put_row(&bitflags, flag_value_buf, r);
+    }
+    G_percent(nrows, nrows, 1);	/* finish it */
+
+    Rast_close(ele_fd);
+    G_free(ele_buf);
+    G_free(wabuf);
+    G_free(flag_value_buf);
+    G_free(stream_id);
+    G_free(aspect);
+
+    if (acc_fd >= 0) {
+	Rast_close(acc_fd);
+	G_free(acc_buf);
+    }
+    
+    G_debug(1, "%lld non-NULL cells", n_points);
+
+    return n_points;
+}

Added: grass-addons/grass7/grass7/raster/r.stream.extract/local_proto.h
===================================================================
--- grass-addons/grass7/grass7/raster/r.stream.extract/local_proto.h	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.stream.extract/local_proto.h	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,89 @@
+
+#ifndef __LOCAL_PROTO_H__
+#define __LOCAL_PROTO_H__
+
+#include <grass/raster.h>
+#include "flag.h"
+#include "seg.h"
+
+#define GW_LARGE_INT off_t
+
+#define INDEX(r, c) ((r) * ncols + (c))
+#define MAXDEPTH 1000     /* maximum supported tree depth of stream network */
+
+#define POINT       struct a_point
+POINT {
+    int r, c;
+};
+
+#define HEAP_PNT    struct heap_point
+HEAP_PNT {
+   GW_LARGE_INT added;
+   CELL ele;
+   POINT pnt;
+};
+
+#define WAT_ALT    struct wat_altitude
+WAT_ALT {
+   CELL ele;
+   DCELL wat;
+};
+
+struct snode
+{
+    int r, c;
+    int id;
+    int n_trib;           /* number of tributaries */
+    int n_trib_total;     /* number of all upstream stream segments */
+    int n_alloc;          /* n allocated tributaries */
+    int *trib;
+};
+
+/* extern variables */
+extern struct snode *stream_node;
+extern int nrows, ncols;
+extern GW_LARGE_INT n_search_points, n_points, nxt_avail_pt;
+extern GW_LARGE_INT heap_size;
+extern unsigned int n_stream_nodes, n_alloc_nodes;
+extern POINT *outlets;
+extern unsigned int n_outlets, n_alloc_outlets;
+extern char drain[3][3];
+extern char sides;
+extern int c_fac;
+extern int ele_scale;
+extern int have_depressions;
+
+extern SSEG search_heap;
+extern SSEG astar_pts;
+extern BSEG bitflags;
+extern SSEG watalt;
+extern BSEG asp;
+extern CSEG stream;
+
+/* load.c */
+int load_maps(int, int);
+
+/* init_search.c */
+int init_search(int);
+
+/* do_astar.c */
+int do_astar(void);
+GW_LARGE_INT heap_add(int, int, CELL);
+
+/* streams.c */
+int do_accum(double);
+int extract_streams(double, double, int, int);
+
+/* thin.c */
+int thin_streams(void);
+
+/* basins.c */
+int basin_borders(void);
+
+/* del_streams.c */
+int del_streams(int);
+
+/* close.c */
+int close_maps(char *, char *, char *);
+
+#endif /* __LOCAL_PROTO_H__ */

Added: grass-addons/grass7/grass7/raster/r.stream.extract/main.c
===================================================================
--- grass-addons/grass7/grass7/raster/r.stream.extract/main.c	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.stream.extract/main.c	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,442 @@
+
+/****************************************************************************
+ *
+ * MODULE:       r.stream.extract
+ * AUTHOR(S):    Markus Metz <markus.metz.giswork gmail.com>
+ * PURPOSE:      Hydrological analysis
+ *               Extracts stream networks from accumulation raster with
+ *               given threshold
+ * COPYRIGHT:    (C) 1999-2009 by the GRASS Development Team
+ *
+ *               This program is free software under the GNU General Public
+ *               License (>=v2). Read the file COPYING that comes with GRASS
+ *               for details.
+ *
+ *****************************************************************************/
+#include <stdlib.h>
+#include <string.h>
+#include <float.h>
+#include <math.h>
+#include <grass/raster.h>
+#include <grass/glocale.h>
+#include "local_proto.h"
+
+/* global variables */
+struct snode *stream_node;
+int nrows, ncols;
+GW_LARGE_INT n_search_points, n_points, nxt_avail_pt;
+GW_LARGE_INT heap_size;
+unsigned int n_stream_nodes, n_alloc_nodes;
+POINT *outlets;
+unsigned int n_outlets, n_alloc_outlets;
+char drain[3][3] = { {7, 6, 5}, {8, 0, 4}, {1, 2, 3} };
+char sides;
+int c_fac;
+int ele_scale;
+int have_depressions;
+
+SSEG search_heap;
+SSEG astar_pts;
+BSEG bitflags;
+SSEG watalt;
+BSEG asp;
+CSEG stream;
+
+CELL *astar_order;
+
+int main(int argc, char *argv[])
+{
+    struct
+    {
+	struct Option *ele, *acc, *depression;
+	struct Option *threshold, *d8cut;
+	struct Option *mont_exp;
+	struct Option *min_stream_length;
+	struct Option *memory;
+    } input;
+    struct
+    {
+	struct Option *stream_rast;
+	struct Option *stream_vect;
+	struct Option *dir_rast;
+    } output;
+    struct GModule *module;
+    int ele_fd, acc_fd, depr_fd;
+    double threshold, d8cut, mont_exp;
+    int min_stream_length = 0, memory;
+    int seg_cols, seg_rows;
+    double seg2kb;
+    int num_open_segs, num_open_array_segs, num_seg_total;
+    double memory_divisor, heap_mem, disk_space;
+    const char *mapset;
+
+    G_gisinit(argv[0]);
+
+    /* Set description */
+    module = G_define_module();
+    G_add_keyword(_("raster"));
+    G_add_keyword(_("hydrology"));
+    module->description = _("Stream network extraction");
+
+    input.ele = G_define_standard_option(G_OPT_R_INPUT);
+    input.ele->key = "elevation";
+    input.ele->label = _("Elevation map");
+    input.ele->description = _("Elevation on which entire analysis is based");
+
+    input.acc = G_define_standard_option(G_OPT_R_INPUT);
+    input.acc->key = "accumulation";
+    input.acc->label = _("Accumulation map");
+    input.acc->required = NO;
+    input.acc->description =
+	_("Stream extraction will use provided accumulation instead of calculating it anew");
+
+    input.depression = G_define_standard_option(G_OPT_R_INPUT);
+    input.depression->key = "depression";
+    input.depression->label = _("Map with real depressions");
+    input.depression->required = NO;
+    input.depression->description =
+	_("Streams will not be routed out of real depressions");
+
+    input.threshold = G_define_option();
+    input.threshold->key = "threshold";
+    input.threshold->label = _("Minimum flow accumulation for streams");
+    input.threshold->description = _("Must be > 0");
+    input.threshold->required = YES;
+    input.threshold->type = TYPE_DOUBLE;
+
+    input.d8cut = G_define_option();
+    input.d8cut->key = "d8cut";
+    input.d8cut->label = _("Use SFD above this threshold");
+    input.d8cut->description =
+	_("If accumulation is larger than d8cut, SFD is used instead of MFD."
+	  " Applies only if no accumulation map is given.");
+    input.d8cut->required = NO;
+    input.d8cut->answer = "infinity";
+    input.d8cut->type = TYPE_DOUBLE;
+
+    input.mont_exp = G_define_option();
+    input.mont_exp->key = "mexp";
+    input.mont_exp->type = TYPE_DOUBLE;
+    input.mont_exp->required = NO;
+    input.mont_exp->answer = "0";
+    input.mont_exp->label =
+	_("Montgomery exponent for slope, disabled with 0");
+    input.mont_exp->description =
+	_("Montgomery: accumulation is multiplied with pow(slope,mexp) and then compared with threshold.");
+
+    input.min_stream_length = G_define_option();
+    input.min_stream_length->key = "stream_length";
+    input.min_stream_length->type = TYPE_INTEGER;
+    input.min_stream_length->required = NO;
+    input.min_stream_length->answer = "0";
+    input.min_stream_length->label =
+	_("Delete stream segments shorter than stream_length cells.");
+    input.min_stream_length->description =
+	_("Applies only to first-order stream segments (springs/stream heads).");
+
+    input.memory = G_define_option();
+    input.memory->key = "memory";
+    input.memory->type = TYPE_INTEGER;
+    input.memory->required = NO;
+    input.memory->answer = "300";
+    input.memory->description = _("Maximum memory to be used in MB");
+
+    output.stream_rast = G_define_standard_option(G_OPT_R_OUTPUT);
+    output.stream_rast->key = "stream_rast";
+    output.stream_rast->description =
+	_("Output raster map with unique stream ids");
+    output.stream_rast->required = NO;
+    output.stream_rast->guisection = _("Output options");
+
+    output.stream_vect = G_define_standard_option(G_OPT_V_OUTPUT);
+    output.stream_vect->key = "stream_vect";
+    output.stream_vect->description =
+	_("Output vector with unique stream ids");
+    output.stream_vect->required = NO;
+    output.stream_vect->guisection = _("Output options");
+
+    output.dir_rast = G_define_standard_option(G_OPT_R_OUTPUT);
+    output.dir_rast->key = "direction";
+    output.dir_rast->description =
+	_("Output raster map with flow direction");
+    output.dir_rast->required = NO;
+    output.dir_rast->guisection = _("Output options");
+
+    if (G_parser(argc, argv))
+	exit(EXIT_FAILURE);
+
+    /***********************/
+    /*    check options    */
+    /***********************/
+
+    /* input maps exist ? */
+    if (!G_find_raster(input.ele->answer, ""))
+	G_fatal_error(_("Raster map <%s> not found"), input.ele->answer);
+
+    if (input.acc->answer) {
+	if (!G_find_raster(input.acc->answer, ""))
+	    G_fatal_error(_("Raster map <%s> not found"), input.acc->answer);
+    }
+
+    if (input.depression->answer) {
+	if (!G_find_raster(input.depression->answer, ""))
+	    G_fatal_error(_("Raster map <%s> not found"), input.depression->answer);
+	have_depressions = 1;
+    }
+    else
+	have_depressions = 0;
+
+    /* threshold makes sense */
+    threshold = atof(input.threshold->answer);
+    if (threshold <= 0)
+	G_fatal_error(_("Threshold must be > 0 but is %f"), threshold);
+
+    /* d8cut */
+    if (strcmp(input.d8cut->answer, "infinity") == 0) {
+	d8cut = DBL_MAX;
+    }
+    else {
+	d8cut = atof(input.d8cut->answer);
+	if (d8cut < 0)
+	    G_fatal_error(_("d8cut must be positive or zero but is %f"),
+			  d8cut);
+    }
+
+    /* Montgomery stream initiation */
+    if (input.mont_exp->answer) {
+	mont_exp = atof(input.mont_exp->answer);
+	if (mont_exp < 0)
+	    G_fatal_error(_("Montgomery exponent must be positive or zero but is %f"),
+			  mont_exp);
+	if (mont_exp > 3)
+	    G_warning(_("Montgomery exponent is %f, recommended range is 0.0 - 3.0"),
+		      mont_exp);
+    }
+    else
+	mont_exp = 0;
+
+    /* Minimum stream segment length */
+    if (input.min_stream_length->answer) {
+	min_stream_length = atoi(input.min_stream_length->answer);
+	if (min_stream_length < 0)
+	    G_fatal_error(_("Minimum stream length must be positive or zero but is %d"),
+			  min_stream_length);
+    }
+    else
+	min_stream_length = 0;
+	
+    if (input.memory->answer) {
+	memory = atoi(input.memory->answer);
+	if (memory <= 0)
+	    G_fatal_error(_("Memory must be positive but is %d"),
+			  memory);
+    }
+    else
+	memory = 300;
+
+    /* Check for some output map */
+    if ((output.stream_rast->answer == NULL)
+	&& (output.stream_vect->answer == NULL)
+	&& (output.dir_rast->answer == NULL)) {
+	G_fatal_error(_("Sorry, you must choose at least one output map."));
+    }
+
+    /*********************/
+    /*    preparation    */
+    /*********************/
+
+    /* open input maps */
+    mapset = G_find_raster2(input.ele->answer, "");
+    ele_fd = Rast_open_old(input.ele->answer, mapset);
+    if (ele_fd < 0)
+	G_fatal_error(_("Could not open input map %s"), input.ele->answer);
+
+    if (input.acc->answer) {
+	mapset = G_find_raster2(input.acc->answer, "");
+	acc_fd = Rast_open_old(input.acc->answer, mapset);
+	if (acc_fd < 0)
+	    G_fatal_error(_("Could not open input map %s"),
+			  input.acc->answer);
+    }
+    else
+	acc_fd = -1;
+
+    if (input.depression->answer) {
+	mapset = G_find_raster2(input.depression->answer, "");
+	depr_fd = Rast_open_old(input.depression->answer, mapset);
+	if (depr_fd < 0)
+	    G_fatal_error(_("Could not open input map %s"),
+			  input.depression->answer);
+    }
+    else
+	depr_fd = -1;
+
+    /* set global variables */
+    nrows = Rast_window_rows();
+    ncols = Rast_window_cols();
+    sides = 8;	/* not a user option */
+    c_fac = 5;	/* not a user option, MFD covergence factor 5 gives best results */
+
+    /* segment structures */
+    seg_rows = seg_cols = 64;
+    seg2kb = seg_rows * seg_cols / 1024.;
+
+    /* balance segment files */
+    /* elevation + accumulation: * 2 */
+    memory_divisor = sizeof(WAT_ALT) * 2;
+    disk_space = sizeof(WAT_ALT);
+    /* aspect: as is */
+    memory_divisor += sizeof(char);
+    disk_space += sizeof(char);
+    /* stream ids: / 2 */
+    memory_divisor += sizeof(int) / 2.;
+    disk_space += sizeof(int);
+    /* flags: * 4 */
+    memory_divisor += sizeof(char) * 4;
+    disk_space += sizeof(char);
+    /* astar_points: / 16 */
+    /* ideally only a few but large segments */
+    memory_divisor += sizeof(POINT) / 16.;
+    disk_space += sizeof(POINT);
+    /* heap points: / 4 */
+    memory_divisor += sizeof(HEAP_PNT) / 4.;
+    disk_space += sizeof(HEAP_PNT);
+    
+    /* KB -> MB */
+    memory_divisor *= seg2kb / 1024.;
+    disk_space *= seg2kb / 1024.;
+
+    num_open_segs = memory / memory_divisor;
+    heap_mem = num_open_segs * seg2kb * sizeof(HEAP_PNT) /
+               (4. * 1024.);
+    num_seg_total = (ncols / seg_cols + 1) * (nrows / seg_rows + 1);
+    if (num_open_segs > num_seg_total) {
+	heap_mem += (num_open_segs - num_seg_total) * memory_divisor;
+	heap_mem -= (num_open_segs - num_seg_total) * seg2kb *
+		    sizeof(HEAP_PNT) / (4. * 1024.);
+	num_open_segs = num_seg_total;
+    }
+    if (num_open_segs < 16) {
+	num_open_segs = 16;
+	heap_mem = num_open_segs * seg2kb * sizeof(HEAP_PNT) /
+	           (4. * 1024.);
+    }
+    G_verbose_message(_("%.2f%% of data are kept in memory"),
+                      100. * num_open_segs / num_seg_total);
+    disk_space *= num_seg_total;
+    if (disk_space < 1024.0)
+	G_verbose_message(_("Will need up to %.2f MB of disk space"), disk_space);
+    else
+	G_verbose_message(_("Will need up to %.2f GB (%.0f MB) of disk space"),
+	           disk_space / 1024.0, disk_space);
+
+    /* open segment files */
+    G_verbose_message(_("Creating temporary files..."));
+    seg_open(&watalt, nrows, ncols, seg_rows, seg_cols, num_open_segs * 2,
+        sizeof(WAT_ALT), 1);
+    if (num_open_segs * 2 > num_seg_total)
+	heap_mem += (num_open_segs * 2 - num_seg_total) * seg2kb *
+	            sizeof(WAT_ALT) / 1024.;
+    cseg_open(&stream, seg_rows, seg_cols, num_open_segs / 2.);
+    bseg_open(&asp, seg_rows, seg_cols, num_open_segs);
+    bseg_open(&bitflags, seg_rows, seg_cols, num_open_segs * 4);
+    if (num_open_segs * 4 > num_seg_total)
+	heap_mem += (num_open_segs * 4 - num_seg_total) * seg2kb / 1024.;
+
+    /* load maps */
+    if (load_maps(ele_fd, acc_fd) < 0)
+	G_fatal_error(_("Could not load input map(s)"));
+    else if (!n_points)
+	G_fatal_error(_("No non-NULL cells in input map(s)"));
+
+    G_debug(1, "open segments for A* points");
+    /* columns per segment */
+    seg_cols = seg_rows * seg_rows;
+    num_seg_total = n_points / seg_cols;
+    if (n_points % seg_cols > 0)
+	num_seg_total++;
+    /* no need to have more segments open than exist */
+    num_open_array_segs = num_open_segs / 16.;
+    if (num_open_array_segs > num_seg_total)
+	num_open_array_segs = num_seg_total;
+    if (num_open_array_segs < 1)
+	num_open_array_segs = 1;
+    
+    G_debug(1, "segment size for A* points: %d", seg_cols);
+    seg_open(&astar_pts, 1, n_points, 1, seg_cols, num_open_array_segs,
+	     sizeof(POINT), 1);
+
+    /* one-based d-ary search_heap with astar_pts */
+    G_debug(1, "open segments for A* search heap");
+	
+    /* allowed memory for search heap in MB */
+    G_debug(1, "heap memory %.2f MB", heap_mem);
+    /* columns per segment */
+    /* larger is faster */
+    seg_cols = seg_rows * seg_rows * seg_rows;
+    num_seg_total = n_points / seg_cols;
+    if (n_points % seg_cols > 0)
+	num_seg_total++;
+    /* no need to have more segments open than exist */
+    num_open_array_segs = (1 << 20) * heap_mem / (seg_cols * sizeof(HEAP_PNT));
+    if (num_open_array_segs > num_seg_total)
+	num_open_array_segs = num_seg_total;
+    if (num_open_array_segs < 2)
+	num_open_array_segs = 2;
+
+    G_debug(1, "A* search heap open segments %d, total %d",
+            num_open_array_segs, num_seg_total);
+    G_debug(1, "segment size for heap points: %d", seg_cols);
+    /* the search heap will not hold more than 5% of all points at any given time ? */
+    /* chances are good that the heap will fit into one large segment */
+    seg_open(&search_heap, 1, n_points + 1, 1, seg_cols,
+	     num_open_array_segs, sizeof(HEAP_PNT), 1);
+
+    /********************/
+    /*    processing    */
+    /********************/
+
+    /* initialize A* search */
+    if (init_search(depr_fd) < 0)
+	G_fatal_error(_("Could not initialize search"));
+
+    /* sort elevation and get initial stream direction */
+    if (do_astar() < 0)
+	G_fatal_error(_("Could not sort elevation map"));
+    seg_close(&search_heap);
+
+    if (acc_fd < 0) {
+	/* accumulate surface flow */
+	if (do_accum(d8cut) < 0)
+	    G_fatal_error(_("Could not calculate flow accumulation"));
+    }
+
+    /* extract streams */
+    if (extract_streams
+	(threshold, mont_exp, min_stream_length, acc_fd < 0) < 0)
+	G_fatal_error(_("Could not extract streams"));
+
+    seg_close(&astar_pts);
+    seg_close(&watalt);
+
+    /* thin streams */
+    if (thin_streams() < 0)
+	G_fatal_error(_("Could not thin streams"));
+
+    /* delete short streams */
+    if (min_stream_length) {
+	if (del_streams(min_stream_length) < 0)
+	    G_fatal_error(_("Could not delete short stream segments"));
+    }
+
+    /* write output maps */
+    if (close_maps(output.stream_rast->answer, output.stream_vect->answer,
+		   output.dir_rast->answer) < 0)
+	G_fatal_error(_("Could not write output maps"));
+
+    bseg_close(&asp);
+    cseg_close(&stream);
+    bseg_close(&bitflags);
+
+    exit(EXIT_SUCCESS);
+}

Added: grass-addons/grass7/grass7/raster/r.stream.extract/r.stream.extract.html
===================================================================
--- grass-addons/grass7/grass7/raster/r.stream.extract/r.stream.extract.html	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.stream.extract/r.stream.extract.html	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,239 @@
+<h2>DESCRIPTION</h2>
+
+<em>r.stream.extract</em> extracts streams in both raster and vector
+format from a required input <em>elevation</em> map and optional input
+<em>accumulation map</em>.
+
+<h2>OPTIONS</h2>
+
+<dl>
+<dt><em>elevation</em> 
+<dd>Input map, required: Elevation on which entire analysis is based.
+NULL (nodata) cells are ignored, zero and negative values are valid
+elevation data. Gaps in the elevation map that are located within the
+area of interest must be filled beforehand, e.g. with
+<em>r.fillnulls</em>, to avoid distortions.
+<p>
+<dt><em>accumulation</em>
+<dd>Input map, optional: Accumulation values of the provided
+<em>accumulation</em> map are used and not calculated from the input
+<em>elevation</em> map. If <em>accumulation</em> is given,
+<em>elevation</em> must be exactly the same map used to calculate
+<em>accumulation</em>. If <em>accumulation</em> was calculated with
+<a href="r.terraflow.html">r.terraflow</a>, the filled elevation output
+of r.terraflow must be used. Further on, the current region should be 
+aligned to the <em>accumulation map</em>. Flow direction is
+first calculated from <em>elevation</em> and then adjusted to
+<em>accumulation</em>. It is not necessary to provide <em>accumulation</em>
+as the number of cells, it can also be the optionally adjusted or
+weighed total contributing area in square meters or any other unit. 
+When an original flow accumulation map is adjusted or weighed, the 
+adjustment or weighing should not convert valid accumulation values to 
+NULL (nodata) values.
+<p>
+<dt><em>depression</em> 
+<dd>Input map, optional: All non-NULL and non-zero cells will be regarded
+as real depressions. Streams will not be routed out of depressions. If an
+area is marked as depression but the elevation model has no depression
+at this location, streams will not stop there. If a flow accumulation map
+and a map with real depressions are provided, the flow accumulation map
+must match the depression map such that flow is not distributed out of 
+the indicated depressions. It is recommended to use internally computed
+flow accumulation if a depression map is provided.
+<p>
+<dt><em>threshold</em>
+<dd>Required: <em>threshold</em> for stream initiation by overland flow:
+the minumum (optionally modifed) flow accumulation value that will initiate
+a new stream. If Montgomery's method for channel initiation is used, the
+cell value of the accumulation input map is multiplied by
+(tan(local slope))<sup>mexp</sup> and then compared to <em>threshold</em>.
+<p>
+<dt><em>d8cut</em>
+<dd>Minimum amount of overland flow (accumulation) when SFD (D8) will be
+used instead of MFD (FD8) to calculate flow accumulation. Only applies
+if no accumulation map is provided. Setting to 0 disables MFD completely.
+<p>
+<dt><em>mexp</em>
+<dd>Use the method of Montgomery and Foufoula-Georgiou (1993) to
+initiate a stream with exponent <em>mexp</em>. The cell value of the
+accumulation input map is multiplied by (tan(local slope))<sup>mexp</sup>
+and then compared to <em>threshold</em>. If threshold is reached or
+exceeded, a new stream is initiated. The default value 0 disables
+Montgomery. Montgomery and Foufoula-Georgiou (1993) generally recommend
+to use 2.0 as exponent. <em>mexp</em> values closer to 0 will produce
+streams more similar to streams extracted with Montgomery disabled.
+Larger <em>mexp</em> values decrease the number of streams in flat areas
+and increase the number of streams in steep areas. If <em>weight</em> is
+given, the weight is applied first.
+<p>
+<dt><em>stream_length</em>
+<dd>Minimum stream length in number of cells for first-order (head/spring)
+stream segments. All first-order stream segments shorter than
+<em>stream_length</em> will be deleted.
+
+<p>
+<dt><em>stream_rast</em>
+<dd>Output raster map with extracted streams. Cell values encode unique
+ID for each stream segment.
+<p>
+<dt><em>stream_vect</em>
+<dd>Output vector map with extracted stream segments and points. Points
+are written at the start location of each stream segment and at the
+outlet of a stream network. In layer 1, categories are unique IDs,
+identical to the cell value of the raster output. The attribute table
+for layer 1 holds information about the type of stream segment: start
+segment, or intermediate segment with tributaries. Columns are cat int,
+stream_type varchar(), type_code int. The encoding for type_code is 0 =
+start, 1 = intermediate. In layer 2, categories are identical to
+type_code in layer 1 with additional category 2 = outlet for outlet
+points. Points with category 1 = intermediate in layer 2 are at the
+location of confluences.
+<p>
+<dt><em>direction</em>
+<dd>Output raster map with flow direction for all non-NULL cells in
+input elevation. Flow direction is of D8 type with a range of 1 to 8.
+Multiplying values with 45 gives degrees CCW from East. Flow direction
+was adjusted during thinning, taking shortcuts and skipping cells that
+were eliminated by the thinning procedure.
+</dl>
+
+<h2>NOTES</h2>
+
+<h4>Stream extraction</h4>
+If no accumulation input map is provided, flow accumulation is
+determined with a hydrological anaylsis similar to
+<a href="r.watershed.html">r.watershed</a>. The algorithm is
+MFD (FD8) after Holmgren 1994, as for
+<a href="r.watershed.html">r.watershed</a>. The <em>threshold</em>
+option determines the number of streams and detail of stream networks.
+Whenever flow accumulation reaches <em>threshold</em>, a new stream is
+started and traced downstream to its outlet point. As for
+<a href="r.watershed.html">r.watershed</a>, flow accumulation is
+calculated as the number of cells draining through a cell.
+
+<h4>Weighed flow accumulation</h4>
+Flow accumulation can be calculated first, e.g. with
+<a href="r.watershed.html">r.watershed</a>, and then modified before
+using it as input for <em>r.stream.extract</em>. In its general form, a
+weighed accumulation map is generated by first creating a weighing map
+and then multiplying the accumulation map with the weighing map using
+<a href="r.mapcalc.html">r.mapcalc</a>. It is highly recommended to
+evaluate the weighed flow accumulation map first, before using it as
+input for <em>r.stream.extract</em>.
+<p>
+This allows e.g. to decrease the number of streams in dry areas and
+increase the number of streams in wet areas by setting <em>weight</em>
+to smaller than 1 in dry areas and larger than 1 in wet areas.
+<p>
+Another possibility is to restrict channel initiation to valleys
+determined from terrain morphology. Valleys can be determined with
+<a href="r.param.scale.html">r.param.scale</a> param=crosc
+(cross-sectional or tangential curvature). Curvature values < 0
+indicate concave features, i.e. valleys. The size of the processing
+window determines whether narrow or broad valleys will be identified
+(See example below).
+
+<h4>Defining a region of interest</h4>
+The stream extraction procedure can be restricted to a certain region of 
+interest, e.g. a subbasin, by setting the computational region with 
+<em>g.region</em> and/or creating a MASK. Such region of interest should 
+be a complete catchment area, complete in the sense that the complete 
+area upstream of an outlet point is included and buffered with at least 
+one cell.
+
+<h4>Stream output</h4>
+The <em>stream_rast</em> output raster and vector contains stream
+segments with unique IDs. Note that these IDs are different from the IDs
+assigned by <a href="r.watershed.html">r.watershed</a>. The vector
+output also contains points at the location of the start of a stream
+segment, at confluences and at stream network outlet locations.
+<p>
+
+<h2>EXAMPLE</h2>
+This example is based on the elevation map <em>elevation.10m</em> in the
+sample dataset spearfish60 and uses valleys determined with
+<a href="r.param.scale.html">r.param.scale</a> to weigh an accumulation
+map produced with <a href="r.watershed.html">r.watershed</a>.
+
+<pre>
+# set region
+g.region -p rast=elevation.10m at PERMANENT
+
+# calculate flow accumulation
+r.watershed ele=elevation.10m at PERMANENT acc=elevation.10m.acc -f
+
+# curvature to get narrow valleys
+r.param.scale input="elevation.10m at PERMANENT" output="tangential_curv_5" size=5 param=crosc
+
+# curvature to get a bit broader valleys
+r.param.scale input="elevation.10m at PERMANENT" output="tangential_curv_7" size=7 param=crosc
+
+# curvature to get broad valleys
+r.param.scale input="elevation.10m at PERMANENT" output="tangential_curv_11" size=11 param=crosc
+
+# create weight map
+r.mapcalc "weight = if(tangential_curv_5 < 0, -100 * tangential_curv_5, \
+                    if(tangential_curv_7 < 0, -100 * tangential_curv_7, \
+		    if(tangential_curv_11 < 0, -100 * tangential_curv_11, 0.000001)))"
+
+# weigh accumulation map
+r.mapcalc "elevation.10m.acc.weighed = elevation.10m.acc * weight"
+
+# copy color table from original accumulation map
+r.colors map=elevation.10m.acc.weighed raster=elevation.10m.acc
+</pre>
+
+Display both the original and the weighed accumulation map.
+<br>
+Compare them and proceed if the weighed accumulation map makes sense.
+
+<pre>
+# extract streams
+r.stream.extract elevation=elevation.10m at PERMANENT \
+                 accumulation=elevation.10m.acc.weighed \
+		 threshold=1000 \
+		 stream_rast=elevation.10m.streams
+
+# extract streams using the original accumulation map
+r.stream.extract elevation=elevation.10m at PERMANENT \
+                 accumulation=elevation.10m.acc \
+		 threshold=1000 \
+		 stream_rast=elevation.10m.streams.noweight
+</pre>
+
+Now display both stream maps and decide which one is more realistic.
+
+<h2>SEE ALSO</h2>
+
+<em>
+<a href="r.watershed.html">r.watershed</a>,
+<a href="r.terraflow.html">r.terraflow</a>,
+<a href="r.param.scale.html">r.param.scale</a>,
+<a href="r.mapcalc.html">r.mapcalc</a>,
+<a href="r.thin.html">r.thin</a>,
+<a href="r.to.vect.html">r.to.vect</a>
+</em>
+
+<h2>REFERENCES</h2>
+Ehlschlaeger, C. (1989). <i>Using the A<sup>T</sup> Search Algorithm
+to Develop Hydrologic Models from Digital Elevation Data</i>,
+<b>Proceedings of International Geographic Information Systems (IGIS)
+Symposium '89</b>, pp 275-281 (Baltimore, MD, 18-19 March 1989).<br>
+URL: <a href="http://faculty.wiu.edu/CR-Ehlschlaeger2/older/IGIS/paper.html">
+http://faculty.wiu.edu/CR-Ehlschlaeger2/older/IGIS/paper.html</a>
+
+<p>
+Holmgren, P. (1994). <i>Multiple flow direction algorithms for runoff 
+modelling in grid based elevation models: An empirical evaluation.</i>
+<b>Hydrological Processes</b> Vol 8(4), pp 327-334.<br>
+DOI: <a href="http://dx.doi.org/10.1002/hyp.3360080405">10.1002/hyp.3360080405</a>
+
+<p>
+Montgomery, D.R., Foufoula-Georgiou, E. (1993). <i>Channel network source
+representation using digital elevation models.</i>
+<b>Water Resources Research</b> Vol 29(12), pp 3925-3934. 
+
+<h2>AUTHOR</h2>
+Markus Metz
+
+<p><i>Last changed: $Date: 2012-04-09 21:11:44 +0200 (Mon, 09 Apr 2012) $</i>

Added: grass-addons/grass7/grass7/raster/r.stream.extract/seg.c
===================================================================
--- grass-addons/grass7/grass7/raster/r.stream.extract/seg.c	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.stream.extract/seg.c	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,112 @@
+#include <unistd.h>
+#include <fcntl.h>
+#include <grass/glocale.h>
+#include "seg.h"
+
+int
+seg_open(SSEG *sseg, int nrows, int ncols, int row_in_seg, int col_in_seg,
+	 int nsegs_in_memory, int size_struct, int fill)
+{
+    char *filename;
+    int errflag;
+    int fd;
+
+    sseg->filename = NULL;
+    sseg->fd = -1;
+
+    filename = G_tempfile();
+    if (-1 == (fd = creat(filename, 0666))) {
+	G_warning(_("seg_open(): unable to create segment file"));
+	return -2;
+    }
+    if (fill)
+	errflag = segment_format(fd, nrows, ncols, row_in_seg,
+	                         col_in_seg, size_struct);
+    else
+	errflag = segment_format_nofill(fd, nrows, ncols, row_in_seg,
+	                         col_in_seg, size_struct);
+
+    if (0 > errflag) {
+	close(fd);
+	unlink(filename);
+	if (errflag == -1) {
+	    G_warning(_("seg_open(): could not write segment file"));
+	    return -1;
+	}
+	else {
+	    G_warning(_("seg_open(): illegal configuration parameter(s)"));
+	    return -3;
+	}
+    }
+    close(fd);
+    if (-1 == (fd = open(filename, 2))) {
+	unlink(filename);
+	G_warning(_("seg_open(): unable to re-open segment file"));
+	return -4;
+    }
+    if (0 > (errflag = segment_init(&(sseg->seg), fd, nsegs_in_memory))) {
+	close(fd);
+	unlink(filename);
+	if (errflag == -1) {
+	    G_warning(_("seg_open(): could not read segment file"));
+	    return -5;
+	}
+	else {
+	    G_warning(_("seg_open(): out of memory"));
+	    return -6;
+	}
+    }
+    sseg->filename = filename;
+    sseg->fd = fd;
+    return 0;
+}
+
+int seg_close(SSEG *sseg)
+{
+    segment_release(&(sseg->seg));
+    close(sseg->fd);
+    unlink(sseg->filename);
+    return 0;
+}
+
+int seg_put(SSEG *sseg, char *value, int row, int col)
+{
+    if (segment_put(&(sseg->seg), value, row, col) < 0) {
+	G_warning(_("seg_put(): could not write segment file"));
+	return -1;
+    }
+    return 0;
+}
+
+int seg_put_row(SSEG *sseg, char *value, int row)
+{
+    if (segment_put_row(&(sseg->seg), value, row) < 0) {
+	G_warning(_("seg_put_row(): could not write segment file"));
+	return -1;
+    }
+    return 0;
+}
+
+int seg_get(SSEG *sseg, char *value, int row, int col)
+{
+    if (segment_get(&(sseg->seg), value, row, col) < 0) {
+	G_warning(_("seg_get(): could not read segment file"));
+	return -1;
+    }
+    return 0;
+}
+
+int seg_get_row(SSEG *sseg, char *value, int row)
+{
+    if (segment_get_row(&(sseg->seg), value, row) < 0) {
+	G_warning(_("seg_get_row(): could not read segment file"));
+	return -1;
+    }
+    return 0;
+}
+
+int seg_flush(SSEG *sseg)
+{
+    segment_flush(&(sseg->seg));
+    return 0;
+}

Added: grass-addons/grass7/grass7/raster/r.stream.extract/seg.h
===================================================================
--- grass-addons/grass7/grass7/raster/r.stream.extract/seg.h	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.stream.extract/seg.h	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,78 @@
+#ifndef __SEG_H__
+#define __SEG_H__
+
+#include <grass/raster.h>
+#include <grass/segment.h>
+
+#define CSEG struct _c_s_e_g_
+CSEG {
+    SEGMENT seg;		/* segment structure */
+    int fd;			/* fd for reading/writing segment file */
+    char *filename;		/* name of segment file */
+    char *name;			/* raster map read into segment file */
+    char *mapset;
+};
+
+#define DSEG struct _d_s_e_g_
+DSEG {
+    SEGMENT seg;		/* segment structure */
+    int fd;			/* fd for reading/writing segment file */
+    char *filename;		/* name of segment file */
+    char *name;			/* raster map read into segment file */
+    char *mapset;
+};
+
+#define BSEG struct _b_s_e_g_
+BSEG {
+    SEGMENT seg;		/* segment structure */
+    int fd;			/* fd for reading/writing segment file */
+    char *filename;		/* name of segment file */
+    char *name;			/* raster map read into segment file */
+    char *mapset;
+};
+
+#define SSEG struct _s_s_e_g_
+SSEG {
+    SEGMENT seg;		/* segment structure */
+    int fd;			/* fd for reading/writing segment file */
+    char *filename;		/* name of segment file */
+};
+
+/* bseg.c */
+int bseg_close(BSEG *);
+int bseg_get(BSEG *, char *, int, int);
+int bseg_open(BSEG *, int, int, int);
+int bseg_put(BSEG *, char *, int, int);
+int bseg_put_row(BSEG *, char *, int);
+int bseg_read_raster(BSEG *, char *, char *);
+int bseg_write_raster(BSEG *, char *);
+
+/* cseg.c */
+int cseg_close(CSEG *);
+int cseg_get(CSEG *, CELL *, int, int);
+int cseg_open(CSEG *, int, int, int);
+int cseg_put(CSEG *, CELL *, int, int);
+int cseg_put_row(CSEG *, CELL *, int);
+int cseg_read_raster(CSEG *, char *, char *);
+int cseg_write_raster(CSEG *, char *);
+
+/* dseg.c */
+int dseg_close(DSEG *);
+int dseg_get(DSEG *, double *, int, int);
+int dseg_open(DSEG *, int, int, int);
+int dseg_put(DSEG *, double *, int, int);
+int dseg_put_row(DSEG *, double *, int);
+int dseg_read_raster(DSEG *, char *, char *);
+int dseg_write_raster(DSEG *, char *);
+
+/* seg.c */
+int seg_close(SSEG *);
+int seg_get(SSEG *, char *, int, int);
+int seg_open(SSEG *, int, int, int, int, int, int, int);
+int seg_put(SSEG *, char *, int, int);
+int seg_put_row(SSEG *, char *, int);
+int seg_get(SSEG *, char *, int, int);
+int seg_get_row(SSEG *, char *, int);
+int seg_flush(SSEG *);
+
+#endif /* __SEG_H__ */

Added: grass-addons/grass7/grass7/raster/r.stream.extract/streams.c
===================================================================
--- grass-addons/grass7/grass7/raster/r.stream.extract/streams.c	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.stream.extract/streams.c	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,730 @@
+#include <stdlib.h>
+#include <math.h>
+#include <grass/raster.h>
+#include <grass/glocale.h>
+#include "local_proto.h"
+
+double mfd_pow(double base)
+{
+    int i;
+    double result = base;
+
+    for (i = 2; i <= c_fac; i++) {
+	result *= base;
+    }
+    return result;
+}
+
+int continue_stream(CELL stream_id, int r, int c, int r_max, int c_max,
+		    int *stream_no)
+{
+    char aspect;
+    CELL curr_stream, stream_nbr, old_stream;
+    int r_nbr, c_nbr;
+    int asp_r[9] = { 0, -1, -1, -1, 0, 1, 1, 1, 0 };
+    int asp_c[9] = { 0, 1, 0, -1, -1, -1, 0, 1, 1 };
+    int stream_node_step = 1000;
+    char this_flag_value;
+
+    G_debug(3, "continue stream");
+    
+    cseg_get(&stream, &curr_stream, r_max, c_max);
+
+    if (curr_stream <= 0) {
+	/* no confluence, just continue */
+	G_debug(3, "no confluence, just continue stream");
+	curr_stream = stream_id;
+	cseg_put(&stream, &curr_stream, r_max, c_max);
+	bseg_get(&bitflags, &this_flag_value, r_max, c_max);
+	FLAG_SET(this_flag_value, STREAMFLAG);
+	bseg_put(&bitflags, &this_flag_value, r_max, c_max);
+	return 0;
+    }
+
+    G_debug(3, "confluence");
+	    
+    /* new confluence */
+    if (stream_node[curr_stream].r != r_max ||
+	stream_node[curr_stream].c != c_max) {
+	size_t new_size;
+	
+	G_debug(3, "new confluence");
+	/* set new stream id */
+	(*stream_no)++;
+	/* add stream node */
+	if (*stream_no >= n_alloc_nodes - 1) {
+	    n_alloc_nodes += stream_node_step;
+	    stream_node =
+		(struct snode *)G_realloc(stream_node,
+					  n_alloc_nodes *
+					  sizeof(struct snode));
+	}
+	stream_node[*stream_no].r = r_max;
+	stream_node[*stream_no].c = c_max;
+	stream_node[*stream_no].id = *stream_no;
+	stream_node[*stream_no].n_trib = 0;
+	stream_node[*stream_no].n_trib_total = 0;
+	stream_node[*stream_no].n_alloc = 0;
+	stream_node[*stream_no].trib = NULL;
+	n_stream_nodes++;
+
+	/* debug */
+	if (n_stream_nodes != *stream_no)
+	    G_warning(_("BUG: stream_no %d and n_stream_nodes %d out of sync"),
+		      *stream_no, n_stream_nodes);
+
+
+	stream_node[*stream_no].n_alloc += 2;
+	new_size = stream_node[*stream_no].n_alloc * sizeof(int);
+	stream_node[*stream_no].trib =
+	    (int *)G_realloc(stream_node[*stream_no].trib, new_size);
+
+	/* add the two tributaries */
+	G_debug(3, "add tributaries");
+	stream_node[*stream_no].trib[stream_node[*stream_no].n_trib++] =
+	    curr_stream;
+	stream_node[*stream_no].trib[stream_node[*stream_no].n_trib++] =
+	    stream_id;
+
+	/* update stream IDs downstream */
+	G_debug(3, "update stream IDs downstream");
+	r_nbr = r_max;
+	c_nbr = c_max;
+	old_stream = curr_stream;
+	curr_stream = *stream_no;
+	cseg_put(&stream, &curr_stream, r_nbr, c_nbr);
+	bseg_get(&asp, &aspect, r_nbr, c_nbr);
+
+	while (aspect > 0) {
+	    r_nbr = r_nbr + asp_r[(int)aspect];
+	    c_nbr = c_nbr + asp_c[(int)aspect];
+	    cseg_get(&stream, &stream_nbr, r_nbr, c_nbr);
+	    if (stream_nbr != old_stream)
+		aspect = -1;
+	    else {
+		cseg_put(&stream, &curr_stream, r_nbr, c_nbr);
+		bseg_get(&asp, &aspect, r_nbr, c_nbr);
+	    }
+	}
+    }
+    else {
+	/* stream node already existing here */
+	G_debug(3, "existing confluence");
+	/* add new tributary to stream node */
+	if (stream_node[curr_stream].n_trib >=
+	    stream_node[curr_stream].n_alloc) {
+	    size_t new_size;
+
+	    stream_node[curr_stream].n_alloc += 2;
+	    new_size = stream_node[curr_stream].n_alloc * sizeof(int);
+	    stream_node[curr_stream].trib =
+		(int *)G_realloc(stream_node[curr_stream].trib, new_size);
+	}
+
+	stream_node[curr_stream].trib[stream_node[curr_stream].n_trib++] =
+	    stream_id;
+    }
+
+    G_debug(3, "%d tribs", stream_node[curr_stream].n_trib);
+    if (stream_node[curr_stream].n_trib == 1)
+	G_warning(_("BUG: stream node %d has only 1 tributary: %d"), curr_stream,
+		  stream_node[curr_stream].trib[0]);
+
+    return 1;
+}
+
+/*
+ * accumulate surface flow
+ */
+int do_accum(double d8cut)
+{
+    int r, c, dr, dc;
+    CELL ele_val, *ele_nbr;
+    DCELL value, *wat_nbr;
+    struct Cell_head window;
+    int mfd_cells, astar_not_set;
+    double *dist_to_nbr, *weight, sum_weight, max_weight;
+    double dx, dy;
+    int r_nbr, c_nbr, r_max, c_max, ct_dir, np_side;
+    int is_worked;
+    char aspect;
+    double max_acc, prop;
+    int edge;
+    int asp_r[9] = { 0, -1, -1, -1, 0, 1, 1, 1, 0 };
+    int asp_c[9] = { 0, 1, 0, -1, -1, -1, 0, 1, 1 };
+    int nextdr[8] = { 1, -1, 0, 0, -1, 1, 1, -1 };
+    int nextdc[8] = { 0, 0, -1, 1, 1, -1, 1, -1 };
+    unsigned int workedon, killer, count;
+    char *flag_nbr, this_flag_value;
+    POINT astarpoint;
+    WAT_ALT wa;
+
+    G_message(_("Calculating flow accumulation..."));
+
+    /* distances to neighbours */
+    dist_to_nbr = (double *)G_malloc(sides * sizeof(double));
+    weight = (double *)G_malloc(sides * sizeof(double));
+    flag_nbr = (char *)G_malloc(sides * sizeof(char));
+    wat_nbr = (DCELL *)G_malloc(sides * sizeof(DCELL));
+    ele_nbr = (CELL *)G_malloc(sides * sizeof(CELL));
+
+    G_get_set_window(&window);
+
+    for (ct_dir = 0; ct_dir < sides; ct_dir++) {
+	/* get r, c (r_nbr, c_nbr) for neighbours */
+	r_nbr = nextdr[ct_dir];
+	c_nbr = nextdc[ct_dir];
+	/* account for rare cases when ns_res != ew_res */
+	dy = abs(r_nbr) * window.ns_res;
+	dx = abs(c_nbr) * window.ew_res;
+	if (ct_dir < 4)
+	    dist_to_nbr[ct_dir] = dx + dy;
+	else
+	    dist_to_nbr[ct_dir] = sqrt(dx * dx + dy * dy);
+    }
+
+    /* distribute and accumulate */
+    count = 0;
+    for (killer = 0; killer < n_points; killer++) {
+
+	G_percent(killer, n_points, 1);
+	
+	seg_get(&astar_pts, (char *)&astarpoint, 0, killer);
+	r = astarpoint.r;
+	c = astarpoint.c;
+
+	bseg_get(&asp, &aspect, r, c);
+
+	/* do not distribute flow along edges or out of real depressions */
+	if (aspect <= 0) {
+	    bseg_get(&bitflags, &this_flag_value, r, c);
+	    FLAG_UNSET(this_flag_value, WORKEDFLAG);
+	    bseg_put(&bitflags, &this_flag_value, r, c);
+	    continue;
+	}
+
+	if (aspect) {
+	    dr = r + asp_r[abs((int)aspect)];
+	    dc = c + asp_c[abs((int)aspect)];
+	}
+
+	r_max = dr;
+	c_max = dc;
+
+	seg_get(&watalt, (char *)&wa, r, c);
+	value = wa.wat;
+
+	/* WORKEDFLAG has been set during A* Search
+	 * reversed meaning here: 0 = done, 1 = not yet done */
+	bseg_get(&bitflags, &this_flag_value, r, c);
+	FLAG_UNSET(this_flag_value, WORKEDFLAG);
+	bseg_put(&bitflags, &this_flag_value, r, c);
+
+	/***************************************/
+	/*  get weights for flow distribution  */
+	/***************************************/
+
+	max_weight = 0;
+	sum_weight = 0;
+	np_side = -1;
+	mfd_cells = 0;
+	astar_not_set = 1;
+	ele_val = wa.ele;
+	edge = 0;
+	/* this loop is needed to get the sum of weights */
+	for (ct_dir = 0; ct_dir < sides; ct_dir++) {
+	    /* get r_nbr, c_nbr for neighbours */
+	    r_nbr = r + nextdr[ct_dir];
+	    c_nbr = c + nextdc[ct_dir];
+	    weight[ct_dir] = -1;
+	    wat_nbr[ct_dir] = 0;
+	    ele_nbr[ct_dir] = 0;
+
+	    /* check that neighbour is within region */
+	    if (r_nbr >= 0 && r_nbr < nrows && c_nbr >= 0 && c_nbr < ncols) {
+
+		bseg_get(&bitflags, &flag_nbr[ct_dir], r_nbr, c_nbr);
+		if ((edge = FLAG_GET(flag_nbr[ct_dir], NULLFLAG)))
+		    break;
+		seg_get(&watalt, (char *)&wa, r_nbr, c_nbr);
+		wat_nbr[ct_dir] = wa.wat;
+		ele_nbr[ct_dir] = wa.ele;
+
+		/* WORKEDFLAG has been set during A* Search
+		 * reversed meaning here: 0 = done, 1 = not yet done */
+		is_worked = FLAG_GET(flag_nbr[ct_dir], WORKEDFLAG) == 0;
+		if (is_worked == 0) {
+		    if (ele_nbr[ct_dir] <= ele_val) {
+			if (ele_nbr[ct_dir] < ele_val) {
+			    weight[ct_dir] =
+				mfd_pow((ele_val -
+					 ele_nbr[ct_dir]) / dist_to_nbr[ct_dir]);
+			}
+			if (ele_nbr[ct_dir] == ele_val) {
+			    weight[ct_dir] =
+				mfd_pow(0.5 / dist_to_nbr[ct_dir]);
+			}
+			sum_weight += weight[ct_dir];
+			mfd_cells++;
+
+			if (weight[ct_dir] > max_weight) {
+			    max_weight = weight[ct_dir];
+			}
+
+			if (dr == r_nbr && dc == c_nbr) {
+			    astar_not_set = 0;
+			}
+		    }
+		}
+		if (dr == r_nbr && dc == c_nbr)
+		    np_side = ct_dir;
+	    }
+	    else
+		edge = 1;
+	    if (edge)
+		break;
+	}
+
+	/* do not distribute flow along edges, this causes artifacts */
+	if (edge) {
+	    G_debug(3, "edge");
+	    continue;
+	}
+
+	/* honour A * path 
+	 * mfd_cells == 0: fine, SFD along A * path
+	 * mfd_cells == 1 && astar_not_set == 0: fine, SFD along A * path
+	 * mfd_cells > 0 && astar_not_set == 1: A * path not included, add to mfd_cells
+	 */
+
+	/************************************/
+	/*  distribute and accumulate flow  */
+	/************************************/
+
+	/* MFD, A * path not included, add to mfd_cells */
+	if (mfd_cells > 0 && astar_not_set == 1) {
+	    mfd_cells++;
+	    sum_weight += max_weight;
+	    weight[np_side] = max_weight;
+	}
+
+	/* use SFD (D8) if d8cut threshold exceeded */
+	if (fabs(value) > d8cut)
+	    mfd_cells = 0;
+
+	max_acc = -1;
+
+	if (mfd_cells > 1) {
+	    prop = 0.0;
+	    for (ct_dir = 0; ct_dir < sides; ct_dir++) {
+		/* get r, c (r_nbr, c_nbr) for neighbours */
+		r_nbr = r + nextdr[ct_dir];
+		c_nbr = c + nextdc[ct_dir];
+
+		/* check that neighbour is within region */
+		if (r_nbr >= 0 && r_nbr < nrows && c_nbr >= 0 &&
+		    c_nbr < ncols && weight[ct_dir] > -0.5) {
+		    is_worked = FLAG_GET(flag_nbr[ct_dir], WORKEDFLAG) == 0;
+		    if (is_worked == 0) {
+
+			weight[ct_dir] = weight[ct_dir] / sum_weight;
+			/* check everything sums up to 1.0 */
+			prop += weight[ct_dir];
+
+			wa.wat = wat_nbr[ct_dir] + value * weight[ct_dir];
+			wa.ele = ele_nbr[ct_dir];
+			seg_put(&watalt, (char *)&wa, r_nbr, c_nbr);
+		    }
+		    else if (ct_dir == np_side) {
+			/* check for consistency with A * path */
+			workedon++;
+		    }
+		}
+	    }
+	    if (fabs(prop - 1.0) > 5E-6f) {
+		G_warning(_("MFD: cumulative proportion of flow distribution not 1.0 but %f"),
+			  prop);
+	    }
+	}
+	/* get out of depression in SFD mode */
+	else {
+	    wa.wat = wat_nbr[np_side] + value;
+	    wa.ele = ele_nbr[np_side];
+	    seg_put(&watalt, (char *)&wa, dr, dc);
+	}
+    }
+    G_percent(1, 1, 2);
+
+    G_free(dist_to_nbr);
+    G_free(weight);
+    G_free(wat_nbr);
+    G_free(ele_nbr);
+    G_free(flag_nbr);
+
+    return 1;
+}
+
+/*
+ * extracts streams for threshold, accumulation is provided
+ */
+int extract_streams(double threshold, double mont_exp, int min_length, int internal_acc)
+{
+    int r, c, dr, dc;
+    CELL is_swale, ele_val, *ele_nbr;
+    DCELL value, valued, *wat_nbr;
+    struct Cell_head window;
+    int mfd_cells, stream_cells, swale_cells, astar_not_set;
+    double *dist_to_nbr;
+    double dx, dy;
+    int r_nbr, c_nbr, r_max, c_max, ct_dir, np_side, max_side;
+    int is_worked;
+    char aspect;
+    double max_acc;
+    int edge, flat;
+    int asp_r[9] = { 0, -1, -1, -1, 0, 1, 1, 1, 0 };
+    int asp_c[9] = { 0, 1, 0, -1, -1, -1, 0, 1, 1 };
+    int nextdr[8] = { 1, -1, 0, 0, -1, 1, 1, -1 };
+    int nextdc[8] = { 0, 0, -1, 1, 1, -1, 1, -1 };
+    /* sides */
+    /*
+     *  | 7 | 1 | 4 |
+     *  | 2 |   | 3 |
+     *  | 5 | 0 | 6 |
+     */
+    GW_LARGE_INT workedon, killer, count;
+    int stream_no = 0, stream_node_step = 1000;
+    double slope, diag;
+    char *flag_nbr, this_flag_value;
+    POINT astarpoint;
+    WAT_ALT wa;
+
+    G_message(_("Extracting streams..."));
+
+    /* init stream nodes */
+    n_alloc_nodes = stream_node_step;
+    stream_node =
+	(struct snode *)G_malloc(n_alloc_nodes * sizeof(struct snode));
+    n_stream_nodes = 0;
+
+    /* init outlet nodes */
+    n_alloc_outlets = stream_node_step;
+    outlets =
+	(POINT *)G_malloc(n_alloc_outlets * sizeof(POINT));
+    n_outlets = 0;
+
+    /* distances to neighbours */
+    dist_to_nbr = (double *)G_malloc(sides * sizeof(double));
+    flag_nbr = (char *)G_malloc(sides * sizeof(char));
+    wat_nbr = (DCELL *)G_malloc(sides * sizeof(DCELL));
+    ele_nbr = (CELL *)G_malloc(sides * sizeof(CELL));
+
+    G_get_set_window(&window);
+
+    for (ct_dir = 0; ct_dir < sides; ct_dir++) {
+	/* get r, c (r_nbr, c_nbr) for neighbours */
+	r_nbr = nextdr[ct_dir];
+	c_nbr = nextdc[ct_dir];
+	/* account for rare cases when ns_res != ew_res */
+	dy = abs(r_nbr) * window.ns_res;
+	dx = abs(c_nbr) * window.ew_res;
+	if (ct_dir < 4)
+	    dist_to_nbr[ct_dir] = dx + dy;
+	else
+	    dist_to_nbr[ct_dir] = sqrt(dx * dx + dy * dy);
+    }
+
+    diag = sqrt(2);
+
+    workedon = 0;
+
+    /* extract streams */
+    count = 0;
+    for (killer =  0; killer < n_points; killer++) {
+	G_percent(killer, n_points, 1);
+	
+	seg_get(&astar_pts, (char *)&astarpoint, 0, killer);
+	r = astarpoint.r;
+	c = astarpoint.c;
+
+	bseg_get(&asp, &aspect, r, c);
+
+	bseg_get(&bitflags, &this_flag_value, r, c);
+	/* internal acc: SET, external acc: UNSET */
+	if (internal_acc)
+	    FLAG_SET(this_flag_value, WORKEDFLAG);
+	else
+	    FLAG_UNSET(this_flag_value, WORKEDFLAG);
+	bseg_put(&bitflags, &this_flag_value, r, c);
+
+	/* do not distribute flow along edges */
+	if (aspect <= 0) {
+	    G_debug(3, "edge");
+	    is_swale = FLAG_GET(this_flag_value, STREAMFLAG);
+	    if (is_swale) {
+		G_debug(2, "edge outlet");
+		/* add outlet point */
+		if (n_outlets >= n_alloc_outlets) {
+		    n_alloc_outlets += stream_node_step;
+		    outlets =
+			(POINT *)G_realloc(outlets,
+						  n_alloc_outlets *
+						  sizeof(POINT));
+		}
+		outlets[n_outlets].r = r;
+		outlets[n_outlets].c = c;
+		n_outlets++;
+	    }
+
+	    if (aspect == 0) {
+		/* can only happen with real depressions */
+		if (!have_depressions)
+		    G_fatal_error(_("Bug in stream extraction"));
+		G_debug(2, "bottom of real depression");
+	    } 
+	    continue;
+	}
+
+	if (aspect) {
+	    dr = r + asp_r[abs((int)aspect)];
+	    dc = c + asp_c[abs((int)aspect)];
+	}
+	else {
+	    /* can only happen with real depressions,
+	     * but should not get to here */
+	    dr = r;
+	    dc = c;
+	}
+
+	r_nbr = r_max = dr;
+	c_nbr = c_max = dc;
+
+	seg_get(&watalt, (char *)&wa, r, c);
+	value = wa.wat;
+
+	/**********************************/
+	/*  find main drainage direction  */
+	/**********************************/
+
+	max_acc = -1;
+	max_side = np_side = -1;
+	mfd_cells = 0;
+	stream_cells = 0;
+	swale_cells = 0;
+	astar_not_set = 1;
+	ele_val = wa.ele;
+	edge = 0;
+	flat = 1;
+	/* find main drainage direction */
+	for (ct_dir = 0; ct_dir < sides; ct_dir++) {
+	    /* get r_nbr, c_nbr for neighbours */
+	    r_nbr = r + nextdr[ct_dir];
+	    c_nbr = c + nextdc[ct_dir];
+	    wat_nbr[ct_dir] = 0;
+	    ele_nbr[ct_dir] = 0;
+	    flag_nbr[ct_dir] = 0;
+
+	    /* check that neighbour is within region */
+	    if (r_nbr >= 0 && r_nbr < nrows && c_nbr >= 0 && c_nbr < ncols) {
+
+		if (dr == r_nbr && dc == c_nbr)
+		    np_side = ct_dir;
+
+		bseg_get(&bitflags, &flag_nbr[ct_dir], r_nbr, c_nbr);
+		if ((edge = FLAG_GET(flag_nbr[ct_dir], NULLFLAG)))
+		    break;
+		seg_get(&watalt, (char *)&wa, r_nbr, c_nbr);
+		wat_nbr[ct_dir] = wa.wat;
+		ele_nbr[ct_dir] = wa.ele;
+
+		/* check for swale cells */
+		is_swale = FLAG_GET(flag_nbr[ct_dir], STREAMFLAG);
+		if (is_swale)
+		    swale_cells++;
+
+		/* check for stream cells */
+		valued = fabs(wat_nbr[ct_dir]);
+		/* check all upstream neighbours */
+		if (valued >= threshold && ct_dir != np_side &&
+		    ele_nbr[ct_dir] > ele_val)
+		    stream_cells++;
+
+		is_worked = FLAG_GET(flag_nbr[ct_dir], WORKEDFLAG);
+		if (!internal_acc)
+		    is_worked = is_worked == 0;
+
+		if (is_worked == 0) {
+		    if (ele_nbr[ct_dir] != ele_val)
+			flat = 0;
+		    if (ele_nbr[ct_dir] <= ele_val) {
+
+			mfd_cells++;
+
+			/* set main drainage direction */
+			if (valued >= max_acc) {
+			    max_acc = valued;
+			    r_max = r_nbr;
+			    c_max = c_nbr;
+			    max_side = ct_dir;
+			}
+
+			if (dr == r_nbr && dc == c_nbr) {
+			    astar_not_set = 0;
+			}
+		    }
+		}
+		else if (ct_dir == np_side && !edge) {
+		    /* check for consistency with A * path */
+		    workedon++;
+		}
+	    }
+	    else
+		edge = 1;
+	    if (edge)
+		break;
+	}
+
+	is_swale = FLAG_GET(this_flag_value, STREAMFLAG);
+
+	/* do not continue streams along edges, these are artifacts */
+	if (edge) {
+	    G_debug(3, "edge");
+	    if (is_swale) {
+		G_debug(2, "edge outlet");
+		/* add outlet point */
+		if (n_outlets >= n_alloc_outlets) {
+		    n_alloc_outlets += stream_node_step;
+		    outlets =
+			(POINT *)G_realloc(outlets,
+						  n_alloc_outlets *
+						  sizeof(POINT));
+		}
+		outlets[n_outlets].r = r;
+		outlets[n_outlets].c = c;
+		n_outlets++;
+		if (aspect > 0) {
+		    aspect = -1 * drain[r - r_nbr + 1][c - c_nbr + 1];
+		    bseg_put(&asp, &aspect, r, c);
+		}
+	    }
+	    continue;
+	}
+
+	if (np_side < 0)
+	    G_fatal_error("np_side < 0");
+	    
+	/* set main drainage direction to A* path if possible */
+	if (mfd_cells > 0 && max_side != np_side) {
+	    if (fabs(wat_nbr[np_side] >= max_acc)) {
+		max_acc = fabs(wat_nbr[np_side]);
+		r_max = dr;
+		c_max = dc;
+		max_side = np_side;
+	    }
+	}
+	if (mfd_cells == 0) {
+	    flat = 0;
+	    r_max = dr;
+	    c_max = dc;
+	    max_side = np_side;
+	}
+
+	/* update aspect */
+	/* r_max == r && c_max == c should not happen */
+	if ((r_max != dr || c_max != dc) && (r_max != r || c_max != c)) {
+	    aspect = drain[r - r_max + 1][c - c_max + 1];
+	    bseg_put(&asp, &aspect, r, c);
+	}
+
+	/**********************/
+	/*  start new stream  */
+	/**********************/
+
+	/* Montgomery's stream initiation acc * (tan(slope))^mont_exp */
+	/* uses whatever unit is accumulation */
+	if (mont_exp > 0) {
+	    if (r_max == r && c_max == c)
+		G_warning
+		    (_("Can't use Montgomery's method, no stream direction found"));
+	    else {
+		slope = (double)(ele_val - ele_nbr[max_side]) / ele_scale;
+
+		if (max_side > 3)
+		    slope /= diag;
+
+		value *= pow(fabs(slope), mont_exp);
+	    }
+	}
+
+	if (!is_swale && fabs(value) >= threshold && stream_cells < 1 &&
+	    swale_cells < 1 && !flat) {
+	    G_debug(2, "start new stream");
+	    is_swale = ++stream_no;
+	    cseg_put(&stream, &is_swale, r, c);
+	    FLAG_SET(this_flag_value, STREAMFLAG);
+	    bseg_put(&bitflags, &this_flag_value, r, c);
+	    /* add stream node */
+	    if (stream_no >= n_alloc_nodes - 1) {
+		n_alloc_nodes += stream_node_step;
+		stream_node =
+		    (struct snode *)G_realloc(stream_node,
+					      n_alloc_nodes *
+					      sizeof(struct snode));
+	    }
+	    stream_node[stream_no].r = r;
+	    stream_node[stream_no].c = c;
+	    stream_node[stream_no].id = stream_no;
+	    stream_node[stream_no].n_trib = 0;
+	    stream_node[stream_no].n_trib_total = 0;
+	    stream_node[stream_no].n_alloc = 0;
+	    stream_node[stream_no].trib = NULL;
+	    n_stream_nodes++;
+
+	    /* debug */
+	    if (n_stream_nodes != stream_no)
+		G_warning(_("BUG: stream_no %d and n_stream_nodes %d out of sync"),
+			  stream_no, n_stream_nodes);
+	}
+
+	/*********************/
+	/*  continue stream  */
+	/*********************/
+
+	if (is_swale > 0) {
+	    cseg_get(&stream, &is_swale, r, c);
+	    if (r_max == r && c_max == c) {
+		/* can't continue stream, add outlet point
+		 * r_max == r && c_max == c should not happen */
+		G_debug(1, "can't continue stream at r %d c %d", r, c);
+
+		if (n_outlets >= n_alloc_outlets) {
+		    n_alloc_outlets += stream_node_step;
+		    outlets =
+			(POINT *)G_malloc(n_alloc_outlets *
+						 sizeof(POINT));
+		}
+		outlets[n_outlets].r = r;
+		outlets[n_outlets].c = c;
+		n_outlets++;
+	    }
+	    else {
+		continue_stream(is_swale, r, c, r_max, c_max, 
+				&stream_no);
+	    }
+	}
+    }
+    G_percent(1, 1, 2);
+    if (workedon)
+	G_warning(_("MFD: A * path already processed when setting drainage direction: %lld of %lld cells"),
+		  workedon, n_points);
+
+    G_free(dist_to_nbr);
+    G_free(wat_nbr);
+    G_free(ele_nbr);
+    G_free(flag_nbr);
+
+    G_debug(1, "%d outlets", n_outlets);
+    G_debug(1, "%d nodes", n_stream_nodes);
+    G_debug(1, "%d streams", stream_no);
+
+    return 1;
+}

Added: grass-addons/grass7/grass7/raster/r.stream.extract/thin.c
===================================================================
--- grass-addons/grass7/grass7/raster/r.stream.extract/thin.c	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.stream.extract/thin.c	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,172 @@
+#include <stdlib.h>
+#include <grass/gis.h>
+#include <grass/glocale.h>
+#include "local_proto.h"
+
+int thin_seg(int stream_id)
+{
+    int thinned = 0;
+    int r, c, r_nbr, c_nbr, last_r, last_c;
+    CELL curr_stream, no_stream = 0;
+    int asp_r[9] = { 0, -1, -1, -1, 0, 1, 1, 1, 0 };
+    int asp_c[9] = { 0, 1, 0, -1, -1, -1, 0, 1, 1 };
+    char flag_value, aspect;
+
+    r = stream_node[stream_id].r;
+    c = stream_node[stream_id].c;
+
+    cseg_get(&stream, &curr_stream, r, c);
+
+    bseg_get(&asp, &aspect, r, c);
+    if (aspect > 0) {
+	/* get downstream point */
+	last_r = r + asp_r[(int)aspect];
+	last_c = c + asp_c[(int)aspect];
+	cseg_get(&stream, &curr_stream, last_r, last_c);
+
+	if (curr_stream != stream_id)
+	    return thinned;
+
+	/* get next downstream point */
+	bseg_get(&asp, &aspect, last_r, last_c);
+	while (aspect > 0) {
+	    r_nbr = last_r + asp_r[(int)aspect];
+	    c_nbr = last_c + asp_c[(int)aspect];
+
+	    if (r_nbr == last_r && c_nbr == last_c)
+		return thinned;
+	    if (r_nbr < 0 || r_nbr >= nrows || c_nbr < 0 || c_nbr >= ncols)
+		return thinned;
+	    cseg_get(&stream, &curr_stream, r_nbr, c_nbr);
+	    if (curr_stream != stream_id)
+		return thinned;
+	    if (abs(r_nbr - r) < 2 && abs(c_nbr - c) < 2) {
+		/* eliminate last point */
+		cseg_put(&stream, &no_stream, last_r, last_c);
+		bseg_get(&bitflags, &flag_value, last_r, last_c);
+		FLAG_UNSET(flag_value, STREAMFLAG);
+		bseg_put(&bitflags, &flag_value, last_r, last_c);
+		/* update start point */
+		aspect = drain[r - r_nbr + 1][c - c_nbr + 1];
+		bseg_put(&asp, &aspect, r, c);
+
+		thinned = 1;
+	    }
+	    else {
+		/* nothing to eliminate, continue from last point */
+		r = last_r;
+		c = last_c;
+	    }
+	    last_r = r_nbr;
+	    last_c = c_nbr;
+	    bseg_get(&asp, &aspect, last_r, last_c);
+	}
+    }
+
+    return thinned;
+}
+
+int thin_streams(void)
+{
+    int i, j, r, c, done;
+    CELL stream_id;
+    int next_node;
+    struct sstack
+    {
+	int stream_id;
+	int next_trib;
+    } *nodestack;
+    int top = 0, stack_step = 1000;
+    int n_trib_total;
+    int n_thinned = 0;
+
+    G_message(_("Thinning stream segments..."));
+
+    nodestack = (struct sstack *)G_malloc(stack_step * sizeof(struct sstack));
+
+    for (i = 0; i < n_outlets; i++) {
+	G_percent(i, n_outlets, 2);
+	r = outlets[i].r;
+	c = outlets[i].c;
+	cseg_get(&stream, &stream_id, r, c);
+
+	if (stream_id == 0)
+	    continue;
+
+	/* add root node to stack */
+	G_debug(2, "add root node");
+	top = 0;
+	nodestack[top].stream_id = stream_id;
+	nodestack[top].next_trib = 0;
+
+	/* depth first post order traversal */
+	G_debug(2, "traverse");
+	while (top >= 0) {
+
+	    done = 1;
+	    stream_id = nodestack[top].stream_id;
+	    G_debug(3, "stream_id %d, top %d", stream_id, top);
+	    if (nodestack[top].next_trib < stream_node[stream_id].n_trib) {
+		/* add to stack */
+		G_debug(3, "get next node");
+		next_node =
+		    stream_node[stream_id].trib[nodestack[top].next_trib];
+		G_debug(3, "add to stack: next %d, trib %d, n trib %d",
+			next_node, nodestack[top].next_trib,
+			stream_node[stream_id].n_trib);
+		nodestack[top].next_trib++;
+		top++;
+		if (top >= stack_step) {
+		    /* need more space */
+		    stack_step += 1000;
+		    nodestack =
+			(struct sstack *)G_realloc(nodestack,
+						   stack_step *
+						   sizeof(struct sstack));
+		}
+
+		nodestack[top].next_trib = 0;
+		nodestack[top].stream_id = next_node;
+		done = 0;
+		G_debug(3, "go further down");
+	    }
+	    if (done) {
+		/* thin stream segment */
+		G_debug(3, "thin stream segment %d", stream_id);
+
+		if (thin_seg(stream_id) == 0)
+		    G_debug(3, "segment %d not thinned", stream_id);
+		else {
+		    G_debug(3, "segment %d thinned", stream_id);
+		    n_thinned++;
+		}
+
+		top--;
+		/* count tributaries */
+		if (top >= 0) {
+		    n_trib_total = 0;
+		    stream_id = nodestack[top].stream_id;
+		    for (j = 0; j < stream_node[stream_id].n_trib; j++) {
+			/* intermediate */
+			if (stream_node[stream_node[stream_id].trib[j]].
+			    n_trib > 0)
+			    n_trib_total +=
+				stream_node[stream_node[stream_id].trib[j]].
+				n_trib_total;
+			/* start */
+			else
+			    n_trib_total++;
+		    }
+		    stream_node[stream_id].n_trib_total = n_trib_total;
+		}
+	    }
+	}
+    }
+    G_percent(n_outlets, n_outlets, 1);	/* finish it */
+
+    G_free(nodestack);
+    
+    G_verbose_message(_("%d of %d stream segments were thinned"), n_thinned, n_stream_nodes);
+
+    return 1;
+}

Added: grass-addons/grass7/grass7/raster/r.stream.order/Makefile
===================================================================
--- grass-addons/grass7/grass7/raster/r.stream.order/Makefile	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.stream.order/Makefile	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,14 @@
+MODULE_TOPDIR = ../..
+
+PGM = r.stream.order
+
+LIBES = $(GISLIB) $(RASTERLIB) $(SEGMENTLIB) $(VECTORLIB) $(DBMILIB)
+DEPENDENCIES = $(GISDEP) $(RASTERDEP) $(SEGMENTDEP) $(VECTORDEP) $(DBMIDEP)
+
+EXTRA_INC = $(VECT_INC)
+EXTRA_CFLAGS = $(VECT_CFLAGS)
+
+include $(MODULE_TOPDIR)/include/Make/Module.make
+
+default: cmd
+

Added: grass-addons/grass7/grass7/raster/r.stream.order/io.c
===================================================================
--- grass-addons/grass7/grass7/raster/r.stream.order/io.c	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.stream.order/io.c	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,564 @@
+#include "io.h"
+/* all in ram functions section */
+
+int ram_create_map(MAP * map, RASTER_MAP_TYPE data_type)
+{
+
+    /* 
+     * allocates 0 filled nrows*ncols map of type void;
+     * map parameters are stored in structure;
+     * map: map to be created;
+     * map type to be created must be CELL, FCELL, DCELL;
+     * */
+
+    int r;
+
+    if (data_type < 0 || data_type > 2)
+	G_fatal_error(_("ram_creat: Cannot create map of unrecognised type"));
+
+    map->data_type = data_type;
+    map->map_name = NULL;
+    map->nrows = Rast_window_rows();
+    map->ncols = Rast_window_cols();
+    map->data_size = Rast_cell_size(data_type);
+
+    /* preparing internal map */
+    switch (map->data_type) {
+    case CELL_TYPE:
+	map->map = G_calloc(map->nrows, sizeof(CELL *));
+	break;
+
+    case FCELL_TYPE:
+	map->map = G_calloc(map->nrows, sizeof(FCELL *));
+	break;
+
+    case DCELL_TYPE:
+	map->map = G_calloc(map->nrows, sizeof(DCELL *));
+	break;
+    }
+
+    for (r = 0; r < map->nrows; ++r)
+	(map->map)[r] = G_calloc(map->ncols, map->data_size);
+
+    return 0;
+}
+
+int ram_read_map(MAP * map, char *input_map_name, int check_res,
+		 RASTER_MAP_TYPE check_data_type)
+{
+    /*
+     * Funciton read external map and put it in MAP structure (created with create_map)
+     * map: map to be read can be of any data type, read map is converted to target map if neccesary.
+     * input_map_name: name of the map to be read;
+     * map pointer to map stucture (created with create_map);
+     * check_res: [1]: check res correspondence between region and map [0 no check];
+     * check_data_type [CELL, FCELL, DCELL] check if reading map is of particular type, [-1] no check;
+     */
+
+    int r, c;
+    char *mapset;
+    struct Cell_head cellhd, this_window;
+    char *maptypes[] = { "CELL", "FCELL", "DCELL" };
+    int input_map_fd;
+    RASTER_MAP_TYPE input_data_type;
+    size_t input_data_size;
+    void *input_buffer = NULL;
+    void *input_pointer;
+
+    /* checking if map exist */
+    mapset = (char *)G_find_raster2(input_map_name, "");
+    if (mapset == NULL)
+	G_fatal_error(_("Raster map <%s> not found"), input_map_name);
+
+    /* checking if region and input are the same */
+    G_get_window(&this_window);
+    Rast_get_cellhd(input_map_name, mapset, &cellhd);
+    if (check_res)
+	if (this_window.ew_res != cellhd.ew_res ||
+	    this_window.ns_res != cellhd.ns_res)
+	    G_fatal_error(_("Region resolution and map %s resolution differs. \
+		Run g.region rast=%s to set proper region resolution"),
+			  input_map_name, input_map_name);
+
+    /* checking if input map is of required type */
+    if (check_data_type != map->data_type)
+	G_debug(1,
+		"ram_open:required map type and internal map type differs: conversion forced!");
+    input_data_type = Rast_map_type(input_map_name, mapset);
+    if (check_data_type != -1)
+	if (input_data_type != check_data_type)
+	    G_fatal_error(_("<%s> is not of type %s"),
+			  input_map_name, maptypes[check_data_type]);
+
+    input_map_fd = Rast_open_old(input_map_name, mapset);
+    input_data_size = Rast_cell_size(input_data_type);
+
+    {				/* reading range */
+	struct Range map_range;
+	struct FPRange map_fp_range;
+	int min, max;
+
+	if (input_data_type == CELL_TYPE) {
+	    Rast_init_range(&map_range);
+	    Rast_read_range(input_map_name, mapset, &map_range);
+	    Rast_get_range_min_max(&map_range, &min, &max);
+	    map->min = (double)min;
+	    map->max = (double)max;
+	}
+	else {
+	    Rast_init_fp_range(&map_fp_range);
+	    Rast_read_fp_range(input_map_name, mapset, &map_fp_range);
+	    Rast_get_fp_range_min_max(&map_fp_range, &(map->min),
+				      &(map->max));
+	}
+    }
+    /* end opening and checking */
+
+    input_buffer = Rast_allocate_buf(input_data_type);
+
+    /* start reading */
+    G_message(_("Reading map <%s>"), input_map_name);
+
+    for (r = 0; r < map->nrows; ++r) {
+	G_percent(r, map->nrows, 2);
+
+	Rast_get_row(input_map_fd, input_buffer, r, input_data_type);
+	input_pointer = input_buffer;
+
+	for (c = 0; c < map->ncols; ++c)
+	    if (!Rast_is_null_value
+		(input_pointer + c * input_data_size, input_data_type))
+		switch (map->data_type) {
+		case CELL_TYPE:
+		    ((CELL **) map->map)[r][c] =
+			Rast_get_c_value(input_pointer + c * input_data_size,
+					 input_data_type);
+		    break;
+		case FCELL_TYPE:
+		    ((FCELL **) map->map)[r][c] =
+			Rast_get_f_value(input_pointer + c * input_data_size,
+					 input_data_type);
+		    break;
+		case DCELL_TYPE:
+		    ((DCELL **) map->map)[r][c] =
+			Rast_get_d_value(input_pointer + c * input_data_size,
+					 input_data_type);
+		    break;
+		default:
+		    G_fatal_error(_("ram_open:Wrong internal data type"));
+		    break;
+		}
+    }				/*end for r */
+
+    G_free(input_buffer);
+    G_percent(r, map->nrows, 2);
+    Rast_close(input_map_fd);
+    return 0;
+}				/* end create floating point map */
+
+int ram_reset_map(MAP * map, int value)
+{
+    /*
+     * set all cells in the map to value
+     */
+    int r;
+
+    for (r = 0; r < map->nrows; ++r)
+	memset((map->map)[r], value, map->ncols * map->data_size);
+    return 0;
+}
+
+int ram_write_map(MAP * map, char *output_map_name,
+		  RASTER_MAP_TYPE output_data_type, int convert_to_null,
+		  double value)
+{
+    /* 
+     * write map to disk with output_map_name and output_data_type [CELL, FCELL, DCELL];
+     * if output_data_type = -1 than internal map type is used for output;
+     * if output map != -1 and types differ data_type, conversion is forced
+     * convert to null: check if convert to null a particular value in dataset;
+     */
+
+    int r, c;
+    int output_fd = 0;
+    struct History history;
+    void *row;
+
+    /* check for output format */
+    if (output_data_type == -1)
+	output_data_type = map->data_type;
+
+    if (output_data_type != map->data_type)
+	G_debug(1,
+		"ram_write:required map type and internal map type differs: conversion forced!");
+
+    G_message(_("Writing map <%s>"), output_map_name);
+    output_fd = Rast_open_new(output_map_name, output_data_type);
+
+    /* writing */
+    for (r = 0; r < map->nrows; ++r) {
+	G_percent(r, map->nrows, 2);
+
+	if (convert_to_null) {
+	    row = map->map[r];
+	    switch (map->data_type) {
+	    case CELL_TYPE:
+		for (c = 0; c < map->ncols; ++c)
+		    if (((CELL *) row)[c] == (CELL) value)
+			Rast_set_c_null_value(row + c * (map->data_size), 1);
+		break;
+	    case FCELL_TYPE:
+		for (c = 0; c < map->ncols; ++c)
+		    if (((FCELL *) row)[c] == (FCELL) value)
+			Rast_set_f_null_value(row + c * (map->data_size), 1);
+		break;
+	    case DCELL_TYPE:
+		for (c = 0; c < map->ncols; ++c)
+		    if (((DCELL *) row)[c] == (DCELL) value)
+			Rast_set_d_null_value(row + c * (map->data_size), 1);
+		break;
+	    default:
+		G_debug(1, "ram_null:Cannot convert to null at: %d %d", r, c);
+	    }
+	}
+
+	Rast_put_row(output_fd, (map->map)[r], output_data_type);
+    }
+    G_percent(r, map->nrows, 2);
+    Rast_close(output_fd);
+    Rast_short_history(output_map_name, "raster", &history);
+    Rast_command_history(&history);
+    Rast_write_history(output_map_name, &history);
+    G_message(_("<%s> Done"), output_map_name);
+    return 0;
+}
+
+int ram_release_map(MAP *map)
+{
+    /* 
+     * free memory allocated for map, set pointer to null;
+     */
+    int r;
+
+    for (r = 0; r < map->nrows; ++r)
+	G_free((map->map)[r]);
+    G_free(map->map);
+    map = NULL;
+    return 0;
+}
+
+
+/* memory swap functions section */
+
+
+int seg_create_map(SEG * seg, int srows, int scols, int number_of_segs,
+		   RASTER_MAP_TYPE data_type)
+{
+    /* create segment  and returns pointer to it;
+     * seg must be declared first;
+     * parameters are stored in structure;
+     * seg: segment to be created;
+     * srows, scols segment size
+     * number of segs max number of segs stored in memory
+     * data_type to be created must be CELL, FCELL, DCELL;
+     */
+
+    char *filename;
+    int fd;
+    int local_number_of_segs;
+
+    seg->fd = -1;
+    seg->filename = NULL;
+    seg->map_name = NULL;
+    seg->mapset = NULL;
+    seg->data_type = data_type;
+    seg->nrows = Rast_window_rows();
+    seg->ncols = Rast_window_cols();
+
+    local_number_of_segs =
+	(seg->nrows / srows + 1) * (seg->ncols / scols + 1);
+    number_of_segs =
+	(number_of_segs >
+	 local_number_of_segs) ? local_number_of_segs : number_of_segs;
+
+    G_debug(3, "seg_creat:number of segments %d", number_of_segs);
+
+    switch (seg->data_type) {
+    case CELL_TYPE:
+	seg->data_size = sizeof(CELL);
+	break;
+    case FCELL_TYPE:
+	seg->data_size = sizeof(FCELL);
+	break;
+    case DCELL_TYPE:
+	seg->data_size = sizeof(DCELL);
+	break;
+    default:
+	G_fatal_error(_("seg_create: unrecognisabe data type"));
+    }
+
+    filename = G_tempfile();
+    fd = creat(filename, 0666);
+
+    if (0 >
+	segment_format(fd, seg->nrows, seg->ncols, srows, scols,
+		       seg->data_size)) {
+	close(fd);
+	unlink(filename);
+	G_fatal_error(_("seg_create: cannot format segment"));
+    }
+
+    close(fd);
+    if (0 > (fd = open(filename, 2))) {
+	unlink(filename);
+	G_fatal_error(_("seg_create: cannot re-open file"));
+    }
+
+    if (0 > (fd = segment_init(&(seg->seg), fd, number_of_segs))) {
+	unlink(filename);
+	G_fatal_error(_("seg_create: cannot init segment file or out of memory"));
+    }
+
+    seg->filename = G_store(filename);
+    seg->fd = fd;
+    return 0;
+}
+
+int seg_read_map(SEG * seg, char *input_map_name, int check_res,
+		 RASTER_MAP_TYPE check_data_type)
+{
+
+    /*
+     * Funciton read external map and put it in SEG structure (created with seg_create_map)
+     * map to be read can be of any data type, read map is converted if neccesary.
+     * input_map_name: name of the map to be read;
+     * seg: pointer to map stucture (created with create_map);
+     * check_res: [1]: check res correspondence between region and map [0 no check];
+     * check_data_type [CELL, FCELL, DCELL] check if reading map is of particular type, [-1] no check;
+     */
+
+    int input_fd;
+    int r, c;
+    char *mapset;
+    struct Cell_head cellhd, this_window;
+    char *maptypes[] = { "CELL", "FCELL", "DCELL" };
+    RASTER_MAP_TYPE input_data_type;
+    size_t input_data_size;
+    void *input_buffer = NULL;
+    void *target_buffer = NULL;
+    void *input_pointer = NULL;
+
+    /* checking if map exist */
+    mapset = (char *)G_find_raster2(input_map_name, "");
+    if (mapset == NULL)
+	G_fatal_error(_("seg_read:Raster map <%s> not found"),
+		      input_map_name);
+    seg->mapset = mapset;
+
+    /* checking if region and input are the same */
+    G_get_window(&this_window);
+    Rast_get_cellhd(input_map_name, mapset, &cellhd);
+
+    /* check resolution equal anyinteger check;  equal 0 no check */
+    if (check_res)
+	if (this_window.ew_res != cellhd.ew_res ||
+	    this_window.ns_res != cellhd.ns_res)
+	    G_fatal_error(_("Region resolution and map %s resolution differs. \
+		Run g.region rast=%s to set proper region resolution"),
+			  input_map_name, input_map_name);
+
+    if (check_data_type != seg->data_type)
+	G_debug(1,
+		"ram_open:required map type and internal map type differs: conversion forced!");
+    input_data_type = Rast_map_type(input_map_name, mapset);
+    if (check_data_type != -1)
+	if (input_data_type != check_data_type)
+	    G_fatal_error(_("<%s> is not of type %s"),
+			  input_map_name, maptypes[check_data_type]);
+
+    input_fd = Rast_open_old(input_map_name, mapset);
+    input_data_size = Rast_cell_size(input_data_type);
+
+    {				/* reading range */
+	struct Range map_range;
+	struct FPRange map_fp_range;
+	int min, max;
+
+	if (input_data_type == CELL_TYPE) {
+	    Rast_init_range(&map_range);
+	    Rast_read_range(input_map_name, mapset, &map_range);
+	    Rast_get_range_min_max(&map_range, &min, &max);
+	    seg->min = (double)min;
+	    seg->max = (double)max;
+	}
+	else {
+	    Rast_init_fp_range(&map_fp_range);
+	    Rast_read_fp_range(input_map_name, mapset, &map_fp_range);
+	    Rast_get_fp_range_min_max(&map_fp_range, &(seg->min),
+				      &(seg->max));
+	}
+    }
+
+    /* end opening and checking */
+
+    G_message(_("Reading map <%s>"), input_map_name);
+    input_buffer = Rast_allocate_buf(input_data_type);
+
+    target_buffer = Rast_allocate_buf(seg->data_type);
+
+    for (r = 0; r < seg->nrows; ++r) {
+	G_percent(r, seg->nrows, 2);
+	Rast_get_row(input_fd, input_buffer, r, input_data_type);
+	input_pointer = input_buffer;
+	memset(target_buffer, 0, seg->ncols * seg->data_size);
+
+	for (c = 0; c < seg->ncols; ++c)
+	    if (!Rast_is_null_value
+		(input_pointer + c * input_data_size, input_data_type)) {
+		switch (seg->data_type) {
+		case CELL_TYPE:
+		    ((CELL *) target_buffer)[c] =
+			Rast_get_c_value(input_pointer + c * input_data_size,
+					 input_data_type);
+		    break;
+		case FCELL_TYPE:
+		    ((FCELL *) target_buffer)[c] =
+			Rast_get_f_value(input_pointer + c * input_data_size,
+					 input_data_type);
+		    break;
+		case DCELL_TYPE:
+		    ((DCELL *) target_buffer)[c] =
+			Rast_get_d_value(input_pointer + c * input_data_size,
+					 input_data_type);
+		    break;
+		default:
+		    G_fatal_error(_("Wrong internal data type"));
+		    break;
+		}
+	    }
+
+	if (0 > segment_put_row(&(seg->seg), target_buffer, r)) {
+	    G_free(input_buffer);
+	    G_free(target_buffer);
+	    Rast_close(input_fd);
+	    G_fatal_error(_("seg_read: Cannot segment put row %d for map %s"),
+			  r, input_map_name);
+	}
+    }				/* end for row */
+
+    G_percent(r, seg->nrows, 2);
+    Rast_close(input_fd);
+    G_free(input_buffer);
+    G_free(target_buffer);
+
+    seg->map_name = G_store(input_map_name);
+    seg->mapset = G_store(mapset);
+
+    return 0;
+}
+
+int seg_reset_map(SEG * seg, int value)
+{
+    /*
+     * set all cells in the map to value
+     */
+    int r, c;
+
+    for (r = 0; r < seg->nrows; ++r)
+	for (c = 0; c < seg->ncols; ++c)
+	    segment_put(&(seg->seg), &value, r, c);
+
+    return 0;
+}
+
+int seg_write_map(SEG * seg, char *output_map_name,
+		  RASTER_MAP_TYPE output_data_type, int convert_to_null,
+		  double value)
+{
+    /* 
+     * write seg to disk with output_map_name and output_data_type [CELL, FCELL, DCELL];
+     * if output_data_type = -1 than internal map type is used for output;
+     * if output map != -1 and types differ data_type, conversion is forced
+     * convert to null: check if convert to null a particular value in dataset;
+     */
+    int output_fd;
+    int r, c;
+    void *output_buffer;
+    void *row;
+    struct History history;
+
+    /* check for output format */
+    if (output_data_type == -1)
+	output_data_type = seg->data_type;
+
+    if (output_data_type != seg->data_type)
+	G_debug(1,
+		"ram_write:required map type and internal map type differs: conversion forced!");
+
+    G_message(_("Writing map <%s>"), output_map_name);
+    output_fd = Rast_open_new(output_map_name, output_data_type);
+    output_buffer = Rast_allocate_buf(output_data_type);
+    segment_flush(&(seg->seg));
+
+    /* writing */
+    for (r = 0; r < seg->nrows; ++r) {
+
+	G_percent(r, seg->nrows, 2);
+	if (0 > segment_get_row(&(seg->seg), output_buffer, r))
+	    G_warning(_("seg_write: Cannot segment read row %d for map %s"),
+		      r, output_map_name);
+
+	if (convert_to_null) {
+
+	    row = output_buffer;
+	    switch (seg->data_type) {
+	    case CELL_TYPE:
+		for (c = 0; c < seg->ncols; ++c)
+		    if (((CELL *) output_buffer)[c] == (CELL) value)
+			Rast_set_c_null_value(row + c * (seg->data_size), 1);
+		break;
+	    case FCELL_TYPE:
+		for (c = 0; c < seg->ncols; ++c)
+		    if (((FCELL *) output_buffer)[c] == (FCELL) value)
+			Rast_set_f_null_value(row + c * (seg->data_size), 1);
+		break;
+	    case DCELL_TYPE:
+		for (c = 0; c < seg->ncols; ++c)
+		    if (((DCELL *) output_buffer)[c] == (DCELL) value)
+			Rast_set_d_null_value(row + c * (seg->data_size), 1);
+		break;
+	    default:
+		G_warning(_("ram_null:Cannot convert to null at: %d %d"), r,
+			  c);
+	    }
+	}
+	Rast_put_row(output_fd, output_buffer, output_data_type);
+    }
+
+    G_percent(r, seg->nrows, 2);
+    G_free(output_buffer);
+    Rast_close(output_fd);
+    Rast_short_history(output_map_name, "raster", &history);
+    Rast_command_history(&history);
+    Rast_write_history(output_map_name, &history);
+    G_message(_("%s Done"), output_map_name);
+
+    return 0;
+}
+
+int seg_release_map(SEG * seg)
+{
+    /* 
+     * release segment close files, set pointers to null;
+     */
+    segment_release(&(seg->seg));
+    close(seg->fd);
+    unlink(seg->filename);
+
+    if (seg->map_name)
+	G_free(seg->map_name);
+    if (seg->mapset)
+	G_free(seg->mapset);
+
+    return 0;
+}

Added: grass-addons/grass7/grass7/raster/r.stream.order/io.h
===================================================================
--- grass-addons/grass7/grass7/raster/r.stream.order/io.h	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.stream.order/io.h	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,59 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <string.h>
+#include <math.h>
+#include <grass/glocale.h>
+#include <grass/gis.h>
+#include <grass/raster.h>
+#include <grass/segment.h>
+
+#define NOT_IN_REGION(x) (r + nextr[(x)] < 0 || r + nextr[(x)] > (nrows - 1) || \
+                          c + nextc[(x)] < 0 || c + nextc[(x)] > (ncols - 1))
+#define NR(x) (r + nextr[(x)])
+#define NC(x) (c + nextc[(x)])
+#define INDEX(r,c) ((r) * ncols + (c))
+#define DIAG(x) (((x) + 4) > 8 ? ((x) - 4) : ((x) + 4))
+
+#define SROWS 256
+#define SCOLS 256
+
+typedef struct {
+	void **map; /* matrix of data */
+	double min, max; /* data range : may requre casting */
+	int nrows, ncols;
+	char *map_name; /* map name, unused */
+	RASTER_MAP_TYPE data_type; /* type of data */
+	size_t data_size; /* type of data */
+} MAP;
+
+typedef struct {
+	SEGMENT seg;		/* segmented data store */
+	int fd;					/* segment temporary file name descriptor */
+	char *filename; /* segment temporary file name */
+	char *map_name; /* map name converted to segment */
+	char *mapset;
+	int nrows, ncols; /* store nrows and rcols */
+	RASTER_MAP_TYPE data_type; /* data type of the map */
+	size_t data_size; /* size of cell returned by sizeof */
+	double min, max; /* data range */
+} SEG;
+
+
+/* all in ram functions */
+int ram_create_map(MAP *, RASTER_MAP_TYPE);
+int ram_read_map(MAP *, char *, int, RASTER_MAP_TYPE);
+int ram_reset_map(MAP *, int);
+int ram_write_map(MAP *, char *, RASTER_MAP_TYPE, int, double);
+int ram_release_map(MAP *);
+int ram_destory_map(MAP *);
+
+/* memory swap functions */
+int seg_create_map(SEG *, int, int, int, RASTER_MAP_TYPE);
+int seg_read_map(SEG *, char *, int, RASTER_MAP_TYPE);
+int seg_reset_map (SEG *, int);
+int seg_write_map(SEG *, char *, RASTER_MAP_TYPE, int, double);
+int seg_release_map(SEG *);
+

Added: grass-addons/grass7/grass7/raster/r.stream.order/local_proto.h
===================================================================
--- grass-addons/grass7/grass7/raster/r.stream.order/local_proto.h	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.stream.order/local_proto.h	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,29 @@
+#include "io.h"
+#include "local_vars.h"
+
+/* stream init */
+int stream_init(int min_index_of_stream, int max_index_of_stream);
+int stream_sample_map(char* input_map_name, int number_of_streams, int what);
+
+/* stream topology */
+int ram_stream_topology(CELL** streams, CELL** dirs, int number_of_streams);
+int ram_stream_geometry(CELL** streams, CELL** dirs);
+int seg_stream_topology(SEGMENT* streams, SEGMENT* dirs, int number_of_streams);
+int seg_stream_geometry(SEGMENT* streams, SEGMENT* dirs);
+
+/* stream order */
+int strahler(int* strahler);
+int shreve(int* shreve);
+int horton(const int* strahler, int* horton, int number_of_streams);
+int hack(int* hack, int* topo_dim, int number_of_streams);
+
+/* stream raster close */
+int ram_close_raster_order(CELL** streams, int number_of_streams, int zerofill);
+int seg_close_raster_order(SEGMENT* streams, int number_of_streams, int zerofill);
+
+/* stream vector */
+int ram_create_vector(CELL** streams, CELL** dirs, char* out_vector, int number_of_streams);
+int seg_create_vector(SEGMENT* streams, SEGMENT* dirs, char* out_vector, int number_of_streams);
+int stream_add_table (int number_of_streams);
+
+

Added: grass-addons/grass7/grass7/raster/r.stream.order/local_vars.h
===================================================================
--- grass-addons/grass7/grass7/raster/r.stream.order/local_vars.h	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.stream.order/local_vars.h	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,66 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include <grass/glocale.h>
+#include <grass/gis.h>
+#include <grass/raster.h>
+#include <grass/vector.h>
+#include <grass/dbmi.h>
+
+#ifdef MAIN
+#  define GLOBAL
+#else
+#  define GLOBAL extern
+#endif
+
+typedef enum {o_streams, o_dirs, o_elev, o_accum, input_size } inputs;
+/* eny new oredering systems must be also declared here before orders_size*/
+typedef enum {o_strahler, o_horton, o_shreve, o_hack, o_topo, orders_size } orders;
+
+typedef struct {
+	char* name;
+	int required;
+	char* description;
+} IO;
+
+typedef struct {
+    int stream;	/* topology */
+    int next_stream;
+    int trib_num;
+    int trib[5];
+    int cells_num;
+    int init; /* index to recalculate into r,c*/
+    int outlet; /* index to recalculate into r,c */
+    double length;   /* geometry */ 
+    double accum_length;
+    double distance; /* distance to outlet */
+    double stright; /* use next to calculate sinusoid */
+    double accum;
+    double init_elev;
+    double outlet_elev; /* use next to calculate drop and gradient */
+} STREAM;
+
+GLOBAL char** output_map_names;
+GLOBAL int ** all_orders;
+
+GLOBAL int nextr[9];
+GLOBAL int nextc[9];
+GLOBAL int nrows, ncols;
+GLOBAL int use_vector, use_accum;
+
+
+/* stream topo */
+GLOBAL int init_num, outlet_num;
+GLOBAL STREAM* stream_attributes;
+GLOBAL unsigned int* init_streams;
+GLOBAL unsigned int* outlet_streams;
+GLOBAL unsigned long int* init_cells;
+
+/* output vector */
+GLOBAL struct Map_info Out; 
+
+
+
+
+

Added: grass-addons/grass7/grass7/raster/r.stream.order/main.c
===================================================================
--- grass-addons/grass7/grass7/raster/r.stream.order/main.c	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.stream.order/main.c	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,287 @@
+
+/****************************************************************************
+ *
+ * MODULE:			r.stream.order
+ * AUTHOR(S):		Jarek Jasiewicz jarekj amu.edu.pl
+ *							 
+ * PURPOSE:			Calculate Strahler's and more streams hierarchy
+ *							It use r.stream.extract or r.watershed output files: 
+ * 							stream, direction, accumulation and elevation. 
+ * 							The output are set of raster maps and vector file containing
+ * 							addational stream attributes.
+ *
+ * COPYRIGHT:		(C) 2009,2010 by the GRASS Development Team
+ *
+ *							This program is free software under the GNU General Public 
+ *							License (>=v2). Read the file COPYING that comes with GRASS
+ *							for details.
+ *
+ *****************************************************************************/
+#define MAIN
+#include <grass/glocale.h>
+#include "local_proto.h"
+
+int nextr[9] = { 0, -1, -1, -1, 0, 1, 1, 1, 0 };
+int nextc[9] = { 0, 1, 0, -1, -1, -1, 0, 1, 1 };
+
+
+int main(int argc, char *argv[])
+{
+
+    IO input[] = {
+	{"streams", YES, "output of r.stream.extract or r.watershed"},
+	{"dirs", YES, "output of r.stream.extract or r.watershed"},
+	{"elevation", NO, "any type digital elevation model"},
+	{"accum", NO,
+	 "any type acc map created by r.watershed or used in r.stream.extract"}
+    };
+
+    /* add new basic rdering here and in local_vars.h declaration 
+     * it will be added to output without addational programing.
+     * Ordering functions are to be added in stream_order.c file.
+     * Addational operations may shall be done in common part sections
+     * derivative orders (like Scheideggers/Shreve) shall be added only 
+     * to table definition as a formula and to description file. */
+    IO output[] = {
+	{"strahler", NO, "Strahler's stream order"},
+	{"horton", NO, "Original Hortons's stream order"},
+	{"shreve", NO, "Shereve's stream magnitude"},
+	{"hack", NO, "Hack's streams or Gravelius stream hierarchy"},
+	{"topo", NO, "Topological dimension of streams"}
+    };
+    struct GModule *module;	/* GRASS module for parsing arguments */
+
+    struct Option *opt_input[input_size];
+    struct Option *opt_output[orders_size];
+    struct Option *opt_swapsize;
+    struct Option *opt_vector;
+    struct Flag *flag_zerofill, *flag_accum, *flag_segmentation;
+
+    int output_num = 0;
+    int num_seg;		/* number of segments */
+    int segmentation, zerofill;
+    int i;			/* iteration vars */
+    int number_of_segs;
+    int number_of_streams;
+    char *in_streams = NULL, *in_dirs = NULL, *in_elev = NULL, *in_accum =
+	NULL;
+    char *out_vector = NULL;
+
+    G_gisinit(argv[0]);
+
+    module = G_define_module();
+    module->description =
+	_("Calculate Strahler's and more streams hierarchy. Basic module for topological analysis of drainage network");
+    G_add_keyword("Strahler Stream Order");
+    G_add_keyword("Hack Streams");
+    G_add_keyword("Stream network topology");
+    G_add_keyword("Stream network geometry");
+    G_add_keyword("Nework vectorisation");
+
+    for (i = 0; i < input_size; ++i) {
+	opt_input[i] = G_define_standard_option(G_OPT_R_INPUT);
+	opt_input[i]->key = input[i].name;
+	opt_input[i]->required = input[i].required;
+	opt_input[i]->description = _(input[i].description);
+    }
+
+    opt_vector = G_define_standard_option(G_OPT_V_OUTPUT);
+    opt_vector->key = "vector";
+    opt_vector->required = NO;
+    opt_vector->description =
+	_("OUTPUT vector file to write stream atributes");
+    opt_vector->guisection = _("Output");
+
+    for (i = 0; i < orders_size; ++i) {
+	opt_output[i] = G_define_standard_option(G_OPT_R_OUTPUT);
+	opt_output[i]->key = output[i].name;
+	opt_output[i]->required = NO;
+	opt_output[i]->description = _(output[i].description);
+	opt_output[i]->guisection = _("Output");
+    }
+
+    opt_swapsize = G_define_option();
+    opt_swapsize->key = "memory";
+    opt_swapsize->type = TYPE_INTEGER;
+    opt_swapsize->answer = "300";
+    opt_swapsize->description = _("Max memory used in memory swap mode (MB)");
+    opt_swapsize->guisection = _("Optional");
+
+    flag_zerofill = G_define_flag();
+    flag_zerofill->key = 'z';
+    flag_zerofill->description =
+	_("Create zero-valued background instead of NULL");
+
+    flag_segmentation = G_define_flag();
+    flag_segmentation->key = 'm';
+    flag_segmentation->description = _("Use memory swap (operation is slow)");
+
+    flag_accum = G_define_flag();
+    flag_accum->key = 'a';
+    flag_accum->description =
+	_("Use flow accumulation to trace horton and hack models");
+
+    if (G_parser(argc, argv))	/* parser */
+	exit(EXIT_FAILURE);
+
+
+    /* check output names */
+    zerofill = (flag_zerofill->answer != 0);
+    segmentation = (flag_segmentation->answer != 0);
+    use_accum = (flag_accum->answer != 0);
+    use_vector = (opt_vector->answer != NULL);
+
+    number_of_segs = (int)atof(opt_swapsize->answer);
+    number_of_segs = number_of_segs < 32 ? (int)(32 / 0.12) : number_of_segs / 0.12;
+
+    if (use_vector)
+	if (!opt_input[o_elev]->answer || !opt_input[o_accum]->answer)
+	    G_fatal_error(_("To calculate vector file both accum and elev are required"));
+    if (use_accum)
+	if (!opt_input[o_accum]->answer)
+	    G_fatal_error(_("with -a (use accumulation) accum map is required"));
+
+    for (i = 0; i < orders_size; ++i) {
+	if (!opt_output[i]->answer)
+	    continue;
+	if (G_legal_filename(opt_output[i]->answer) < 0)
+	    G_fatal_error(_("<%s> is an illegal file name"),
+			  opt_output[i]->answer);
+	output_num++;
+    }				/* end for */
+    if (!output_num && !opt_vector->answer)
+	G_fatal_error(_("You must select one or more output orders maps or insert the table name"));
+
+    /* start */
+    in_streams = opt_input[o_streams]->answer;
+    in_dirs = opt_input[o_dirs]->answer;
+    in_elev = opt_input[o_elev]->answer;
+    in_accum = opt_input[o_accum]->answer;
+    out_vector = opt_vector->answer;
+
+    output_map_names = (char **)G_malloc(orders_size * sizeof(char *));
+    for (i = 0; i < orders_size; ++i)
+	output_map_names[i] = opt_output[i]->answer;
+
+    nrows = Rast_window_rows();
+    ncols = Rast_window_cols();
+
+    /* ALL IN RAM VERSION */
+    if (!segmentation) {
+	G_message("ALL IN RAM CALCULATION");
+	MAP map_streams, map_dirs;
+	CELL **streams, **dirs;
+
+	ram_create_map(&map_streams, CELL_TYPE);
+	ram_read_map(&map_streams, in_streams, 1, CELL_TYPE);
+	ram_create_map(&map_dirs, CELL_TYPE);
+	ram_read_map(&map_dirs, in_dirs, 1, CELL_TYPE);
+	stream_init((int)map_streams.min, (int)map_streams.max);
+	number_of_streams = (int)(map_streams.max + 1);
+	streams = (CELL **) map_streams.map;
+	dirs = (CELL **) map_dirs.map;
+
+	ram_stream_topology(streams, dirs, number_of_streams);
+
+	if (out_vector || output_map_names[o_horton] ||
+	    output_map_names[o_hack] || output_map_names[o_topo])
+	    ram_stream_geometry(streams, dirs);
+
+	/* common part */
+	if (use_vector) {
+	    stream_sample_map(in_elev, number_of_streams, 0);
+	    stream_sample_map(in_elev, number_of_streams, 1);
+	}
+	if (use_accum || use_vector)
+	    stream_sample_map(in_accum, number_of_streams, 2);
+
+	if (output_map_names[o_strahler] || output_map_names[o_horton] ||
+	    out_vector)
+	    strahler(all_orders[o_strahler]);
+
+	if (output_map_names[o_horton] || out_vector)
+	    horton(all_orders[o_strahler], all_orders[o_horton],
+		   number_of_streams);
+
+	if (output_map_names[o_shreve] || out_vector)
+	    shreve(all_orders[o_shreve]);
+
+	if (output_map_names[o_hack] || output_map_names[o_topo] ||
+	    out_vector)
+	    hack(all_orders[o_hack], all_orders[o_topo], number_of_streams);
+	/* end of common part */
+
+	if (out_vector)
+	    ram_create_vector(streams, dirs, out_vector, number_of_streams);
+
+	ram_close_raster_order(streams, number_of_streams, zerofill);
+	ram_release_map(&map_streams);
+	ram_release_map(&map_dirs);
+	/* end ram section */
+    }
+
+    /* SEGMENTATION VERSION */
+    if (segmentation) {
+	G_message("MEMORY SWAP CALCULATION: MAY TAKE SOME TIME!");
+
+	SEG map_streams, map_dirs;
+	SEGMENT *streams, *dirs;
+
+	seg_create_map(&map_streams, SROWS, SCOLS, number_of_segs, CELL_TYPE);
+	seg_read_map(&map_streams, in_streams, 1, CELL_TYPE);
+	seg_create_map(&map_dirs, SROWS, SCOLS, number_of_segs, CELL_TYPE);
+	seg_read_map(&map_dirs, in_dirs, 1, CELL_TYPE);
+	stream_init((int)map_streams.min, (int)map_streams.max);
+	number_of_streams = (int)(map_streams.max + 1);
+	streams = &map_streams.seg;
+	dirs = &map_dirs.seg;
+
+	seg_stream_topology(streams, dirs, number_of_streams);
+
+	if (out_vector || output_map_names[o_horton] ||
+	    output_map_names[o_hack] || output_map_names[o_topo])
+	    seg_stream_geometry(streams, dirs);
+
+	/* common part */
+	if (use_vector) {
+	    stream_sample_map(in_elev, number_of_streams, 0);
+	    stream_sample_map(in_elev, number_of_streams, 1);
+	}
+	if (use_accum || use_vector)
+	    stream_sample_map(in_accum, number_of_streams, 2);
+
+	if (output_map_names[o_strahler] || output_map_names[o_horton] ||
+	    out_vector)
+	    strahler(all_orders[o_strahler]);
+
+	if (output_map_names[o_horton] || out_vector)
+	    horton(all_orders[o_strahler], all_orders[o_horton],
+		   number_of_streams);
+
+	if (output_map_names[o_shreve] || out_vector)
+	    shreve(all_orders[o_shreve]);
+
+	if (output_map_names[o_hack] || output_map_names[o_topo] ||
+	    out_vector)
+	    hack(all_orders[o_hack], all_orders[o_topo], number_of_streams);
+	/* end of common part */
+
+	if (out_vector)
+	    seg_create_vector(streams, dirs, out_vector, number_of_streams);
+
+	seg_close_raster_order(streams, number_of_streams, zerofill);
+	seg_release_map(&map_streams);
+	seg_release_map(&map_dirs);
+	/* end segmentation section */
+    }
+
+
+    /* free */
+    G_free(stream_attributes);
+    G_free(init_streams);
+    G_free(outlet_streams);
+    G_free(init_cells);
+
+    exit(EXIT_SUCCESS);
+
+}

Added: grass-addons/grass7/grass7/raster/r.stream.order/orders.png
===================================================================
(Binary files differ)


Property changes on: grass-addons/grass7/grass7/raster/r.stream.order/orders.png
___________________________________________________________________
Added: svn:mime-type
   + application/octet-stream

Added: grass-addons/grass7/grass7/raster/r.stream.order/r.stream.order.html
===================================================================
--- grass-addons/grass7/grass7/raster/r.stream.order/r.stream.order.html	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.stream.order/r.stream.order.html	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,289 @@
+<h2>DESCRIPTION</h2>
+
+<h2>OPTIONS</h2>
+<dl>
+<dt><b>-z</b></dt>
+<dd>Creates zero-value background instead of NULL. For some reason (like map
+algebra calculation) zero-valued background may be required. This flag produces
+zero-filled background instead of null (default).</dd>
+<dt><b>-a</b></dt>
+<dd>Uses accumulation map instead of cumulated stream length to determine main
+branch at bifuraction. Works well only with SFD networks</dd>
+<dt><b>-m</b></dt>
+<dd>Only for very large data sets. Use segment library to optimise memory
+consumption during analysis</dd>
+<dt><b>stream network map</b></dt>
+<dd>Name of input stream map on which ordering will be performed produced by
+r.watershed or r.stream.extract. Because streams network produced by r.watershed
+and r.stream.extract may slighty differ in detail it is required to 
+use both stream and direction map produced by the same module. Stream background
+shall have NULL value or zero value. 
+Background values of NULL are by default produced by r.watershed and
+r.stream.extract. If not 0 or NULL use <a href="r.mapcalc.html">r.mapcalc</a> to
+set background values to null.  
+</dd>
+<dt><b>flow direction map</b></dt>
+<dd>Name of input direction map produced by r.watershed or r.stream.extract. If
+r.stream.extract output map is used, it only has non-NULL values in places where
+streams occur. NULL (nodata) cells are ignored, zero and negative values are
+valid direction data if they vary from -8 to 8 (CCW from East in steps of 45
+degrees). Direction map shall be of type CELL values. Region resolution and map
+resoultion must be the same. 
+Also <em>stream</em> network and <em>direction</em> maps must have the same
+resolution. It is checked by default. If resolutions differ the module informs
+about it and stops. Region boundary
+and maps boundary may be differ but it may lead to unexpected results.</dd>
+<dt><b>accumulation map</b></dt>
+<dd>Flow accumulation (optional, not recommended): name of flow accumulation
+file produced by r.watershed or used in r.stream.extract. This map is an option
+only if Horton's or Hack's ordering is performed. Normally both Horton and Hack
+ordering is calculated on cumulative stream lrngth which is calculated
+internaly. Flow accumulation can be used if user want to calculate main stream
+as most accumulated stream. Flow accumulation map shall be of DCELL type, as is
+by default produced by r.watershed or converted do DCELL with r.mapcalc.</dd>
+<dt><b>elevation map</b></dt>
+<dd>Used to calculate geometrical properites of the network stored in the
+table.</dd>
+</dl>
+<h2>OUTPUTS</h2>
+
+<p>At least one output map is required: </p>
+<dl>
+<dt><b>vector</b></dt>
+<dd>Vector network with table where stream network topology can be stored.
+Because r.stream.order is prepared to work both with r.watershed and
+r.stream.extract, it may be yused to create correct vector from r.watershed
+results.<dd>
+
+<dt><b>strahler</b></dt>
+<dd>Name of Strahler's stream order output map: see notes for detail. </dd>
+
+<dt><b>shreve</b></dt>
+<dd>Name of Shreve's stream magnitude output map: see notes for detail.</dd>
+
+<dt><b>horton</b></dt>
+<dd>Name of Horton's stream order output map (require accum file): see notes for
+detail.</dd>
+
+<dt><b>hack</b></dt>
+<dd>Name of Hack's main streams output map : see notes for detail.</dd>
+
+<dt><b>top</b></dt>
+<dd>Name of topological dimensions streams output map: see notes for
+detail.</dd>
+</dl>
+
+<h3>Stream ordering example:</h3>
+<center>
+<img src=orders.png border=1><br>
+</center>
+
+<p>
+<h4>Strahler's stream order</h4>
+Strahler's stream order is a modification of Horton's streams order which fixes
+the ambiguity of Horton's ordering. 
+In Strahler's ordering the main channel is not determined; instead the ordering
+is based on the hierarchy of tributaries. The 	
+ordering follows these rules:
+<ol>
+<li>if the node has no children, its Strahler order is 1.
+<li>if the node has one and only one tributuary with Strahler greatest order i,
+and all other tributaries have order less than i, then the order remains i.
+<li>if the node has two or more tributaries with greatest order i, then the
+Strahler order of the node is i + 1.
+</ol>
+Strahler's stream ordering starts in initial links which assigns order one. It
+proceeds downstream. At every node it verifies that there are at least 2 equal
+tributaries with maximum order. If not it continues with highest order, if yes
+it increases the node's order by 1 and continues downstream with new order. 
+<br>
+<b>Advantages and disadvantages of Strahler's ordering: </b>
+ Strahler's stream order has a good mathematical background. All catchments with
+streams in this context are directed graphs, oriented from the root towards the
+leaves. Equivalent definition of the Strahler number of a tree is that it is the
+height of the largest complete binary tree that can be homeomorphically embedded
+into the given tree; the Strahler number of a node in a tree is equivalent to
+the height of the largest complete binary tree that can be embedded below that
+node. The disadvantage of that methods is the lack of distinguishing a main
+channel which may interfere with the analytical process in highly elongated
+catchments
+
+<h4>Horton's stream order</h4>
+Horton's stream order applies to the stream as a whole but not to segments or
+links since the order on any channel remains unchanged from source till it
+"dies" in the higher order stream or in the outlet of the catchment. The main
+segment of the catchment gets the order of the whole catchment, while its
+tributaries get the order of their own subcatchments. The main difficulties of
+the Horton's order are criteria to be considered to distinguish between "true"
+first order segments and extension of higher order segments. Thqat is the reason
+why Horton's ordering has rather historical sense and is substituted by the more
+unequivocal Strahler's ordering system. There are no natural algorithms to order
+stream network according to Horton' paradigm. The algorithm used in
+r.stream.order requires to first calculate Strahler's stream order (downstream)
+and next recalculate to Horton ordering (upstream). To make a decision about
+proper ordering it uses first Strahler ordering, and next, if both branches have
+the same orders it uses flow accumulation to choose the actual link. The
+algorithm starts with the outlet, where the outlet link is assigned the
+corresponding Strahler order. Next it goes upstream and determines links
+according to Strahler ordering. If the orders of tributaries differ, the
+algorithm proceeds with the channel of highest order, if all orders are the
+same, it chooses that one with higher flow length rate or higher catchment area
+if accumulation is used. When it reaches the initial channel it goes back to the
+last undetermined branch, assign its Strahler order as Horton order and goes
+upstream to the next initial links. In that way stream orders remain unchanged
+from the point where Horton's order have been determined to the source. 
+  
+<br>
+<b>Advantages and disadvantages of Horton's ordering:</b> 
+The main advantages of Horton's ordering is that it produces natural stream
+ordering with main streams and its tributaries. The main disadvantage is that it
+requires prior Strahler's ordering. In some cases this may result in unnatural
+ordering, where the highest order will be ascribed not to the channel with
+higher accumulation but to the channel which leads to the most branched parts of
+the the catchment. 
+<p>
+<h4>Shreve's stream magnitude</h4>
+That ordering method is similar to Consisted Associated Integers proposed by
+Scheidegger. It assigns magnitude of 1 for every initial channel. The magnitude
+of the following channel is the sum of magnitudes of its tributaries. The number
+of a particular link is the number of initials which contribute to it. 
+
+<h4>Scheidegger's stream magnitude</h4>
+That ordering method is similar to Shreve's stream magnitude. It assigns
+magnitude of 2 for every initial channel. The magnitude of the following channel
+is the sum of magnitudes of its tributaries. The number of a particular link is
+the number of streams -1 contributing to it. Consisted Associated Integers
+(Scheidegger) is aviallable only in attribute table. To achive Consisted
+Associated Integers (Scheidegger) raster the result of Shreve's magnitude is to
+be multiplied by 2: 
+<p>
+<code>r.mapcalc scheidegger=shreve*2</code>
+<p>
+<h4>Drwal's stream hierarchy (old style)</h4>
+That ordering method is a compromise between Strahler ordering and Shreve
+magnitude. It assigns order of 1 for every initial channel. The order of the
+following channel is calculated according Strahler formula, except, that streams
+which do not increase order of next channel are not lost. To increase next
+channel to the hiher order R+1 are require two channels of order R, or one R and
+two R-1 or one R, and four R-2 or one R, one R-1 and two R-2 etc. The the order
+of particular link show the possible value of Strahler'order if the network was
+close to idealised binary tree. Drwal's order is aviallable only in attribute
+table.To achive Drwal's raster the result of Shreve's magnitude is to be
+recalculated according formula: <b>floor(log(shreve,2))+1</b>
+<p>
+<code>r.mapcalc drwal=int(log(shreve,2))+1</code>
+<p>
+<b>Advantages and disadvantages of Drwal's hierarhy:</b> 
+The main advantages of Drwal's hierarchy is that it produces natural stream
+ordering with whcich takes into advantage both ordering and magnitude. It shows
+the real impact of particular links of the network run-off. The main
+desadvantage is that it minimise bifuraction ratio ot the network.
+
+<p>
+<h4>Hack's main streams or Gravelius order</h4>
+This method of ordering calculates main streams of main catchment and every
+subcatchments. Main stream of every catchment is set to 1, and consequently all
+its tributaries receive order 2. Their tributaries receive order 3 etc. The
+order of every stream remains constant up to its initial link. The route of
+every main stream is determined according to the maximum flow length value of
+particular streams. So the main stream of every subcatchment is the longest
+stream or strean with highest accumulation rate if accumulation map is used. In
+most cases the main stream is the longest watercourse of the catchment, but in
+some cases, when a catchment consists of both rounded and elongated
+subcatchments these rules may not be maintained. The algorithm assigns 1 to
+every outlets stream and goes upstream according to maximum flow accumulation of
+every branch. When it reaches an initial stream it step back to the first
+unassigned confluence. It assigns order 2 to unordered tributaries and again
+goes upstream to the next initial stream. The process runs until all branches of
+all outlets are ordered. 
+<br>
+<b>Advantages and disadvantages of main stream ordering:</b>
+The biggest advantage of that method is the possibility to compare and analyze
+topology upstream, according to main streams. Because all tributaries of main
+channel have order of 2, streams can be quickly and easily filtered and its
+proprieties and relation to main stream determined. The main disadvantage of
+that method is the problem with the comparison of subcatchment topology of the
+same order. Subcatchments of the same order may be both highly branched and
+widespread in the catchment area and a small subcatchment with only one stream. 
+<h4>Topological dimension streams order</h4>
+This method of ordering calculates topological distance of every stream from
+catchment outlet.
+<br>
+
+<h4>Stream network topology table description connected with vector file</h4>
+<ul>
+	<li><b>cat</b> integer: category;
+	<li><b>stream</b>integer: stream number, usually equal to cat;
+	<li><b>next_stream</b> integer: stream to which contribute current
+stream (downstream);
+	<li><b>prev_streams</b>; two or more contributing streams (upstream);
+	<li><b>strahler</b> integer: Strahler's stream order:
+	<li><b>horton</b> integer: Hortons's stream order:
+	<li><b>shreve</b> integer: Shreve's stream magnitude;
+	<li><b>scheidegger</b> integer: Scheidegger's Consisted Associated
+Integers;
+	<li><b>drwal</b> integer: Drwal's stream hierarchy;
+	<li><b>hack</b> integer: Hack's main streams or Gravelius order;
+	<li><b>topo</b> integer: Topological dimension streams order;
+	<li><b>length</b> double precision: stream length;
+	<li><b>cum_length</b> double precision: length of stream from source;
+	<li><b>out_dist</b> double precision: distance of current stream init
+from outlet;
+	<li><b>stright</b> double precision: length of stream as stright line;
+	<li><b>sinusiod</b> double precision: fractal dimention: stream
+length/stright stream length;
+	<li><b>elev_init</b> double precision: elevation of  stream init;
+	<li><b>elev_outlet</b> double precision: elevation of  stream outlet;
+	<li><b>drop</b> double precision: difference between stream init and
+outlet + drop outlet;
+	<li><b>out_drop</b> double precision: drop at the outlet of the stream;
+	<li><b>gradient</b> double precision: drop/length;
+</ul>
+<h2>NOTES</h2>
+<p>
+Module can work only if direction map, stream map and region map has same
+settings. It is also required that stream map and direction map come from the
+same source. For lots of reason this limitation probably cannot be omitted. This
+means if stream map comes from r.stream.extract also direction map from
+r.stream.extract must be used. If stream network was generated with MFD method
+also MFD direction map must be used. Nowadays f direction map comes from
+r.stream.extract  must be patched by direction map from r.watershed. (with
+r.patch). 
+
+<h2>SEE ALSO</h2>
+
+<em>
+<a href="r.watershed.html">r.watershed</a>,
+<a href="r.stream.extract.html">r.stream.extract</a>,
+<a href="r.stream.basins.html">r.stream.basins</a>,
+<a href="r.stream.stats.html">r.stream.stats</a>,
+<a href="r.mapcalc.html">r.mapcalc</a>,
+</em>
+
+<h2>REFERENCES</h2>
+Drwal, J., (1982), <i>Wykształecenie i organizacja sieci hydrograficznej jako
+podstawa oceny struktury odpływu na terenach młodoglacjalnych</i>, <b>Rozprawy i
+monografie</b>, Gdańsk 1982, 130 pp (in Polish)<p>
+Hack, J., (1957), <i>Studies of longitudinal stream profiles in Virginia and
+Maryland</i>, 
+<b>U.S. Geological Survey Professional Paper</b>, 294-B<p>
+Horton, R. E. (1945), <i>Erosional development of streams and their drainage
+basins: hydro-physical approach to quantitative morphology</i>,<b>Geological
+Society of America Bulletin</b> 56 (3): 275-370<br>
+Scheidegger A. E., (1966), <i>Statistical Description of River Networks</i>.
+<b>Water Resour. Res.</b>, 2(4): 785-790
+Shreve, R.,  (1966),<i>Statistical Law of Stream Numbers</i>, <b>J. Geol.</b>,
+74, 17-37.<p>
+Strahler, A. N. (1952), <i>Hypsometric (area-altitude) analysis of erosional
+topology</i>,<b>Geological Society of America Bulletin</b> 63 (11): 1117–1142<p>
+Strahler, A. N. (1957), <i>Quantitative analysis of watershed
+geomorphology</i>,<b>Transactions of the American Geophysical Union</b> 8 (6):
+913–920.<p>
+Woldenberg, M. J., (1967), <i>Geography and properties of surfaces,</i>
+<b>Harvard Papers in Theoretical Geography</b>, 1: 95–189.
+
+<h2>AUTHOR</h2>
+Jarek  Jasiewicz
+
+<p><i>Last changed: $Date: 2011-11-08 22:56:45 +0100 (Tue, 08 Nov 2011) $</i>
+

Added: grass-addons/grass7/grass7/raster/r.stream.order/stream_init.c
===================================================================
--- grass-addons/grass7/grass7/raster/r.stream.order/stream_init.c	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.stream.order/stream_init.c	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,134 @@
+#include "local_proto.h"
+int stream_init(int min_index_of_stream, int max_index_of_stream)
+{
+    int i, j;
+    int number_of_streams = max_index_of_stream;
+
+    if (max_index_of_stream == 0)
+	G_fatal_error(_("Empty stream input map: check if a stream map"));
+    if (min_index_of_stream < 0)
+	G_fatal_error(_("Stream map has negative values: check if a stream map"));
+
+    stream_attributes =
+	(STREAM *) G_malloc((number_of_streams + 1) * sizeof(STREAM));
+    for (i = 0; i < max_index_of_stream + 1; ++i) {
+	stream_attributes[i].next_stream = -1;
+	stream_attributes[i].stream = -1;
+	stream_attributes[i].trib_num = -1;
+	stream_attributes[i].trib[0] = 0;
+	stream_attributes[i].trib[1] = 0;
+	stream_attributes[i].trib[2] = 0;
+	stream_attributes[i].trib[3] = 0;
+	stream_attributes[i].trib[4] = 0;
+	stream_attributes[i].cells_num = 0;
+	stream_attributes[i].init = 0;
+	stream_attributes[i].outlet = 0;
+	stream_attributes[i].length = 0.;
+	stream_attributes[i].accum_length = 0.;
+	stream_attributes[i].distance = 0.;
+	stream_attributes[i].stright = 0.;
+	stream_attributes[i].accum = 0.;
+	stream_attributes[i].init_elev = -10000;
+	stream_attributes[i].outlet_elev = -10000;
+    }
+
+    all_orders = (int **)G_malloc(orders_size * sizeof(int *));
+    for (i = 0; i < orders_size; ++i)
+	all_orders[i] =
+	    (int *)G_malloc((number_of_streams + 1) * sizeof(int));
+
+    for (i = 0; i < orders_size; ++i)
+	for (j = 0; j < number_of_streams + 1; ++j)
+	    all_orders[i][j] = -1;
+
+    return 0;
+}
+
+int compare_inits(const void *a, const void *b)
+{
+    return (*(STREAM **) a)->init - (*(STREAM **) b)->init;
+}
+
+int compare_outlets(const void *a, const void *b)
+{
+    return (*(STREAM **) a)->outlet - (*(STREAM **) b)->outlet;
+}
+
+int stream_sample_map(char *input_map_name, int number_of_streams, int what)
+{
+
+    /* if what == 2 sample outputs only for accum map */
+    /* if what == 1 sample outputs only for elev map */
+    /* if what == 0 sample inits only for elev map) */
+
+    char *mapset;
+    int input_map_fd;
+    int i;
+    int r, c, cur_row = -1;
+    RASTER_MAP_TYPE input_data_type;
+    size_t input_data_size;
+    void *input_buffer;
+    void *input_ptr;
+
+    STREAM **pointers_to_stream;
+
+    pointers_to_stream =
+	(STREAM **) G_malloc(sizeof(STREAM *) * (number_of_streams));
+    for (i = 0; i < (number_of_streams); ++i)
+	*(pointers_to_stream + i) = stream_attributes + i;
+
+    if (what)
+	qsort(pointers_to_stream, (number_of_streams), sizeof(STREAM *),
+	      compare_outlets);
+    else
+	qsort(pointers_to_stream, (number_of_streams), sizeof(STREAM *),
+	      compare_inits);
+
+
+    mapset = (char *)G_find_raster2(input_map_name, "");
+    if (mapset == NULL)
+	G_fatal_error(_("Raster map <%s> not found"), input_map_name);
+    input_map_fd = Rast_open_old(input_map_name, mapset);
+    input_data_type = Rast_map_type(input_map_name, mapset);
+    input_data_size = Rast_cell_size(input_data_type);
+    input_buffer = Rast_allocate_buf(input_data_type);
+
+    for (i = 0; i < (number_of_streams); ++i) {
+	if (pointers_to_stream[i]->stream == -1)
+	    continue;
+
+	if (what) {
+	    r = (int)pointers_to_stream[i]->outlet / ncols;
+	    c = (int)pointers_to_stream[i]->outlet % ncols;
+	}
+	else {
+	    r = (int)pointers_to_stream[i]->init / ncols;
+	    c = (int)pointers_to_stream[i]->init % ncols;
+	}
+
+	if (r > cur_row) {
+	    Rast_get_row(input_map_fd, input_buffer, r, input_data_type);
+	    input_ptr = input_buffer;
+	}
+	switch (what) {
+	case 0:		/* inits for elev */
+	    pointers_to_stream[i]->init_elev =
+		Rast_get_d_value(input_ptr + c * input_data_size,
+				 input_data_type);
+	    break;
+	case 1:		/* outlets for elev */
+	    pointers_to_stream[i]->outlet_elev =
+		Rast_get_d_value(input_ptr + c * input_data_size,
+				 input_data_type);
+	    break;
+	case 2:		/* outlets for accum */
+	    pointers_to_stream[i]->accum =
+		Rast_get_d_value(input_ptr + c * input_data_size,
+				 input_data_type);
+	    break;
+	}
+    }
+    G_free(input_buffer);
+    G_free(pointers_to_stream);
+    return 0;
+}

Added: grass-addons/grass7/grass7/raster/r.stream.order/stream_order.c
===================================================================
--- grass-addons/grass7/grass7/raster/r.stream.order/stream_order.c	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.stream.order/stream_order.c	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,278 @@
+/* 
+   All algorithms used in analysis ar not recursive. For Strahler order and Shreve magnitude starts from initial channel and  proceed downstream. Algortitms try to assgin order for branch and if it is imposible start from next initial channel, till all branches are ordered.
+   For Hortor and Hack ordering it proceed upstream and uses stack data structure to determine unordered branch. 
+   Algorithm of Hack main stram according idea of Markus Metz.
+ */
+
+#include "local_proto.h"
+int strahler(int *strahler)
+{
+
+    int i, j, done = 1;
+    int cur_stream, next_stream;
+    int max_strahler = 0, max_strahler_num;
+    STREAM *SA = stream_attributes;	/* for better code readability */
+
+    G_message(_("Calculating Strahler's stream order ..."));
+
+    for (j = 0; j < init_num; ++j) {	/* main loop on inits */
+
+	cur_stream = SA[init_streams[j]].stream;
+	do {			/* we must go at least once, if stream is of first order and is outlet */
+	    max_strahler_num = 1;
+	    max_strahler = 0;
+	    next_stream = SA[cur_stream].next_stream;
+
+	    if (SA[cur_stream].trib_num == 0) {	/* assign 1 for spring stream */
+		strahler[cur_stream] = 1;
+		cur_stream = next_stream;
+		done = 1;
+	    }
+	    else {
+		done = 1;
+
+		for (i = 0; i < SA[cur_stream].trib_num; ++i) {	/* loop for determining strahler */
+		    if (strahler[SA[cur_stream].trib[i]] < 0) {
+			done = 0;
+			break;	/* strahler is not determined, break for loop */
+		    }
+		    else if (strahler[SA[cur_stream].trib[i]] > max_strahler) {
+			max_strahler = strahler[SA[cur_stream].trib[i]];
+			max_strahler_num = 1;
+		    }
+		    else if (strahler[SA[cur_stream].trib[i]] == max_strahler) {
+			++max_strahler_num;
+		    }
+		}		/* end determining strahler */
+
+		if (done == 1) {
+		    strahler[cur_stream] = (max_strahler_num > 1) ?
+			++max_strahler : max_strahler;
+		    cur_stream = next_stream;	/* if next_stream<0 we in outlet stream */
+		}
+
+	    }
+	} while (done && next_stream > 0);
+    }				/* end for of main loop */
+    return 0;
+}				/* end strahler */
+
+int shreve(int *shreve)
+{
+
+    int i, j, done = 1;
+    int cur_stream, next_stream;
+    int max_shreve = 0;
+    STREAM *SA = stream_attributes;	/* for better code readability */
+
+    G_message(_("Calculating Shreve's stream magnitude, Scheidegger's consistent integer and Drwal's streams hierarchy (old style) ..."));
+
+    for (j = 0; j < init_num; ++j) {	/* main loop on inits */
+
+	cur_stream = SA[init_streams[j]].stream;
+	do {			/* we must go at least once, if stream is of first order and is outlet */
+
+	    max_shreve = 0;
+	    next_stream = SA[cur_stream].next_stream;
+
+	    if (SA[cur_stream].trib_num == 0) {	/* assign 1 for spring stream */
+
+		shreve[cur_stream] = 1;
+		cur_stream = next_stream;
+		done = 1;
+
+	    }
+	    else {
+		done = 1;
+
+		for (i = 0; i < SA[cur_stream].trib_num; ++i) {	/* loop for determining shreve */
+		    if (shreve[SA[cur_stream].trib[i]] < 0) {
+			done = 0;
+			break;	/* shreeve is not determined, break for loop */
+		    }
+		    else {
+			max_shreve += shreve[SA[cur_stream].trib[i]];
+		    }
+		}		/* end determining shreve */
+
+		if (done == 1) {
+		    shreve[cur_stream] = max_shreve;
+		    cur_stream = next_stream;	/* if next_stream<0 we in outlet stream */
+		}
+	    }
+
+	} while (done && next_stream > 0);
+    }				/* end main loop */
+    return 0;
+}				/* end shreeve */
+
+int horton(const int *strahler, int *horton, int number_of_streams)
+{
+
+    int *stack;
+    int stack_max = number_of_streams;
+    int top, i, j;
+    int cur_stream, cur_horton;
+    int max_strahler;
+    double max_accum, accum;
+    int up_stream = 0;
+    STREAM *SA = stream_attributes;	/* for better code readability */
+
+    G_message(_("Calculating Hortons's stream order ..."));
+    stack = (int *)G_malloc(stack_max * sizeof(int));
+
+    for (j = 0; j < outlet_num; ++j) {
+	cur_stream = SA[outlet_streams[j]].stream;	/* outlet: init */
+	cur_horton = strahler[cur_stream];
+	stack[0] = 0;
+	stack[1] = cur_stream;
+	top = 1;
+
+	do {			/* on every stream */
+	    max_strahler = 0;
+	    max_accum = 0;
+
+	    if (SA[cur_stream].trib_num == 0) {	/* spring: go back on stack */
+
+		horton[cur_stream] = cur_horton;
+		cur_stream = stack[--top];
+
+	    }
+	    else if (SA[cur_stream].trib_num > 1) {	/* node */
+
+		up_stream = 0;	/* calculating up_stream */
+		for (i = 0; i < SA[cur_stream].trib_num; ++i) {
+		    if (horton[SA[cur_stream].trib[i]] < 0) {
+
+			if (strahler[SA[cur_stream].trib[i]] > max_strahler) {
+			    max_strahler = strahler[SA[cur_stream].trib[i]];
+			    max_accum =
+				(use_accum) ? SA[SA[cur_stream].trib[i]].
+				accum : SA[SA[cur_stream].trib[i]].
+				accum_length;
+			    up_stream = SA[cur_stream].trib[i];
+
+			}
+			else if (strahler[SA[cur_stream].trib[i]] ==
+				 max_strahler) {
+
+			    accum =
+				(use_accum) ? SA[SA[cur_stream].trib[i]].
+				accum : SA[SA[cur_stream].trib[i]].
+				accum_length;
+
+			    if (accum > max_accum) {
+				max_accum =
+				    (use_accum) ? SA[SA[cur_stream].trib[i]].
+				    accum : SA[SA[cur_stream].trib[i]].
+				    accum_length;
+
+				up_stream = SA[cur_stream].trib[i];
+			    }
+			}
+		    }
+		}		/* end determining up_stream */
+
+		if (up_stream) {	/* at least one branch is not assigned */
+		    if (horton[cur_stream] < 0) {
+			horton[cur_stream] = cur_horton;
+		    }
+		    else {
+			cur_horton = strahler[up_stream];
+		    }
+		    cur_stream = up_stream;
+		    stack[++top] = cur_stream;
+
+		}
+		else {		/* all asigned, go downstream */
+		    cur_stream = stack[--top];
+
+		}		/* end up_stream */
+	    }			/* end spring/node */
+	} while (cur_stream);
+    }				/* end for outlets */
+    G_free(stack);
+    return 0;
+}
+
+int hack(int *hack, int *topo_dim, int number_of_streams)
+{				/* also calculate topological dimension */
+
+    int *stack;
+    int top, i, j;
+    int cur_stream, cur_hack;
+    double accum, max_accum;
+    int up_stream = 0;
+    int stack_max = number_of_streams;
+    double cur_distance = 0;
+    STREAM *SA = stream_attributes;	/* for better code readability */
+
+    G_message(_("Calculating Hack's main streams and topological dimension..."));
+    stack = (int *)G_malloc(stack_max * sizeof(int));
+
+    for (j = 0; j < outlet_num; ++j) {
+
+	cur_stream = SA[outlet_streams[j]].stream;	/* outlet: init */
+	cur_hack = 1;
+	stack[0] = 0;
+	stack[1] = cur_stream;
+	top = 1;
+
+	topo_dim[cur_stream] = top;
+	cur_distance = SA[cur_stream].distance = SA[cur_stream].length;
+	do {
+	    max_accum = 0;
+
+	    if (SA[cur_stream].trib_num == 0) {	/* spring: go back on stack */
+
+		hack[cur_stream] = cur_hack;
+		cur_stream = stack[--top];
+
+	    }
+	    else if (SA[cur_stream].trib_num > 1) {	/* node */
+		up_stream = 0;	/* calculating up_stream */
+
+		for (i = 0; i < SA[cur_stream].trib_num; ++i) {	/* determining upstream */
+		    if (hack[SA[cur_stream].trib[i]] < 0) {
+
+			accum =
+			    (use_accum) ? SA[SA[cur_stream].trib[i]].
+			    accum : SA[SA[cur_stream].trib[i]].accum_length;
+
+			if (accum > max_accum) {
+			    max_accum =
+				(use_accum) ? SA[SA[cur_stream].trib[i]].
+				accum : SA[SA[cur_stream].trib[i]].
+				accum_length;
+			    up_stream = SA[cur_stream].trib[i];
+			}
+		    }
+		}		/* end determining up_stream */
+
+		if (up_stream) {	/* at least one branch is not assigned */
+
+		    if (hack[cur_stream] < 0) {
+			hack[cur_stream] = cur_hack;
+		    }
+		    else {
+			cur_hack = hack[cur_stream];
+			++cur_hack;
+		    }
+
+		    cur_distance = SA[cur_stream].distance;
+		    cur_stream = up_stream;
+		    stack[++top] = cur_stream;
+		    SA[cur_stream].distance =
+			cur_distance + SA[cur_stream].length;
+		    topo_dim[cur_stream] = top;
+		}
+		else {		/* all asigned, go downstream */
+		    cur_stream = stack[--top];
+
+		}		/* end up_stream */
+	    }			/* end spring/node */
+	} while (cur_stream);
+    }				/* end for outlets */
+    G_free(stack);
+    return 0;
+}

Added: grass-addons/grass7/grass7/raster/r.stream.order/stream_raster_close.c
===================================================================
--- grass-addons/grass7/grass7/raster/r.stream.order/stream_raster_close.c	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.stream.order/stream_raster_close.c	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,130 @@
+#include "local_proto.h"
+int ram_close_raster_order(CELL **streams, int number_of_streams,
+			   int zerofill)
+{
+
+    G_message("Closing maps...");
+    int *output_fd;
+    int r, c, i;
+    CELL *output_buffer, *streams_buffer;
+    struct History history;
+    size_t data_size;
+
+    output_fd = (int *)G_malloc(orders_size * sizeof(int));
+    for (i = 0; i < orders_size; ++i) {
+	if (output_map_names[i] == NULL)
+	    continue;
+	output_fd[i] = Rast_open_c_new(output_map_names[i]);
+    }
+
+    /* this is not very elegant but use for compatibility with seg version */
+
+    data_size = Rast_cell_size(CELL_TYPE);
+    output_buffer = Rast_allocate_c_buf();
+
+    for (r = 0; r < nrows; ++r) {
+	streams_buffer = streams[r];
+
+	for (i = 0; i < orders_size; ++i) {
+
+	    if (output_map_names[i] == NULL)
+		continue;
+
+	    if (zerofill)
+		memset(output_buffer, 0, ncols * data_size);
+	    else
+		Rast_set_c_null_value(output_buffer, ncols);
+
+	    for (c = 0; c < ncols; ++c)
+		if (streams_buffer[c])
+		    output_buffer[c] = all_orders[i][streams_buffer[c]];
+
+	    Rast_put_c_row(output_fd[i], output_buffer);
+	}			/* end i */
+    }
+
+    G_free(output_buffer);
+    for (i = 0; i < orders_size; ++i)
+	G_free(all_orders[i]);
+    G_free(all_orders);
+
+
+    for (i = 0; i < orders_size; ++i) {
+	if (output_map_names[i] == NULL)
+	    continue;
+	Rast_close(output_fd[i]);
+	Rast_short_history(output_map_names[i], "raster", &history);
+	Rast_command_history(&history);
+	Rast_write_history(output_map_names[i], &history);
+	G_message(_("%s Done"), output_map_names[i]);
+    }
+
+    G_free(output_fd);
+    return 0;
+}
+
+
+int seg_close_raster_order(SEGMENT *streams, int number_of_streams,
+			   int zerofill)
+{
+
+    int *output_fd;
+    int r, c, i;
+    CELL *output_buffer, *streams_buffer;
+    struct History history;
+    size_t data_size;
+
+    output_fd = (int *)G_malloc(orders_size * sizeof(int));
+    for (i = 0; i < orders_size; ++i) {
+	if (output_map_names[i] == NULL)
+	    continue;
+	output_fd[i] = Rast_open_c_new(output_map_names[i]);
+    }
+
+    data_size = Rast_cell_size(CELL_TYPE);
+    output_buffer = Rast_allocate_c_buf();
+    streams_buffer = Rast_allocate_c_buf();
+    segment_flush(streams);
+
+    for (r = 0; r < nrows; ++r) {
+	if (0 > segment_get_row(streams, streams_buffer, r))
+	    G_warning(_("seg_write: Cannot segment read row %d for map %s"),
+		      r, output_map_names[i]);
+
+	for (i = 0; i < orders_size; ++i) {
+
+	    if (output_map_names[i] == NULL)
+		continue;
+
+	    if (zerofill)
+		memset(output_buffer, 0, ncols * data_size);
+	    else
+		Rast_set_c_null_value(output_buffer, ncols);
+
+	    for (c = 0; c < ncols; ++c)
+		if (!Rast_is_c_null_value(&streams_buffer[c]))
+		    output_buffer[c] = all_orders[i][streams_buffer[c]];
+
+	    Rast_put_c_row(output_fd[i], output_buffer);
+	}			/* end i */
+    }
+
+    G_free(output_buffer);
+    G_free(streams_buffer);
+    for (i = 0; i < orders_size; ++i)
+	G_free(all_orders[i]);
+    G_free(all_orders);
+
+    for (i = 0; i < orders_size; ++i) {
+	if (output_map_names[i] == NULL)
+	    continue;
+	Rast_close(output_fd[i]);
+	Rast_short_history(output_map_names[i], "raster", &history);
+	Rast_command_history(&history);
+	Rast_write_history(output_map_names[i], &history);
+	G_message(_("%s Done"), output_map_names[i]);
+    }
+
+    G_free(output_fd);
+    return 0;
+}

Added: grass-addons/grass7/grass7/raster/r.stream.order/stream_topology.c
===================================================================
--- grass-addons/grass7/grass7/raster/r.stream.order/stream_topology.c	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.stream.order/stream_topology.c	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,431 @@
+#include "local_proto.h"
+
+int ram_number_of_tribs(int r, int c, CELL **streams, CELL **dirs)
+{
+
+    int trib = 0;
+    int i, j;
+
+    for (i = 1; i < 9; ++i) {
+	if (NOT_IN_REGION(i))
+	    continue;
+	j = DIAG(i);
+	if (streams[NR(i)][NC(i)] && dirs[NR(i)][NC(i)] == j)
+	    trib++;
+    }
+
+    if (trib > 5)
+	G_fatal_error(_("Error finding nodes. \
+		Stream and direction maps probably do not match..."));
+    if (trib > 3)
+	G_warning(_("Stream network may be too dense..."));
+
+    return trib;
+}
+
+int ram_stream_topology(CELL **streams, CELL **dirs, int number_of_streams)
+{
+
+    int d, i, j;		/* d: direction, i: iteration */
+    int r, c;
+    int next_r, next_c;
+    int trib_num, trib = 0;
+    int next_stream = -1, cur_stream;
+    STREAM *SA = stream_attributes;	/* for better code readability */
+
+    init_num = 0, outlet_num = 0;
+
+    G_message(_("Finding nodes..."));
+
+    outlet_streams = (unsigned int *)G_malloc((number_of_streams) *
+					      sizeof(unsigned int));
+    init_streams = (unsigned int *)G_malloc((number_of_streams) *
+					    sizeof(unsigned int));
+    init_cells = (unsigned
+		  long int *)G_malloc((number_of_streams) * sizeof(unsigned
+								   long int));
+    /* free at the end */
+
+    for (r = 0; r < nrows; ++r)
+	for (c = 0; c < ncols; ++c)
+	    if (streams[r][c]) {
+		trib_num = ram_number_of_tribs(r, c, streams, dirs);
+		trib = 0;
+		d = abs(dirs[r][c]);	/* r.watershed! */
+		if (d < 1 || NOT_IN_REGION(d) || !streams[NR(d)][NC(d)])
+		    next_stream = -1;
+		else
+		    next_stream = streams[NR(d)][NC(d)];
+
+		cur_stream = streams[r][c];
+
+		if (cur_stream != next_stream) {	/* junction: building topology */
+
+		    if (outlet_num > (number_of_streams - 1))
+			G_fatal_error(_("Error finding nodes. \
+				Stream and direction maps probably do not match..."));
+
+		    SA[cur_stream].stream = cur_stream;
+		    SA[cur_stream].next_stream = next_stream;
+
+		    if (next_stream < 0)	/* is outlet stream */
+			outlet_streams[outlet_num++] = cur_stream;
+		}
+
+		if (trib_num == 0) {	/* is init */
+		    if (init_num > (number_of_streams - 1))
+			G_fatal_error(_("Error finding nodes. \
+				Stream and direction maps probably do not match..."));
+
+		    SA[cur_stream].trib_num = 0;
+		    init_cells[init_num] = r * ncols + c;
+		    init_streams[init_num++] = cur_stream;	/* collecting inits */
+		}
+
+		if (trib_num > 1) {	/* adding tributuaries */
+		    SA[cur_stream].trib_num = trib_num;
+
+		    for (i = 1; i < 9; ++i) {
+			if (trib > 4)
+			    G_fatal_error(_("Error finding nodes. \
+					Stream and direction maps probably do not match..."));
+			if (NOT_IN_REGION(i))
+			    continue;
+			j = DIAG(i);
+			next_r = NR(i);
+			next_c = NC(i);
+			if (streams[next_r][next_c] &&
+			    dirs[next_r][next_c] == j)
+			    SA[cur_stream].trib[trib++] =
+				streams[next_r][next_c];
+		    }		/* end for i... */
+		}
+	    }			/* end if streams */
+    return 0;
+}
+
+int ram_stream_geometry(CELL **streams, CELL **dirs)
+{
+
+    int i, s, d;		/* s - streams index; d - direction */
+    int done = 1;
+    int r, c;
+    int next_r, next_c;
+    int prev_r, prev_c;
+    int cur_stream;
+    float cur_northing, cur_easting;
+    float next_northing, next_easting;
+    float init_northing, init_easting;
+    double cur_length = 0.;
+    double cur_accum_length = 0.;
+    STREAM *SA = stream_attributes;	/* for better code readability */
+    struct Cell_head window;
+
+    G_get_window(&window);
+
+    G_message(_("Finding longest streams..."));
+    G_begin_distance_calculations();
+
+    for (s = 0; s < init_num; ++s) {	/* main loop on springs */
+	r = (int)init_cells[s] / ncols;
+	c = (int)init_cells[s] % ncols;
+	cur_stream = streams[r][c];
+	cur_length = 0;
+	done = 1;
+
+	SA[cur_stream].init = init_cells[s];	/* stored as index */
+
+	init_northing = window.north - (r + .5) * window.ns_res;
+	init_easting = window.west + (c + .5) * window.ew_res;
+
+	while (done) {
+	    cur_northing = window.north - (r + .5) * window.ns_res;
+	    cur_easting = window.west + (c + .5) * window.ew_res;
+
+	    d = abs(dirs[r][c]);
+	    next_r = NR(d);
+	    next_c = NC(d);
+
+	    if (d < 1 || NOT_IN_REGION(d) || !streams[next_r][next_c]) {
+		cur_length = (window.ns_res + window.ew_res) / 2;
+		SA[cur_stream].accum_length += cur_length;
+		SA[cur_stream].length += cur_length;
+		SA[cur_stream].stright =
+		    G_distance(cur_easting, cur_northing, init_easting,
+			       init_northing);
+		SA[cur_stream].outlet = (r * ncols + c);	/* add outlet to sorting */
+		break;
+	    }
+
+	    next_northing = window.north - (next_r + .5) * window.ns_res;
+	    next_easting = window.west + (next_c + .5) * window.ew_res;
+	    cur_length =
+		G_distance(next_easting, next_northing, cur_easting,
+			   cur_northing);
+	    SA[cur_stream].accum_length += cur_length;
+	    SA[cur_stream].length += cur_length;
+	    prev_r = r;
+	    prev_c = c;
+	    r = next_r;
+	    c = next_c;
+
+	    if (streams[next_r][next_c] != cur_stream) {
+		SA[cur_stream].stright =
+		    G_distance(next_easting, next_northing, init_easting,
+			       init_northing);
+		init_northing = cur_northing;
+		init_easting = cur_easting;
+
+		SA[cur_stream].outlet = (prev_r * ncols + prev_c);
+		cur_stream = streams[next_r][next_c];
+
+		cur_accum_length = 0;
+		SA[cur_stream].init = (r * ncols + c);
+
+		for (i = 0; i < SA[cur_stream].trib_num; ++i) {
+		    if (SA[SA[cur_stream].trib[i]].accum_length == 0) {
+			done = 0;
+			cur_accum_length = 0;
+			break;	/* do not pass accum */
+		    }
+		    if (SA[SA[cur_stream].trib[i]].accum_length >
+			cur_accum_length)
+			cur_accum_length =
+			    SA[SA[cur_stream].trib[i]].accum_length;
+		}		/* end for i */
+		SA[cur_stream].accum_length = cur_accum_length;
+	    }			/* end if */
+	}			/* end while */
+    }				/* end for s */
+    return 0;
+}
+
+int seg_number_of_tribs(int r, int c, SEGMENT *streams, SEGMENT *dirs)
+{
+
+    int trib = 0;
+    int i, j;
+    int streams_cell = 0;
+    int dirs_cell = 0;
+
+    for (i = 1; i < 9; ++i) {
+	if (NOT_IN_REGION(i))
+	    continue;
+
+	j = DIAG(i);
+
+	segment_get(streams, &streams_cell, NR(i), NC(i));
+	segment_get(dirs, &dirs_cell, NR(i), NC(i));
+
+	if (streams_cell && dirs_cell == j)
+	    trib++;
+    }
+
+    if (trib > 5)
+	G_fatal_error(_("Error finding nodes. \
+		Stream and direction maps probably do not match..."));
+    if (trib > 3)
+	G_warning(_("Stream network may be too dense..."));
+
+    return trib;
+}
+
+int seg_stream_topology(SEGMENT *streams, SEGMENT *dirs,
+			int number_of_streams)
+{
+
+    int d, i, j;		/* d: direction, i: iteration */
+    int r, c;
+    int next_r, next_c;
+    int trib_num, trib = 0;
+    int next_stream = -1, cur_stream;
+    int streams_cell, dirs_cell;
+    int next_streams_cell, trib_dirs_cell, trib_stream_cell;
+    STREAM *SA = stream_attributes;	/* for better code readability */
+
+    init_num = 0, outlet_num = 0;
+
+    G_message(_("Finding nodes..."));
+
+    outlet_streams = (unsigned int *)G_malloc((number_of_streams) *
+					      sizeof(unsigned int));
+    init_streams = (unsigned int *)G_malloc((number_of_streams) *
+					    sizeof(unsigned int));
+    init_cells = (unsigned
+		  long int *)G_malloc((number_of_streams) * sizeof(unsigned
+								   long int));
+
+    for (r = 0; r < nrows; ++r) {
+	G_percent(r, nrows, 2);
+	for (c = 0; c < ncols; ++c) {
+	    segment_get(streams, &streams_cell, r, c);
+	    segment_get(dirs, &dirs_cell, r, c);
+
+	    if (streams_cell) {
+		trib_num = seg_number_of_tribs(r, c, streams, dirs);
+		trib = 0;
+
+		d = abs(dirs_cell);	/* r.watershed! */
+		if (NOT_IN_REGION(d))
+		    next_stream = -1;
+		else
+		    segment_get(streams, &next_streams_cell, NR(d), NC(d));
+
+		if (d < 1 || NOT_IN_REGION(d) || !next_streams_cell)
+		    next_stream = -1;
+		else
+		    segment_get(streams, &next_stream, NR(d), NC(d));
+
+		cur_stream = streams_cell;
+
+		if (cur_stream != next_stream) {	/* junction: building topology */
+		    if (outlet_num > (number_of_streams - 1))
+			G_fatal_error(_("Error finding nodes. \
+				Stream and direction maps probably do not match..."));
+
+		    SA[cur_stream].stream = cur_stream;
+		    SA[cur_stream].next_stream = next_stream;
+
+		    if (next_stream < 0)	/* is outlet stream */
+			outlet_streams[outlet_num++] = cur_stream;
+		}
+
+		if (trib_num == 0) {	/* is init */
+		    if (init_num > (number_of_streams - 1))
+			G_fatal_error(_("Error finding nodes. \
+				Stream and direction maps probably do not match..."));
+
+		    SA[cur_stream].trib_num = 0;
+		    init_cells[init_num] = r * ncols + c;
+		    init_streams[init_num++] = cur_stream;	/* collecting inits */
+		}
+
+		if (trib_num > 1) {	/* adding tributuaries */
+		    SA[cur_stream].trib_num = trib_num;
+
+		    for (i = 1; i < 9; ++i) {
+
+			if (trib > 4)
+			    G_fatal_error(_("Error finding nodes. \
+					Stream and direction maps probably do not match..."));
+			if (NOT_IN_REGION(i))
+			    continue;
+			j = DIAG(i);
+			next_r = NR(i);
+			next_c = NC(i);
+			segment_get(streams, &trib_stream_cell, next_r,
+				    next_c);
+			segment_get(dirs, &trib_dirs_cell, next_r, next_c);
+
+			if (trib_stream_cell && trib_dirs_cell == j)
+			    SA[cur_stream].trib[trib++] = trib_stream_cell;
+		    }		/* end for i... */
+		}
+	    }			/* end if streams */
+	}
+    }				/* end r, c */
+    G_percent(r, nrows, 2);
+    return 0;
+}
+
+int seg_stream_geometry(SEGMENT *streams, SEGMENT *dirs)
+{
+
+    int i, s, d;		/* s - streams index; d - direction */
+    int done = 1;
+    int r, c;
+    int next_r, next_c;
+    int prev_r, prev_c;
+    int cur_stream, next_stream, dirs_cell;
+    float cur_northing, cur_easting;
+    float next_northing, next_easting;
+    float init_northing, init_easting;
+    double cur_length = 0.;
+    double cur_accum_length = 0.;
+    STREAM *SA = stream_attributes;	/* for better code readability */
+    struct Cell_head window;
+
+    G_get_window(&window);
+
+    G_message(_("Finding longest streams..."));
+    G_begin_distance_calculations();
+
+    for (s = 0; s < init_num; ++s) {	/* main loop on springs */
+	G_percent(s, init_num, 2);
+	r = (int)init_cells[s] / ncols;
+	c = (int)init_cells[s] % ncols;
+	segment_get(streams, &cur_stream, r, c);
+	cur_length = 0;
+	done = 1;
+
+	SA[cur_stream].init = init_cells[s];	/* stored as index */
+
+	init_northing = window.north - (r + .5) * window.ns_res;
+	init_easting = window.west + (c + .5) * window.ew_res;
+
+	while (done) {
+	    cur_northing = window.north - (r + .5) * window.ns_res;
+	    cur_easting = window.west + (c + .5) * window.ew_res;
+
+	    segment_get(dirs, &dirs_cell, r, c);
+	    d = abs(dirs_cell);
+	    next_r = NR(d);
+	    next_c = NC(d);
+	    if (NOT_IN_REGION(d))
+		Rast_set_c_null_value(&next_stream, 1);
+	    else
+		segment_get(streams, &next_stream, next_r, next_c);
+
+	    if (d < 1 || NOT_IN_REGION(d) || !next_stream) {
+		cur_length = (window.ns_res + window.ew_res) / 2;
+		SA[cur_stream].accum_length += cur_length;
+		SA[cur_stream].length += cur_length;
+		SA[cur_stream].stright =
+		    G_distance(cur_easting, cur_northing, init_easting,
+			       init_northing);
+		SA[cur_stream].outlet = (r * ncols + c);	/* add outlet to sorting */
+		break;
+	    }
+
+	    next_northing = window.north - (next_r + .5) * window.ns_res;
+	    next_easting = window.west + (next_c + .5) * window.ew_res;
+	    cur_length =
+		G_distance(next_easting, next_northing, cur_easting,
+			   cur_northing);
+	    SA[cur_stream].accum_length += cur_length;
+	    SA[cur_stream].length += cur_length;
+	    prev_r = r;
+	    prev_c = c;
+	    r = next_r;
+	    c = next_c;
+
+	    if (next_stream != cur_stream) {
+		SA[cur_stream].stright =
+		    G_distance(next_easting, next_northing, init_easting,
+			       init_northing);
+		init_northing = cur_northing;
+		init_easting = cur_easting;
+
+		SA[cur_stream].outlet = (prev_r * ncols + prev_c);
+		cur_stream = next_stream;
+		cur_accum_length = 0;
+		SA[cur_stream].init = (r * ncols + c);
+
+		for (i = 0; i < SA[cur_stream].trib_num; ++i) {
+		    if (SA[SA[cur_stream].trib[i]].accum_length == 0) {
+			done = 0;
+			cur_accum_length = 0;
+			break;	/* do not pass accum */
+		    }
+		    if (SA[SA[cur_stream].trib[i]].accum_length >
+			cur_accum_length)
+			cur_accum_length =
+			    SA[SA[cur_stream].trib[i]].accum_length;
+		}		/* end for i */
+		SA[cur_stream].accum_length = cur_accum_length;
+	    }			/* end if */
+	}			/* end while */
+    }				/* end for s */
+    G_percent(s, init_num, 2);
+    return 0;
+}

Added: grass-addons/grass7/grass7/raster/r.stream.order/stream_vector.c
===================================================================
--- grass-addons/grass7/grass7/raster/r.stream.order/stream_vector.c	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.stream.order/stream_vector.c	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,362 @@
+#include "local_proto.h"
+int ram_create_vector(CELL ** streams, CELL ** dirs, char *out_vector,
+		      int number_of_streams)
+{
+
+    int i, d;
+    int r, c;
+    int next_r, next_c;
+    int add_outlet = 0;
+    int cur_stream;
+    float northing, easting;
+    struct Cell_head window;
+    struct line_pnts *Segments;
+    struct line_cats *Cats;
+    STREAM *SA = stream_attributes;	/* for better code readability */
+
+    G_get_window(&window);
+    Segments = Vect_new_line_struct();
+    Cats = Vect_new_cats_struct();
+    Vect_open_new(&Out, out_vector, 0);
+
+    Vect_reset_line(Segments);
+    Vect_reset_cats(Cats);
+
+    for (i = 0; i < number_of_streams; ++i) {
+
+	if (SA[i].stream == -1)
+	    continue;		/* empty category */
+
+	add_outlet = 0;
+	r = (int)SA[i].init / ncols;
+	c = (int)SA[i].init % ncols;
+
+	cur_stream = SA[i].stream;
+	Vect_cat_set(Cats, 1, cur_stream);
+	easting = window.west + (c + .5) * window.ew_res;
+	northing = window.north - (r + .5) * window.ns_res;
+	Vect_append_point(Segments, easting, northing, 0);
+	Vect_write_line(&Out, GV_POINT, Segments, Cats);
+	Vect_reset_line(Segments);
+	Vect_append_point(Segments, easting, northing, 0);
+
+	while (streams[r][c] == cur_stream) {
+
+	    d = abs(dirs[r][c]);
+	    next_r = NR(d);
+	    next_c = NC(d);
+
+	    easting = window.west + (next_c + .5) * window.ew_res;
+	    northing = window.north - (next_r + .5) * window.ns_res;
+	    Vect_append_point(Segments, easting, northing, 0);
+
+	    if (d < 1 || NOT_IN_REGION(d) || !streams[next_r][next_c]) {
+		add_outlet = 1;
+		break;
+	    }
+	    r = next_r;
+	    c = next_c;
+	}			/* end while */
+
+	Vect_cat_set(Cats, 1, cur_stream);
+	Vect_write_line(&Out, GV_LINE, Segments, Cats);
+	Vect_reset_line(Segments);
+	Vect_reset_cats(Cats);
+
+	if (add_outlet) {
+	    Vect_cat_set(Cats, 1, 0);
+	    Vect_reset_line(Segments);
+	    Vect_append_point(Segments, easting, northing, 0);
+	    Vect_write_line(&Out, GV_POINT, Segments, Cats);
+	    Vect_reset_line(Segments);
+	    Vect_reset_cats(Cats);
+	}
+    }
+
+    /* build vector after adding table */
+    if (0 < stream_add_table(number_of_streams))
+	G_warning(_("Cannot add table to vector %s"), out_vector);
+    Vect_hist_command(&Out);
+    Vect_build(&Out);
+    Vect_close(&Out);
+
+    return 0;
+}
+
+int seg_create_vector(SEGMENT * streams, SEGMENT * dirs, char *out_vector,
+		      int number_of_streams)
+{
+
+    int i, d;
+    int r, c;
+    int next_r, next_c;
+    int add_outlet;
+    int streams_cell, dirs_cell;
+    int cur_stream, next_stream;
+    float northing, easting;
+    struct Cell_head window;
+    struct line_pnts *Segments;
+    struct line_cats *Cats;
+    STREAM *SA = stream_attributes;	/* for better code readability */
+
+    G_get_window(&window);
+    Segments = Vect_new_line_struct();
+    Cats = Vect_new_cats_struct();
+    Vect_open_new(&Out, out_vector, 0);
+
+    Vect_reset_line(Segments);
+    Vect_reset_cats(Cats);
+
+    for (i = 0; i < number_of_streams; ++i) {
+	if (SA[i].stream == -1)
+	    continue;
+
+	add_outlet = 0;
+	r = (int)SA[i].init / ncols;
+	c = (int)SA[i].init % ncols;
+
+	cur_stream = SA[i].stream;
+	Vect_cat_set(Cats, 1, cur_stream);
+	easting = window.west + (c + .5) * window.ew_res;
+	northing = window.north - (r + .5) * window.ns_res;
+	Vect_append_point(Segments, easting, northing, 0);
+	Vect_write_line(&Out, GV_POINT, Segments, Cats);
+	Vect_reset_line(Segments);
+	Vect_append_point(Segments, easting, northing, 0);
+
+	segment_get(streams, &streams_cell, r, c);
+	while (streams_cell == cur_stream) {
+
+	    segment_get(dirs, &dirs_cell, r, c);
+	    d = abs(dirs_cell);
+	    next_r = NR(d);
+	    next_c = NC(d);
+
+	    easting = window.west + (next_c + .5) * window.ew_res;
+	    northing = window.north - (next_r + .5) * window.ns_res;
+	    Vect_append_point(Segments, easting, northing, 0);
+
+	    if (NOT_IN_REGION(d))
+		Rast_set_c_null_value(&next_stream, 1);
+	    else
+		segment_get(streams, &next_stream, next_r, next_c);
+
+	    if (d < 1 || NOT_IN_REGION(d) || !next_stream) {
+		add_outlet = 1;
+		break;
+	    }
+	    r = next_r;
+	    c = next_c;
+	    segment_get(streams, &streams_cell, r, c);
+	}			/* end while */
+
+	Vect_cat_set(Cats, 1, cur_stream);
+	Vect_write_line(&Out, GV_LINE, Segments, Cats);
+	Vect_reset_line(Segments);
+	Vect_reset_cats(Cats);
+
+	if (add_outlet) {
+	    Vect_cat_set(Cats, 1, 0);
+	    Vect_reset_line(Segments);
+	    Vect_append_point(Segments, easting, northing, 0);
+	    Vect_write_line(&Out, GV_POINT, Segments, Cats);
+	    Vect_reset_line(Segments);
+	    Vect_reset_cats(Cats);
+	}
+    }
+
+    /* build vector after adding table */
+    if (0 < stream_add_table(number_of_streams))
+	G_warning(_("Cannot add table to vector %s"), out_vector);
+    Vect_hist_command(&Out);
+    Vect_build(&Out);
+    Vect_close(&Out);
+    return 0;
+}
+
+int stream_add_table(int number_of_streams)
+{
+
+    int i;
+    int max_trib = 0;
+    struct field_info *Fi;
+    STREAM *SA = stream_attributes;	/* for better code readability */
+    dbDriver *driver;
+    dbHandle handle;
+    dbString table_name, db_sql, val_string;
+    char *cat_col_name = "cat";
+    char buf[1000];
+    char ins_prev_streams[50];	/* insert */
+
+    /* rest of table definition */
+    char *tab_cat_col_name = "cat integer";
+    char *tab_stream = "stream integer";
+    char *tab_next_stream = "next_stream integer";
+    char *tab_prev_streams;
+    char *tab_orders =
+	"strahler integer, horton integer, shreve integer, hack integer, topo_dim integer";
+    char *tab_scheidegger = "scheidegger integer";
+    char *tab_drwal_old = "drwal_old integer";
+    char *tab_length = "length double precision";
+    char *tab_stright = "stright double precision";
+    char *tab_sinusoid = "sinosoid double precision";
+    char *tab_cumlength = "cum_length double precision";
+    char *tab_accum = "flow_accum double precision";
+    char *tab_distance = "out_dist double precision";
+    char *tab_elev_init = "source_elev double precision";
+    char *tab_elev_outlet = "outlet_elev double precision";
+    char *tab_drop = "elev_drop double precision";
+    char *tab_out_drop = "out_drop double precision";
+    char *tab_gradient = "gradient double precision";
+
+    /* addational atrributes */
+    int scheidegger, drwal_old = -1;
+    double sinusoid = 1, elev_drop, out_drop = 0, gradient = -1;
+    char insert_orders[60];	/* must have to be increased if new orders are added */
+
+    db_init_string(&db_sql);
+    db_init_string(&val_string);
+    db_init_string(&table_name);
+    db_init_handle(&handle);
+
+    Fi = Vect_default_field_info(&Out, 1, NULL, GV_1TABLE);
+    driver = db_start_driver_open_database(Fi->driver,
+					   Vect_subst_var(Fi->database,
+							         &Out));
+
+    /* create table */
+    for (i = 0; i < number_of_streams; ++i)
+	if (SA[i].trib_num > max_trib)
+	    max_trib = SA[i].trib_num;
+
+    switch (max_trib) {
+    case 2:
+	tab_prev_streams = "prev_str01 integer, prev_str02 integer";
+	break;
+    case 3:
+	tab_prev_streams =
+	    "prev_str01 integer, prev_str02 integer, prev_str03 integer";
+	break;
+    case 4:
+	tab_prev_streams =
+	    "prev_str01 integer, prev_str02 integer, prev_str03 integer, prev_str04 integer";
+	break;
+    case 5:
+	tab_prev_streams =
+	    "prev_str01 integer, prev_str02 integer, prev_str03 integer, prev_str04 integer, prev_str05 integer";
+	break;
+    default:
+	G_fatal_error("Error with number of tributuaries");
+	break;
+    }
+
+    sprintf(buf, "create table %s (%s, %s, %s, %s, %s, \
+																%s, %s, %s, %s, %s, \
+																%s, %s, %s, %s, %s, \
+																%s,	%s,	%s)", Fi->table, tab_cat_col_name,	/* 1 */
+	    tab_stream, tab_next_stream, tab_prev_streams, tab_orders,	/* 5 */
+	    tab_scheidegger, tab_drwal_old, tab_length, tab_stright, tab_sinusoid,	/* 10 */
+	    tab_cumlength, tab_accum, tab_distance, tab_elev_init, tab_elev_outlet,	/* 15 */
+	    tab_drop, tab_out_drop, tab_gradient	/* 18 */
+	);
+
+    db_set_string(&db_sql, buf);
+
+    if (db_execute_immediate(driver, &db_sql) != DB_OK) {
+	db_close_database(driver);
+	db_shutdown_driver(driver);
+	G_warning("Cannot create table %s", db_get_string(&db_sql));
+	return -1;
+    }
+
+    if (db_create_index2(driver, Fi->table, cat_col_name) != DB_OK)
+	G_warning(_("cannot create index on table %s"), Fi->table);
+
+    if (db_grant_on_table(driver, Fi->table,
+			  DB_PRIV_SELECT, DB_GROUP | DB_PUBLIC) != DB_OK) {
+	G_warning(_("cannot grant privileges on table %s"), Fi->table);
+	return -1;
+    }
+    db_begin_transaction(driver);
+
+    for (i = 0; i < number_of_streams; ++i) {
+
+	if (SA[i].stream < 0)
+	    continue;
+
+	/* calc addational parameters */
+
+	scheidegger = (all_orders[o_shreve][i]) * 2;
+
+	if (all_orders[o_shreve][i] > 0)
+	    drwal_old = (int)(log(all_orders[o_shreve][i]) / log(2)) + 1;
+
+	sinusoid = -1;
+	if (SA[i].stright > 0)
+	    sinusoid = SA[i].length / SA[i].stright;
+
+	out_drop = 0;
+	if (SA[i].next_stream > 0)
+	    out_drop = SA[i].outlet_elev - SA[SA[i].next_stream].init_elev;
+
+	elev_drop = (SA[i].init_elev - SA[i].outlet_elev) + out_drop;
+	if (elev_drop < 0)
+	    elev_drop = 0;
+
+	gradient = -1;
+	if (SA[i].length > 0)
+	    gradient = elev_drop / SA[i].length;
+
+	switch (max_trib) {
+	case 2:
+	    sprintf(ins_prev_streams, "%d, %d", SA[i].trib[0], SA[i].trib[1]);
+	    break;
+	case 3:
+	    sprintf(ins_prev_streams, "%d ,%d, %d", SA[i].trib[0],
+		    SA[i].trib[1], SA[i].trib[2]);
+	    break;
+	case 4:
+	    sprintf(ins_prev_streams, "%d, %d, %d, %d", SA[i].trib[0],
+		    SA[i].trib[1], SA[i].trib[2], SA[i].trib[3]);
+	    break;
+	case 5:
+	    sprintf(ins_prev_streams, "%d, %d, %d, %d, %d", SA[i].trib[0],
+		    SA[i].trib[1], SA[i].trib[2], SA[i].trib[3],
+		    SA[i].trib[4]);
+	    break;
+	default:
+	    G_fatal_error("Error with number of tributuaries");
+	    break;
+	}
+
+	sprintf(insert_orders, "%d, %d, %d, %d, %d",
+		all_orders[0][i], all_orders[1][i],
+		all_orders[2][i], all_orders[3][i], all_orders[4][i]);
+
+	sprintf(buf, "insert into %s values(	%d, %d, %d, %s, %s, \
+																				%d, %d, %f, %f, %f, \
+																				%f, %f, %f, %f, %f, \
+																				%f,	%f, %f)", Fi->table, i,	/* 1 */
+		SA[i].stream, SA[i].next_stream, ins_prev_streams,	/* buffer created before */
+		insert_orders,	/* 5 *//* buffer created before */
+		scheidegger, drwal_old, SA[i].length, SA[i].stright, sinusoid,	/* 10 */
+		SA[i].accum_length, fabs(SA[i].accum), SA[i].distance, SA[i].init_elev, SA[i].outlet_elev,	/* 15 */
+		elev_drop, out_drop, gradient	/* 18 */
+	    );
+
+	db_set_string(&db_sql, buf);
+
+	if (db_execute_immediate(driver, &db_sql) != DB_OK) {
+	    db_close_database(driver);
+	    db_shutdown_driver(driver);
+	    G_warning(_("Cannot inset new row: %s"), db_get_string(&db_sql));
+	    return -1;
+	}
+    }				/* end for */
+
+    db_commit_transaction(driver);
+    db_close_database_shutdown_driver(driver);
+    Vect_map_add_dblink(&Out, 1, NULL, Fi->table,
+			cat_col_name, Fi->database, Fi->driver);
+    return 0;
+}

Added: grass-addons/grass7/grass7/raster/r.stream.segment/Makefile
===================================================================
--- grass-addons/grass7/grass7/raster/r.stream.segment/Makefile	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.stream.segment/Makefile	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,14 @@
+MODULE_TOPDIR = ../..
+
+PGM = r.stream.segment
+
+LIBES = $(GISLIB) $(RASTERLIB) $(SEGMENTLIB) $(VECTORLIB) $(DBMILIB)
+DEPENDENCIES = $(GISDEP) $(RASTERDEP) $(SEGMENTDEP) $(VECTORDEP) $(DBMIDEP)
+
+EXTRA_INC = $(VECT_INC)
+EXTRA_CFLAGS = $(VECT_CFLAGS)
+
+include $(MODULE_TOPDIR)/include/Make/Module.make
+
+default: cmd
+

Added: grass-addons/grass7/grass7/raster/r.stream.segment/dirs.png
===================================================================
(Binary files differ)


Property changes on: grass-addons/grass7/grass7/raster/r.stream.segment/dirs.png
___________________________________________________________________
Added: svn:mime-type
   + application/octet-stream

Added: grass-addons/grass7/grass7/raster/r.stream.segment/io.c
===================================================================
--- grass-addons/grass7/grass7/raster/r.stream.segment/io.c	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.stream.segment/io.c	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,564 @@
+#include "io.h"
+/* all in ram functions section */
+
+int ram_create_map(MAP * map, RASTER_MAP_TYPE data_type)
+{
+
+    /* 
+     * allocates 0 filled nrows*ncols map of type void;
+     * map parameters are stored in structure;
+     * map: map to be created;
+     * map type to be created must be CELL, FCELL, DCELL;
+     * */
+
+    int r;
+
+    if (data_type < 0 || data_type > 2)
+	G_fatal_error(_("ram_creat: Cannot create map of unrecognised type"));
+
+    map->data_type = data_type;
+    map->map_name = NULL;
+    map->nrows = Rast_window_rows();
+    map->ncols = Rast_window_cols();
+    map->data_size = Rast_cell_size(data_type);
+
+    /* preparing internal map */
+    switch (map->data_type) {
+    case CELL_TYPE:
+	map->map = G_calloc(map->nrows, sizeof(CELL *));
+	break;
+
+    case FCELL_TYPE:
+	map->map = G_calloc(map->nrows, sizeof(FCELL *));
+	break;
+
+    case DCELL_TYPE:
+	map->map = G_calloc(map->nrows, sizeof(DCELL *));
+	break;
+    }
+
+    for (r = 0; r < map->nrows; ++r)
+	(map->map)[r] = G_calloc(map->ncols, map->data_size);
+
+    return 0;
+}
+
+int ram_read_map(MAP * map, char *input_map_name, int check_res,
+		 RASTER_MAP_TYPE check_data_type)
+{
+    /*
+     * Funciton read external map and put it in MAP structure (created with create_map)
+     * map: map to be read can be of any data type, read map is converted to target map if neccesary.
+     * input_map_name: name of the map to be read;
+     * map pointer to map stucture (created with create_map);
+     * check_res: [1]: check res correspondence between region and map [0 no check];
+     * check_data_type [CELL, FCELL, DCELL] check if reading map is of particular type, [-1] no check;
+     */
+
+    int r, c;
+    char *mapset;
+    struct Cell_head cellhd, this_window;
+    char *maptypes[] = { "CELL", "FCELL", "DCELL" };
+    int input_map_fd;
+    RASTER_MAP_TYPE input_data_type;
+    size_t input_data_size;
+    void *input_buffer = NULL;
+    void *input_pointer;
+
+    /* checking if map exist */
+    mapset = (char *)G_find_raster2(input_map_name, "");
+    if (mapset == NULL)
+	G_fatal_error(_("Raster map <%s> not found"), input_map_name);
+
+    /* checking if region and input are the same */
+    G_get_window(&this_window);
+    Rast_get_cellhd(input_map_name, mapset, &cellhd);
+    if (check_res)
+	if (this_window.ew_res != cellhd.ew_res ||
+	    this_window.ns_res != cellhd.ns_res)
+	    G_fatal_error(_("Region resolution and map %s resolution differs. \
+		Run g.region rast=%s to set proper region resolution"),
+			  input_map_name, input_map_name);
+
+    /* checking if input map is of required type */
+    if (check_data_type != map->data_type)
+	G_debug(1,
+		"ram_open:required map type and internal map type differs: conversion forced!");
+    input_data_type = Rast_map_type(input_map_name, mapset);
+    if (check_data_type != -1)
+	if (input_data_type != check_data_type)
+	    G_fatal_error(_("<%s> is not of type %s"),
+			  input_map_name, maptypes[check_data_type]);
+
+    input_map_fd = Rast_open_old(input_map_name, mapset);
+    input_data_size = Rast_cell_size(input_data_type);
+
+    {				/* reading range */
+	struct Range map_range;
+	struct FPRange map_fp_range;
+	int min, max;
+
+	if (input_data_type == CELL_TYPE) {
+	    Rast_init_range(&map_range);
+	    Rast_read_range(input_map_name, mapset, &map_range);
+	    Rast_get_range_min_max(&map_range, &min, &max);
+	    map->min = (double)min;
+	    map->max = (double)max;
+	}
+	else {
+	    Rast_init_fp_range(&map_fp_range);
+	    Rast_read_fp_range(input_map_name, mapset, &map_fp_range);
+	    Rast_get_fp_range_min_max(&map_fp_range, &(map->min),
+				      &(map->max));
+	}
+    }
+    /* end opening and checking */
+
+    input_buffer = Rast_allocate_buf(input_data_type);
+
+    /* start reading */
+    G_message(_("Reading map <%s>"), input_map_name);
+
+    for (r = 0; r < map->nrows; ++r) {
+	G_percent(r, map->nrows, 2);
+
+	Rast_get_row(input_map_fd, input_buffer, r, input_data_type);
+	input_pointer = input_buffer;
+
+	for (c = 0; c < map->ncols; ++c)
+	    if (!Rast_is_null_value
+		(input_pointer + c * input_data_size, input_data_type))
+		switch (map->data_type) {
+		case CELL_TYPE:
+		    ((CELL **) map->map)[r][c] =
+			Rast_get_c_value(input_pointer + c * input_data_size,
+					 input_data_type);
+		    break;
+		case FCELL_TYPE:
+		    ((FCELL **) map->map)[r][c] =
+			Rast_get_f_value(input_pointer + c * input_data_size,
+					 input_data_type);
+		    break;
+		case DCELL_TYPE:
+		    ((DCELL **) map->map)[r][c] =
+			Rast_get_d_value(input_pointer + c * input_data_size,
+					 input_data_type);
+		    break;
+		default:
+		    G_fatal_error(_("ram_open:Wrong internal data type"));
+		    break;
+		}
+    }				/*end for r */
+
+    G_free(input_buffer);
+    G_percent(r, map->nrows, 2);
+    Rast_close(input_map_fd);
+    return 0;
+}				/* end create floating point map */
+
+int ram_reset_map(MAP * map, int value)
+{
+    /*
+     * set all cells in the map to value
+     */
+    int r;
+
+    for (r = 0; r < map->nrows; ++r)
+	memset((map->map)[r], value, map->ncols * map->data_size);
+    return 0;
+}
+
+int ram_write_map(MAP * map, char *output_map_name,
+		  RASTER_MAP_TYPE output_data_type, int convert_to_null,
+		  double value)
+{
+    /* 
+     * write map to disk with output_map_name and output_data_type [CELL, FCELL, DCELL];
+     * if output_data_type = -1 than internal map type is used for output;
+     * if output map != -1 and types differ data_type, conversion is forced
+     * convert to null: check if convert to null a particular value in dataset;
+     */
+
+    int r, c;
+    int output_fd = 0;
+    struct History history;
+    void *row;
+
+    /* check for output format */
+    if (output_data_type == -1)
+	output_data_type = map->data_type;
+
+    if (output_data_type != map->data_type)
+	G_debug(1,
+		"ram_write:required map type and internal map type differs: conversion forced!");
+
+    G_message(_("Writing map <%s>"), output_map_name);
+    output_fd = Rast_open_new(output_map_name, output_data_type);
+
+    /* writing */
+    for (r = 0; r < map->nrows; ++r) {
+	G_percent(r, map->nrows, 2);
+
+	if (convert_to_null) {
+	    row = map->map[r];
+	    switch (map->data_type) {
+	    case CELL_TYPE:
+		for (c = 0; c < map->ncols; ++c)
+		    if (((CELL *) row)[c] == (CELL) value)
+			Rast_set_c_null_value(row + c * (map->data_size), 1);
+		break;
+	    case FCELL_TYPE:
+		for (c = 0; c < map->ncols; ++c)
+		    if (((FCELL *) row)[c] == (FCELL) value)
+			Rast_set_f_null_value(row + c * (map->data_size), 1);
+		break;
+	    case DCELL_TYPE:
+		for (c = 0; c < map->ncols; ++c)
+		    if (((DCELL *) row)[c] == (DCELL) value)
+			Rast_set_d_null_value(row + c * (map->data_size), 1);
+		break;
+	    default:
+		G_debug(1, "ram_null:Cannot convert to null at: %d %d", r, c);
+	    }
+	}
+
+	Rast_put_row(output_fd, (map->map)[r], output_data_type);
+    }
+    G_percent(r, map->nrows, 2);
+    Rast_close(output_fd);
+    Rast_short_history(output_map_name, "raster", &history);
+    Rast_command_history(&history);
+    Rast_write_history(output_map_name, &history);
+    G_message(_("<%s> Done"), output_map_name);
+    return 0;
+}
+
+int ram_release_map(MAP *map)
+{
+    /* 
+     * free memory allocated for map, set pointer to null;
+     */
+    int r;
+
+    for (r = 0; r < map->nrows; ++r)
+	G_free((map->map)[r]);
+    G_free(map->map);
+    map = NULL;
+    return 0;
+}
+
+
+/* memory swap functions section */
+
+
+int seg_create_map(SEG * seg, int srows, int scols, int number_of_segs,
+		   RASTER_MAP_TYPE data_type)
+{
+    /* create segment  and returns pointer to it;
+     * seg must be declared first;
+     * parameters are stored in structure;
+     * seg: segment to be created;
+     * srows, scols segment size
+     * number of segs max number of segs stored in memory
+     * data_type to be created must be CELL, FCELL, DCELL;
+     */
+
+    char *filename;
+    int fd;
+    int local_number_of_segs;
+
+    seg->fd = -1;
+    seg->filename = NULL;
+    seg->map_name = NULL;
+    seg->mapset = NULL;
+    seg->data_type = data_type;
+    seg->nrows = Rast_window_rows();
+    seg->ncols = Rast_window_cols();
+
+    local_number_of_segs =
+	(seg->nrows / srows + 1) * (seg->ncols / scols + 1);
+    number_of_segs =
+	(number_of_segs >
+	 local_number_of_segs) ? local_number_of_segs : number_of_segs;
+
+    G_debug(3, "seg_creat:number of segments %d", number_of_segs);
+
+    switch (seg->data_type) {
+    case CELL_TYPE:
+	seg->data_size = sizeof(CELL);
+	break;
+    case FCELL_TYPE:
+	seg->data_size = sizeof(FCELL);
+	break;
+    case DCELL_TYPE:
+	seg->data_size = sizeof(DCELL);
+	break;
+    default:
+	G_fatal_error(_("seg_create: unrecognisabe data type"));
+    }
+
+    filename = G_tempfile();
+    fd = creat(filename, 0666);
+
+    if (0 >
+	segment_format(fd, seg->nrows, seg->ncols, srows, scols,
+		       seg->data_size)) {
+	close(fd);
+	unlink(filename);
+	G_fatal_error(_("seg_create: cannot format segment"));
+    }
+
+    close(fd);
+    if (0 > (fd = open(filename, 2))) {
+	unlink(filename);
+	G_fatal_error(_("seg_create: cannot re-open file"));
+    }
+
+    if (0 > (fd = segment_init(&(seg->seg), fd, number_of_segs))) {
+	unlink(filename);
+	G_fatal_error(_("seg_create: cannot init segment file or out of memory"));
+    }
+
+    seg->filename = G_store(filename);
+    seg->fd = fd;
+    return 0;
+}
+
+int seg_read_map(SEG * seg, char *input_map_name, int check_res,
+		 RASTER_MAP_TYPE check_data_type)
+{
+
+    /*
+     * Funciton read external map and put it in SEG structure (created with seg_create_map)
+     * map to be read can be of any data type, read map is converted if neccesary.
+     * input_map_name: name of the map to be read;
+     * seg: pointer to map stucture (created with create_map);
+     * check_res: [1]: check res correspondence between region and map [0 no check];
+     * check_data_type [CELL, FCELL, DCELL] check if reading map is of particular type, [-1] no check;
+     */
+
+    int input_fd;
+    int r, c;
+    char *mapset;
+    struct Cell_head cellhd, this_window;
+    char *maptypes[] = { "CELL", "FCELL", "DCELL" };
+    RASTER_MAP_TYPE input_data_type;
+    size_t input_data_size;
+    void *input_buffer = NULL;
+    void *target_buffer = NULL;
+    void *input_pointer = NULL;
+
+    /* checking if map exist */
+    mapset = (char *)G_find_raster2(input_map_name, "");
+    if (mapset == NULL)
+	G_fatal_error(_("seg_read:Raster map <%s> not found"),
+		      input_map_name);
+    seg->mapset = mapset;
+
+    /* checking if region and input are the same */
+    G_get_window(&this_window);
+    Rast_get_cellhd(input_map_name, mapset, &cellhd);
+
+    /* check resolution equal anyinteger check;  equal 0 no check */
+    if (check_res)
+	if (this_window.ew_res != cellhd.ew_res ||
+	    this_window.ns_res != cellhd.ns_res)
+	    G_fatal_error(_("Region resolution and map %s resolution differs. \
+		Run g.region rast=%s to set proper region resolution"),
+			  input_map_name, input_map_name);
+
+    if (check_data_type != seg->data_type)
+	G_debug(1,
+		"ram_open:required map type and internal map type differs: conversion forced!");
+    input_data_type = Rast_map_type(input_map_name, mapset);
+    if (check_data_type != -1)
+	if (input_data_type != check_data_type)
+	    G_fatal_error(_("<%s> is not of type %s"),
+			  input_map_name, maptypes[check_data_type]);
+
+    input_fd = Rast_open_old(input_map_name, mapset);
+    input_data_size = Rast_cell_size(input_data_type);
+
+    {				/* reading range */
+	struct Range map_range;
+	struct FPRange map_fp_range;
+	int min, max;
+
+	if (input_data_type == CELL_TYPE) {
+	    Rast_init_range(&map_range);
+	    Rast_read_range(input_map_name, mapset, &map_range);
+	    Rast_get_range_min_max(&map_range, &min, &max);
+	    seg->min = (double)min;
+	    seg->max = (double)max;
+	}
+	else {
+	    Rast_init_fp_range(&map_fp_range);
+	    Rast_read_fp_range(input_map_name, mapset, &map_fp_range);
+	    Rast_get_fp_range_min_max(&map_fp_range, &(seg->min),
+				      &(seg->max));
+	}
+    }
+
+    /* end opening and checking */
+
+    G_message(_("Reading map <%s>"), input_map_name);
+    input_buffer = Rast_allocate_buf(input_data_type);
+
+    target_buffer = Rast_allocate_buf(seg->data_type);
+
+    for (r = 0; r < seg->nrows; ++r) {
+	G_percent(r, seg->nrows, 2);
+	Rast_get_row(input_fd, input_buffer, r, input_data_type);
+	input_pointer = input_buffer;
+	memset(target_buffer, 0, seg->ncols * seg->data_size);
+
+	for (c = 0; c < seg->ncols; ++c)
+	    if (!Rast_is_null_value
+		(input_pointer + c * input_data_size, input_data_type)) {
+		switch (seg->data_type) {
+		case CELL_TYPE:
+		    ((CELL *) target_buffer)[c] =
+			Rast_get_c_value(input_pointer + c * input_data_size,
+					 input_data_type);
+		    break;
+		case FCELL_TYPE:
+		    ((FCELL *) target_buffer)[c] =
+			Rast_get_f_value(input_pointer + c * input_data_size,
+					 input_data_type);
+		    break;
+		case DCELL_TYPE:
+		    ((DCELL *) target_buffer)[c] =
+			Rast_get_d_value(input_pointer + c * input_data_size,
+					 input_data_type);
+		    break;
+		default:
+		    G_fatal_error(_("Wrong internal data type"));
+		    break;
+		}
+	    }
+
+	if (0 > segment_put_row(&(seg->seg), target_buffer, r)) {
+	    G_free(input_buffer);
+	    G_free(target_buffer);
+	    Rast_close(input_fd);
+	    G_fatal_error(_("seg_read: Cannot segment put row %d for map %s"),
+			  r, input_map_name);
+	}
+    }				/* end for row */
+
+    G_percent(r, seg->nrows, 2);
+    Rast_close(input_fd);
+    G_free(input_buffer);
+    G_free(target_buffer);
+
+    seg->map_name = G_store(input_map_name);
+    seg->mapset = G_store(mapset);
+
+    return 0;
+}
+
+int seg_reset_map(SEG * seg, int value)
+{
+    /*
+     * set all cells in the map to value
+     */
+    int r, c;
+
+    for (r = 0; r < seg->nrows; ++r)
+	for (c = 0; c < seg->ncols; ++c)
+	    segment_put(&(seg->seg), &value, r, c);
+
+    return 0;
+}
+
+int seg_write_map(SEG * seg, char *output_map_name,
+		  RASTER_MAP_TYPE output_data_type, int convert_to_null,
+		  double value)
+{
+    /* 
+     * write seg to disk with output_map_name and output_data_type [CELL, FCELL, DCELL];
+     * if output_data_type = -1 than internal map type is used for output;
+     * if output map != -1 and types differ data_type, conversion is forced
+     * convert to null: check if convert to null a particular value in dataset;
+     */
+    int output_fd;
+    int r, c;
+    void *output_buffer;
+    void *row;
+    struct History history;
+
+    /* check for output format */
+    if (output_data_type == -1)
+	output_data_type = seg->data_type;
+
+    if (output_data_type != seg->data_type)
+	G_debug(1,
+		"ram_write:required map type and internal map type differs: conversion forced!");
+
+    G_message(_("Writing map <%s>"), output_map_name);
+    output_fd = Rast_open_new(output_map_name, output_data_type);
+    output_buffer = Rast_allocate_buf(output_data_type);
+    segment_flush(&(seg->seg));
+
+    /* writing */
+    for (r = 0; r < seg->nrows; ++r) {
+
+	G_percent(r, seg->nrows, 2);
+	if (0 > segment_get_row(&(seg->seg), output_buffer, r))
+	    G_warning(_("seg_write: Cannot segment read row %d for map %s"),
+		      r, output_map_name);
+
+	if (convert_to_null) {
+
+	    row = output_buffer;
+	    switch (seg->data_type) {
+	    case CELL_TYPE:
+		for (c = 0; c < seg->ncols; ++c)
+		    if (((CELL *) output_buffer)[c] == (CELL) value)
+			Rast_set_c_null_value(row + c * (seg->data_size), 1);
+		break;
+	    case FCELL_TYPE:
+		for (c = 0; c < seg->ncols; ++c)
+		    if (((FCELL *) output_buffer)[c] == (FCELL) value)
+			Rast_set_f_null_value(row + c * (seg->data_size), 1);
+		break;
+	    case DCELL_TYPE:
+		for (c = 0; c < seg->ncols; ++c)
+		    if (((DCELL *) output_buffer)[c] == (DCELL) value)
+			Rast_set_d_null_value(row + c * (seg->data_size), 1);
+		break;
+	    default:
+		G_warning(_("ram_null:Cannot convert to null at: %d %d"), r,
+			  c);
+	    }
+	}
+	Rast_put_row(output_fd, output_buffer, output_data_type);
+    }
+
+    G_percent(r, seg->nrows, 2);
+    G_free(output_buffer);
+    Rast_close(output_fd);
+    Rast_short_history(output_map_name, "raster", &history);
+    Rast_command_history(&history);
+    Rast_write_history(output_map_name, &history);
+    G_message(_("%s Done"), output_map_name);
+
+    return 0;
+}
+
+int seg_release_map(SEG * seg)
+{
+    /* 
+     * release segment close files, set pointers to null;
+     */
+    segment_release(&(seg->seg));
+    close(seg->fd);
+    unlink(seg->filename);
+
+    if (seg->map_name)
+	G_free(seg->map_name);
+    if (seg->mapset)
+	G_free(seg->mapset);
+
+    return 0;
+}

Added: grass-addons/grass7/grass7/raster/r.stream.segment/io.h
===================================================================
--- grass-addons/grass7/grass7/raster/r.stream.segment/io.h	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.stream.segment/io.h	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,59 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <string.h>
+#include <math.h>
+#include <grass/glocale.h>
+#include <grass/gis.h>
+#include <grass/raster.h>
+#include <grass/segment.h>
+
+#define NOT_IN_REGION(x) (r + nextr[(x)] < 0 || r + nextr[(x)] > (nrows - 1) || \
+                          c + nextc[(x)] < 0 || c + nextc[(x)] > (ncols - 1))
+#define NR(x) (r + nextr[(x)])
+#define NC(x) (c + nextc[(x)])
+#define INDEX(r,c) ((r) * ncols + (c))
+#define DIAG(x) (((x) + 4) > 8 ? ((x) - 4) : ((x) + 4))
+
+#define SROWS 256
+#define SCOLS 256
+
+typedef struct {
+	void **map; /* matrix of data */
+	double min, max; /* data range : may requre casting */
+	int nrows, ncols;
+	char *map_name; /* map name, unused */
+	RASTER_MAP_TYPE data_type; /* type of data */
+	size_t data_size; /* type of data */
+} MAP;
+
+typedef struct {
+	SEGMENT seg;		/* segmented data store */
+	int fd;					/* segment temporary file name descriptor */
+	char *filename; /* segment temporary file name */
+	char *map_name; /* map name converted to segment */
+	char *mapset;
+	int nrows, ncols; /* store nrows and rcols */
+	RASTER_MAP_TYPE data_type; /* data type of the map */
+	size_t data_size; /* size of cell returned by sizeof */
+	double min, max; /* data range */
+} SEG;
+
+
+/* all in ram functions */
+int ram_create_map(MAP *, RASTER_MAP_TYPE);
+int ram_read_map(MAP *, char *, int, RASTER_MAP_TYPE);
+int ram_reset_map(MAP *, int);
+int ram_write_map(MAP *, char *, RASTER_MAP_TYPE, int, double);
+int ram_release_map(MAP *);
+int ram_destory_map(MAP *);
+
+/* memory swap functions */
+int seg_create_map(SEG *, int, int, int, RASTER_MAP_TYPE);
+int seg_read_map(SEG *, char *, int, RASTER_MAP_TYPE);
+int seg_reset_map (SEG *, int);
+int seg_write_map(SEG *, char *, RASTER_MAP_TYPE, int, double);
+int seg_release_map(SEG *);
+

Added: grass-addons/grass7/grass7/raster/r.stream.segment/local_proto.h
===================================================================
--- grass-addons/grass7/grass7/raster/r.stream.segment/local_proto.h	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.stream.segment/local_proto.h	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,30 @@
+#include "io.h"
+#include "local_vars.h"
+
+int free_attributes(int number_of_streams);
+int convert_border_dir(int r, int c, int dir);
+
+int create_sectors(STREAM *cur_stream, int seg_length, int seg_skip,
+		   double seg_treshold);
+int calc_tangents(STREAM *cur_stream, int seg_length, int seg_skip,
+		  int number_streams);
+
+int create_sector_vector(char *out_vector, int number_of_streams, int radians);
+int create_segment_vector(char *out_vector, int number_of_streams,
+			  int radians);
+
+
+int ram_build_streamlines(CELL **streams, CELL **dirs, FCELL **elevation,
+			  int number_of_streams);
+int ram_fill_streams(CELL **unique_streams, int number_of_streams);
+int ram_find_contributing_cell(int r, int c, CELL **dirs, FCELL **elevation);
+int ram_identify_next_stream(CELL **streams, int number_of_streams);
+int ram_number_of_streams(CELL **streams, CELL **dirs, int *ordered);
+
+int seg_build_streamlines(SEGMENT *streams, SEGMENT *dirs,
+			  SEGMENT *elevation, int number_of_streams);
+int seg_fill_streams(SEGMENT *unique_streams, int number_of_streams);
+int seg_find_contributing_cell(int r, int c, SEGMENT *dirs,
+			       SEGMENT *elevation);
+int seg_identify_next_stream(SEGMENT *streams, int number_of_streams);
+int seg_number_of_streams(SEGMENT *streams, SEGMENT *dirs, int *ordered);

Added: grass-addons/grass7/grass7/raster/r.stream.segment/local_vars.h
===================================================================
--- grass-addons/grass7/grass7/raster/r.stream.segment/local_vars.h	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.stream.segment/local_vars.h	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,75 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include <grass/glocale.h>
+#include <grass/gis.h>
+#include <grass/raster.h>
+#include <grass/vector.h>
+#include <grass/dbmi.h>
+
+#define SQRT2 1.414214
+	
+
+	
+typedef struct {
+	int stream;
+	int next_stream;
+	int number_of_cells;
+	int order;
+	unsigned long int * points;
+	float * elevation;
+	double * distance;
+	unsigned long int init;
+	unsigned long int outlet; /* outlet is cell from next stream */
+	int last_cell_dir; /* to add outlet to vector */
+	float direction;
+	float length;
+	float stright;
+	float drop;
+	float tangent;
+	float continuation;
+	int number_of_sectors;
+	int* sector_breakpoints; /* index of breakpoints in *points vector */
+	int* sector_cats;
+	float* sector_directions;
+	float* sector_strights;
+	double* sector_lengths;
+	float* sector_drops; /* gradient calculated at the end */
+} STREAM;	
+
+typedef struct {
+	float long_dir_diff;
+	float short_dir_diff;
+	int long_break;
+	int decision;
+} DIRCELLS;
+
+#ifdef MAIN
+#	define GLOBAL
+#else
+#	define GLOBAL extern
+#endif
+
+#ifdef MAIN
+#	define GLOBAL
+#else
+#	define GLOBAL extern
+#endif
+
+#ifndef PI
+ #define PI (4*atan(1))
+#endif
+
+#define DEG2RAD(d) ((d)*PI/180)
+#define RAD2DEG(r) ((r)*180/PI)
+
+GLOBAL int nextr[9];
+GLOBAL int nextc[9];
+
+GLOBAL int nrows, ncols; 
+GLOBAL STREAM* stream_attributes;
+
+GLOBAL struct Cell_head window;
+
+

Added: grass-addons/grass7/grass7/raster/r.stream.segment/main.c
===================================================================
--- grass-addons/grass7/grass7/raster/r.stream.segment/main.c	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.stream.segment/main.c	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,303 @@
+
+/****************************************************************************
+ *
+ * MODULE:			 r.stream.segment
+ * AUTHOR(S):		 Jarek Jasiewicz jarekj amu.edu.pl
+ *							 
+ * PURPOSE:			 Calculate geometrical attributes for segments of current order, 
+ * 							 divide segments on near stright line portons and 
+ * 							 and segment orientation and angles between streams and its
+ *               tributuaries. For stream direction it use algorithim to divide
+ *               particular streams of the same order  into near-stright line
+ *               portions.
+ * 				
+ *							
+ *
+ * COPYRIGHT:		 (C) 2002,2010 by the GRASS Development Team
+ *
+ *							 This program is free software under the GNU General Public
+ *							 License (>=v2). Read the file COPYING that comes with GRASS
+ *							 for details.
+ *
+ *****************************************************************************/
+#define MAIN
+#include <grass/glocale.h>
+#include "local_proto.h"
+
+int nextr[9] = { 0, -1, -1, -1, 0, 1, 1, 1, 0 };
+int nextc[9] = { 0, 1, 0, -1, -1, -1, 0, 1, 1 };
+
+
+int main(int argc, char *argv[])
+{
+
+    struct GModule *module;	/* GRASS module for parsing arguments */
+    struct Option *in_dir_opt,	/* options */
+     *in_stm_opt,
+	*in_elev_opt,
+	*out_segment_opt,
+	*out_sector_opt,
+	*opt_length, *opt_skip, *opt_threshold, *opt_swapsize;
+
+    struct Flag *flag_radians, *flag_segmentation;	/* segmentation library */
+
+    int i;
+    int seg_length, seg_skip;
+    int radians, segmentation;	/* flags */
+    double seg_treshold;
+    int number_of_streams, ordered;
+
+    /* initialize GIS environment */
+    G_gisinit(argv[0]);		/* reads grass env, stores program name to G_program_name() */
+
+    /* initialize module */
+    module = G_define_module();
+    module->description =
+	_("Divide network into near strigh-line segments and calculate its order");
+    G_add_keyword("Stream divide");
+    G_add_keyword("Stream direction");
+    G_add_keyword("Stream gradient");
+
+    in_stm_opt = G_define_standard_option(G_OPT_R_INPUT);
+    in_stm_opt->key = "streams";
+    in_stm_opt->description = "Name of streams mask input map";
+
+    in_dir_opt = G_define_standard_option(G_OPT_R_INPUT);
+    in_dir_opt->key = "dirs";
+    in_dir_opt->description = "Name of flow direction input map";
+
+    in_elev_opt = G_define_standard_option(G_OPT_R_INPUT);
+    in_elev_opt->key = "elevation";
+    in_elev_opt->description = "Name of elevation map";
+
+    out_segment_opt = G_define_standard_option(G_OPT_V_OUTPUT);
+    out_segment_opt->key = "segments";
+    out_segment_opt->description =
+	_("OUTPUT vector file to write segment atributes");
+
+    out_sector_opt = G_define_standard_option(G_OPT_V_OUTPUT);
+    out_sector_opt->key = "sectors";
+    out_sector_opt->description =
+	_("OUTPUT vector file to write segment atributes");
+
+    opt_length = G_define_option();
+    opt_length->key = "length";
+    opt_length->label = _("Search length to calculate direction");
+    opt_length->description = _("Must be > 0");
+    opt_length->answer = "15";
+    opt_length->type = TYPE_INTEGER;
+    opt_length->guisection = _("Optional");
+
+    opt_skip = G_define_option();
+    opt_skip->key = "skip";
+    opt_skip->label = _("Skip segments shorter than");
+    opt_skip->description = _("Must be >= 0");
+    opt_skip->answer = "5";
+    opt_skip->type = TYPE_INTEGER;
+    opt_skip->guisection = _("Optional");
+
+    opt_threshold = G_define_option();
+    opt_threshold->key = "treshold";
+    opt_threshold->label = _("Max angle (degrees) beetwen stream segments");
+    opt_threshold->description = _("Must be > 0");
+    opt_threshold->answer = "160";
+    opt_threshold->type = TYPE_DOUBLE;
+    opt_threshold->guisection = _("Optional");
+
+    opt_swapsize = G_define_option();
+    opt_swapsize->key = "memory";
+    opt_swapsize->type = TYPE_INTEGER;
+    opt_swapsize->answer = "300";
+    opt_swapsize->description = _("Max memory used in memory swap mode (MB)");
+    opt_swapsize->guisection = _("Optional");
+
+    flag_radians = G_define_flag();
+    flag_radians->key = 'r';
+    flag_radians->description =
+	_("Output angles in radians (default: degrees)");
+
+    flag_segmentation = G_define_flag();
+    flag_segmentation->key = 'm';
+    flag_segmentation->description = _("Use memory swap (operation is slow)");
+
+
+    if (G_parser(argc, argv))	/* parser */
+	exit(EXIT_FAILURE);
+
+    seg_length = atoi(opt_length->answer);
+    seg_treshold = atof(opt_threshold->answer);
+    seg_skip = atoi(opt_skip->answer);
+    radians = (flag_radians->answer != 0);
+    segmentation = (flag_segmentation->answer != 0);
+
+    if (seg_length <= 0)
+	G_fatal_error("Search's length must be > 0");
+    if (seg_treshold < 0 || seg_treshold > 180)
+	G_fatal_error("Treshold must be between 0 and 180");
+    if (seg_skip < 0)
+	G_fatal_error("Segment's length must be >= 0");
+
+    seg_treshold = DEG2RAD(seg_treshold);
+    nrows = Rast_window_rows();
+    ncols = Rast_window_cols();
+    Rast_get_window(&window);
+    G_begin_distance_calculations();
+
+
+
+    if (!segmentation) {
+	MAP map_dirs, map_streams, map_elevation, map_unique_streams;
+	CELL **streams, **dirs, **unique_streams = NULL;
+	FCELL **elevation;
+
+	G_message(_("ALL IN RAM CALCULATION"));
+	ram_create_map(&map_streams, CELL_TYPE);
+	ram_read_map(&map_streams, in_stm_opt->answer, 1, CELL_TYPE);
+	ram_create_map(&map_dirs, CELL_TYPE);
+	ram_read_map(&map_dirs, in_dir_opt->answer, 1, CELL_TYPE);
+	ram_create_map(&map_elevation, FCELL_TYPE);
+	ram_read_map(&map_elevation, in_elev_opt->answer, 0, -1);
+
+	streams = (CELL **) map_streams.map;
+	dirs = (CELL **) map_dirs.map;
+	elevation = (FCELL **) map_elevation.map;
+
+	number_of_streams =
+	    ram_number_of_streams(streams, dirs, &ordered) + 1;
+	ram_build_streamlines(streams, dirs, elevation, number_of_streams);
+
+	if (ordered) {
+	    ram_create_map(&map_unique_streams, CELL_TYPE);
+	    unique_streams = (CELL **) map_unique_streams.map;
+	    ram_fill_streams(unique_streams, number_of_streams);
+	    ram_identify_next_stream(unique_streams, number_of_streams);
+	    ram_release_map(&map_unique_streams);
+	}
+	else
+	    ram_identify_next_stream(streams, number_of_streams);
+
+	ram_release_map(&map_streams);
+	ram_release_map(&map_dirs);
+	ram_release_map(&map_elevation);
+    }
+
+
+    if (segmentation) {
+	SEG map_dirs, map_streams, map_elevation, map_unique_streams;
+	SEGMENT *streams, *dirs, *unique_streams = NULL;
+	SEGMENT *elevation;
+	int number_of_segs;
+
+	G_message(_("MEMORY SWAP CALCULATION - MAY TAKE SOME TIME"));
+	number_of_segs = (int)atof(opt_swapsize->answer);
+	number_of_segs = number_of_segs < 32 ? (int)(32 / 0.18) : number_of_segs / 0.18;
+
+	seg_create_map(&map_streams, SROWS, SCOLS, number_of_segs, CELL_TYPE);
+	seg_read_map(&map_streams, in_stm_opt->answer, 1, CELL_TYPE);
+	seg_create_map(&map_dirs, SROWS, SCOLS, number_of_segs, CELL_TYPE);
+	seg_read_map(&map_dirs, in_dir_opt->answer, 1, CELL_TYPE);
+	seg_create_map(&map_elevation, SROWS, SCOLS, number_of_segs,
+		       FCELL_TYPE);
+	seg_read_map(&map_elevation, in_elev_opt->answer, 0, -1);
+
+	streams = &map_streams.seg;
+	dirs = &map_dirs.seg;
+	elevation = &map_elevation.seg;
+
+	number_of_streams =
+	    seg_number_of_streams(streams, dirs, &ordered) + 1;
+	seg_build_streamlines(streams, dirs, elevation, number_of_streams);
+
+	if (ordered) {
+	    seg_create_map(&map_unique_streams, SROWS, SCOLS, number_of_segs,
+			   CELL_TYPE);
+	    unique_streams = &map_unique_streams.seg;
+	    seg_fill_streams(unique_streams, number_of_streams);
+	    seg_identify_next_stream(unique_streams, number_of_streams);
+	    seg_release_map(&map_unique_streams);
+	}
+	else
+	    seg_identify_next_stream(streams, number_of_streams);
+
+	seg_release_map(&map_streams);
+	seg_release_map(&map_dirs);
+	seg_release_map(&map_elevation);
+    }
+
+
+
+
+
+
+
+    for (i = 1; i < number_of_streams; ++i)
+	G_message("%d %d %d", stream_attributes[i].stream,
+		  stream_attributes[i].next_stream,
+		  stream_attributes[i].last_cell_dir);
+
+
+    /*
+       for(i=1;i<number_of_streams;++i)
+       printf("STREAM %d NEXT_STREAM %d POINT %d \n",
+       stream_attributes[i].stream,
+       stream_attributes[i].next_stream,
+       stream_attributes[i].outlet);
+
+     */
+    G_message("Creating sectors and calculating attributes...");
+
+    for (i = 1; i < number_of_streams; ++i) {
+	create_sectors(&stream_attributes[i], seg_length, seg_skip,
+		       seg_treshold);
+	calc_tangents(&stream_attributes[i], seg_length, seg_skip,
+		      number_of_streams);
+    }
+
+
+
+
+
+    /*
+
+
+       for(j=1;j<number_of_streams;++j)
+       G_message("STREAM %d   ncells %d len %f str %f sin %f",
+       stream_attributes[j].stream,
+       stream_attributes[j].number_of_cells,
+       stream_attributes[j].length,
+       stream_attributes[j].stright,
+       stream_attributes[j].length/stream_attributes[j].stright);
+       G_message("%d",j);
+
+
+       for(j=1;j<number_of_streams;++j)
+       printf("STREAM %d   max %f min %f drop %f\n",
+       stream_attributes[j].stream,
+       stream_attributes[j].elevation[1],
+       stream_attributes[j].elevation[stream_attributes[j].number_of_cells-1],
+       stream_attributes[j].drop);
+
+       for(j=1;j<number_of_streams;++j)
+       for (i = 0; i < stream_attributes[j].number_of_sectors; ++i)
+       printf("%d  cat %d |BRAEK %d | dir %.2f | len %.2f | drop %.3f  \n" ,j,
+       stream_attributes[j].sector_cats[i],
+       stream_attributes[j].sector_breakpoints[i],
+       stream_attributes[j].sector_directions[i],
+       stream_attributes[j].sector_lengths[i],
+       stream_attributes[j].sector_drops[i]);
+
+       for(j=1;j<number_of_streams;++j) {
+       printf("        %d %d \n" ,j,stream_attributes[j].number_of_cells);
+       for (i = 0; i <= stream_attributes[j].number_of_cells; ++i)
+       printf("%d %f \n" ,i,stream_attributes[j].elevation[i]);
+       }
+     */
+
+    create_segment_vector(out_segment_opt->answer, number_of_streams,
+			  radians);
+    create_sector_vector(out_sector_opt->answer, number_of_streams, radians);
+
+    free_attributes(number_of_streams);
+    G_message("Done");
+    exit(EXIT_SUCCESS);
+}

Added: grass-addons/grass7/grass7/raster/r.stream.segment/r.stream.segment.html
===================================================================
--- grass-addons/grass7/grass7/raster/r.stream.segment/r.stream.segment.html	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.stream.segment/r.stream.segment.html	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,199 @@
+<h2>DESCRIPTION</h2>
+
+<h2>OPTIONS</h2>
+<dl>
+<dt><b>-r</b></dt>
+<dd>Directions and azimut output in radians. Default is degrees.</dd>
+<dt><b>-m</b></dt>
+<dd>Only for very large data sets. Use segment library to optimize memory
+consumption during analysis</dd>
+<dt><b>stream</b></dt>
+<dd>Stream network: name of input stream map. Streams shall be ordered according
+one of the r.stream.order ordering system as well as unordered (with original
+stream identifiers)  Because streams network produced by r.watershed and
+r.stream.extract may slighty differ in detail it is required to use both stream
+and direction map produced by the same module. Stream background shall have NULL
+value or zero value. Background values of NULL are by default produced by
+r.watershed and r.stream.extract. If not 0 or NULL use <a
+href="r.mapcalc.html">r.mapcalc</a> to set background values to null.  
+</dd>
+<dt><b>dirs</b></dt>
+<dd>Flow direction: name of input direction map produced by r.watershed or
+r.stream.extract. If r.stream.extract output map is used, it only has non-NULL
+values in places where streams occur. NULL (nodata) cells are ignored, zero and
+negative values are valid direction data if they vary from -8 to 8 (CCW from
+East in steps of 45 degrees). Direction map shall be of type CELL values. Region
+resolution and map resoultion must be the same. 
+Also <em>stream</em> network map must have the same resolution. It is checked by
+default. If resolutions differ the module informs about it and stops. Region
+boundary and maps boundary may be differ but it may lead to unexpected
+results.</dd>
+<dt><b>elevation</b></dt>
+<dd>Elevation: name of input elevation map. Map can be of type CELL, FCELL or
+DCELL. It is not restricted to resolution of region settings as streams and
+dirs.</dd>
+<dt><b>length</b></dt>
+<dd>Integer values indicating the search length (in cells) to determine stright
+line. The longest length parameter the module treats more tolerant local stream
+undulation and inequalities. Default value of 15 is suitable for  30 meters
+DEMS. More detail DEMS may requre longer length.</dd>
+
+<dt><b>skip</b></dt>
+<dd>Integer values indicating the length (in cells) local short segment to skip
+and join them to the longer neigbour. The shortest length parameter the more
+short segments will be produced by the module due to undulation and
+inequalities. Default value of 5 is suitable for  30 meters DEMS. More details
+DEMS may requre longer length.</dd>
+
+<dt><b>treshold</b></dt>
+<dd>real value indicates the internal angle between upstream and downsteam
+direction to treat actual cell as lying on the stright line. greater value (up to
+180 degrees) produces more segments. Lesser values produced less segments.
+Values below 90 in most cases will not produce any addational segments to these
+resulting from ordering
+</dl>
+<dl>
+<h2>OUTPUTS</h2>
+<p>The module produces two vector maps: one representing original segments
+(where segment is a streamline where its order remains unchanged) and second
+divided into near stright line sectors resulting form segmentation proccess.
+Most of segment and sectors attributes are the same as in r.stream.order vector
+output.</p>
+<dl>
+<dt><b>segments</b></dt>
+<dd>
+Vector map where every segment has its own category and following attributes:
+<ul>
+<li><b>segment</b>: integer, segment identifier
+<li><b>next_segment</b>: integer, topological next segment identifier
+<li><b>s_order</b>: integer, segment order
+<li><b>next_order</b>: integer, topological next segment order
+<li><b>direction</b>: double precision, full segment direction (0-360)
+<li><b>azimuth</b>: double precision, full segment azimuth (0-180) 
+<li><b>length</b>: double precision, segment length
+<li><b>stright</b>: double precision, length of stright line between segment
+nodes
+<li><b>sinusoid</b>: double precision, sinusoid (length/stright)
+<li><b>elev_min</b>: double precision, minimum elevation (elevation at segment
+start)
+<li><b>elev_max</b>: double precision, maximum elevation (elevation at segment
+end)
+<li><b>s_drop</b>: double precision, deifference between start and end of the
+segment
+<li><b>gradient</b>: double precision, drop/length
+<li><b>out_direction</b>: double precision, direction (0-360) of segment end
+sector
+<li><b>out_azimuth</b>: double precision,  azimuth (0-180) of segment end sector
+<li><b>out_length</b>: double precision, length of segment end sector
+<li><b>out_drop</b>: double precision, drop of segment end sector
+<li><b>out_gradient</b>: double precision, gradient of segment end sector
+<li><b>tangent_dir</b>: double precision, direction of tangent in segment outlet
+to the next stream 
+<li><b>tangent_azimuth</b>: double precision, azimuth of tangent in segment
+outlet to the next stream 
+<li><b>next_direction</b>: double precision, direction of next stream in join
+with current segment 
+<li><b>next_azimuth</b>: double precision, azimuth of next stream in join with
+current segment 
+</ul>
+<img src="dirs.png">
+</dd>
+<dt><b>sectors</b></dt>
+<dd>Vector map where every sector has its own category and following attributes:
+<ul>
+<li><b>sector</b>: integer, sector category
+<li><b>segment</b>: integer, segment category (to estabilsh relationship)
+<li><b>s_order</b>: integer, segment order
+<li><b>direction</b>: double precision, sector direction
+<li><b>azimuth</b>: double precision, sector azimuth
+<li><b>length</b>: double precision, sector length
+<li><b>stright</b>: double precision, length of stright line between sector
+nodes
+<li><b>sinusoid</b>: double precision, sinusoid (length/stright)
+<li><b>elev_min</b>: double precision, minimum elevation (elevation at sector
+start)
+<li><b>elev_max</b>: double precision, minimum elevation (elevation at sector
+end)
+<li><b>s_drop</b>: double precision, deifference between start and end of the
+sector
+<li><b>gradient</b>: double precision, drop/length
+</ul>
+<img src="sectors.png">
+Relation between segments and sector may be set up by segment key.
+</dd>
+</dl>
+<p>
+The main idea comes from works of Horton (1932) and Howard (1971, 1990). The
+module is designed to inverstigate network lineaments and calculate angle
+relations between tributaries and its major streams. The main problem in
+calculating directional parameters is that streams usually are not straight
+lines. Therefore as the first step of the procedure, partitioning of streams
+into near-straight-line segments is required.
+<p>
+The segmentation process uses a method similar to the one used by Van & Ventura
+(1997) to detect corners and partition curves into straight lines and gentle
+arcs. Because it is almost impossible to determine exactly straight sections
+without creating numerous very short segments, the division process requires
+some approximation. The approximation is made based on three parameters: (1) the
+downstream/upstream search length, (2) the short segment skipping threshold, and
+(3) the maximum angle between downstream/upstream segments to be considered as a
+straight line. In order to designate straight sections of the streams, the
+algorithm is searching for those points where curves significantly change their
+direction.
+The definition of stream segments depends on the ordering method selected by the
+user,  Strahler's, Horton's or Hack's main stream, or the network may remain
+unordered. All junctions of streams to streams of higher order are always split
+points, but for ordered networks, streams of higher order may be divided into
+sections which ignore junctions with streams of lower order. In unordered
+networks all junctions are always split points.
+In extended mode the module also calculates the direction of a stream to its
+higher order stream If the higher order stream begins at the junction with the
+current stream (Strahler's ordering only) or if the network is unordered, the
+direction is calculated as the direction of the line between junction point and
+downstream point (Howard 1971) within the user-defined global search distance.
+If a higher order stream continues at the junction, its direction is calculated
+as the direction of the tangent line to the stream of higher order at the
+junction point. To avoid local fluctuation, the tangent line is approximated as
+a secant line joining downstream/upstream points at a distance globally defined
+by the search length parameter (1). Such a definition of the angle between
+streams is not fully compatible with Horton's original criterion.
+
+<h2>NOTES</h2>
+<p>
+Module can work only if direction map, stream map and region map has same
+settings. It is also required that stream map and direction map come from the
+same source. For lots of reason this limitation probably cannot be omitted.  
+this means if stream map comes from r.stream.extract also direction map from
+r.stream.extract must be used. If stream network was generated with MFD method
+also MFD direction map must be used.
+
+
+<h2>SEE ALSO</h2>
+
+<em>
+<a href="r.watershed.html">r.watershed</a>,
+<a href="r.stream.extract.html">r.stream.extract</a>,
+<a href="r.stream.order.html">r.stream.order</a>,
+<a href="r.stream.basins.html">r.stream.basins</a>,
+<a href="r.stream.slope.html">r.stream.slope</a>,
+<a href="r.stream.stats.html">r.stream.stats</a>,
+<a href="r.mapcalc.html">r.mapcalc</a>,
+</em>
+
+<h2>REFERENCES</h2>
+<p>Horton, R. E., (1932). Drainage basin characteristics: Am. Geophys. Union
+Trans., (3), 350-361.
+<p>Howard, A.D. (1971). Optimal angles of stream junction: Geometric, Stability
+to capture and Minimum Power Criteria, Water Resour. Res. 7(4), 863-873.
+<p>Howard, A.D. (1990). Theoretical model of optimal drainage networks Water
+Resour. Res., 26(9),  2107-2117.
+<p>Van, W., Ventura, J.A. (1997). Segmentation of Planar Curves into
+Straight-Line Segments and Elliptical Arcs, Graphical Models and Image
+Processing 59(6), 484-494.
+
+<h2>AUTHOR</h2>
+Jarek Jasiewicz, Adam Mickiewicz University, Geoecology and Geoinformation
+Institute.
+
+<p><i>Last changed: $Date: 2011-11-08 22:56:45 +0100 (Tue, 08 Nov 2011) $</i>
+

Added: grass-addons/grass7/grass7/raster/r.stream.segment/sectors.png
===================================================================
(Binary files differ)


Property changes on: grass-addons/grass7/grass7/raster/r.stream.segment/sectors.png
___________________________________________________________________
Added: svn:mime-type
   + application/octet-stream

Added: grass-addons/grass7/grass7/raster/r.stream.segment/stream_segment.c
===================================================================
--- grass-addons/grass7/grass7/raster/r.stream.segment/stream_segment.c	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.stream.segment/stream_segment.c	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,283 @@
+#include "local_proto.h"
+static int sector_cat = 0;
+
+float calc_dir(int rp, int cp, int rn, int cn)
+{
+    return
+	(cp - cn) == 0 ?
+	(rp - rn) > 0 ? 0 : PI :
+	(cp - cn) < 0 ?
+	PI / 2 + atan((rp - rn) / (float)(cp - cn)) :
+	3 * PI / 2 + atan((rp - rn) / (float)(cp - cn));
+}
+
+float calc_length(double *distance, int start, int stop)
+{
+    float cum_length = 0;
+    int i;
+
+    for (i = start; i < stop; ++i)
+	cum_length += distance[i];
+    return cum_length;
+}
+
+double calc_drop(float *elevation, int start, int stop)
+{
+    float result;
+
+    result = elevation[start] - elevation[stop];
+    return result < 0 ? 0 : result;
+}
+
+double calc_stright(int rp, int cp, int rn, int cn)
+{
+    double northing, easting, next_northing, next_easting;
+
+    northing = window.north - (rp + .5) * window.ns_res;
+    easting = window.west + (cp + .5) * window.ew_res;
+    next_northing = window.north - (rn + .5) * window.ns_res;
+    next_easting = window.west + (cn + .5) * window.ew_res;
+    return G_distance(easting, northing, next_easting, next_northing);
+}
+
+int create_sectors(STREAM *cur_stream, int seg_length, int seg_skip,
+		   double seg_treshold)
+{
+    DIRCELLS *streamline;
+    unsigned long int *P;	/* alias for points */
+
+    int i, prev_i = 0;
+    int number_of_cells;
+    int cell_down, cell_up;
+    int r, c, r_up, c_up, r_down, c_down;
+    int seg_length_short = seg_length / 3;
+    float dir_down, dir_up, dir_diff;
+
+    float local_minimum = PI;
+    int number_of_sectors = 0;
+    int local_minimum_point = 0;
+    int sector_index = 0;
+    int in_loop = 0;
+    int num_of_points = 0, num_of_breakpoints = 0;
+
+    number_of_cells = cur_stream->number_of_cells - 1;
+    P = cur_stream->points;
+
+    streamline =
+	(DIRCELLS *) G_malloc((number_of_cells + 1) * sizeof(DIRCELLS));
+
+    /* init cells */
+    for (i = 0; i < number_of_cells + 1; ++i) {
+	streamline[i].long_dir_diff = 0;
+	streamline[i].short_dir_diff = 0;
+	streamline[i].long_break = 0;
+	streamline[i].decision = 0;
+    }
+
+    /* upstream: to init, downstream: to outlet */
+    for (i = seg_skip; i < number_of_cells - seg_skip; ++i) {
+	cell_up = i < seg_length ? i : seg_length;
+	cell_down = i > number_of_cells - 1 - seg_length ?
+	    number_of_cells - 1 - i : seg_length;
+
+	r = (int)P[i] / ncols;
+	c = (int)P[i] % ncols;
+	r_up = (int)P[i - cell_up] / ncols;
+	c_up = (int)P[i - cell_up] % ncols;
+	r_down = (int)P[i + cell_down] / ncols;
+	c_down = (int)P[i + cell_down] % ncols;
+
+	dir_down = calc_dir(r, c, r_down, c_down);
+	dir_up = calc_dir(r, c, r_up, c_up);
+	dir_diff = fabs(dir_up - dir_down);
+	streamline[i].long_dir_diff =
+	    dir_diff > PI ? PI * 2 - dir_diff : dir_diff;
+	streamline[i].long_break =
+	    (streamline[i].long_dir_diff < seg_treshold) ? 1 : 0;
+
+	cell_up = i < seg_length_short ? i : seg_length_short;
+	cell_down = i > number_of_cells - 1 - seg_length_short ?
+	    number_of_cells - 1 - i : seg_length_short;
+
+	r = (int)P[i] / ncols;
+	c = (int)P[i] % ncols;
+	r_up = (int)P[i - cell_up] / ncols;
+	c_up = (int)P[i - cell_up] % ncols;
+	r_down = (int)P[i + cell_down] / ncols;
+	c_down = (int)P[i + cell_down] % ncols;
+
+	dir_down = calc_dir(r, c, r_down, c_down);
+	dir_up = calc_dir(r, c, r_up, c_up);
+	dir_diff = fabs(dir_up - dir_down);
+	streamline[i].short_dir_diff =
+	    dir_diff > PI ? PI * 2 - dir_diff : dir_diff;
+    }
+
+    /* look for breakpoints */
+    for (i = 0; i < number_of_cells; ++i) {
+
+	if (streamline[i].long_break) {
+	    num_of_breakpoints = 0;
+	    if (local_minimum > streamline[i].short_dir_diff) {
+		local_minimum = streamline[i].short_dir_diff;
+		local_minimum_point = i;
+		in_loop = 1;
+	    }			/* end local minimum */
+
+	}
+	else if (!streamline[i].long_break && in_loop) {
+	    num_of_breakpoints++;
+	    if (num_of_breakpoints == (seg_length / 5)) {
+		streamline[local_minimum_point].decision = 1;
+		local_minimum = PI;
+		in_loop = 0;
+	    }
+	}
+    }
+
+    /* cleaning breakpoints */
+    for (i = 0, num_of_points = 0; i < number_of_cells; ++i, ++num_of_points) {
+
+	if (streamline[i].decision) {
+	    //printf("       BEFORE  %d %d\n",i,num_of_points);
+	    if (i < seg_skip || (i > seg_skip && num_of_points < seg_skip)) {
+		streamline[i].decision = 0;
+		i = local_minimum_point;
+	    }
+	    else {
+		local_minimum_point = i;
+	    }
+	    num_of_points = 0;
+	}
+    }
+
+    /* number of segment in streamline */
+    for (i = 0; i < number_of_cells + 1; ++i)
+	if (streamline[i].decision == 1 || i == (number_of_cells - 1))
+	    number_of_sectors++;
+
+
+    cur_stream->number_of_sectors = number_of_sectors;
+    cur_stream->sector_breakpoints =
+	(int *)G_malloc(number_of_sectors * sizeof(int));
+    cur_stream->sector_cats =
+	(int *)G_malloc(number_of_sectors * sizeof(int));
+    cur_stream->sector_directions =
+	(float *)G_malloc(number_of_sectors * sizeof(float));
+    cur_stream->sector_strights =
+	(float *)G_malloc(number_of_sectors * sizeof(float));
+    cur_stream->sector_lengths =
+	(double *)G_malloc(number_of_sectors * sizeof(double));
+    cur_stream->sector_drops =
+	(float *)G_malloc(number_of_sectors * sizeof(float));
+
+    /* add attributies */
+    for (i = 0, prev_i = 0; i < number_of_cells + 1; ++i) {
+	if (streamline[i].decision == 1 || i == (number_of_cells - 1)) {
+
+	    r = (int)P[i] / ncols;
+	    c = (int)P[i] % ncols;
+	    r_up = (int)P[prev_i] / ncols;
+	    c_up = (int)P[prev_i] % ncols;
+
+	    cur_stream->sector_breakpoints[sector_index] = i;
+
+	    cur_stream->sector_directions[sector_index] =
+		calc_dir(r_up, c_up, r, c);
+
+	    cur_stream->sector_lengths[sector_index] =
+		calc_length(cur_stream->distance, prev_i, i);
+
+	    cur_stream->sector_strights[sector_index] =
+		calc_stright(r_up, c_up, r, c);
+
+	    cur_stream->sector_drops[sector_index] =
+		calc_drop(cur_stream->elevation, prev_i, i);
+
+	    cur_stream->sector_cats[sector_index] = ++sector_cat;
+	    sector_index++;
+	    if (i < (number_of_cells - 1))
+		prev_i = i;
+	}
+    }
+
+
+    /*
+       for (i = 0; i < number_of_cells; ++i)
+       printf("%d | %f  %f |break %d | Dec %d  \n" ,i,
+       streamline[i].long_dir_diff,
+       streamline[i].short_dir_diff,
+       streamline[i].long_break,
+       streamline[i].decision); 
+
+     */
+    G_free(streamline);
+    return 0;
+}
+
+int calc_tangents(STREAM *cur_stream, int seg_length, int seg_skip,
+		  int number_streams)
+{
+
+    int i;
+    int cell_up, cell_down;
+    int r, c, r_up, c_up, r_down, c_down;
+    STREAM *SA = stream_attributes;
+    unsigned long int *P = cur_stream->points;
+    int next_stream = cur_stream->next_stream;
+    int outlet = cur_stream->outlet;
+    int last_cell = cur_stream->number_of_cells - 1;
+    int reached_end = 1;
+
+    /*before calc tangents add rest of streamline attributes */
+    r_up = (int)P[1] / ncols;
+    c_up = (int)P[1] % ncols;
+    r_down = (int)P[last_cell] / ncols;
+    c_down = (int)P[last_cell] % ncols;
+
+    cur_stream->direction = calc_dir(r_up, c_up, r_down, c_down);
+    cur_stream->length = calc_length(cur_stream->distance, 1, last_cell);
+    cur_stream->stright = calc_stright(r_up, c_up, r_down, c_down);
+    cur_stream->drop = calc_drop(cur_stream->elevation, 1, last_cell);
+
+    if (next_stream < 1) {
+	cur_stream->tangent = -1;
+	cur_stream->continuation = -1;
+	return 0;
+    }
+
+    /* find location of outlet in next stream */
+    for (i = 1; i < SA[next_stream].number_of_cells; ++i) {
+	if (SA[next_stream].points[i] == outlet) {
+	    reached_end = 0;
+	    break;
+	}
+    }
+
+    /* outlet not lies on the next stream */
+    if (reached_end) {
+	G_warning(_("Network topology error: cannot identify stream join for stream %d"),
+		  cur_stream->stream);
+	cur_stream->tangent = -1;
+	cur_stream->continuation = -1;
+	return 0;
+    }
+
+    cell_up = i <= seg_length ? i - 1 : seg_length;
+    cell_down = i >= (SA[next_stream].number_of_cells - seg_length) ?
+	SA[next_stream].number_of_cells - seg_length - 1 : seg_length;
+
+    r = (int)SA[next_stream].points[i] / ncols;
+    c = (int)SA[next_stream].points[i] % ncols;
+    r_up = (int)SA[next_stream].points[i - cell_up] / ncols;
+    c_up = (int)SA[next_stream].points[i - cell_up] % ncols;
+    r_down = (int)SA[next_stream].points[i + cell_down] / ncols;
+    c_down = (int)SA[next_stream].points[i + cell_down] % ncols;
+
+    cur_stream->continuation = calc_dir(r, c, r_down, c_down);
+    cur_stream->tangent = i == 1 ? -1 :
+	i < seg_skip ? cur_stream->continuation : calc_dir(r_up, c_up, r_down,
+							   c_down);
+
+    return 0;
+}

Added: grass-addons/grass7/grass7/raster/r.stream.segment/stream_topology.c
===================================================================
--- grass-addons/grass7/grass7/raster/r.stream.segment/stream_topology.c	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.stream.segment/stream_topology.c	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,570 @@
+#include "local_proto.h"
+double get_distance(int r, int c, int d)
+{
+    double northing, easting, next_northing, next_easting;
+    int next_r, next_c;
+
+    next_r = NR(d);
+    next_c = NC(d);
+    northing = window.north - (r + .5) * window.ns_res;
+    easting = window.west + (c + .5) * window.ew_res;
+    next_northing = window.north - (next_r + .5) * window.ns_res;
+    next_easting = window.west + (next_c + .5) * window.ew_res;
+    return G_distance(easting, northing, next_easting, next_northing);
+}
+
+int ram_trib_nums(int r, int c, CELL ** streams, CELL ** dirs)
+{				/* calculate number of tributuaries */
+
+    int trib_num = 0;
+    int i, j;
+    int next_r, next_c;
+
+    for (i = 1; i < 9; ++i) {
+	if (NOT_IN_REGION(i))
+	    continue;
+
+	j = DIAG(i);
+	next_r = NR(i);
+	next_c = NC(i);
+
+	if (streams[next_r][next_c] > 0 && dirs[next_r][next_c] == j)
+	    trib_num++;
+    }
+
+    if (trib_num > 1)
+	for (i = 1; i < 9; ++i) {
+	    if (NOT_IN_REGION(i))
+		continue;
+
+	    j = DIAG(i);
+	    next_r = NR(i);
+	    next_c = NC(i);
+
+	    if (streams[next_r][next_c] == streams[r][c] &&
+		dirs[next_r][next_c] == j)
+		trib_num--;
+	}
+
+    if (trib_num > 5)
+	G_fatal_error(_("Error finding inits. Stream and direction maps probably do not match..."));
+    if (trib_num > 3)
+	G_warning(_("Stream network may be too dense..."));
+
+    return trib_num;
+}				/* end trib_num */
+
+
+int seg_trib_nums(int r, int c, SEGMENT *streams, SEGMENT *dirs)
+{				/* calculate number of tributuaries */
+
+    int trib_num = 0;
+    int i, j;
+    int next_r, next_c;
+    int streams_cell, streams_next_cell, dirs_next_cell;
+
+    segment_get(streams, &streams_cell, r, c);
+    for (i = 1; i < 9; ++i) {
+	if (NOT_IN_REGION(i))
+	    continue;
+
+	j = DIAG(i);
+	next_r = NR(i);
+	next_c = NC(i);
+
+	segment_get(streams, &streams_next_cell, next_r, next_c);
+	segment_get(dirs, &dirs_next_cell, next_r, next_c);
+
+	if (streams_next_cell > 0 && dirs_next_cell == j)
+	    trib_num++;
+    }
+
+    if (trib_num > 1)
+	for (i = 1; i < 9; ++i) {
+	    if (NOT_IN_REGION(i))
+		continue;
+
+	    j = DIAG(i);
+	    next_r = NR(i);
+	    next_c = NC(i);
+
+	    segment_get(streams, &streams_next_cell, next_r, next_c);
+	    segment_get(dirs, &dirs_next_cell, next_r, next_c);
+
+	    if (streams_next_cell == streams_cell && dirs_next_cell == j)
+		trib_num--;
+	}
+
+    if (trib_num > 5)
+	G_fatal_error(_("Error finding inits. Stream and direction maps probably do not match..."));
+    if (trib_num > 3)
+	G_warning(_("Stream network may be too dense..."));
+
+    return trib_num;
+}				/* end trib_num */
+
+
+int ram_number_of_streams(CELL **streams, CELL **dirs, int *ordered)
+{
+    int r, c;
+    int stream_num = 0;
+    int one = 0, two = 0;
+
+    for (r = 0; r < nrows; ++r)
+	for (c = 0; c < ncols; ++c)
+	    if (streams[r][c] > 0)
+		if (ram_trib_nums(r, c, streams, dirs) != 1) {
+		    stream_num++;
+		    if (streams[r][c] == 1)
+			one++;
+		    if (streams[r][c] == 2)
+			two++;
+		}
+    *ordered = (one > 1 || two > 1) ? 1 : 0;
+    /* if there is more than 1 stream with identifier 1 or 2  network is ordered */
+
+    return stream_num;
+}
+
+int seg_number_of_streams(SEGMENT *streams, SEGMENT *dirs, int *ordered)
+{
+    int r, c;
+    int stream_num = 0;
+    int one = 0, two = 0;
+    int streams_cell;
+
+    for (r = 0; r < nrows; ++r)
+	for (c = 0; c < ncols; ++c) {
+	    segment_get(streams, &streams_cell, r, c);
+	    if (streams_cell > 0)
+		if (seg_trib_nums(r, c, streams, dirs) != 1) {
+		    stream_num++;
+		    if (streams_cell == 1)
+			one++;
+		    if (streams_cell == 2)
+			two++;
+		}
+	}
+    *ordered = (one > 1 || two > 1) ? 1 : 0;
+    /* if there is more than 1 stream with identifier 1 or 2  network is ordered */
+
+    return stream_num;
+}
+
+int ram_build_streamlines(CELL **streams, CELL **dirs, FCELL **elevation,
+			  int number_of_streams)
+{
+    int r, c, i;
+    int d, next_d;
+    int prev_r, prev_c;
+    int stream_num = 1, cell_num = 0;
+    int contrib_cell;
+    STREAM *SA;
+    int border_dir;
+
+    stream_attributes =
+	(STREAM *) G_malloc(number_of_streams * sizeof(STREAM));
+    G_message("Finding inits...");
+    SA = stream_attributes;
+
+    for (r = 0; r < nrows; ++r)
+	for (c = 0; c < ncols; ++c)
+	    if (streams[r][c])
+		if (ram_trib_nums(r, c, streams, dirs) != 1) {	/* adding inits */
+		    if (stream_num > number_of_streams)
+			G_fatal_error(_("Error finding inits. Stream and direction maps probably do not match..."));
+
+		    SA[stream_num].stream = stream_num;
+		    SA[stream_num].init = INDEX(r, c);
+		    stream_num++;
+		}
+
+    for (i = 1; i < stream_num; ++i) {
+
+
+	r = (int)SA[i].init / ncols;
+	c = (int)SA[i].init % ncols;
+	SA[i].order = streams[r][c];
+	SA[i].number_of_cells = 0;
+	do {
+
+	    SA[i].number_of_cells++;
+	    d = abs(dirs[r][c]);
+	    if (NOT_IN_REGION(d) || d == 0)
+		break;
+	    r = NR(d);
+	    c = NC(d);
+	} while (streams[r][c] == SA[i].order);
+
+	SA[i].number_of_cells += 2;	/* add two extra points for init+ and outlet+ */
+    }
+
+    for (i = 1; i < number_of_streams; ++i) {
+
+	SA[i].points = (unsigned long int *)
+	    G_malloc((SA[i].number_of_cells) * sizeof(unsigned long int));
+	SA[i].elevation = (float *)
+	    G_malloc((SA[i].number_of_cells) * sizeof(float));
+	SA[i].distance = (double *)
+	    G_malloc((SA[i].number_of_cells) * sizeof(double));
+
+	r = (int)SA[i].init / ncols;
+	c = (int)SA[i].init % ncols;
+	contrib_cell = ram_find_contributing_cell(r, c, dirs, elevation);
+	prev_r = NR(contrib_cell);
+	prev_c = NC(contrib_cell);
+
+	/* add one point contributing to init to calculate parameters */
+	/* what to do if there is no contributing points? */
+	SA[i].points[0] = (contrib_cell == 0) ? -1 : INDEX(prev_r, prev_c);
+	SA[i].elevation[0] = (contrib_cell == 0) ? -99999 :
+	    elevation[prev_r][prev_c];
+	d = (contrib_cell == 0) ? dirs[r][c] : dirs[prev_r][prev_c];
+	SA[i].distance[0] = (contrib_cell == 0) ? get_distance(r, c, d) :
+	    get_distance(prev_r, prev_c, d);
+
+	SA[i].points[1] = INDEX(r, c);
+	SA[i].elevation[1] = elevation[r][c];
+	d = abs(dirs[r][c]);
+	SA[i].distance[1] = get_distance(r, c, d);
+
+	cell_num = 2;
+	do {
+	    d = abs(dirs[r][c]);
+
+	    if (NOT_IN_REGION(d) || d == 0) {
+		SA[i].points[cell_num] = -1;
+		SA[i].distance[cell_num] = SA[i].distance[cell_num - 1];
+		SA[i].elevation[cell_num] =
+		    2 * SA[i].elevation[cell_num - 1] -
+		    SA[i].elevation[cell_num - 2];
+		border_dir = convert_border_dir(r, c, dirs[r][c]);
+		SA[i].last_cell_dir = border_dir;
+		break;
+	    }
+	    r = NR(d);
+	    c = NC(d);
+	    SA[i].last_cell_dir = dirs[r][c];
+	    SA[i].points[cell_num] = INDEX(r, c);
+	    SA[i].elevation[cell_num] = elevation[r][c];
+	    next_d = (abs(dirs[r][c]) == 0) ? d : abs(dirs[r][c]);
+	    SA[i].distance[cell_num] = get_distance(r, c, next_d);
+	    cell_num++;
+	    if (cell_num > SA[i].number_of_cells)
+		G_fatal_error(_("To much points in stream line..."));
+	} while (streams[r][c] == SA[i].order);
+
+	if (SA[i].elevation[0] == -99999)
+	    SA[i].elevation[0] = 2 * SA[i].elevation[1] - SA[i].elevation[2];
+    }
+    return 0;
+}
+
+
+int seg_build_streamlines(SEGMENT *streams, SEGMENT *dirs,
+			  SEGMENT *elevation, int number_of_streams)
+{
+    int r, c, i;
+    int d, next_d;
+    int prev_r, prev_c;
+    int stream_num = 1, cell_num = 0;
+    int contrib_cell;
+    STREAM *SA;
+    int border_dir;
+    int streams_cell, dirs_cell;
+    int dirs_prev_cell;
+    float elevation_cell, elevation_prev_cell;
+
+    stream_attributes =
+	(STREAM *) G_malloc(number_of_streams * sizeof(STREAM));
+    G_message("Finding inits...");
+    SA = stream_attributes;
+
+    /* finding inits */
+    for (r = 0; r < nrows; ++r)
+	for (c = 0; c < ncols; ++c) {
+	    segment_get(streams, &streams_cell, r, c);
+
+	    if (streams_cell)
+		if (seg_trib_nums(r, c, streams, dirs) != 1) {	/* adding inits */
+		    if (stream_num > number_of_streams)
+			G_fatal_error(_("Error finding inits. Stream and direction maps probably do not match..."));
+
+		    SA[stream_num].stream = stream_num;
+		    SA[stream_num].init = INDEX(r, c);
+		    stream_num++;
+		}
+	}
+
+    /* buildning streamline */
+    for (i = 1; i < stream_num; ++i) {
+
+	r = (int)SA[i].init / ncols;
+	c = (int)SA[i].init % ncols;
+	segment_get(streams, &streams_cell, r, c);
+	SA[i].order = streams_cell;
+	SA[i].number_of_cells = 0;
+
+	do {
+
+	    SA[i].number_of_cells++;
+	    segment_get(dirs, &dirs_cell, r, c);
+
+	    d = abs(dirs_cell);
+	    if (NOT_IN_REGION(d) || d == 0)
+		break;
+	    r = NR(d);
+	    c = NC(d);
+	    segment_get(streams, &streams_cell, r, c);
+	} while (streams_cell == SA[i].order);
+
+	SA[i].number_of_cells += 2;	/* add two extra points for point before init and after outlet */
+    }
+
+    for (i = 1; i < number_of_streams; ++i) {
+
+	SA[i].points = (unsigned long int *)
+	    G_malloc((SA[i].number_of_cells) * sizeof(unsigned long int));
+	SA[i].elevation = (float *)
+	    G_malloc((SA[i].number_of_cells) * sizeof(float));
+	SA[i].distance = (double *)
+	    G_malloc((SA[i].number_of_cells) * sizeof(double));
+
+	r = (int)SA[i].init / ncols;
+	c = (int)SA[i].init % ncols;
+	contrib_cell = seg_find_contributing_cell(r, c, dirs, elevation);
+	prev_r = NR(contrib_cell);
+	prev_c = NC(contrib_cell);
+
+	/* add one point contributing to init to calculate parameters */
+	/* what to do if there is no contributing points? */
+
+	segment_get(dirs, &dirs_cell, r, c);
+	segment_get(dirs, &dirs_prev_cell, prev_r, prev_c);
+	segment_get(elevation, &elevation_prev_cell, prev_r, prev_c);
+	segment_get(elevation, &elevation_cell, r, c);
+
+	SA[i].points[0] = (contrib_cell == 0) ? -1 : INDEX(prev_r, prev_c);
+	SA[i].elevation[0] = (contrib_cell == 0) ? -99999 :
+	    elevation_prev_cell;
+	d = (contrib_cell == 0) ? dirs_cell : dirs_prev_cell;
+	SA[i].distance[0] = (contrib_cell == 0) ? get_distance(r, c, d) :
+	    get_distance(prev_r, prev_c, d);
+
+	SA[i].points[1] = INDEX(r, c);
+	SA[i].elevation[1] = elevation_cell;
+	d = abs(dirs_cell);
+	SA[i].distance[1] = get_distance(r, c, d);
+
+	cell_num = 2;
+	do {
+	    segment_get(dirs, &dirs_cell, r, c);
+	    d = abs(dirs_cell);
+
+	    if (NOT_IN_REGION(d) || d == 0) {
+		SA[i].points[cell_num] = -1;
+		SA[i].distance[cell_num] = SA[i].distance[cell_num - 1];
+		SA[i].elevation[cell_num] =
+		    2 * SA[i].elevation[cell_num - 1] -
+		    SA[i].elevation[cell_num - 2];
+		border_dir = convert_border_dir(r, c, dirs_cell);
+		SA[i].last_cell_dir = border_dir;
+		break;
+	    }
+	    r = NR(d);
+	    c = NC(d);
+	    segment_get(dirs, &dirs_cell, r, c);
+	    SA[i].last_cell_dir = dirs_cell;
+	    SA[i].points[cell_num] = INDEX(r, c);
+	    segment_get(elevation, &SA[i].elevation[cell_num], r, c);
+	    next_d = (abs(dirs_cell) == 0) ? d : abs(dirs_cell);
+	    SA[i].distance[cell_num] = get_distance(r, c, next_d);
+	    cell_num++;
+	    if (cell_num > SA[i].number_of_cells)
+		G_fatal_error(_("To much points in stream line..."));
+	    segment_get(streams, &streams_cell, r, c);
+	} while (streams_cell == SA[i].order);
+
+	if (SA[i].elevation[0] == -99999)
+	    SA[i].elevation[0] = 2 * SA[i].elevation[1] - SA[i].elevation[2];
+    }
+    return 0;
+}
+
+int ram_find_contributing_cell(int r, int c, CELL **dirs, FCELL **elevation)
+{
+    int i, j = 0;
+    int next_r, next_c;
+    float elev_min = 9999;
+
+    for (i = 1; i < 9; ++i) {
+	if (NOT_IN_REGION(i))
+	    continue;
+	next_r = NR(i);
+	next_c = NC(i);
+	if (dirs[next_r][next_c] == DIAG(i) &&
+	    elevation[next_r][next_c] < elev_min) {
+	    elev_min = elevation[next_r][next_c];
+	    j = i;
+	}
+    }
+
+    return j;
+}
+
+int seg_find_contributing_cell(int r, int c, SEGMENT *dirs,
+			       SEGMENT *elevation)
+{
+    int i, j = 0;
+    int next_r, next_c;
+    float elev_min = 9999;
+    int dirs_next_cell;
+    float elevation_next_cell;
+
+    for (i = 1; i < 9; ++i) {
+	if (NOT_IN_REGION(i))
+	    continue;
+	next_r = NR(i);
+	next_c = NC(i);
+	segment_get(elevation, &elevation_next_cell, next_r, next_c);
+	segment_get(dirs, &dirs_next_cell, next_r, next_c);
+
+	if (dirs_next_cell == DIAG(i) && elevation_next_cell < elev_min) {
+	    elev_min = elevation_next_cell;
+	    j = i;
+	}
+    }
+    return j;
+}
+
+int ram_fill_streams(CELL **unique_streams, int number_of_streams)
+{
+    int r, c;
+    int i, j;
+    STREAM *SA;
+
+    SA = stream_attributes;
+
+    for (i = 1; i < number_of_streams; ++i) {
+	for (j = 1; j < SA[i].number_of_cells - 1; ++j) {
+	    r = (int)SA[i].points[j] / ncols;
+	    c = (int)SA[i].points[j] % ncols;
+	    unique_streams[r][c] = SA[i].stream;
+	}
+    }
+    return 0;
+}
+
+int seg_fill_streams(SEGMENT *unique_streams, int number_of_streams)
+{
+    int r, c;
+    int i, j;
+    STREAM *SA;
+
+    SA = stream_attributes;
+
+    for (i = 1; i < number_of_streams; ++i) {
+	for (j = 1; j < SA[i].number_of_cells - 1; ++j) {
+	    r = (int)SA[i].points[j] / ncols;
+	    c = (int)SA[i].points[j] % ncols;
+	    segment_put(unique_streams, &SA[i].stream, r, c);
+	}
+    }
+    return 0;
+}
+
+int ram_identify_next_stream(CELL **streams, int number_of_streams)
+{
+    int r, c;
+    int i;
+    STREAM *SA;
+
+    SA = stream_attributes;
+
+    for (i = 1; i < number_of_streams; ++i) {
+	if (SA[i].points[SA[i].number_of_cells - 1] == -1) {
+	    SA[i].next_stream = -1;
+	    SA[i].outlet = -1;
+	}
+	else {
+	    r = (int)SA[i].points[SA[i].number_of_cells - 1] / ncols;
+	    c = (int)SA[i].points[SA[i].number_of_cells - 1] % ncols;
+	    SA[i].next_stream = streams[r][c];
+	    SA[i].outlet = SA[i].points[SA[i].number_of_cells - 1];
+	}
+    }
+    return 0;
+}
+
+int seg_identify_next_stream(SEGMENT *streams, int number_of_streams)
+{
+    int r, c;
+    int i;
+    STREAM *SA;
+
+    SA = stream_attributes;
+
+    for (i = 1; i < number_of_streams; ++i) {
+	if (SA[i].points[SA[i].number_of_cells - 1] == -1) {
+	    SA[i].next_stream = -1;
+	    SA[i].outlet = -1;
+	}
+	else {
+	    r = (int)SA[i].points[SA[i].number_of_cells - 1] / ncols;
+	    c = (int)SA[i].points[SA[i].number_of_cells - 1] % ncols;
+	    segment_get(streams, &SA[i].next_stream, r, c);
+	    SA[i].outlet = SA[i].points[SA[i].number_of_cells - 1];
+	}
+    }
+    return 0;
+}
+
+
+int free_attributes(int number_of_streams)
+{
+    int i;
+    STREAM *SA;
+
+    SA = stream_attributes;
+
+    for (i = 1; i < number_of_streams; ++i) {
+	G_free(SA[i].points);
+	G_free(SA[i].elevation);
+	G_free(SA[i].distance);
+	G_free(SA[i].sector_breakpoints);
+	G_free(SA[i].sector_cats);
+	G_free(SA[i].sector_directions);
+	G_free(SA[i].sector_lengths);
+	G_free(SA[i].sector_drops);
+    }
+    G_free(stream_attributes);
+    return 0;
+}
+
+
+int convert_border_dir(int r, int c, int dir)
+{
+    /* this function must be added to other modules */
+    /* this is added to fix r.stream.extract issue with broder cell direction */
+    if (dir)
+	return dir;
+
+    if (r == 0 && c == 0)
+	return -3;
+    else if (r == 0 && c == ncols - 1)
+	return -1;
+    else if (r == nrows - 1 && c == ncols - 1)
+	return -7;
+    else if (r == nrows - 1 && c == 0)
+	return -5;
+    else if (r == 0)
+	return -2;
+    else if (r == nrows - 1)
+	return -6;
+    else if (c == 0)
+	return -4;
+    else if (c == ncols - 1)
+	return -8;
+    else
+	return 0;
+}

Added: grass-addons/grass7/grass7/raster/r.stream.segment/stream_vector.c
===================================================================
--- grass-addons/grass7/grass7/raster/r.stream.segment/stream_vector.c	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.stream.segment/stream_vector.c	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,344 @@
+#include "local_proto.h"
+
+int create_sector_vector(char *out_vector, int number_of_streams, int radians)
+{
+    int i, j, k;
+    int r, c, d;
+    int start, stop;
+    float northing, easting;
+    struct Map_info Out;
+    struct line_pnts *Segments;
+    struct line_cats *Cats;
+    STREAM *SA = stream_attributes;	/* for better code readability */
+
+    struct field_info *Fi;
+    dbString table_name, db_sql, val_string;
+    dbDriver *driver;
+    dbHandle handle;
+    char *cat_col_name = "cat";
+    char buf[1000];
+
+    int sector_category, segment, sector, order;
+    double direction, azimuth, length, stright, sinusoid;
+    double elev_min, elev_max, drop, gradient;
+
+    Segments = Vect_new_line_struct();
+    Cats = Vect_new_cats_struct();
+    Vect_open_new(&Out, out_vector, 0);
+
+    Vect_reset_line(Segments);
+    Vect_reset_cats(Cats);
+
+    for (i = 1; i < number_of_streams; ++i) {
+	stop = 1;
+	for (j = 0; j < SA[i].number_of_sectors; ++j) {
+	    start = stop;
+	    stop = (j == SA[i].number_of_sectors - 1) ?
+		SA[i].sector_breakpoints[j] +
+		1 : SA[i].sector_breakpoints[j] + 1;
+	    Vect_cat_set(Cats, 1, SA[i].sector_cats[j]);
+	    for (k = start; k <= stop; ++k) {
+		if (SA[i].points[k] == -1) {
+		    d = abs(SA[i].last_cell_dir);
+		    r = NR(d);
+		    c = NC(d);
+		}
+		else {
+		    r = (int)SA[i].points[k] / ncols;
+		    c = (int)SA[i].points[k] % ncols;
+		}
+		easting = window.west + (c + .5) * window.ew_res;
+		northing = window.north - (r + .5) * window.ns_res;
+		Vect_append_point(Segments, easting, northing, 0);
+	    }
+	    Vect_write_line(&Out, GV_LINE, Segments, Cats);
+	    Vect_reset_line(Segments);
+	    Vect_reset_cats(Cats);
+	}
+    }
+
+    /* add attributes */
+    db_init_string(&db_sql);
+    db_init_string(&val_string);
+    db_init_string(&table_name);
+    db_init_handle(&handle);
+
+    Fi = Vect_default_field_info(&Out, 1, NULL, GV_1TABLE);
+    driver = db_start_driver_open_database(Fi->driver, Fi->database);
+    if (driver == NULL) {
+	G_fatal_error(_("Unable to start driver <%s>"), Fi->driver);
+    }
+
+    /* create table */
+    sprintf(buf, "create table %s (%s integer, \
+		segment integer, \
+		sector integer, \
+		s_order integer, \
+		direction double precision, \
+		azimuth double precision, \
+		length double precision, \
+		stright double precision, \
+		sinusoid double precision, \
+		elev_min double precision, \
+		elev_max double precision, \
+		s_drop double precision, \
+		gradient double precision)", Fi->table, cat_col_name);
+
+    //printf("%s \n",buf);
+
+    db_set_string(&db_sql, buf);
+
+    if (db_execute_immediate(driver, &db_sql) != DB_OK) {
+	db_close_database(driver);
+	db_shutdown_driver(driver);
+	G_fatal_error("Cannot create table %s", db_get_string(&db_sql));
+    }
+
+    if (db_create_index2(driver, Fi->table, cat_col_name) != DB_OK)
+	G_warning("cannot create index");
+
+    if (db_grant_on_table(driver, Fi->table,
+			  DB_PRIV_SELECT, DB_GROUP | DB_PUBLIC) != DB_OK)
+	G_fatal_error("cannot grant privileges on table %s", Fi->table);
+
+    db_begin_transaction(driver);
+
+    for (i = 1; i < number_of_streams; ++i) {
+	stop = 1;
+	for (j = 0; j < SA[i].number_of_sectors; ++j) {
+	    start = stop;
+	    stop = SA[i].sector_breakpoints[j];
+
+	    /* calculate and add parameters */
+	    sector_category = SA[i].sector_cats[j];
+	    segment = SA[i].stream;
+	    sector = j + 1;
+	    order = SA[i].order;
+	    direction = SA[i].sector_directions[j];
+	    azimuth = direction <= PI ? direction : direction - PI;
+	    length = SA[i].sector_lengths[j];
+	    stright = SA[i].sector_strights[j];
+	    sinusoid = length / stright;
+	    elev_max = SA[i].elevation[start];
+	    elev_min = SA[i].elevation[stop];
+	    drop = elev_max - elev_min;
+	    gradient = drop / length;
+
+	    if (!radians) {
+		direction = RAD2DEG(direction);
+		azimuth = RAD2DEG(azimuth);
+	    }
+
+	    sprintf(buf, "insert into %s values( %d, %d, %d, %d, \
+																			%f, %f, %f, %f, %f, \
+																			%f, %f, %f, %f)", Fi->table, sector_category, segment, sector, order,	/*4 */
+		    direction, azimuth, length, stright, sinusoid,	/*9 */
+		    elev_max, elev_min, drop, gradient);	/*13 */
+
+	    //printf("%s  \n",buf); }}
+
+
+	    db_set_string(&db_sql, buf);
+
+	    if (db_execute_immediate(driver, &db_sql) != DB_OK) {
+		db_close_database(driver);
+		db_shutdown_driver(driver);
+		G_fatal_error(_("Cannot inset new row: %s"),
+			      db_get_string(&db_sql));
+	    }
+	}
+    }
+    db_commit_transaction(driver);
+    db_close_database_shutdown_driver(driver);
+    Vect_map_add_dblink(&Out, 1, NULL, Fi->table,
+			cat_col_name, Fi->database, Fi->driver);
+
+    Vect_hist_command(&Out);
+    Vect_build(&Out);
+    Vect_close(&Out);
+    return 0;
+
+}
+
+int create_segment_vector(char *out_vector, int number_of_streams,
+			  int radians)
+{
+    int i, k;
+    int r, c, d;
+    float northing, easting;
+    struct Map_info Out;
+    struct line_pnts *Segments;
+    struct line_cats *Cats;
+    STREAM *SA = stream_attributes;	/* for better code readability */
+
+    struct field_info *Fi;
+    dbString table_name, db_sql, val_string;
+    dbDriver *driver;
+    dbHandle handle;
+    char *cat_col_name = "cat";
+    char buf[1000];
+
+    /* variables to store table attributes */
+    int last;
+    int segment, next_segment, order, next_order;
+    double direction, azimuth, length, stright, sinusoid;
+    double elev_min, elev_max, drop, gradient;
+    double out_direction, out_azimuth, out_length, out_drop, out_gradient;
+    double tangent_dir, tangent_azimuth, next_direction, next_azimuth;
+
+    Segments = Vect_new_line_struct();
+    Cats = Vect_new_cats_struct();
+    Vect_open_new(&Out, out_vector, 0);
+
+    Vect_reset_line(Segments);
+    Vect_reset_cats(Cats);
+
+    for (i = 1; i < number_of_streams; ++i) {
+	Vect_cat_set(Cats, 1, SA[i].stream);
+	for (k = 1; k < SA[i].number_of_cells; ++k) {
+	    if (SA[i].points[k] == -1) {
+		d = abs(SA[i].last_cell_dir);
+		r = NR(d);
+		c = NC(d);
+	    }
+	    else {
+		r = (int)SA[i].points[k] / ncols;
+		c = (int)SA[i].points[k] % ncols;
+	    }
+	    easting = window.west + (c + .5) * window.ew_res;
+	    northing = window.north - (r + .5) * window.ns_res;
+	    Vect_append_point(Segments, easting, northing, 0);
+	}
+	Vect_write_line(&Out, GV_LINE, Segments, Cats);
+	Vect_reset_line(Segments);
+	Vect_reset_cats(Cats);
+    }
+
+    /* add attributes */
+    db_init_string(&db_sql);
+    db_init_string(&val_string);
+    db_init_string(&table_name);
+    db_init_handle(&handle);
+
+    Fi = Vect_default_field_info(&Out, 1, NULL, GV_1TABLE);
+    driver = db_start_driver_open_database(Fi->driver, Fi->database);
+    if (driver == NULL) {
+	G_fatal_error(_("Unable to start driver <%s>"), Fi->driver);
+    }
+
+    /* create table */
+    sprintf(buf, "create table %s (%s integer, \
+		segment integer, \
+		next_segment integer, \
+		s_order integer, \
+		next_order integer, \
+		direction double precision, \
+		azimuth double precision, \
+		length double precision, \
+		stright double precision, \
+		sinusoid double precision, \
+		elev_min double precision, \
+		elev_max double precision, \
+		s_drop double precision, \
+		gradient double precision, \
+		out_direction double precision, \
+		out_azimuth double precision, \
+		out_length double precision, \
+		out_drop double precision, \
+		out_gradient double precision, \
+		tangent_dir double precision, \
+		tangent_azimuth double precision, \
+		next_direction double precision, \
+		next_azimuth double precision)", Fi->table, cat_col_name);
+
+    //printf("%s \n",buf);
+
+    db_set_string(&db_sql, buf);
+
+    if (db_execute_immediate(driver, &db_sql) != DB_OK) {
+	db_close_database(driver);
+	db_shutdown_driver(driver);
+	G_fatal_error("Cannot create table %s", db_get_string(&db_sql));
+    }
+
+    if (db_create_index2(driver, Fi->table, cat_col_name) != DB_OK)
+	G_warning("cannot create index");
+
+    if (db_grant_on_table(driver, Fi->table,
+			  DB_PRIV_SELECT, DB_GROUP | DB_PUBLIC) != DB_OK)
+	G_fatal_error("cannot grant privileges on table %s", Fi->table);
+
+    db_begin_transaction(driver);
+
+    for (i = 1; i < number_of_streams; ++i) {
+	/* calculate and add parameters */
+	segment = SA[i].stream;
+	next_segment = SA[i].next_stream;
+	order = SA[i].order;
+	next_order = next_segment == -1 ? -1 : SA[next_segment].order;
+	direction = SA[i].direction;
+	azimuth = direction <= PI ? direction : direction - PI;
+	length = SA[i].length;
+	stright = SA[i].stright;
+	sinusoid = length / stright;
+	elev_max = SA[i].elevation[1];
+	elev_min = SA[i].elevation[SA[i].number_of_cells - 1];
+	drop = SA[i].drop;
+	gradient = drop / length;
+	last = SA[i].number_of_sectors - 1;
+	out_direction = SA[i].sector_directions[last];
+	out_azimuth =
+	    out_direction <= PI ? out_direction : out_direction - PI;
+	out_length = SA[i].sector_lengths[last];
+	out_drop = SA[i].sector_drops[last];
+	out_gradient = out_drop / out_length;
+	tangent_dir = SA[i].tangent;
+	tangent_azimuth = tangent_dir <= PI ? tangent_dir : tangent_dir - PI;
+	next_direction = SA[i].continuation;
+	next_azimuth =
+	    next_direction <= PI ? next_direction : next_direction - PI;
+
+	if (!radians) {
+	    direction = RAD2DEG(direction);
+	    azimuth = RAD2DEG(azimuth);
+	    out_direction = RAD2DEG(out_direction);
+	    out_azimuth = RAD2DEG(out_azimuth);
+	    tangent_dir = RAD2DEG(tangent_dir);
+	    tangent_azimuth = RAD2DEG(tangent_azimuth);
+	    next_direction = RAD2DEG(next_direction);
+	    next_azimuth = RAD2DEG(next_azimuth);
+	}
+
+	sprintf(buf, "insert into %s values( %d, %d, %d, %d, %d, \
+																			%f, %f, %f, %f, %f, \
+																			%f, %f, %f, %f,			\
+																			%f, %f, %f, %f, %f, \
+																			%f, %f, %f, %f)", Fi->table, i, segment, next_segment, order, next_order,	/*5 */
+		direction, azimuth, length, stright, sinusoid,	/*10 */
+		elev_max, elev_min, drop, gradient,	/*14 */
+		out_direction, out_azimuth, out_length, out_drop, out_gradient,	/*19 */
+		tangent_dir, tangent_azimuth, next_direction, next_azimuth);	/*23 */
+
+	/* printf("%s  \n",buf); */
+
+
+	db_set_string(&db_sql, buf);
+
+	if (db_execute_immediate(driver, &db_sql) != DB_OK) {
+	    db_close_database(driver);
+	    db_shutdown_driver(driver);
+	    G_fatal_error(_("Cannot inset new row: %s"),
+			  db_get_string(&db_sql));
+	}
+
+    }
+    db_commit_transaction(driver);
+    db_close_database_shutdown_driver(driver);
+    Vect_map_add_dblink(&Out, 1, NULL, Fi->table,
+			cat_col_name, Fi->database, Fi->driver);
+
+    Vect_hist_command(&Out);
+    Vect_build(&Out);
+    Vect_close(&Out);
+    return 0;
+}

Added: grass-addons/grass7/grass7/raster/r.stream.slope/Makefile
===================================================================
--- grass-addons/grass7/grass7/raster/r.stream.slope/Makefile	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.stream.slope/Makefile	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,11 @@
+MODULE_TOPDIR = ../..
+
+PGM = r.stream.slope
+
+LIBES = $(GISLIB) $(RASTERLIB) $(SEGMENTLIB)
+DEPENDENCIES = $(GISDEP) $(RASTERDEP) $(SEGMENTDEP)
+
+include $(MODULE_TOPDIR)/include/Make/Module.make
+
+default: cmd
+

Added: grass-addons/grass7/grass7/raster/r.stream.slope/main.c
===================================================================
--- grass-addons/grass7/grass7/raster/r.stream.slope/main.c	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.stream.slope/main.c	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,403 @@
+
+/****************************************************************************
+ *
+ * MODULE:       r.stream.slope
+ * AUTHOR(S):    Jarek Jasiewicz jarekj amu.edu.pl
+ *               
+ * PURPOSE:      Suplementary module for r.stream.distance for slope subsystem, 
+ * 							 calculate local downsteam elevation change 
+ * 							 and local downstream minimum and maximum curvature
+        
+ * COPYRIGHT:    (C) 2002,2010 by the GRASS Development Team
+ *
+ *               This program is free software under the GNU General Public
+ *   	    	 	  License (>=v2). Read the file COPYING that comes with GRASS
+ *   	    	 	  for details.
+ *
+ *****************************************************************************/
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <grass/gis.h>
+#include <grass/raster.h>
+#include <grass/glocale.h>
+#define MAIN
+
+
+#define SQRT2 1.414214
+#define NR(x) r + nextr[(x)]
+#define NC(x) c + nextc[(x)]
+#define DIAG(x) (((x) + 4) > 8 ? ((x) - 4) : ((x) + 4))
+#define NOT_IN_REGION(x) (r+nextr[(x)] < 0 || r+nextr[(x)] > 2 || c+nextc[(x)] < 0 || c+nextc[(x)] > (ncols-1))
+
+int nextr[9] = { 0, -1, -1, -1, 0, 1, 1, 1, 0 };
+int nextc[9] = { 0, 1, 0, -1, -1, -1, 0, 1, 1 };
+
+int nrows, ncols;
+CELL **dir_rows;
+DCELL **elev_rows;
+struct Cell_head window;
+
+DCELL calculate_difference(int r, int c);
+DCELL calculate_gradient(int r, int c);
+DCELL calculate_max_curvature(int r, int c);
+DCELL calculate_min_curvature(int r, int c);
+
+int main(int argc, char *argv[])
+{
+    struct GModule *module;
+    struct Option *in_dir_opt,	/* options */
+     *in_elev_opt,
+	*out_differnce_opt,
+	*out_gradient_opt, *out_max_curv_opt, *out_min_curv_opt;
+    struct Cell_head cellhd;
+    struct History history;
+
+    int r, c, d, i, cur_row;
+    int elev_map_type, elev_data_size;
+    int gradient;
+
+    int in_dir_fd, in_elev_fd;
+    int out_difference_fd, out_gradient_fd, out_max_curv_fd, out_min_curv_fd;
+    double cellsize;
+    char *mapset;
+    void *tmp_buffer;
+    DCELL *tmp_elev_buf;
+    CELL *tmp_dir_buf;
+    DCELL *out_difference_buf, *out_gradient_buf, *out_max_curv_buf,
+	*out_min_curv_buf;
+
+    G_gisinit(argv[0]);
+    module = G_define_module();
+    module->description = _("Calculate local parameters for slope subsystem");
+
+    in_dir_opt = G_define_standard_option(G_OPT_R_INPUT);
+    in_dir_opt->key = "dir";
+    in_dir_opt->description = "Name of flow direction input map";
+
+    in_elev_opt = G_define_standard_option(G_OPT_R_INPUT);
+    in_elev_opt->key = "elevation";
+    in_elev_opt->description = "Name of elevation map";
+
+    out_differnce_opt = G_define_standard_option(G_OPT_R_OUTPUT);
+    out_differnce_opt->key = "difference";
+    out_differnce_opt->required = NO;
+    out_differnce_opt->description =
+	"Output local downstream elevation difference";
+
+    out_gradient_opt = G_define_standard_option(G_OPT_R_OUTPUT);
+    out_gradient_opt->key = "gradient";
+    out_gradient_opt->required = NO;
+    out_gradient_opt->description = "Output local downstream gradient";
+
+    out_max_curv_opt = G_define_standard_option(G_OPT_R_OUTPUT);
+    out_max_curv_opt->key = "maxcurv";
+    out_max_curv_opt->required = NO;
+    out_max_curv_opt->description =
+	"Output local downstream maximium cuvature";
+
+    out_min_curv_opt = G_define_standard_option(G_OPT_R_OUTPUT);
+    out_min_curv_opt->key = "mincurv";
+    out_min_curv_opt->required = NO;
+    out_min_curv_opt->description =
+	"Output local downstream minimum cuvature";
+
+    if (G_parser(argc, argv))	/* parser */
+	exit(EXIT_FAILURE);
+
+    /* open map */
+    mapset = (char *)G_find_raster2(in_dir_opt->answer, "");
+    if (mapset == NULL)
+	G_fatal_error(_("Raster map <%s> not found"), in_dir_opt->answer);
+
+    G_get_window(&window);
+    Rast_get_cellhd(in_dir_opt->answer, mapset, &cellhd);
+    if (window.ew_res != cellhd.ew_res || window.ns_res != cellhd.ns_res)
+	G_fatal_error(_("Region resolution and map %s resolution differs. \
+		Run g.region rast=%s to set proper region resolution"), in_dir_opt->answer, in_dir_opt->answer);
+
+    if (Rast_map_type(in_dir_opt->answer, mapset) != CELL_TYPE)
+	G_fatal_error(_("<%s> is not of type CELL"), in_dir_opt->answer);
+
+    in_dir_fd = Rast_open_old(in_dir_opt->answer, mapset);
+
+    mapset = (char *)G_find_raster2(in_elev_opt->answer, "");
+    if (mapset == NULL)
+	G_fatal_error(_("Raster map <%s> not found"), in_elev_opt->answer);
+
+    elev_map_type = Rast_map_type(in_elev_opt->answer, mapset);
+    elev_data_size = Rast_cell_size(elev_map_type);
+    in_elev_fd = Rast_open_old(in_elev_opt->answer, mapset);
+
+    nrows = Rast_window_rows();
+    ncols = Rast_window_cols();
+
+    G_begin_distance_calculations();
+
+    if (out_differnce_opt->answer) {
+	out_difference_fd =
+	    Rast_open_new(out_differnce_opt->answer, DCELL_TYPE);
+	out_difference_buf = Rast_allocate_d_buf();
+    }
+
+    if (out_gradient_opt->answer) {
+	out_gradient_fd = Rast_open_new(out_gradient_opt->answer, DCELL_TYPE);
+	out_gradient_buf = Rast_allocate_d_buf();
+    }
+
+    if (out_max_curv_opt->answer) {
+	out_max_curv_fd = Rast_open_new(out_max_curv_opt->answer, DCELL_TYPE);
+	out_max_curv_buf = Rast_allocate_d_buf();
+    }
+
+    if (out_min_curv_opt->answer) {
+	out_min_curv_fd = Rast_open_new(out_min_curv_opt->answer, DCELL_TYPE);
+	out_min_curv_buf = Rast_allocate_d_buf();
+    }
+
+    dir_rows = (CELL **) G_malloc(3 * sizeof(CELL *));
+    elev_rows = (DCELL **) G_malloc(3 * sizeof(DCELL *));
+
+    /* init shift buffer */
+    tmp_buffer = Rast_allocate_buf(elev_map_type);
+
+    for (i = 0; i < 3; ++i) {
+	dir_rows[i] = Rast_allocate_c_buf();
+	elev_rows[i] = Rast_allocate_d_buf();
+	Rast_get_row(in_dir_fd, dir_rows[i], i, CELL_TYPE);
+	Rast_get_row(in_elev_fd, tmp_buffer, i, elev_map_type);
+	for (c = 0; c < ncols; ++c)
+	    elev_rows[i][c] =
+		Rast_get_d_value(tmp_buffer + c * elev_data_size,
+				 elev_map_type);
+    }
+
+    for (r = 0; r < nrows; ++r) {	/*main loop */
+
+	G_percent(r, nrows, 2);
+
+	if (r == 0)
+	    cur_row = 0;
+	else if (r == (nrows - 1))
+	    cur_row = 2;
+	else
+	    cur_row = 1;
+
+	for (c = 0; c < ncols; ++c) {
+	    if (out_differnce_opt->answer)
+		out_difference_buf[c] = calculate_difference(cur_row, c);
+	    if (out_gradient_opt->answer)
+		out_gradient_buf[c] = calculate_gradient(cur_row, c);
+	    if (out_max_curv_opt->answer)
+		out_max_curv_buf[c] = calculate_max_curvature(cur_row, c);
+	    if (out_min_curv_opt->answer)
+		out_min_curv_buf[c] = calculate_min_curvature(cur_row, c);
+	}
+
+	if (out_differnce_opt->answer)
+	    Rast_put_row(out_difference_fd, out_difference_buf, DCELL_TYPE);
+	if (out_gradient_opt->answer)
+	    Rast_put_row(out_gradient_fd, out_gradient_buf, DCELL_TYPE);
+	if (out_max_curv_opt->answer)
+	    Rast_put_row(out_max_curv_fd, out_max_curv_buf, DCELL_TYPE);
+	if (out_min_curv_opt->answer)
+	    Rast_put_row(out_min_curv_fd, out_min_curv_buf, DCELL_TYPE);
+
+	/* shift buffer */
+
+	if (r != 0 && r < nrows - 2) {
+
+	    tmp_elev_buf = elev_rows[0];
+	    tmp_dir_buf = dir_rows[0];
+
+	    for (i = 1; i < 3; ++i) {
+		dir_rows[i - 1] = dir_rows[i];
+		elev_rows[i - 1] = elev_rows[i];
+	    }
+
+	    dir_rows[2] = tmp_dir_buf;
+	    elev_rows[2] = tmp_elev_buf;
+	    Rast_get_row(in_dir_fd, dir_rows[2], r + 2, CELL_TYPE);
+	    Rast_get_row(in_elev_fd, tmp_buffer, r + 2, elev_map_type);
+
+	    for (c = 0; c < ncols; ++c)
+		elev_rows[2][c] =
+		    Rast_get_d_value(tmp_buffer + c * elev_data_size,
+				     elev_map_type);
+	}
+    }
+    G_percent(r, nrows, 2);
+
+    if (out_differnce_opt->answer) {
+	G_free(out_difference_buf);
+	Rast_close(out_difference_fd);
+	Rast_short_history(out_differnce_opt->answer, "raster", &history);
+	Rast_command_history(&history);
+	Rast_write_history(out_differnce_opt->answer, &history);
+    }
+
+    if (out_gradient_opt->answer) {
+	G_free(out_gradient_buf);
+	Rast_close(out_gradient_fd);
+	Rast_short_history(out_gradient_opt->answer, "raster", &history);
+	Rast_command_history(&history);
+	Rast_write_history(out_gradient_opt->answer, &history);
+    }
+
+    if (out_max_curv_opt->answer) {
+	G_free(out_max_curv_buf);
+	Rast_close(out_max_curv_fd);
+	Rast_short_history(out_max_curv_opt->answer, "raster", &history);
+	Rast_command_history(&history);
+	Rast_write_history(out_max_curv_opt->answer, &history);
+    }
+
+    if (out_min_curv_opt->answer) {
+	G_free(out_min_curv_buf);
+	Rast_close(out_min_curv_fd);
+	Rast_short_history(out_min_curv_opt->answer, "raster", &history);
+	Rast_command_history(&history);
+	Rast_write_history(out_min_curv_opt->answer, &history);
+    }
+
+    exit(EXIT_SUCCESS);
+}
+
+DCELL calculate_difference(int r, int c)
+{
+    int d;
+
+    d = dir_rows[r][c];
+
+    if (NOT_IN_REGION(d))
+	return 0.;
+    return elev_rows[r][c] - elev_rows[NR(d)][NC(d)];
+}
+
+
+DCELL calculate_gradient(int r, int c)
+{
+
+    int d;
+    double easting, northing, next_easting, next_northing;
+    double distance;
+
+    d = dir_rows[r][c];
+
+    if (NOT_IN_REGION(d))
+	return 0.;
+
+    northing = window.north - (r + .5) * window.ns_res;
+    easting = window.west + (c + .5) * window.ew_res;
+    next_northing = window.north - (NR(d) + .5) * window.ns_res;
+    next_easting = window.west + (NC(d) + .5) * window.ew_res;
+    distance = G_distance(easting, northing, next_easting, next_northing);
+
+    return (elev_rows[r][c] - elev_rows[NR(d)][NC(d)]) / distance;
+
+
+}
+
+DCELL calculate_max_curvature(int r, int c)
+{
+
+    int i, j = 0, d;
+    double easting, northing, next_easting, next_northing;
+    double elev_max = -1000;
+    double diff_up, diff_down, diff_elev, first_derivative, second_derivative;
+    double distance_up, distance_down, distance;
+
+    d = dir_rows[r][c];
+
+    if (NOT_IN_REGION(d))
+	return 0.;
+
+    for (i = 1; i < 9; ++i) {
+	if (NOT_IN_REGION(i))
+	    continue;
+	if (dir_rows[NR(i)][NC(i)] == DIAG(i) &&
+	    elev_rows[NR(i)][NC(i)] > elev_max) {
+	    elev_max = elev_rows[NR(i)][NC(i)];
+	    j = i;
+	}
+    }
+    if (elev_max == -1000)
+	elev_max = elev_rows[r][c];
+    diff_up = elev_max - elev_rows[r][c];
+    diff_down = elev_rows[r][c] - elev_rows[NR(d)][NC(d)];
+    diff_elev = elev_max - elev_rows[NR(d)][NC(d)];
+    if (diff_elev < 0)
+	diff_elev = 0;
+
+    northing = window.north - (r + .5) * window.ns_res;
+    easting = window.west + (c + .5) * window.ew_res;
+    next_northing = window.north - (NR(j) + .5) * window.ns_res;
+    next_easting = window.west + (NC(j) + .5) * window.ew_res;
+    distance_up = G_distance(easting, northing, next_easting, next_northing);
+
+    northing = window.north - (r + .5) * window.ns_res;
+    easting = window.west + (c + .5) * window.ew_res;
+    next_northing = window.north - (NR(d) + .5) * window.ns_res;
+    next_easting = window.west + (NC(d) + .5) * window.ew_res;
+    distance_down =
+	G_distance(easting, northing, next_easting, next_northing);
+    distance = distance_up + distance_down;
+    first_derivative = diff_elev / distance;
+    second_derivative = (diff_up - diff_down) / distance;
+
+    return second_derivative / pow((1 + first_derivative * first_derivative),
+				   1.5);
+
+}
+
+DCELL calculate_min_curvature(int r, int c)
+{
+    int i, j = 0, d;
+    int next_r, next_c;
+    double easting, northing, next_easting, next_northing;
+    double elev_min = 9999;
+    double diff_up, diff_down, diff_elev, first_derivative, second_derivative;
+    double distance_up, distance_down, distance;
+
+    d = dir_rows[r][c];
+
+    if (NOT_IN_REGION(d))
+	return 0.;
+
+    for (i = 1; i < 9; ++i) {
+	if (NOT_IN_REGION(i))
+	    continue;
+	if (dir_rows[NR(i)][NC(i)] == DIAG(i) &&
+	    elev_rows[NR(i)][NC(i)] < elev_min) {
+	    elev_min = elev_rows[NR(i)][NC(i)];
+	    j = i;
+	}
+    }
+
+
+    if (elev_min == 9999)
+	elev_min = elev_rows[r][c];
+    diff_up = elev_min - elev_rows[r][c];
+    diff_down = elev_rows[r][c] - elev_rows[NR(d)][NC(d)];
+    diff_elev = elev_min - elev_rows[NR(d)][NC(d)];
+
+    northing = window.north - (r + .5) * window.ns_res;
+    easting = window.west + (c + .5) * window.ew_res;
+    next_northing = window.north - (NR(j) + .5) * window.ns_res;
+    next_easting = window.west + (NC(j) + .5) * window.ew_res;
+    distance_up = G_distance(easting, northing, next_easting, next_northing);
+
+    northing = window.north - (r + .5) * window.ns_res;
+    easting = window.west + (c + .5) * window.ew_res;
+    next_northing = window.north - (NR(d) + .5) * window.ns_res;
+    next_easting = window.west + (NC(d) + .5) * window.ew_res;
+    distance_down =
+	G_distance(easting, northing, next_easting, next_northing);
+
+    distance = distance_up + distance_down;
+    first_derivative = diff_elev / distance;
+    second_derivative = (diff_up - diff_down) / distance;
+    return second_derivative / pow((1 + first_derivative * first_derivative),
+				   1.5);
+
+}

Added: grass-addons/grass7/grass7/raster/r.stream.slope/r.stream.slope.html
===================================================================
--- grass-addons/grass7/grass7/raster/r.stream.slope/r.stream.slope.html	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.stream.slope/r.stream.slope.html	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,57 @@
+<h2>DESCRIPTION</h2>
+
+<h2>OPTIONS</h2>
+<dl>
+<dt><b>dirs</b></dt>
+<dd>Flow direction: name of input direction map produced by r.watershed or
+r.stream.extract. If r.stream.extract output map is used, it only has non-NULL
+values in places where streams occur. NULL (nodata) cells are ignored, zero and
+negative values are valid direction data if they vary from -8 to 8 (CCW from
+East in steps of 45 degrees). Direction map shall be of type CELL values. Region
+resolution and map resoultion must be the same.</dd>
+
+<dt><b>elevation</b></dt>
+<dd>Elevation: name of input elevation map or any other map we want to calculate
+. Map can be of type CELL, FCELL or DCELL. It is not restricted to resolution of
+region settings like <b>dirs</b>. </dd>
+</dl>
+<h2>OUTPUTS</h2>
+<dl>
+<dt><b>difference</b></dt>
+<dd>Downstream elevation difference: Difference between elevation of current
+cell and downstream cell. Shall always be posivtive. Negative values show, that
+current cell is pit or depression cell. Module is prepared to be used with
+elevation but can be also used to calculate local difference of any feature
+along watercourses in slope subsystem. In that way elevation map must be
+replaced by map we want to calculate. If we use different map than elevation,
+rest of parameters have no sense to calculate</dd>
+<dt><b>gradient</b></dt>
+<dd>Downstream gradinet: Downstream elevation difference divided by
+distance.</dd>
+<dt><b>maxcurv</b></dt>
+<dd>Maximum linear curvature along watercourse. Calculated along watercourse
+between highest upstream cell, current cell and downstream cell (there can be
+only one or no downstream cell but more than on upstream)</dd>
+<dt><b>maxcurv</b></dt>
+<dd>Calculated along watercourse between lowest upstream cell, current cell and
+downstream cell (there can be only one or no downstream cell but more than on
+upstream)</dd>
+</dl>
+
+
+<h2>SEE ALSO</h2>
+
+<em>
+<a href="r.watershed.html">r.watershed</a>,
+<a href="r.stream.extract.html">r.stream.extract</a>,
+<a href="r.stream.order.html">r.stream.order</a>,
+<a href="r.stream.basins.html">r.stream.basins</a>,
+<a href="r.mapcalc.html">r.mapcalc</a>,
+</em>
+
+<h2>AUTHOR</h2>
+Jarek Jasiewicz, Adam Mickiewicz University, Geoecology and Geoinformation
+Institute.
+
+<p><i>Last changed: $Date: 2011-11-08 22:56:45 +0100 (Tue, 08 Nov 2011) $</i>
+

Added: grass-addons/grass7/grass7/raster/r.stream.snap/Makefile
===================================================================
--- grass-addons/grass7/grass7/raster/r.stream.snap/Makefile	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.stream.snap/Makefile	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,14 @@
+MODULE_TOPDIR = ../..
+
+PGM = r.stream.snap
+
+LIBES = $(GISLIB) $(RASTERLIB) $(SEGMENTLIB) $(VECTORLIB) $(DBMILIB)
+DEPENDENCIES = $(GISDEP) $(RASTERDEP) $(SEGMENTDEP) $(VECTORDEP) $(DBMIDEP)
+
+EXTRA_INC = $(VECT_INC)
+EXTRA_CFLAGS = $(VECT_CFLAGS)
+
+include $(MODULE_TOPDIR)/include/Make/Module.make
+
+default: cmd
+

Added: grass-addons/grass7/grass7/raster/r.stream.snap/io.c
===================================================================
--- grass-addons/grass7/grass7/raster/r.stream.snap/io.c	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.stream.snap/io.c	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,564 @@
+#include "io.h"
+/* all in ram functions section */
+
+int ram_create_map(MAP * map, RASTER_MAP_TYPE data_type)
+{
+
+    /* 
+     * allocates 0 filled nrows*ncols map of type void;
+     * map parameters are stored in structure;
+     * map: map to be created;
+     * map type to be created must be CELL, FCELL, DCELL;
+     * */
+
+    int r;
+
+    if (data_type < 0 || data_type > 2)
+	G_fatal_error(_("ram_creat: Cannot create map of unrecognised type"));
+
+    map->data_type = data_type;
+    map->map_name = NULL;
+    map->nrows = Rast_window_rows();
+    map->ncols = Rast_window_cols();
+    map->data_size = Rast_cell_size(data_type);
+
+    /* preparing internal map */
+    switch (map->data_type) {
+    case CELL_TYPE:
+	map->map = G_calloc(map->nrows, sizeof(CELL *));
+	break;
+
+    case FCELL_TYPE:
+	map->map = G_calloc(map->nrows, sizeof(FCELL *));
+	break;
+
+    case DCELL_TYPE:
+	map->map = G_calloc(map->nrows, sizeof(DCELL *));
+	break;
+    }
+
+    for (r = 0; r < map->nrows; ++r)
+	(map->map)[r] = G_calloc(map->ncols, map->data_size);
+
+    return 0;
+}
+
+int ram_read_map(MAP * map, char *input_map_name, int check_res,
+		 RASTER_MAP_TYPE check_data_type)
+{
+    /*
+     * Funciton read external map and put it in MAP structure (created with create_map)
+     * map: map to be read can be of any data type, read map is converted to target map if neccesary.
+     * input_map_name: name of the map to be read;
+     * map pointer to map stucture (created with create_map);
+     * check_res: [1]: check res correspondence between region and map [0 no check];
+     * check_data_type [CELL, FCELL, DCELL] check if reading map is of particular type, [-1] no check;
+     */
+
+    int r, c;
+    char *mapset;
+    struct Cell_head cellhd, this_window;
+    char *maptypes[] = { "CELL", "FCELL", "DCELL" };
+    int input_map_fd;
+    RASTER_MAP_TYPE input_data_type;
+    size_t input_data_size;
+    void *input_buffer = NULL;
+    void *input_pointer;
+
+    /* checking if map exist */
+    mapset = (char *)G_find_raster2(input_map_name, "");
+    if (mapset == NULL)
+	G_fatal_error(_("Raster map <%s> not found"), input_map_name);
+
+    /* checking if region and input are the same */
+    G_get_window(&this_window);
+    Rast_get_cellhd(input_map_name, mapset, &cellhd);
+    if (check_res)
+	if (this_window.ew_res != cellhd.ew_res ||
+	    this_window.ns_res != cellhd.ns_res)
+	    G_fatal_error(_("Region resolution and map %s resolution differs. \
+		Run g.region rast=%s to set proper region resolution"),
+			  input_map_name, input_map_name);
+
+    /* checking if input map is of required type */
+    if (check_data_type != map->data_type)
+	G_debug(1,
+		"ram_open:required map type and internal map type differs: conversion forced!");
+    input_data_type = Rast_map_type(input_map_name, mapset);
+    if (check_data_type != -1)
+	if (input_data_type != check_data_type)
+	    G_fatal_error(_("<%s> is not of type %s"),
+			  input_map_name, maptypes[check_data_type]);
+
+    input_map_fd = Rast_open_old(input_map_name, mapset);
+    input_data_size = Rast_cell_size(input_data_type);
+
+    {				/* reading range */
+	struct Range map_range;
+	struct FPRange map_fp_range;
+	int min, max;
+
+	if (input_data_type == CELL_TYPE) {
+	    Rast_init_range(&map_range);
+	    Rast_read_range(input_map_name, mapset, &map_range);
+	    Rast_get_range_min_max(&map_range, &min, &max);
+	    map->min = (double)min;
+	    map->max = (double)max;
+	}
+	else {
+	    Rast_init_fp_range(&map_fp_range);
+	    Rast_read_fp_range(input_map_name, mapset, &map_fp_range);
+	    Rast_get_fp_range_min_max(&map_fp_range, &(map->min),
+				      &(map->max));
+	}
+    }
+    /* end opening and checking */
+
+    input_buffer = Rast_allocate_buf(input_data_type);
+
+    /* start reading */
+    G_message(_("Reading map <%s>"), input_map_name);
+
+    for (r = 0; r < map->nrows; ++r) {
+	G_percent(r, map->nrows, 2);
+
+	Rast_get_row(input_map_fd, input_buffer, r, input_data_type);
+	input_pointer = input_buffer;
+
+	for (c = 0; c < map->ncols; ++c)
+	    if (!Rast_is_null_value
+		(input_pointer + c * input_data_size, input_data_type))
+		switch (map->data_type) {
+		case CELL_TYPE:
+		    ((CELL **) map->map)[r][c] =
+			Rast_get_c_value(input_pointer + c * input_data_size,
+					 input_data_type);
+		    break;
+		case FCELL_TYPE:
+		    ((FCELL **) map->map)[r][c] =
+			Rast_get_f_value(input_pointer + c * input_data_size,
+					 input_data_type);
+		    break;
+		case DCELL_TYPE:
+		    ((DCELL **) map->map)[r][c] =
+			Rast_get_d_value(input_pointer + c * input_data_size,
+					 input_data_type);
+		    break;
+		default:
+		    G_fatal_error(_("ram_open:Wrong internal data type"));
+		    break;
+		}
+    }				/*end for r */
+
+    G_free(input_buffer);
+    G_percent(r, map->nrows, 2);
+    Rast_close(input_map_fd);
+    return 0;
+}				/* end create floating point map */
+
+int ram_reset_map(MAP * map, int value)
+{
+    /*
+     * set all cells in the map to value
+     */
+    int r;
+
+    for (r = 0; r < map->nrows; ++r)
+	memset((map->map)[r], value, map->ncols * map->data_size);
+    return 0;
+}
+
+int ram_write_map(MAP * map, char *output_map_name,
+		  RASTER_MAP_TYPE output_data_type, int convert_to_null,
+		  double value)
+{
+    /* 
+     * write map to disk with output_map_name and output_data_type [CELL, FCELL, DCELL];
+     * if output_data_type = -1 than internal map type is used for output;
+     * if output map != -1 and types differ data_type, conversion is forced
+     * convert to null: check if convert to null a particular value in dataset;
+     */
+
+    int r, c;
+    int output_fd = 0;
+    struct History history;
+    void *row;
+
+    /* check for output format */
+    if (output_data_type == -1)
+	output_data_type = map->data_type;
+
+    if (output_data_type != map->data_type)
+	G_debug(1,
+		"ram_write:required map type and internal map type differs: conversion forced!");
+
+    G_message(_("Writing map <%s>"), output_map_name);
+    output_fd = Rast_open_new(output_map_name, output_data_type);
+
+    /* writing */
+    for (r = 0; r < map->nrows; ++r) {
+	G_percent(r, map->nrows, 2);
+
+	if (convert_to_null) {
+	    row = map->map[r];
+	    switch (map->data_type) {
+	    case CELL_TYPE:
+		for (c = 0; c < map->ncols; ++c)
+		    if (((CELL *) row)[c] == (CELL) value)
+			Rast_set_c_null_value(row + c * (map->data_size), 1);
+		break;
+	    case FCELL_TYPE:
+		for (c = 0; c < map->ncols; ++c)
+		    if (((FCELL *) row)[c] == (FCELL) value)
+			Rast_set_f_null_value(row + c * (map->data_size), 1);
+		break;
+	    case DCELL_TYPE:
+		for (c = 0; c < map->ncols; ++c)
+		    if (((DCELL *) row)[c] == (DCELL) value)
+			Rast_set_d_null_value(row + c * (map->data_size), 1);
+		break;
+	    default:
+		G_debug(1, "ram_null:Cannot convert to null at: %d %d", r, c);
+	    }
+	}
+
+	Rast_put_row(output_fd, (map->map)[r], output_data_type);
+    }
+    G_percent(r, map->nrows, 2);
+    Rast_close(output_fd);
+    Rast_short_history(output_map_name, "raster", &history);
+    Rast_command_history(&history);
+    Rast_write_history(output_map_name, &history);
+    G_message(_("<%s> Done"), output_map_name);
+    return 0;
+}
+
+int ram_release_map(MAP *map)
+{
+    /* 
+     * free memory allocated for map, set pointer to null;
+     */
+    int r;
+
+    for (r = 0; r < map->nrows; ++r)
+	G_free((map->map)[r]);
+    G_free(map->map);
+    map = NULL;
+    return 0;
+}
+
+
+/* memory swap functions section */
+
+
+int seg_create_map(SEG * seg, int srows, int scols, int number_of_segs,
+		   RASTER_MAP_TYPE data_type)
+{
+    /* create segment  and returns pointer to it;
+     * seg must be declared first;
+     * parameters are stored in structure;
+     * seg: segment to be created;
+     * srows, scols segment size
+     * number of segs max number of segs stored in memory
+     * data_type to be created must be CELL, FCELL, DCELL;
+     */
+
+    char *filename;
+    int fd;
+    int local_number_of_segs;
+
+    seg->fd = -1;
+    seg->filename = NULL;
+    seg->map_name = NULL;
+    seg->mapset = NULL;
+    seg->data_type = data_type;
+    seg->nrows = Rast_window_rows();
+    seg->ncols = Rast_window_cols();
+
+    local_number_of_segs =
+	(seg->nrows / srows + 1) * (seg->ncols / scols + 1);
+    number_of_segs =
+	(number_of_segs >
+	 local_number_of_segs) ? local_number_of_segs : number_of_segs;
+
+    G_debug(3, "seg_creat:number of segments %d", number_of_segs);
+
+    switch (seg->data_type) {
+    case CELL_TYPE:
+	seg->data_size = sizeof(CELL);
+	break;
+    case FCELL_TYPE:
+	seg->data_size = sizeof(FCELL);
+	break;
+    case DCELL_TYPE:
+	seg->data_size = sizeof(DCELL);
+	break;
+    default:
+	G_fatal_error(_("seg_create: unrecognisabe data type"));
+    }
+
+    filename = G_tempfile();
+    fd = creat(filename, 0666);
+
+    if (0 >
+	segment_format(fd, seg->nrows, seg->ncols, srows, scols,
+		       seg->data_size)) {
+	close(fd);
+	unlink(filename);
+	G_fatal_error(_("seg_create: cannot format segment"));
+    }
+
+    close(fd);
+    if (0 > (fd = open(filename, 2))) {
+	unlink(filename);
+	G_fatal_error(_("seg_create: cannot re-open file"));
+    }
+
+    if (0 > (fd = segment_init(&(seg->seg), fd, number_of_segs))) {
+	unlink(filename);
+	G_fatal_error(_("seg_create: cannot init segment file or out of memory"));
+    }
+
+    seg->filename = G_store(filename);
+    seg->fd = fd;
+    return 0;
+}
+
+int seg_read_map(SEG * seg, char *input_map_name, int check_res,
+		 RASTER_MAP_TYPE check_data_type)
+{
+
+    /*
+     * Funciton read external map and put it in SEG structure (created with seg_create_map)
+     * map to be read can be of any data type, read map is converted if neccesary.
+     * input_map_name: name of the map to be read;
+     * seg: pointer to map stucture (created with create_map);
+     * check_res: [1]: check res correspondence between region and map [0 no check];
+     * check_data_type [CELL, FCELL, DCELL] check if reading map is of particular type, [-1] no check;
+     */
+
+    int input_fd;
+    int r, c;
+    char *mapset;
+    struct Cell_head cellhd, this_window;
+    char *maptypes[] = { "CELL", "FCELL", "DCELL" };
+    RASTER_MAP_TYPE input_data_type;
+    size_t input_data_size;
+    void *input_buffer = NULL;
+    void *target_buffer = NULL;
+    void *input_pointer = NULL;
+
+    /* checking if map exist */
+    mapset = (char *)G_find_raster2(input_map_name, "");
+    if (mapset == NULL)
+	G_fatal_error(_("seg_read:Raster map <%s> not found"),
+		      input_map_name);
+    seg->mapset = mapset;
+
+    /* checking if region and input are the same */
+    G_get_window(&this_window);
+    Rast_get_cellhd(input_map_name, mapset, &cellhd);
+
+    /* check resolution equal anyinteger check;  equal 0 no check */
+    if (check_res)
+	if (this_window.ew_res != cellhd.ew_res ||
+	    this_window.ns_res != cellhd.ns_res)
+	    G_fatal_error(_("Region resolution and map %s resolution differs. \
+		Run g.region rast=%s to set proper region resolution"),
+			  input_map_name, input_map_name);
+
+    if (check_data_type != seg->data_type)
+	G_debug(1,
+		"ram_open:required map type and internal map type differs: conversion forced!");
+    input_data_type = Rast_map_type(input_map_name, mapset);
+    if (check_data_type != -1)
+	if (input_data_type != check_data_type)
+	    G_fatal_error(_("<%s> is not of type %s"),
+			  input_map_name, maptypes[check_data_type]);
+
+    input_fd = Rast_open_old(input_map_name, mapset);
+    input_data_size = Rast_cell_size(input_data_type);
+
+    {				/* reading range */
+	struct Range map_range;
+	struct FPRange map_fp_range;
+	int min, max;
+
+	if (input_data_type == CELL_TYPE) {
+	    Rast_init_range(&map_range);
+	    Rast_read_range(input_map_name, mapset, &map_range);
+	    Rast_get_range_min_max(&map_range, &min, &max);
+	    seg->min = (double)min;
+	    seg->max = (double)max;
+	}
+	else {
+	    Rast_init_fp_range(&map_fp_range);
+	    Rast_read_fp_range(input_map_name, mapset, &map_fp_range);
+	    Rast_get_fp_range_min_max(&map_fp_range, &(seg->min),
+				      &(seg->max));
+	}
+    }
+
+    /* end opening and checking */
+
+    G_message(_("Reading map <%s>"), input_map_name);
+    input_buffer = Rast_allocate_buf(input_data_type);
+
+    target_buffer = Rast_allocate_buf(seg->data_type);
+
+    for (r = 0; r < seg->nrows; ++r) {
+	G_percent(r, seg->nrows, 2);
+	Rast_get_row(input_fd, input_buffer, r, input_data_type);
+	input_pointer = input_buffer;
+	memset(target_buffer, 0, seg->ncols * seg->data_size);
+
+	for (c = 0; c < seg->ncols; ++c)
+	    if (!Rast_is_null_value
+		(input_pointer + c * input_data_size, input_data_type)) {
+		switch (seg->data_type) {
+		case CELL_TYPE:
+		    ((CELL *) target_buffer)[c] =
+			Rast_get_c_value(input_pointer + c * input_data_size,
+					 input_data_type);
+		    break;
+		case FCELL_TYPE:
+		    ((FCELL *) target_buffer)[c] =
+			Rast_get_f_value(input_pointer + c * input_data_size,
+					 input_data_type);
+		    break;
+		case DCELL_TYPE:
+		    ((DCELL *) target_buffer)[c] =
+			Rast_get_d_value(input_pointer + c * input_data_size,
+					 input_data_type);
+		    break;
+		default:
+		    G_fatal_error(_("Wrong internal data type"));
+		    break;
+		}
+	    }
+
+	if (0 > segment_put_row(&(seg->seg), target_buffer, r)) {
+	    G_free(input_buffer);
+	    G_free(target_buffer);
+	    Rast_close(input_fd);
+	    G_fatal_error(_("seg_read: Cannot segment put row %d for map %s"),
+			  r, input_map_name);
+	}
+    }				/* end for row */
+
+    G_percent(r, seg->nrows, 2);
+    Rast_close(input_fd);
+    G_free(input_buffer);
+    G_free(target_buffer);
+
+    seg->map_name = G_store(input_map_name);
+    seg->mapset = G_store(mapset);
+
+    return 0;
+}
+
+int seg_reset_map(SEG * seg, int value)
+{
+    /*
+     * set all cells in the map to value
+     */
+    int r, c;
+
+    for (r = 0; r < seg->nrows; ++r)
+	for (c = 0; c < seg->ncols; ++c)
+	    segment_put(&(seg->seg), &value, r, c);
+
+    return 0;
+}
+
+int seg_write_map(SEG * seg, char *output_map_name,
+		  RASTER_MAP_TYPE output_data_type, int convert_to_null,
+		  double value)
+{
+    /* 
+     * write seg to disk with output_map_name and output_data_type [CELL, FCELL, DCELL];
+     * if output_data_type = -1 than internal map type is used for output;
+     * if output map != -1 and types differ data_type, conversion is forced
+     * convert to null: check if convert to null a particular value in dataset;
+     */
+    int output_fd;
+    int r, c;
+    void *output_buffer;
+    void *row;
+    struct History history;
+
+    /* check for output format */
+    if (output_data_type == -1)
+	output_data_type = seg->data_type;
+
+    if (output_data_type != seg->data_type)
+	G_debug(1,
+		"ram_write:required map type and internal map type differs: conversion forced!");
+
+    G_message(_("Writing map <%s>"), output_map_name);
+    output_fd = Rast_open_new(output_map_name, output_data_type);
+    output_buffer = Rast_allocate_buf(output_data_type);
+    segment_flush(&(seg->seg));
+
+    /* writing */
+    for (r = 0; r < seg->nrows; ++r) {
+
+	G_percent(r, seg->nrows, 2);
+	if (0 > segment_get_row(&(seg->seg), output_buffer, r))
+	    G_warning(_("seg_write: Cannot segment read row %d for map %s"),
+		      r, output_map_name);
+
+	if (convert_to_null) {
+
+	    row = output_buffer;
+	    switch (seg->data_type) {
+	    case CELL_TYPE:
+		for (c = 0; c < seg->ncols; ++c)
+		    if (((CELL *) output_buffer)[c] == (CELL) value)
+			Rast_set_c_null_value(row + c * (seg->data_size), 1);
+		break;
+	    case FCELL_TYPE:
+		for (c = 0; c < seg->ncols; ++c)
+		    if (((FCELL *) output_buffer)[c] == (FCELL) value)
+			Rast_set_f_null_value(row + c * (seg->data_size), 1);
+		break;
+	    case DCELL_TYPE:
+		for (c = 0; c < seg->ncols; ++c)
+		    if (((DCELL *) output_buffer)[c] == (DCELL) value)
+			Rast_set_d_null_value(row + c * (seg->data_size), 1);
+		break;
+	    default:
+		G_warning(_("ram_null:Cannot convert to null at: %d %d"), r,
+			  c);
+	    }
+	}
+	Rast_put_row(output_fd, output_buffer, output_data_type);
+    }
+
+    G_percent(r, seg->nrows, 2);
+    G_free(output_buffer);
+    Rast_close(output_fd);
+    Rast_short_history(output_map_name, "raster", &history);
+    Rast_command_history(&history);
+    Rast_write_history(output_map_name, &history);
+    G_message(_("%s Done"), output_map_name);
+
+    return 0;
+}
+
+int seg_release_map(SEG * seg)
+{
+    /* 
+     * release segment close files, set pointers to null;
+     */
+    segment_release(&(seg->seg));
+    close(seg->fd);
+    unlink(seg->filename);
+
+    if (seg->map_name)
+	G_free(seg->map_name);
+    if (seg->mapset)
+	G_free(seg->mapset);
+
+    return 0;
+}

Added: grass-addons/grass7/grass7/raster/r.stream.snap/io.h
===================================================================
--- grass-addons/grass7/grass7/raster/r.stream.snap/io.h	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.stream.snap/io.h	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,59 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <string.h>
+#include <math.h>
+#include <grass/glocale.h>
+#include <grass/gis.h>
+#include <grass/raster.h>
+#include <grass/segment.h>
+
+#define NOT_IN_REGION(x) (r + nextr[(x)] < 0 || r + nextr[(x)] > (nrows - 1) || \
+                          c + nextc[(x)] < 0 || c + nextc[(x)] > (ncols - 1))
+#define NR(x) (r + nextr[(x)])
+#define NC(x) (c + nextc[(x)])
+#define INDEX(r,c) ((r) * ncols + (c))
+#define DIAG(x) (((x) + 4) > 8 ? ((x) - 4) : ((x) + 4))
+
+#define SROWS 256
+#define SCOLS 256
+
+typedef struct {
+	void **map; /* matrix of data */
+	double min, max; /* data range : may requre casting */
+	int nrows, ncols;
+	char *map_name; /* map name, unused */
+	RASTER_MAP_TYPE data_type; /* type of data */
+	size_t data_size; /* type of data */
+} MAP;
+
+typedef struct {
+	SEGMENT seg;		/* segmented data store */
+	int fd;					/* segment temporary file name descriptor */
+	char *filename; /* segment temporary file name */
+	char *map_name; /* map name converted to segment */
+	char *mapset;
+	int nrows, ncols; /* store nrows and rcols */
+	RASTER_MAP_TYPE data_type; /* data type of the map */
+	size_t data_size; /* size of cell returned by sizeof */
+	double min, max; /* data range */
+} SEG;
+
+
+/* all in ram functions */
+int ram_create_map(MAP *, RASTER_MAP_TYPE);
+int ram_read_map(MAP *, char *, int, RASTER_MAP_TYPE);
+int ram_reset_map(MAP *, int);
+int ram_write_map(MAP *, char *, RASTER_MAP_TYPE, int, double);
+int ram_release_map(MAP *);
+int ram_destory_map(MAP *);
+
+/* memory swap functions */
+int seg_create_map(SEG *, int, int, int, RASTER_MAP_TYPE);
+int seg_read_map(SEG *, char *, int, RASTER_MAP_TYPE);
+int seg_reset_map (SEG *, int);
+int seg_write_map(SEG *, char *, RASTER_MAP_TYPE, int, double);
+int seg_release_map(SEG *);
+

Added: grass-addons/grass7/grass7/raster/r.stream.snap/local_proto.h
===================================================================
--- grass-addons/grass7/grass7/raster/r.stream.snap/local_proto.h	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.stream.snap/local_proto.h	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,11 @@
+#include "io.h"
+#include "local_vars.h"
+
+/* snap.c */
+int create_distance_mask(int);
+int read_points(char *, SEGMENT *, SEGMENT *);
+int snap_point(OUTLET *, int, SEGMENT *, SEGMENT *, double);
+
+/* points_io.c */
+int write_points(char *, int);
+

Added: grass-addons/grass7/grass7/raster/r.stream.snap/local_vars.h
===================================================================
--- grass-addons/grass7/grass7/raster/r.stream.snap/local_vars.h	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.stream.snap/local_vars.h	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,34 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include <grass/glocale.h>
+#include <grass/gis.h>
+#include <grass/raster.h>
+#include <grass/vector.h>
+#include <grass/dbmi.h>
+
+#ifdef MAIN
+#  define GLOBAL
+#else
+#  define GLOBAL extern
+#endif
+
+#define SQR(x) ((x) * (x))
+
+typedef struct
+{
+    int r, c;
+    int di, dj;			/* shift */
+    int cat;
+    double accum;
+    int stream;
+    int status;			/* 1=skipped,2=unresolved,3=snapped,4=correct */
+} OUTLET;
+
+GLOBAL int nextr[9];
+GLOBAL int nextc[9];
+
+GLOBAL OUTLET *points;
+GLOBAL int nrows, ncols;
+GLOBAL float **distance_mask;

Added: grass-addons/grass7/grass7/raster/r.stream.snap/main.c
===================================================================
--- grass-addons/grass7/grass7/raster/r.stream.snap/main.c	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.stream.snap/main.c	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,145 @@
+
+/****************************************************************************
+ *
+ * MODULE:       r.stream.snap
+ * AUTHOR(S):    Jarek Jasiewicz jarekj amu.edu.pl
+ *               
+ * PURPOSE:      Snap ponints features to nearest pour points. Usefull both to
+ *               snap outlets well as sources. Use two parameters: 
+ *               maximum snap distance and minimum accumulation value to snap
+ *               
+ *
+ * COPYRIGHT:    (C) 2002,2010 by the GRASS Development Team
+ *
+ *               This program is free software under the GNU General Public
+ *   	    	 	  License (>=v2). Read the file COPYING that comes with GRASS
+ *   	    	 	  for details.
+ *
+ *****************************************************************************/
+#define MAIN
+#include <grass/glocale.h>
+#include "local_proto.h"
+
+int nextr[9] = { 0, -1, -1, -1, 0, 1, 1, 1, 0 };
+int nextc[9] = { 0, 1, 0, -1, -1, -1, 0, 1, 1 };
+
+int main(int argc, char *argv[])
+{
+
+    struct GModule *module;
+    struct Option *in_points_opt,
+	*out_points_opt,
+	*in_stream_opt,
+	*in_accum_opt,
+	*opt_accum_treshold, *opt_distance_treshold, *opt_swapsize;
+
+    int i;
+    SEG map_streams, map_accum;
+    SEGMENT *streams = NULL, *accum = NULL;
+    int number_of_segs;
+    int number_of_points;
+    int radius;
+    double accum_treshold;
+
+    G_gisinit(argv[0]);
+
+    module = G_define_module();
+    module->description = _("Delineate basins according user' input. \
+	Input can be stream network, point file with outlets or outlet coordinates");
+    G_add_keyword("basins creation");
+
+    in_points_opt = G_define_standard_option(G_OPT_V_INPUT);
+    in_points_opt->description = _("Name of input vector points map");
+
+    out_points_opt = G_define_standard_option(G_OPT_V_OUTPUT);
+    out_points_opt->description = _("Name of output vector points map");
+
+    in_stream_opt = G_define_standard_option(G_OPT_R_INPUT);
+    in_stream_opt->key = "streams";
+    in_stream_opt->required = NO;
+    in_stream_opt->description = _("Name of stream map");
+
+    in_accum_opt = G_define_standard_option(G_OPT_R_INPUT);
+    in_accum_opt->key = "accum";
+    in_accum_opt->required = NO;
+    in_accum_opt->description = _("Name of accumulation map");
+
+    opt_accum_treshold = G_define_option();
+    opt_accum_treshold->key = "accumtres";
+    opt_accum_treshold->type = TYPE_DOUBLE;
+    opt_accum_treshold->answer = "-1";
+    opt_accum_treshold->description =
+	_("Minimum accumulation streshold to snap");
+
+    opt_distance_treshold = G_define_option();
+    opt_distance_treshold->key = "radius";
+    opt_distance_treshold->answer = "1";
+    opt_distance_treshold->type = TYPE_INTEGER;
+    opt_distance_treshold->description =
+	_("Maximum distance to snap (in cells)");
+
+    opt_swapsize = G_define_option();
+    opt_swapsize->key = "memory";
+    opt_swapsize->type = TYPE_INTEGER;
+    opt_swapsize->answer = "300";
+    opt_swapsize->required = NO;
+    opt_swapsize->description = _("Max memory used (MB)");
+
+    if (G_parser(argc, argv))	/* parser */
+	exit(EXIT_FAILURE);
+
+    number_of_segs = (int)atof(opt_swapsize->answer);
+    number_of_segs = number_of_segs < 32 ? (int)(32 / 0.12) : number_of_segs / 0.12;
+
+    radius = atoi(opt_distance_treshold->answer);
+    accum_treshold = atof(opt_accum_treshold->answer);
+
+    nrows = Rast_window_rows();
+    ncols = Rast_window_cols();
+
+    if (G_legal_filename(out_points_opt->answer) < 0)
+	G_fatal_error(_("<%s> is an illegal basin name"),
+		      out_points_opt->answer);
+
+    if (!in_stream_opt->answer && !in_accum_opt->answer)
+	G_fatal_error(_("At least one map of accumulation or streams is required"));
+
+    if (!in_accum_opt->answer)
+	accum_treshold = -1;
+
+
+    /* SEGMENT VERSION ONLY */
+
+    if (in_stream_opt->answer) {
+	seg_create_map(&map_streams, SROWS, SCOLS, number_of_segs, CELL_TYPE);
+	seg_read_map(&map_streams, in_stream_opt->answer, 1, CELL_TYPE);
+	streams = &map_streams.seg;
+    }
+
+    if (in_accum_opt->answer) {
+	seg_create_map(&map_accum, SROWS, SCOLS, number_of_segs, DCELL_TYPE);
+	seg_read_map(&map_accum, in_accum_opt->answer, 0, -1);
+	accum = &map_accum.seg;
+    }
+
+    create_distance_mask(radius);
+    number_of_points = read_points(in_points_opt->answer, streams, accum);
+
+    for (i = 0; i < number_of_points; ++i)
+	snap_point(&points[i], radius, streams, accum, accum_treshold);
+
+    write_points(out_points_opt->answer, number_of_points);
+
+
+    for (i = 0; i < number_of_points; ++i)
+	G_message("AFTER %d %d %d %d",
+		  points[i].r, points[i].c, points[i].di, points[i].dj);
+
+
+    if (in_stream_opt->answer)
+	seg_release_map(&map_streams);
+    if (in_accum_opt->answer)
+	seg_release_map(&map_accum);
+
+    exit(EXIT_SUCCESS);
+}

Added: grass-addons/grass7/grass7/raster/r.stream.snap/points_io.c
===================================================================
--- grass-addons/grass7/grass7/raster/r.stream.snap/points_io.c	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.stream.snap/points_io.c	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,119 @@
+#include "local_proto.h"
+
+int read_points(char *in_point, SEGMENT * streams, SEGMENT * accum)
+{
+    char *mapset;
+    struct Cell_head window;
+    struct Map_info Map;
+    struct bound_box box;
+    int num_point = 0;
+    int total_points = 0;
+    int type, i, j, cat;
+    struct line_pnts *sites;
+    struct line_cats *cats;
+    double absaccum;
+
+    sites = Vect_new_line_struct();
+    cats = Vect_new_cats_struct();
+
+    mapset = G_find_vector2(in_point, "");
+    if (mapset == NULL)
+	G_fatal_error(_("Vector map <%s> not found"), in_point);
+
+    if (Vect_open_old(&Map, in_point, mapset) < 0)
+	G_fatal_error("Cannot open vector map <%s>", in_point);
+
+    G_get_window(&window);
+    Vect_region_box(&window, &box);
+
+    while ((type = Vect_read_next_line(&Map, sites, cats)) > -1) {
+	if (type != GV_POINT)
+	    continue;
+	if (Vect_point_in_box(sites->x[0], sites->y[0], sites->z[0], &box))
+	    num_point++;
+    }
+
+    points = (OUTLET *) G_malloc(num_point * sizeof(OUTLET));
+    total_points = Vect_get_num_lines(&Map);
+    i = 0;
+
+    for (j = 0; j < total_points; ++j) {
+
+	type = Vect_read_line(&Map, sites, cats, j + 1);
+
+	if (type != GV_POINT)
+	    continue;
+
+	if (!Vect_point_in_box(sites->x[0], sites->y[0], sites->z[0], &box))
+	    continue;
+
+	Vect_cat_get(cats, 1, &cat);
+
+	points[i].r = (int)Rast_northing_to_row(sites->y[0], &window);
+	points[i].c = (int)Rast_easting_to_col(sites->x[0], &window);
+	points[i].di = 0;
+	points[i].dj = 0;
+	points[i].cat = cat;
+	if (streams)
+	    segment_get(streams, &points[i].stream, points[i].r, points[i].c);
+	else
+	    points[i].stream = 0;
+	if (accum) {
+	    segment_get(accum, &absaccum, points[i].r, points[i].c);
+	    points[i].accum = fabs(absaccum);
+	}
+	else {
+	    points[i].accum = 0;
+	    points[i].status = 4;	/* default status is 'correct' */
+	}
+	//dodać skip category
+
+	i++;
+    }
+    return num_point;
+}
+
+int write_points(char *out_vector, int number_of_points)
+{
+
+    int i;
+    int r, c;
+    int cat_layer_1, cat_layer_2;
+    float northing, easting;
+    struct Cell_head window;
+    struct Map_info Out;
+    struct line_pnts *Segments;
+    struct line_cats *Cats;
+
+    G_get_window(&window);
+    Segments = Vect_new_line_struct();
+    Cats = Vect_new_cats_struct();
+    Vect_open_new(&Out, out_vector, 0);
+
+    Vect_reset_line(Segments);
+    Vect_reset_cats(Cats);
+
+    for (i = 0; i < number_of_points; ++i) {
+
+	r = points[i].r + points[i].di;
+	c = points[i].c + points[i].dj;
+
+	cat_layer_1 = points[i].cat;
+	cat_layer_2 = points[i].status;
+	Vect_cat_set(Cats, 1, cat_layer_1);
+	Vect_cat_set(Cats, 2, cat_layer_2);
+	easting = window.west + (c + .5) * window.ew_res;
+	northing = window.north - (r + .5) * window.ns_res;
+	Vect_append_point(Segments, easting, northing, 0);
+	Vect_write_line(&Out, GV_POINT, Segments, Cats);
+	Vect_reset_line(Segments);
+	Vect_reset_cats(Cats);
+    }
+
+    /* build vector */
+    Vect_hist_command(&Out);
+    Vect_build(&Out);
+    Vect_close(&Out);
+
+    return 0;
+}

Added: grass-addons/grass7/grass7/raster/r.stream.snap/r.stream.snap.html
===================================================================
--- grass-addons/grass7/grass7/raster/r.stream.snap/r.stream.snap.html	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.stream.snap/r.stream.snap.html	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,93 @@
+<h2>DESCRIPTION</h2>
+<p>
+Module r.stream.snap is a supplementary module for r.stream.extract and
+r.stream.basins to correct position of outlets or stream init points as they do
+not lie on the streamlines.
+<br>
+For outlets situation is clear. Points are snapped to nearest point which lies
+on the streamline. In situation where there can be a small tributuary nearer
+than main stream accumulation treshold shall be high enough to force program
+ignoring this tributuary and snap to the main stream. If there is no
+accumulation map points will be snapped to nearest stream line which in
+particular situation may be wrong. Bacuase r.stream is prepared to work with
+MFD accum maps, both stream network and accum map is neccessary to resolve the
+problem.
+<br>
+While it is assumed accum map is a MFD map, if stream network is not supplied,
+snap point is calculated in different way: treshold is used to select only these
+points in search radius which are accum value is greater than treshold. Next
+mean value of these points is calculated and its value is taken as a new
+treshold. This procedure guarantee that points are snapped to the center of
+stream tube. While for inits small tresholds are in use, it is probable than
+points were snapped to the streamtube border instead of its center.
+</p>
+<p>
+It is strongly recommended, to use both stream network (even pre-generated with
+small accum treshold) and accumulation map, than accum or stream map only.
+</p>
+
+<h2>OPTIONS</h2>
+<dl>
+<dt><b>streams</b></dt>
+<dd>Stream network created by r.stream.extract or r.watershed. If used, points
+are snapped to the nearest streamline point which accumulation is greater than
+treshold. If accumulation is not used point is snapped to the nearest stream.
+</dd>
+
+<dt><b>accum</b></dt>
+<dd>Accumulation map created with r.watershed and used to generate stream network
+with r.stream.extract. If stream network is not in use, point is adaptively
+snapped to the to point where value is greater than mean values of accumulation
+greater than given treshold in a searcyh radius. See description for details.
+</dd>
+<dt><b>radius</b></dt>
+<dd>Search radius (in cells). If there are no streams in search radius, point is
+not snapped. If there are no cells with accumulation greater than accumtreshold
+point also is not snapped.
+</dd>
+
+<dt><b>accumtres</b></dt>
+<dd>Minimum value of accumulation which cell must have to snap point. This
+option is added to snap stream inits to the stream tubes and to distinguish
+between local tributaries and main streams.
+</dd>
+
+<dt><b>input</b></dt>
+<dd>Vector file containing outlets or inits as vector points. Only point's
+categories are used Table attached to it is ignored. Every point shall have his
+own unique category.
+</dd>
+</dl>
+
+
+<h2>OUTPUTS</h2>
+<p>Vector file containing outlets or inits after snapping. On layer 1 original
+categories are preserved, on layer 2 there are four categories which mean:</p>
+<ol>
+<li>skipped (not in use yet)
+<li>unresolved (points remain unsnapped due to lack of streams in search radius
+<li>snapped (points snapped to streamlines)
+<li>correct (points whcich remain on its original position, which was
+originally corrected
+</ol>
+
+
+<h2>SEE ALSO</h2>
+
+<em>
+<a href="r.watershed.html">r.watershed</a>,
+<a href="r.stream.extract.html">r.stream.extract</a>,
+<a href="r.stream.basins.html">r.stream.basins</a>,
+<a href="r.stream.order.html">r.stream.order</a>,
+<a href="r.stream.stats.html">r.stream.stats</a>,
+<a href="r.mapcalc.html">r.mapcalc</a>,
+<a href="r.reclass.html">r.reclass</a>,
+<a href="r.patch.html">r.patch</a>
+</em>
+
+<h2>AUTHOR</h2>
+Jarek Jasiewicz, Adam Mickiewicz University, Geoecology and Geoinformation
+Institute.
+
+<p><i>Last changed: $Date: 2011-11-08 22:56:45 +0100 (Tue, 08 Nov 2011) $</i>
+

Added: grass-addons/grass7/grass7/raster/r.stream.snap/snap.c
===================================================================
--- grass-addons/grass7/grass7/raster/r.stream.snap/snap.c	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.stream.snap/snap.c	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,142 @@
+#include "local_proto.h"
+
+#define SQRT(x) ((x) * (x))   /* ??? */
+
+int create_distance_mask(int radius)
+{
+
+    int i, j;
+    int window = 2 * radius + 1;
+
+    distance_mask = G_malloc(window * sizeof(float *));
+
+    for (i = 0; i < window; i++)
+	distance_mask[i] = G_malloc(window * sizeof(float));
+
+    for (i = 0; i < window; i++)
+	for (j = 0; j < window; j++)
+	    distance_mask[i][j] =
+		(SQR(i - radius) + SQR(j - radius) <= SQR(radius)) ?
+		sqrt(SQR(i - radius) + SQR(j - radius)) : 0;
+
+    return 0;
+}
+
+int snap_point(OUTLET *point, int radius, SEGMENT *streams, SEGMENT *accum,
+	       double accum_treshold)
+{
+
+    int i, j, di = -1, dj = -1;
+    int status = 3;
+    int teststream = 0;
+    float cur_distance = radius;
+    float distance = 0;
+    double absaccum = 0;
+    double sumaccum = 0;
+    double maxaccum = 0;
+    int naccum = -1;
+
+    if (point->stream > 0 && point->accum > accum_treshold)
+	return 0;		/* point lies on line(or skipped) and has proper treshold */
+
+    if (streams) {
+	/* stream version: assume ve have stream network and points 
+	 * are snapped to stream points where accum is greater than treshold
+	 * or to nearest stream point in accum is not supplied */
+
+	for (i = -radius; i <= radius; ++i)
+	    for (j = -radius; j <= radius; ++j) {
+
+		if (point->r + i < 0 || point->r + i >= nrows ||
+		    point->c + j < 0 || point->c + j >= ncols)
+		    continue;
+
+		if (!distance_mask[i + radius][j + radius])
+		    continue;
+
+		segment_get(streams, &teststream, point->r + i, point->c + j);
+		distance = distance_mask[i + radius][j + radius];
+
+		if (teststream) {	/* is stream line */
+
+		    if (accum) {
+			segment_get(accum, &absaccum, point->r + i,
+				    point->c + j);
+			absaccum = fabs(absaccum);
+		    }
+
+		    if (absaccum >= accum_treshold)	/* if no accum absaccum always =-1 */
+			if (cur_distance > distance) {
+			    cur_distance = distance;
+			    di = i;
+			    dj = j;
+			}
+		}
+	    }
+    }				/* end of streams version */
+
+    if (!streams) {
+	/* no stream version: problem for MFD. the snap point is found
+	 * in different manner. It is not only point where accum exceed the 
+	 * treshold (may be far for potential streamline) but must exceed the
+	 * mean value of accums in searach area taken in cells where treshold is exceeded */
+
+	for (i = -radius; i <= radius; ++i)
+	    for (j = -radius; j <= radius; ++j) {
+
+		if (point->r + i < 0 || point->r + i >= nrows ||
+		    point->c + j < 0 || point->c + j >= ncols)
+		    continue;
+
+		if (!distance_mask[i + radius][j + radius])
+		    continue;
+
+		segment_get(accum, &absaccum, point->r + i, point->c + j);
+		absaccum = fabs(absaccum);
+
+		if (absaccum > maxaccum)
+		    maxaccum = absaccum;
+
+		if (absaccum > accum_treshold) {
+		    sumaccum += absaccum;
+		    naccum++;
+		}
+	    }
+
+	if (sumaccum > 0)
+	    /* accum_treshold=(sumaccum/naccum+maxaccum)/2 */ ;
+	accum_treshold = sumaccum / naccum;
+
+	for (i = -radius; i <= radius; ++i)
+	    for (j = -radius; j <= radius; ++j) {
+
+		if (point->r + i < 0 || point->r + i >= nrows ||
+		    point->c + j < 0 || point->c + j >= ncols)
+		    continue;
+
+		if (!distance_mask[i + radius][j + radius])
+		    continue;
+
+		segment_get(accum, &absaccum, point->r + i, point->c + j);
+		absaccum = fabs(absaccum);
+
+		if (accum_treshold > 0 && absaccum > accum_treshold)
+		    if (cur_distance > distance) {
+			cur_distance = distance;
+			di = i;
+			dj = j;
+		    }
+	    }
+    }				/* end of non-streams version */
+    if (di == -1 && dj == -1) {
+	G_warning(_("cannot snap point with cat %d, in a given radius. \
+		Increase search radius"), point->cat);
+	di = 0;
+	dj = 0;
+	status = 2;
+    }
+    point->di = di;
+    point->dj = dj;
+    point->status = status;
+    return 0;
+}

Added: grass-addons/grass7/grass7/raster/r.stream.stats/Makefile
===================================================================
--- grass-addons/grass7/grass7/raster/r.stream.stats/Makefile	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.stream.stats/Makefile	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,11 @@
+MODULE_TOPDIR = ../..
+
+PGM = r.stream.stats
+
+LIBES = $(GISLIB) $(RASTERLIB) $(SEGMENTLIB)
+DEPENDENCIES = $(GISDEP) $(RASTERDEP) $(SEGMENTDEP)
+
+include $(MODULE_TOPDIR)/include/Make/Module.make
+
+default: cmd
+

Added: grass-addons/grass7/grass7/raster/r.stream.stats/io.c
===================================================================
--- grass-addons/grass7/grass7/raster/r.stream.stats/io.c	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.stream.stats/io.c	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,564 @@
+#include "io.h"
+/* all in ram functions section */
+
+int ram_create_map(MAP * map, RASTER_MAP_TYPE data_type)
+{
+
+    /* 
+     * allocates 0 filled nrows*ncols map of type void;
+     * map parameters are stored in structure;
+     * map: map to be created;
+     * map type to be created must be CELL, FCELL, DCELL;
+     * */
+
+    int r;
+
+    if (data_type < 0 || data_type > 2)
+	G_fatal_error(_("ram_creat: Cannot create map of unrecognised type"));
+
+    map->data_type = data_type;
+    map->map_name = NULL;
+    map->nrows = Rast_window_rows();
+    map->ncols = Rast_window_cols();
+    map->data_size = Rast_cell_size(data_type);
+
+    /* preparing internal map */
+    switch (map->data_type) {
+    case CELL_TYPE:
+	map->map = G_calloc(map->nrows, sizeof(CELL *));
+	break;
+
+    case FCELL_TYPE:
+	map->map = G_calloc(map->nrows, sizeof(FCELL *));
+	break;
+
+    case DCELL_TYPE:
+	map->map = G_calloc(map->nrows, sizeof(DCELL *));
+	break;
+    }
+
+    for (r = 0; r < map->nrows; ++r)
+	(map->map)[r] = G_calloc(map->ncols, map->data_size);
+
+    return 0;
+}
+
+int ram_read_map(MAP * map, char *input_map_name, int check_res,
+		 RASTER_MAP_TYPE check_data_type)
+{
+    /*
+     * Funciton read external map and put it in MAP structure (created with create_map)
+     * map: map to be read can be of any data type, read map is converted to target map if neccesary.
+     * input_map_name: name of the map to be read;
+     * map pointer to map stucture (created with create_map);
+     * check_res: [1]: check res correspondence between region and map [0 no check];
+     * check_data_type [CELL, FCELL, DCELL] check if reading map is of particular type, [-1] no check;
+     */
+
+    int r, c;
+    char *mapset;
+    struct Cell_head cellhd, this_window;
+    char *maptypes[] = { "CELL", "FCELL", "DCELL" };
+    int input_map_fd;
+    RASTER_MAP_TYPE input_data_type;
+    size_t input_data_size;
+    void *input_buffer = NULL;
+    void *input_pointer;
+
+    /* checking if map exist */
+    mapset = (char *)G_find_raster2(input_map_name, "");
+    if (mapset == NULL)
+	G_fatal_error(_("Raster map <%s> not found"), input_map_name);
+
+    /* checking if region and input are the same */
+    G_get_window(&this_window);
+    Rast_get_cellhd(input_map_name, mapset, &cellhd);
+    if (check_res)
+	if (this_window.ew_res != cellhd.ew_res ||
+	    this_window.ns_res != cellhd.ns_res)
+	    G_fatal_error(_("Region resolution and map %s resolution differs. \
+		Run g.region rast=%s to set proper region resolution"),
+			  input_map_name, input_map_name);
+
+    /* checking if input map is of required type */
+    if (check_data_type != map->data_type)
+	G_debug(1,
+		"ram_open:required map type and internal map type differs: conversion forced!");
+    input_data_type = Rast_map_type(input_map_name, mapset);
+    if (check_data_type != -1)
+	if (input_data_type != check_data_type)
+	    G_fatal_error(_("<%s> is not of type %s"),
+			  input_map_name, maptypes[check_data_type]);
+
+    input_map_fd = Rast_open_old(input_map_name, mapset);
+    input_data_size = Rast_cell_size(input_data_type);
+
+    {				/* reading range */
+	struct Range map_range;
+	struct FPRange map_fp_range;
+	int min, max;
+
+	if (input_data_type == CELL_TYPE) {
+	    Rast_init_range(&map_range);
+	    Rast_read_range(input_map_name, mapset, &map_range);
+	    Rast_get_range_min_max(&map_range, &min, &max);
+	    map->min = (double)min;
+	    map->max = (double)max;
+	}
+	else {
+	    Rast_init_fp_range(&map_fp_range);
+	    Rast_read_fp_range(input_map_name, mapset, &map_fp_range);
+	    Rast_get_fp_range_min_max(&map_fp_range, &(map->min),
+				      &(map->max));
+	}
+    }
+    /* end opening and checking */
+
+    input_buffer = Rast_allocate_buf(input_data_type);
+
+    /* start reading */
+    G_message(_("Reading map <%s>"), input_map_name);
+
+    for (r = 0; r < map->nrows; ++r) {
+	G_percent(r, map->nrows, 2);
+
+	Rast_get_row(input_map_fd, input_buffer, r, input_data_type);
+	input_pointer = input_buffer;
+
+	for (c = 0; c < map->ncols; ++c)
+	    if (!Rast_is_null_value
+		(input_pointer + c * input_data_size, input_data_type))
+		switch (map->data_type) {
+		case CELL_TYPE:
+		    ((CELL **) map->map)[r][c] =
+			Rast_get_c_value(input_pointer + c * input_data_size,
+					 input_data_type);
+		    break;
+		case FCELL_TYPE:
+		    ((FCELL **) map->map)[r][c] =
+			Rast_get_f_value(input_pointer + c * input_data_size,
+					 input_data_type);
+		    break;
+		case DCELL_TYPE:
+		    ((DCELL **) map->map)[r][c] =
+			Rast_get_d_value(input_pointer + c * input_data_size,
+					 input_data_type);
+		    break;
+		default:
+		    G_fatal_error(_("ram_open:Wrong internal data type"));
+		    break;
+		}
+    }				/*end for r */
+
+    G_free(input_buffer);
+    G_percent(r, map->nrows, 2);
+    Rast_close(input_map_fd);
+    return 0;
+}				/* end create floating point map */
+
+int ram_reset_map(MAP * map, int value)
+{
+    /*
+     * set all cells in the map to value
+     */
+    int r;
+
+    for (r = 0; r < map->nrows; ++r)
+	memset((map->map)[r], value, map->ncols * map->data_size);
+    return 0;
+}
+
+int ram_write_map(MAP * map, char *output_map_name,
+		  RASTER_MAP_TYPE output_data_type, int convert_to_null,
+		  double value)
+{
+    /* 
+     * write map to disk with output_map_name and output_data_type [CELL, FCELL, DCELL];
+     * if output_data_type = -1 than internal map type is used for output;
+     * if output map != -1 and types differ data_type, conversion is forced
+     * convert to null: check if convert to null a particular value in dataset;
+     */
+
+    int r, c;
+    int output_fd = 0;
+    struct History history;
+    void *row;
+
+    /* check for output format */
+    if (output_data_type == -1)
+	output_data_type = map->data_type;
+
+    if (output_data_type != map->data_type)
+	G_debug(1,
+		"ram_write:required map type and internal map type differs: conversion forced!");
+
+    G_message(_("Writing map <%s>"), output_map_name);
+    output_fd = Rast_open_new(output_map_name, output_data_type);
+
+    /* writing */
+    for (r = 0; r < map->nrows; ++r) {
+	G_percent(r, map->nrows, 2);
+
+	if (convert_to_null) {
+	    row = map->map[r];
+	    switch (map->data_type) {
+	    case CELL_TYPE:
+		for (c = 0; c < map->ncols; ++c)
+		    if (((CELL *) row)[c] == (CELL) value)
+			Rast_set_c_null_value(row + c * (map->data_size), 1);
+		break;
+	    case FCELL_TYPE:
+		for (c = 0; c < map->ncols; ++c)
+		    if (((FCELL *) row)[c] == (FCELL) value)
+			Rast_set_f_null_value(row + c * (map->data_size), 1);
+		break;
+	    case DCELL_TYPE:
+		for (c = 0; c < map->ncols; ++c)
+		    if (((DCELL *) row)[c] == (DCELL) value)
+			Rast_set_d_null_value(row + c * (map->data_size), 1);
+		break;
+	    default:
+		G_debug(1, "ram_null:Cannot convert to null at: %d %d", r, c);
+	    }
+	}
+
+	Rast_put_row(output_fd, (map->map)[r], output_data_type);
+    }
+    G_percent(r, map->nrows, 2);
+    Rast_close(output_fd);
+    Rast_short_history(output_map_name, "raster", &history);
+    Rast_command_history(&history);
+    Rast_write_history(output_map_name, &history);
+    G_message(_("<%s> Done"), output_map_name);
+    return 0;
+}
+
+int ram_release_map(MAP *map)
+{
+    /* 
+     * free memory allocated for map, set pointer to null;
+     */
+    int r;
+
+    for (r = 0; r < map->nrows; ++r)
+	G_free((map->map)[r]);
+    G_free(map->map);
+    map = NULL;
+    return 0;
+}
+
+
+/* memory swap functions section */
+
+
+int seg_create_map(SEG * seg, int srows, int scols, int number_of_segs,
+		   RASTER_MAP_TYPE data_type)
+{
+    /* create segment  and returns pointer to it;
+     * seg must be declared first;
+     * parameters are stored in structure;
+     * seg: segment to be created;
+     * srows, scols segment size
+     * number of segs max number of segs stored in memory
+     * data_type to be created must be CELL, FCELL, DCELL;
+     */
+
+    char *filename;
+    int fd;
+    int local_number_of_segs;
+
+    seg->fd = -1;
+    seg->filename = NULL;
+    seg->map_name = NULL;
+    seg->mapset = NULL;
+    seg->data_type = data_type;
+    seg->nrows = Rast_window_rows();
+    seg->ncols = Rast_window_cols();
+
+    local_number_of_segs =
+	(seg->nrows / srows + 1) * (seg->ncols / scols + 1);
+    number_of_segs =
+	(number_of_segs >
+	 local_number_of_segs) ? local_number_of_segs : number_of_segs;
+
+    G_debug(3, "seg_creat:number of segments %d", number_of_segs);
+
+    switch (seg->data_type) {
+    case CELL_TYPE:
+	seg->data_size = sizeof(CELL);
+	break;
+    case FCELL_TYPE:
+	seg->data_size = sizeof(FCELL);
+	break;
+    case DCELL_TYPE:
+	seg->data_size = sizeof(DCELL);
+	break;
+    default:
+	G_fatal_error(_("seg_create: unrecognisabe data type"));
+    }
+
+    filename = G_tempfile();
+    fd = creat(filename, 0666);
+
+    if (0 >
+	segment_format(fd, seg->nrows, seg->ncols, srows, scols,
+		       seg->data_size)) {
+	close(fd);
+	unlink(filename);
+	G_fatal_error(_("seg_create: cannot format segment"));
+    }
+
+    close(fd);
+    if (0 > (fd = open(filename, 2))) {
+	unlink(filename);
+	G_fatal_error(_("seg_create: cannot re-open file"));
+    }
+
+    if (0 > (fd = segment_init(&(seg->seg), fd, number_of_segs))) {
+	unlink(filename);
+	G_fatal_error(_("seg_create: cannot init segment file or out of memory"));
+    }
+
+    seg->filename = G_store(filename);
+    seg->fd = fd;
+    return 0;
+}
+
+int seg_read_map(SEG * seg, char *input_map_name, int check_res,
+		 RASTER_MAP_TYPE check_data_type)
+{
+
+    /*
+     * Funciton read external map and put it in SEG structure (created with seg_create_map)
+     * map to be read can be of any data type, read map is converted if neccesary.
+     * input_map_name: name of the map to be read;
+     * seg: pointer to map stucture (created with create_map);
+     * check_res: [1]: check res correspondence between region and map [0 no check];
+     * check_data_type [CELL, FCELL, DCELL] check if reading map is of particular type, [-1] no check;
+     */
+
+    int input_fd;
+    int r, c;
+    char *mapset;
+    struct Cell_head cellhd, this_window;
+    char *maptypes[] = { "CELL", "FCELL", "DCELL" };
+    RASTER_MAP_TYPE input_data_type;
+    size_t input_data_size;
+    void *input_buffer = NULL;
+    void *target_buffer = NULL;
+    void *input_pointer = NULL;
+
+    /* checking if map exist */
+    mapset = (char *)G_find_raster2(input_map_name, "");
+    if (mapset == NULL)
+	G_fatal_error(_("seg_read:Raster map <%s> not found"),
+		      input_map_name);
+    seg->mapset = mapset;
+
+    /* checking if region and input are the same */
+    G_get_window(&this_window);
+    Rast_get_cellhd(input_map_name, mapset, &cellhd);
+
+    /* check resolution equal anyinteger check;  equal 0 no check */
+    if (check_res)
+	if (this_window.ew_res != cellhd.ew_res ||
+	    this_window.ns_res != cellhd.ns_res)
+	    G_fatal_error(_("Region resolution and map %s resolution differs. \
+		Run g.region rast=%s to set proper region resolution"),
+			  input_map_name, input_map_name);
+
+    if (check_data_type != seg->data_type)
+	G_debug(1,
+		"ram_open:required map type and internal map type differs: conversion forced!");
+    input_data_type = Rast_map_type(input_map_name, mapset);
+    if (check_data_type != -1)
+	if (input_data_type != check_data_type)
+	    G_fatal_error(_("<%s> is not of type %s"),
+			  input_map_name, maptypes[check_data_type]);
+
+    input_fd = Rast_open_old(input_map_name, mapset);
+    input_data_size = Rast_cell_size(input_data_type);
+
+    {				/* reading range */
+	struct Range map_range;
+	struct FPRange map_fp_range;
+	int min, max;
+
+	if (input_data_type == CELL_TYPE) {
+	    Rast_init_range(&map_range);
+	    Rast_read_range(input_map_name, mapset, &map_range);
+	    Rast_get_range_min_max(&map_range, &min, &max);
+	    seg->min = (double)min;
+	    seg->max = (double)max;
+	}
+	else {
+	    Rast_init_fp_range(&map_fp_range);
+	    Rast_read_fp_range(input_map_name, mapset, &map_fp_range);
+	    Rast_get_fp_range_min_max(&map_fp_range, &(seg->min),
+				      &(seg->max));
+	}
+    }
+
+    /* end opening and checking */
+
+    G_message(_("Reading map <%s>"), input_map_name);
+    input_buffer = Rast_allocate_buf(input_data_type);
+
+    target_buffer = Rast_allocate_buf(seg->data_type);
+
+    for (r = 0; r < seg->nrows; ++r) {
+	G_percent(r, seg->nrows, 2);
+	Rast_get_row(input_fd, input_buffer, r, input_data_type);
+	input_pointer = input_buffer;
+	memset(target_buffer, 0, seg->ncols * seg->data_size);
+
+	for (c = 0; c < seg->ncols; ++c)
+	    if (!Rast_is_null_value
+		(input_pointer + c * input_data_size, input_data_type)) {
+		switch (seg->data_type) {
+		case CELL_TYPE:
+		    ((CELL *) target_buffer)[c] =
+			Rast_get_c_value(input_pointer + c * input_data_size,
+					 input_data_type);
+		    break;
+		case FCELL_TYPE:
+		    ((FCELL *) target_buffer)[c] =
+			Rast_get_f_value(input_pointer + c * input_data_size,
+					 input_data_type);
+		    break;
+		case DCELL_TYPE:
+		    ((DCELL *) target_buffer)[c] =
+			Rast_get_d_value(input_pointer + c * input_data_size,
+					 input_data_type);
+		    break;
+		default:
+		    G_fatal_error(_("Wrong internal data type"));
+		    break;
+		}
+	    }
+
+	if (0 > segment_put_row(&(seg->seg), target_buffer, r)) {
+	    G_free(input_buffer);
+	    G_free(target_buffer);
+	    Rast_close(input_fd);
+	    G_fatal_error(_("seg_read: Cannot segment put row %d for map %s"),
+			  r, input_map_name);
+	}
+    }				/* end for row */
+
+    G_percent(r, seg->nrows, 2);
+    Rast_close(input_fd);
+    G_free(input_buffer);
+    G_free(target_buffer);
+
+    seg->map_name = G_store(input_map_name);
+    seg->mapset = G_store(mapset);
+
+    return 0;
+}
+
+int seg_reset_map(SEG * seg, int value)
+{
+    /*
+     * set all cells in the map to value
+     */
+    int r, c;
+
+    for (r = 0; r < seg->nrows; ++r)
+	for (c = 0; c < seg->ncols; ++c)
+	    segment_put(&(seg->seg), &value, r, c);
+
+    return 0;
+}
+
+int seg_write_map(SEG * seg, char *output_map_name,
+		  RASTER_MAP_TYPE output_data_type, int convert_to_null,
+		  double value)
+{
+    /* 
+     * write seg to disk with output_map_name and output_data_type [CELL, FCELL, DCELL];
+     * if output_data_type = -1 than internal map type is used for output;
+     * if output map != -1 and types differ data_type, conversion is forced
+     * convert to null: check if convert to null a particular value in dataset;
+     */
+    int output_fd;
+    int r, c;
+    void *output_buffer;
+    void *row;
+    struct History history;
+
+    /* check for output format */
+    if (output_data_type == -1)
+	output_data_type = seg->data_type;
+
+    if (output_data_type != seg->data_type)
+	G_debug(1,
+		"ram_write:required map type and internal map type differs: conversion forced!");
+
+    G_message(_("Writing map <%s>"), output_map_name);
+    output_fd = Rast_open_new(output_map_name, output_data_type);
+    output_buffer = Rast_allocate_buf(output_data_type);
+    segment_flush(&(seg->seg));
+
+    /* writing */
+    for (r = 0; r < seg->nrows; ++r) {
+
+	G_percent(r, seg->nrows, 2);
+	if (0 > segment_get_row(&(seg->seg), output_buffer, r))
+	    G_warning(_("seg_write: Cannot segment read row %d for map %s"),
+		      r, output_map_name);
+
+	if (convert_to_null) {
+
+	    row = output_buffer;
+	    switch (seg->data_type) {
+	    case CELL_TYPE:
+		for (c = 0; c < seg->ncols; ++c)
+		    if (((CELL *) output_buffer)[c] == (CELL) value)
+			Rast_set_c_null_value(row + c * (seg->data_size), 1);
+		break;
+	    case FCELL_TYPE:
+		for (c = 0; c < seg->ncols; ++c)
+		    if (((FCELL *) output_buffer)[c] == (FCELL) value)
+			Rast_set_f_null_value(row + c * (seg->data_size), 1);
+		break;
+	    case DCELL_TYPE:
+		for (c = 0; c < seg->ncols; ++c)
+		    if (((DCELL *) output_buffer)[c] == (DCELL) value)
+			Rast_set_d_null_value(row + c * (seg->data_size), 1);
+		break;
+	    default:
+		G_warning(_("ram_null:Cannot convert to null at: %d %d"), r,
+			  c);
+	    }
+	}
+	Rast_put_row(output_fd, output_buffer, output_data_type);
+    }
+
+    G_percent(r, seg->nrows, 2);
+    G_free(output_buffer);
+    Rast_close(output_fd);
+    Rast_short_history(output_map_name, "raster", &history);
+    Rast_command_history(&history);
+    Rast_write_history(output_map_name, &history);
+    G_message(_("%s Done"), output_map_name);
+
+    return 0;
+}
+
+int seg_release_map(SEG * seg)
+{
+    /* 
+     * release segment close files, set pointers to null;
+     */
+    segment_release(&(seg->seg));
+    close(seg->fd);
+    unlink(seg->filename);
+
+    if (seg->map_name)
+	G_free(seg->map_name);
+    if (seg->mapset)
+	G_free(seg->mapset);
+
+    return 0;
+}

Added: grass-addons/grass7/grass7/raster/r.stream.stats/io.h
===================================================================
--- grass-addons/grass7/grass7/raster/r.stream.stats/io.h	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.stream.stats/io.h	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,59 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <string.h>
+#include <math.h>
+#include <grass/glocale.h>
+#include <grass/gis.h>
+#include <grass/raster.h>
+#include <grass/segment.h>
+
+#define NOT_IN_REGION(x) (r + nextr[(x)] < 0 || r + nextr[(x)] > (nrows - 1) || \
+                          c + nextc[(x)] < 0 || c + nextc[(x)] > (ncols - 1))
+#define NR(x) (r + nextr[(x)])
+#define NC(x) (c + nextc[(x)])
+#define INDEX(r,c) ((r) * ncols + (c))
+#define DIAG(x) (((x) + 4) > 8 ? ((x) - 4) : ((x) + 4))
+
+#define SROWS 256
+#define SCOLS 256
+
+typedef struct {
+	void **map; /* matrix of data */
+	double min, max; /* data range : may requre casting */
+	int nrows, ncols;
+	char *map_name; /* map name, unused */
+	RASTER_MAP_TYPE data_type; /* type of data */
+	size_t data_size; /* type of data */
+} MAP;
+
+typedef struct {
+	SEGMENT seg;		/* segmented data store */
+	int fd;					/* segment temporary file name descriptor */
+	char *filename; /* segment temporary file name */
+	char *map_name; /* map name converted to segment */
+	char *mapset;
+	int nrows, ncols; /* store nrows and rcols */
+	RASTER_MAP_TYPE data_type; /* data type of the map */
+	size_t data_size; /* size of cell returned by sizeof */
+	double min, max; /* data range */
+} SEG;
+
+
+/* all in ram functions */
+int ram_create_map(MAP *, RASTER_MAP_TYPE);
+int ram_read_map(MAP *, char *, int, RASTER_MAP_TYPE);
+int ram_reset_map(MAP *, int);
+int ram_write_map(MAP *, char *, RASTER_MAP_TYPE, int, double);
+int ram_release_map(MAP *);
+int ram_destory_map(MAP *);
+
+/* memory swap functions */
+int seg_create_map(SEG *, int, int, int, RASTER_MAP_TYPE);
+int seg_read_map(SEG *, char *, int, RASTER_MAP_TYPE);
+int seg_reset_map (SEG *, int);
+int seg_write_map(SEG *, char *, RASTER_MAP_TYPE, int, double);
+int seg_release_map(SEG *);
+

Added: grass-addons/grass7/grass7/raster/r.stream.stats/local_proto.h
===================================================================
--- grass-addons/grass7/grass7/raster/r.stream.stats/local_proto.h	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.stream.stats/local_proto.h	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,26 @@
+#include "io.h"
+#include "local_vars.h"
+
+/* stats prepare */
+int fifo_insert(POINT point);
+POINT fifo_return_del(void);
+/* ram version */
+int ram_init_streams(CELL **streams, CELL **dirs, FCELL **elevation);
+int ram_calculate_streams(CELL **streams, CELL **dirs, FCELL **elevation);
+double ram_calculate_basins_area(CELL **dirs, int r, int c);
+int ram_calculate_basins(CELL **dirs);
+/* seg version */
+int seg_init_streams(SEGMENT *streams, SEGMENT *dirs, SEGMENT *elevation);
+int seg_calculate_streams(SEGMENT *streams, SEGMENT *dirs, SEGMENT *elevation);
+double seg_calculate_basins_area(SEGMENT *dirs, int r, int c);
+int seg_calculate_basins(SEGMENT *dirs);
+
+/* stats calculate */
+double stats_linear_reg(int max_order, double* statistic);
+int stats(int order_max);
+
+/* stats print */
+int print_stats(int order_max);
+int print_stats_total(void);
+int print_stats_orders(int order_max);
+

Added: grass-addons/grass7/grass7/raster/r.stream.stats/local_vars.h
===================================================================
--- grass-addons/grass7/grass7/raster/r.stream.stats/local_vars.h	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.stream.stats/local_vars.h	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,88 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include <grass/glocale.h>
+#include <grass/gis.h>
+#include <grass/raster.h>
+
+#define SQRT2 1.414214
+	
+typedef struct {
+	int r, c;
+	int is_outlet;
+	} POINT;
+	
+typedef struct { 
+	int index;
+	int is_outlet;
+	int r, c; /* outlet */
+	float elev_diff;
+	float elev_spring, elev_outlet;
+	float slope; /* cumulative */
+	float gradient;
+	float length; /* cumulative */
+	int order;
+	double basin_area; /* basin order */
+	int cell_num;
+	} STREAM;	
+	
+typedef struct {
+	int order;
+	int stream_num;
+	double sum_length;
+	double avg_length;
+	double std_length;
+	float avg_slope;
+	float std_slope;
+	float avg_gradient;
+	float std_gradient;
+	double sum_area;
+	double avg_area;
+	double std_area;
+	float avg_elev_diff;
+	float std_elev_diff;
+	float bifur_ratio;
+	float std_bifur_ratio;
+	float reg_bifur_ratio;
+	float length_ratio;
+	float std_length_ratio;
+	float reg_length_ratio;
+	float area_ratio;
+	float std_area_ratio;
+	float reg_area_ratio;
+	float slope_ratio;
+	float std_slope_ratio;
+	float reg_slope_ratio;
+	float gradient_ratio;
+	float std_gradient_ratio;
+	float reg_gradient_ratio;
+	float stream_frequency;
+	float drainage_density;
+} STATS;
+
+
+
+#ifdef MAIN
+#	define GLOBAL
+#else
+#	define GLOBAL extern
+#endif
+
+GLOBAL int nextr[9];
+GLOBAL int nextc[9];
+
+GLOBAL double total_basins;
+GLOBAL int nrows, ncols; 
+
+GLOBAL POINT *fifo_points;
+GLOBAL int fifo_max;
+	
+GLOBAL int outlets_num; /* number outlets: index for stream statistics*/
+GLOBAL STREAM *stat_streams;
+GLOBAL STATS *ord_stats;
+GLOBAL STATS stats_total;
+
+
+
+

Added: grass-addons/grass7/grass7/raster/r.stream.stats/main.c
===================================================================
--- grass-addons/grass7/grass7/raster/r.stream.stats/main.c	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.stream.stats/main.c	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,194 @@
+
+/****************************************************************************
+ *
+ * MODULE:       r.stream.stats
+ * AUTHOR(S):    Jarek Jasiewicz jarekj amu.edu.pl
+ *               
+ * PURPOSE:      Calculate Horton's statistics according stream network and elevation map.
+ *               Program calculates: Bifuarcation ratio, length ratio, area ratio, 
+ *               slope ratio and drainage density
+ *               It uses r.stream.order stream map map, r.watershed  direction map. and DEM
+ *               Stram input map shall contains streams ordered according Strahler's or
+ *               Horton's orders. It also can calculate Hack's laws as an option.
+ *               If input stream comes from r.stream.exteract direction map 
+ *               from r.stream.extract dir map must be patched with that of r.watersheed.
+ *
+ * COPYRIGHT:    (C) 2002,2010 by the GRASS Development Team
+ *
+ *               This program is free software under the GNU General Public
+ *   	    	 	  License (>=v2). Read the file COPYING that comes with GRASS
+ *   	    	 	  for details.
+ *
+ *****************************************************************************/
+#define MAIN
+#include <grass/glocale.h>
+#include "local_proto.h"
+
+int nextr[9] = { 0, -1, -1, -1, 0, 1, 1, 1, 0 };
+int nextc[9] = { 0, 1, 0, -1, -1, -1, 0, 1, 1 };
+
+
+int main(int argc, char *argv[])
+{
+
+    struct GModule *module;
+    struct Option *in_dir_opt,	/* options */
+     *in_stm_opt, *in_elev_opt, *opt_swapsize, *opt_output;
+
+    struct Flag *flag_segmentation,
+	*flag_catchment_total, *flag_orders_summary;
+
+    char *filename;
+    int number_of_segs;
+    int order_max;
+    int segmentation, catchment_total, orders_summary;	/*flags */
+
+    /* initialize GIS environment */
+    G_gisinit(argv[0]);
+
+    /* initialize module */
+    module = G_define_module();
+    module->description =
+	_("Calculate Horton's statistics for Strahler and Horton ordered networks created with r.stream.");
+    G_add_keyword("Horton's statistics");
+    G_add_keyword("Bifuracation ratio");
+    G_add_keyword("Drainege density");
+    G_add_keyword("Catchment statistics");
+
+    in_stm_opt = G_define_standard_option(G_OPT_R_INPUT);
+    in_stm_opt->key = "streams";
+    in_stm_opt->description = "Name of streams mask input map";
+
+    in_dir_opt = G_define_standard_option(G_OPT_R_INPUT);
+    in_dir_opt->key = "dirs";
+    in_dir_opt->description = "Name of flow direction input map";
+
+    in_elev_opt = G_define_standard_option(G_OPT_R_INPUT);
+    in_elev_opt->key = "elevation";
+    in_elev_opt->description = "Name of elevation map";
+
+    opt_swapsize = G_define_option();
+    opt_swapsize->key = "memory";
+    opt_swapsize->type = TYPE_INTEGER;
+    opt_swapsize->answer = "300";
+    opt_swapsize->description = _("Max memory used in memory swap mode (MB)");
+    opt_swapsize->guisection = _("Optional");
+
+    opt_output = G_define_standard_option(G_OPT_F_OUTPUT);
+    opt_output->required = NO;
+    opt_output->description =
+	_("Name for output file (if omitted output to stdout)");
+
+    flag_segmentation = G_define_flag();
+    flag_segmentation->key = 'm';
+    flag_segmentation->description = _("Use memory swap (operation is slow)");
+
+    flag_catchment_total = G_define_flag();
+    flag_catchment_total->key = 'c';
+    flag_catchment_total->description =
+	_("Print only catchment's statistics");
+
+    flag_orders_summary = G_define_flag();
+    flag_orders_summary->key = 'o';
+    flag_orders_summary->description = _("Print only orders' statistics");
+
+    if (G_parser(argc, argv))	/* parser */
+	exit(EXIT_FAILURE);
+
+    segmentation = (flag_segmentation->answer != 0);
+    catchment_total = (flag_catchment_total->answer != 0);
+    orders_summary = (flag_orders_summary->answer != 0);
+
+    filename = opt_output->answer;
+    if (filename != NULL)
+	if (NULL == freopen(filename, "w", stdout))
+	    G_fatal_error(_("Unable to open file <%s> for writing"),
+			  filename);
+
+    nrows = Rast_window_rows();
+    ncols = Rast_window_cols();
+
+    if (!segmentation) {
+	MAP map_dirs, map_streams, map_elevation;
+	CELL **streams, **dirs;
+	FCELL **elevation;
+
+	G_message(_("ALL IN RAM CALCULATION"));
+
+	ram_create_map(&map_streams, CELL_TYPE);
+	ram_read_map(&map_streams, in_stm_opt->answer, 1, CELL_TYPE);
+	ram_create_map(&map_dirs, CELL_TYPE);
+	ram_read_map(&map_dirs, in_dir_opt->answer, 1, CELL_TYPE);
+	ram_create_map(&map_elevation, FCELL_TYPE);
+	ram_read_map(&map_elevation, in_elev_opt->answer, 0, -1);
+
+	streams = (CELL **) map_streams.map;
+	dirs = (CELL **) map_dirs.map;
+	elevation = (FCELL **) map_elevation.map;
+	order_max = (int)map_streams.max;
+
+	ram_init_streams(streams, dirs, elevation);
+	ram_calculate_streams(streams, dirs, elevation);
+	ram_calculate_basins(dirs);
+
+	stats(order_max);
+	if (!catchment_total && !orders_summary)
+	    print_stats(order_max);
+	if (catchment_total)
+	    print_stats_total();
+	if (orders_summary)
+	    print_stats_orders(order_max);
+
+	G_free(stat_streams);
+	G_free(ord_stats);
+
+	ram_release_map(&map_streams);
+	ram_release_map(&map_dirs);
+	ram_release_map(&map_elevation);
+    }
+
+    if (segmentation) {
+	SEG map_dirs, map_streams, map_elevation;
+	SEGMENT *streams, *dirs, *elevation;
+
+	G_message(_("MEMORY SWAP CALCULATION - MAY TAKE SOME TIME"));
+
+	number_of_segs = (int)atof(opt_swapsize->answer);
+	number_of_segs = number_of_segs < 32 ? (int)(32 / 0.18) : number_of_segs / 0.18;
+
+	seg_create_map(&map_streams, SROWS, SCOLS, number_of_segs, CELL_TYPE);
+	seg_read_map(&map_streams, in_stm_opt->answer, 1, CELL_TYPE);
+	seg_create_map(&map_dirs, SROWS, SCOLS, number_of_segs, CELL_TYPE);
+	seg_read_map(&map_dirs, in_dir_opt->answer, 1, CELL_TYPE);
+	seg_create_map(&map_elevation, SROWS, SCOLS, number_of_segs,
+		       FCELL_TYPE);
+	seg_read_map(&map_elevation, in_elev_opt->answer, 0, -1);
+
+	streams = &map_streams.seg;
+	dirs = &map_dirs.seg;
+	elevation = &map_elevation.seg;
+	order_max = (int)map_streams.max;
+
+	seg_init_streams(streams, dirs, elevation);
+	seg_calculate_streams(streams, dirs, elevation);
+	seg_calculate_basins(dirs);
+
+	stats(order_max);
+
+	if (!catchment_total && !orders_summary)
+	    print_stats(order_max);
+	if (catchment_total)
+	    print_stats_total();
+	if (orders_summary)
+	    print_stats_orders(order_max);
+
+	G_free(stat_streams);
+	G_free(ord_stats);
+
+	seg_release_map(&map_streams);
+	seg_release_map(&map_dirs);
+	seg_release_map(&map_elevation);
+
+    }
+    exit(EXIT_SUCCESS);
+}

Added: grass-addons/grass7/grass7/raster/r.stream.stats/r.stream.stats.html
===================================================================
--- grass-addons/grass7/grass7/raster/r.stream.stats/r.stream.stats.html	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.stream.stats/r.stream.stats.html	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,160 @@
+<h2>OPTIONS</h2>
+<dl>
+<dt><b>-c</b></dt>
+<dd>Print only catchment's characteristics. Useful for shell script calculation
+or collecting data in external tables</dd>
+<dt><b>-o</b></dt>
+<dd>Print only parameters for every order. Usefull to visualise Horton's law with
+external software (see example)</dd>
+<dt><b>-m</b></dt>
+<dd>Only for very large data sets. Use segment library to optimise memory
+consumption during analysis</dd>
+<dt><b>stream</b></dt>
+<dd>Stream network: name of input stream map on which ordering will be performed
+produced by r.watershed or r.stream.extract. Because streams network produced by
+r.watershed and r.stream.extract may slighty differ in detail it is required to
+use both stream and direction map produced by the same module. Stream background
+shall have NULL value or zero value. Background values of NULL are by default
+produced by r.watershed and r.stream.extract. If not 0 or NULL use <a
+href="r.mapcalc.html">r.mapcalc</a> to set background values to null.  
+</dd>
+<dt><b>dir</b></dt>
+<dd>Flow direction: name of input direction map produced by r.watershed or
+r.stream.extract. If r.stream.extract output map is used, it only has non-NULL
+values in places where streams occur. NULL (nodata) cells are ignored, zero and
+negative values are valid direction data if they vary from -8 to 8 (CCW from
+East in steps of 45 degrees). Direction map shall be of type CELL values. Region
+resolution and map resoultion must be the same. 
+Also <em>stream</em> network map must have the same resolution. It is checked by
+default. If resolutions differ the module informs about it and stops. Region
+boundary and maps boundary may be differ but it may lead to unexpected
+results.</dd>
+
+<dt><b>elevation</b></dt>
+<dd>Elevation: name of input elevation map. Map can be of type CELL, FCELL or
+DCELL. It is not restricted to resolution of region settings as streams and
+dirs.</dd>
+
+<h2>OUTPUTS</h2>
+Output statistics are send to standard output. To redirect output to file use
+redirection operators: > or >>. If redirection is used, output messages are
+printed on stderr (usually terminal) while statistics are written to the file.
+Statistics can be print as a formatted summary information with number of
+parameters or as a catchement's descriptive statistics and table with statistics
+for every order. 
+
+
+<h2>DESCRIPTION</h2>
+<p>
+Module r.stream.stats is prepared to calculate Hotron's statistics of drainage
+network.
+<p>
+These statistics are calculated according formulas given by R.Horton (1945).
+Because Horton do not defined precisely what is stream slope, it has been
+proposed  proposed 2 different approaches: first (slope) use cell-by-cell slope
+calculation, second (gradient) use difference between elevation of outlet and
+source of every channel to its length to calculate formula. Bifurcation ratio
+for every order is calculated acording formula: 
+<code>n_streams[1]/n_stream[i+1]</code>
+where i the current order and i+1 next higher order. For max order of the map
+number of streams is zero. Rest of the ratios are calculated in similar mode.
+The bifurcation and other ratios for the whole catchment (map) is calculated as
+mean i.e sum of all bifurcation ratio / max_order-1 (for max_order stream
+bifurcation ratio = 0)
+It is strongly recommended to extract stream network using basin map created
+with r.stream.basin. If whole stream order map is used the calculation will be
+performed but results may not have hydrological sense.
+
+For every order (std) means that statstic is calculated with standard deviation:
+<ul>
+<li>number of streams
+<li>total length of streams of  given order
+<li>total area of basins of given order 
+<li>drainage density
+<li>stream density
+
+<li>average length of streams of given order (std)
+<li>average slope (cell by cell inclination) of streams of given order (std)
+<li>average gradient (spring to outlet inclination ) of streams of given order
+(std)
+<li>average area of basins of given order (std)
+<li>avarage elevation difference of given order (std)
+<p>ratios:
+<li>bifuracation ratio
+<li>length ratio
+<li>sloope and gradient ratios
+<li>area ratio
+</ul>
+for the whole basin:
+<ul>
+<li>total number of streams
+<li>total length of streams 
+<li>total basin area
+<li>drainage density
+<li>stream density
+<p>ratios:
+<li>bifurcation ratio (std)
+<li>length ratio (std)
+<li>slope and gradient ratios (std)
+<li>area ratio (std)
+</ul>
+<p>
+For the whole basins ratios are calculated acording two formulas: as a mean of
+ratios for every order, or as a antilog of slope coeficient of the regression
+model: order vs. log10(parameter)
+
+<h2>NOTES</h2>
+<p>
+Module calculates statistics for all streams in input stream map. It is strongly
+recommended to extract only network of one basin, but it is not necessary for
+computation.  Streams for desired basin first can be extracted with following
+mapcalc formula:
+
+<p>
+<code>echo 'sel_streams=if(basin==xxx,streams,null())'|r.mapcalc #xxx category
+of desired basin</code>
+<p>
+
+It is also possible to calculate Horton's statistics for Shreve ordering but it
+has no hydrological sense. Hack (or Gravelius hierarchy) main stream is not the
+same what so called Horton's reverse ordering (see: Horton 1945).
+<p>
+Module can work only if direction map, stream map and region map has same
+settings. It is also required that stream map and direction map come from the
+same source. For lots of reason this limitation probably cannot be omitted.  
+this means if stream map comes from r.stream.extract also direction map from
+r.stream.extract must be used. If stream network was generated with MFD method
+also MFD direction map must be used.
+
+<h2>EXAMPLE</h2>
+Create table with order statistics. This table can easily send to external
+program (like R) to be visualised:
+
+<div class="code"><pre>
+r.stream.stats -o streams=horton dirs=dirs elevation=elevation.10m > tmp_file
+R
+r=read.csv("tmp_file",skip=1,header=TRUE)
+plot(num_of_streams~order,data=r,log="y", 
+	main="Sperafish area", 
+	sub=paste("Bifurcation ratio: ",
+		round(1/10^model$coefficients[2],3)))
+model=lm(log10(num_of_streams)~order,data=r)
+abline(model)
+</pre></div>
+
+<h2>SEE ALSO</h2>
+
+<em>
+<a href="r.watershed.html">r.watershed</a>,
+<a href="r.stream.extract.html">r.stream.extract</a>,
+<a href="r.stream.order.html">r.stream.order</a>,
+<a href="r.stream.basins.html">r.stream.basins</a>,
+<a href="r.mapcalc.html">r.mapcalc</a>,
+</em>
+
+<h2>AUTHOR</h2>
+Jarek Jasiewicz, Adam Mickiewicz University, Geoecology and Geoinformation
+Institute.
+
+<p><i>Last changed: $Date: 2011-11-08 22:56:45 +0100 (Tue, 08 Nov 2011) $</i>
+

Added: grass-addons/grass7/grass7/raster/r.stream.stats/stats_calculate.c
===================================================================
--- grass-addons/grass7/grass7/raster/r.stream.stats/stats_calculate.c	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.stream.stats/stats_calculate.c	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,286 @@
+#include "local_proto.h"
+double stats_linear_reg(int max_order, double *statistic)
+{
+
+    int i;
+    double avg_x = 0, avg_y = 0;
+    double sum_x_square = 0;
+    double sum_x_y = 0;
+    double sum_x = 0;
+    double avg_x_y = 0;
+    double avg_x_square;
+    double result;
+
+    for (i = 1; i <= max_order; ++i) {
+	avg_y += statistic[i];
+	sum_x += i;
+	sum_x_square += i * i;
+	sum_x_y += i * statistic[i];
+    }
+    avg_y /= (float)max_order;
+    avg_x = sum_x / (float)max_order;
+    avg_x_y = sum_x_y / (float)max_order;
+    avg_x_square = sum_x_square / max_order;
+
+
+    result = (avg_x_y - avg_x * avg_y) / (avg_x_square - avg_x * avg_x);
+    return result;
+}
+
+int stats(order_max)
+{
+    int i;
+    int num, ord_num;
+    float snum, ord_snum;
+    float tmp_num;
+    double *statistic;
+
+    ord_stats = (STATS *) G_malloc((order_max + 1) * sizeof(STATS));
+
+    stats_total.order = 0;
+    stats_total.stream_num = 0;
+    stats_total.sum_length = 0.;
+    stats_total.avg_length = 0.;
+    stats_total.std_length = 0.;
+    stats_total.avg_slope = 0.;
+    stats_total.std_slope = 0.;
+    stats_total.avg_gradient = 0.;
+    stats_total.std_gradient = 0.;
+    stats_total.sum_area = 0.;
+    stats_total.avg_area = 0.;
+    stats_total.std_area = 0.;
+    stats_total.avg_elev_diff = 0.;
+    stats_total.std_elev_diff = 0.;
+    stats_total.bifur_ratio = 0.;
+    stats_total.std_bifur_ratio = 0.;
+    stats_total.reg_bifur_ratio = 0.;
+    stats_total.length_ratio = 0.;
+    stats_total.std_length_ratio = 0.;
+    stats_total.reg_length_ratio = 0.;
+    stats_total.area_ratio = 0.;
+    stats_total.std_area_ratio = 0.;
+    stats_total.reg_area_ratio = 0.;
+    stats_total.slope_ratio = 0.;
+    stats_total.std_slope_ratio = 0.;
+    stats_total.reg_slope_ratio = 0.;
+    stats_total.gradient_ratio = 0.;
+    stats_total.std_gradient_ratio = 0.;
+    stats_total.reg_gradient_ratio = 0.;
+    stats_total.stream_frequency = 0.;
+    stats_total.drainage_density = 0.;
+
+    for (i = 0; i <= order_max; ++i) {
+	ord_stats[i].order = i;
+	ord_stats[i].stream_num = 0;
+	ord_stats[i].sum_length = 0.;
+	ord_stats[i].avg_length = 0.;
+	ord_stats[i].std_length = 0.;
+	ord_stats[i].avg_slope = 0.;
+	ord_stats[i].std_slope = 0.;
+	ord_stats[i].avg_gradient = 0.;
+	ord_stats[i].std_gradient = 0.;
+	ord_stats[i].sum_area = 0.;
+	ord_stats[i].avg_area = 0.;
+	ord_stats[i].std_area = 0.;
+	ord_stats[i].avg_elev_diff = 0.;
+	ord_stats[i].std_elev_diff = 0.;
+	ord_stats[i].bifur_ratio = 0.;
+	ord_stats[i].std_bifur_ratio = 0.;
+	ord_stats[i].length_ratio = 0.;
+	ord_stats[i].std_length_ratio = 0.;
+	ord_stats[i].area_ratio = 0.;
+	ord_stats[i].std_area_ratio = 0.;
+	ord_stats[i].slope_ratio = 0.;
+	ord_stats[i].std_slope_ratio = 0.;
+	ord_stats[i].gradient_ratio = 0.;
+	ord_stats[i].std_gradient_ratio = 0.;
+	ord_stats[i].stream_frequency = 0.;
+	ord_stats[i].drainage_density = 0.;
+    }
+    for (i = 0; i < outlets_num; ++i) {	/* recalculate and unify */
+	stat_streams[i].elev_diff =
+	    stat_streams[i].elev_spring - stat_streams[i].elev_outlet;
+	tmp_num =
+	    ((stat_streams[i].cell_num - 1) <
+	     1) ? 1 : stat_streams[i].cell_num - 1;
+	stat_streams[i].slope /= tmp_num;
+	stat_streams[i].gradient =
+	    stat_streams[i].elev_diff / stat_streams[i].length;
+
+	/* calculation */
+	ord_stats[stat_streams[i].order].stream_num++;
+	ord_stats[stat_streams[i].order].sum_length += stat_streams[i].length;
+	ord_stats[stat_streams[i].order].std_length +=
+	    (stat_streams[i].length * stat_streams[i].length);
+	ord_stats[stat_streams[i].order].avg_slope += stat_streams[i].slope;
+	ord_stats[stat_streams[i].order].std_slope +=
+	    (stat_streams[i].slope * stat_streams[i].slope);
+	ord_stats[stat_streams[i].order].avg_gradient +=
+	    stat_streams[i].gradient;
+	ord_stats[stat_streams[i].order].std_gradient +=
+	    (stat_streams[i].gradient * stat_streams[i].gradient);
+	ord_stats[stat_streams[i].order].sum_area +=
+	    stat_streams[i].basin_area;
+	ord_stats[stat_streams[i].order].std_area +=
+	    (stat_streams[i].basin_area * stat_streams[i].basin_area);
+	ord_stats[stat_streams[i].order].avg_elev_diff +=
+	    stat_streams[i].elev_diff;
+	ord_stats[stat_streams[i].order].std_elev_diff +=
+	    (stat_streams[i].elev_diff * stat_streams[i].elev_diff);
+    }
+
+    for (i = 1; i <= order_max; ++i) {
+
+	num = ord_stats[i].stream_num;
+	snum = (ord_stats[i].stream_num > 1) ?
+	    ((float)ord_stats[i].stream_num) / (ord_stats[i].stream_num -
+						1) : 0.;
+
+	ord_stats[i].avg_length = ord_stats[i].sum_length / num;
+	ord_stats[i].avg_slope = ord_stats[i].avg_slope / num;
+	ord_stats[i].avg_gradient = ord_stats[i].avg_gradient / num;
+	ord_stats[i].avg_area = ord_stats[i].sum_area / num;
+	ord_stats[i].avg_elev_diff = ord_stats[i].avg_elev_diff / num;
+
+	ord_stats[i].std_length = sqrt((ord_stats[i].std_length / num -
+					(ord_stats[i].avg_length *
+					 ord_stats[i].avg_length)) * snum);
+
+	ord_stats[i].std_slope = sqrt((ord_stats[i].std_slope / num -
+				       (ord_stats[i].avg_slope *
+					ord_stats[i].avg_slope)) * snum);
+
+	ord_stats[i].std_gradient = sqrt((ord_stats[i].std_gradient / num -
+					  (ord_stats[i].avg_gradient *
+					   ord_stats[i].avg_gradient)) *
+					 snum);
+
+	ord_stats[i].std_area = sqrt((ord_stats[i].std_area / num -
+				      (ord_stats[i].avg_area *
+				       ord_stats[i].avg_area)) * snum);
+
+	ord_stats[i].std_elev_diff = sqrt((ord_stats[i].std_elev_diff / num -
+					   (ord_stats[i].avg_elev_diff *
+					    ord_stats[i].avg_elev_diff)) *
+					  snum);
+
+	ord_stats[i - 1].bifur_ratio =
+	    ord_stats[i - 1].stream_num / (float)ord_stats[i].stream_num;
+
+	ord_stats[i - 1].length_ratio = (i == 1) ? 0 :
+	    ord_stats[i].avg_length / ord_stats[i - 1].avg_length;
+
+	ord_stats[i].area_ratio = (i == 1) ? 0 :
+	    ord_stats[i].avg_area / ord_stats[i - 1].avg_area;
+
+	ord_stats[i - 1].slope_ratio =
+	    ord_stats[i - 1].avg_slope / ord_stats[i].avg_slope;
+
+	ord_stats[i - 1].gradient_ratio =
+	    ord_stats[i - 1].avg_gradient / ord_stats[i].avg_gradient;
+
+	ord_stats[i].stream_frequency =
+	    ord_stats[i].stream_num / ord_stats[i].sum_area;
+
+	ord_stats[i].drainage_density =
+	    ord_stats[i].sum_length / ord_stats[i].sum_area;
+
+	/* total */
+	stats_total.stream_num += ord_stats[i].stream_num;
+	stats_total.sum_length += ord_stats[i].sum_length;
+
+	stats_total.bifur_ratio += ord_stats[i - 1].bifur_ratio;
+	stats_total.length_ratio += ord_stats[i - 1].length_ratio;
+	stats_total.area_ratio += ord_stats[i - 1].area_ratio;
+	stats_total.slope_ratio += ord_stats[i - 1].slope_ratio;
+	stats_total.gradient_ratio += ord_stats[i - 1].gradient_ratio;
+
+	stats_total.std_bifur_ratio +=
+	    (ord_stats[i - 1].bifur_ratio * ord_stats[i - 1].bifur_ratio);
+	stats_total.std_length_ratio +=
+	    (ord_stats[i - 1].length_ratio * ord_stats[i - 1].length_ratio);
+	stats_total.std_area_ratio +=
+	    (ord_stats[i - 1].area_ratio * ord_stats[i - 1].area_ratio);
+	stats_total.std_slope_ratio +=
+	    (ord_stats[i - 1].slope_ratio * ord_stats[i - 1].slope_ratio);
+	stats_total.std_gradient_ratio +=
+	    (ord_stats[i - 1].gradient_ratio *
+	     ord_stats[i - 1].gradient_ratio);
+
+    }				/* end for ... orders */
+    ord_num = order_max - 1;
+    ord_snum = (ord_num == 1) ? 0 : (float)ord_num / (ord_num - 1);
+
+    stats_total.order = order_max;
+    stats_total.sum_area = total_basins;
+    stats_total.sum_length = stats_total.sum_length;
+
+    stats_total.bifur_ratio = stats_total.bifur_ratio / ord_num;
+    stats_total.length_ratio = stats_total.length_ratio / ord_num;
+    stats_total.area_ratio = stats_total.area_ratio / ord_num;
+    stats_total.slope_ratio = stats_total.slope_ratio / ord_num;
+    stats_total.gradient_ratio = stats_total.gradient_ratio / ord_num;
+
+
+    stats_total.std_bifur_ratio =
+	sqrt((stats_total.std_bifur_ratio / ord_num -
+	      (stats_total.bifur_ratio * stats_total.bifur_ratio)) *
+	     ord_snum);
+
+    stats_total.std_length_ratio =
+	sqrt((stats_total.std_length_ratio / ord_num -
+	      (stats_total.length_ratio * stats_total.length_ratio)) *
+	     ord_snum);
+
+    stats_total.std_area_ratio = sqrt((stats_total.std_area_ratio / ord_num -
+				       (stats_total.area_ratio *
+					stats_total.area_ratio)) * ord_snum);
+
+    stats_total.std_slope_ratio =
+	sqrt((stats_total.std_slope_ratio / ord_num -
+	      (stats_total.slope_ratio * stats_total.slope_ratio)) *
+	     ord_snum);
+
+    stats_total.std_gradient_ratio =
+	sqrt((stats_total.std_gradient_ratio / ord_num -
+	      (stats_total.gradient_ratio * stats_total.gradient_ratio)) *
+	     ord_snum);
+
+    stats_total.stream_frequency =
+	stats_total.stream_num / stats_total.sum_area;
+    stats_total.drainage_density =
+	stats_total.sum_length / stats_total.sum_area;
+
+
+    /* linerar regresion statistics */
+    statistic = (double *)G_malloc((order_max + 1) * sizeof(double));
+
+    for (i = 1; i <= order_max; ++i)
+	statistic[i] = log10((double)ord_stats[i].stream_num);
+    stats_total.reg_bifur_ratio =
+	1 / pow(10, stats_linear_reg(order_max, statistic));
+
+    for (i = 1; i <= order_max; ++i)
+	statistic[i] = log10((double)ord_stats[i].avg_length);
+    stats_total.reg_length_ratio =
+	pow(10, stats_linear_reg(order_max, statistic));
+
+    for (i = 1; i <= order_max; ++i)
+	statistic[i] = log10((double)ord_stats[i].avg_area);
+    stats_total.reg_area_ratio =
+	pow(10, stats_linear_reg(order_max, statistic));
+
+    for (i = 1; i <= order_max; ++i)
+	statistic[i] = log10((double)ord_stats[i].avg_slope);
+    stats_total.reg_slope_ratio =
+	1 / pow(10, stats_linear_reg(order_max, statistic));
+
+    for (i = 1; i <= order_max; ++i)
+	statistic[i] = log10((double)ord_stats[i].avg_gradient);
+    stats_total.reg_gradient_ratio =
+	1 / pow(10, stats_linear_reg(order_max, statistic));
+
+    G_free(statistic);
+
+    return 0;
+}

Added: grass-addons/grass7/grass7/raster/r.stream.stats/stats_prepare.c
===================================================================
--- grass-addons/grass7/grass7/raster/r.stream.stats/stats_prepare.c	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.stream.stats/stats_prepare.c	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,464 @@
+#include "local_proto.h"
+static int tail, head, fifo_count;
+
+int fifo_insert(POINT point)
+{
+    if (fifo_count == fifo_max)
+	G_fatal_error("fifo queue: circular buffer too small");
+
+    fifo_points[tail++] = point;
+    if (tail > fifo_max) {
+	G_debug(1, "tail > fifo_max");
+	tail = 0;
+    }
+    fifo_count++;
+    return 0;
+}
+
+POINT fifo_return_del(void)
+{
+    if (head >= fifo_max) {
+	G_debug(1, "head >= fifo_max");
+	head = -1;
+    }
+    fifo_count--;
+
+    return fifo_points[++head];
+}
+
+int ram_init_streams(CELL **streams, CELL **dirs, FCELL **elevation)
+{
+    int d, i;		/* d: direction, i: iteration */
+    int r, c;
+    int next_stream = -1, cur_stream;
+    int out_max = ncols + nrows;
+    POINT *outlets;
+
+    outlets = (POINT *) G_malloc((out_max) * sizeof(POINT));
+    outlets_num = 0;
+
+    for (r = 0; r < nrows; ++r)
+	for (c = 0; c < ncols; ++c)
+	    if (streams[r][c] > 0) {
+		if (outlets_num > (out_max - 1)) {
+		    out_max *= 2;
+		    outlets =
+			(POINT *) G_realloc(outlets, out_max * sizeof(POINT));
+		}
+		d = abs(dirs[r][c]);
+		if (NOT_IN_REGION(d))
+		    next_stream = -1;	/* border */
+		else {
+		    next_stream = streams[NR(d)][NC(d)];
+		    if (next_stream < 1)
+			next_stream = -1;
+		}
+
+		if (d == 0)
+		    next_stream = -1;
+		cur_stream = streams[r][c];
+
+		if (cur_stream != next_stream) {	/* is outlet or node! */
+		    outlets[outlets_num].r = r;
+		    outlets[outlets_num].c = c;
+
+		    if (next_stream == -1)
+			outlets[outlets_num].is_outlet = 1;
+		    else
+			outlets[outlets_num].is_outlet = 0;
+
+		    outlets_num++;
+
+		}
+	    }			/* end if streams */
+
+    stat_streams = (STREAM *) G_malloc((outlets_num) * sizeof(STREAM));
+
+    for (i = 0; i < outlets_num; ++i) {
+	stat_streams[i].r = outlets[i].r;
+	stat_streams[i].c = outlets[i].c;
+	stat_streams[i].is_outlet = outlets[i].is_outlet;
+	stat_streams[i].index = i;
+	stat_streams[i].slope = 0.;
+	stat_streams[i].gradient = 0.;
+	stat_streams[i].length = 0.;
+	stat_streams[i].elev_diff = 0.;
+	stat_streams[i].elev_spring = 0.;
+	stat_streams[i].elev_outlet = elevation[outlets[i].r][outlets[i].c];
+	stat_streams[i].order = streams[outlets[i].r][outlets[i].c];
+	stat_streams[i].basin_area = 0.;
+	stat_streams[i].cell_num = 0;
+    }
+
+    G_free(outlets);
+    return 0;
+}
+
+/////
+
+int seg_init_streams(SEGMENT *streams, SEGMENT *dirs, SEGMENT *elevation)
+{
+    int d, i;		/* d: direction, i: iteration */
+    int r, c;
+    int next_stream = -1, cur_stream;
+    int out_max = ncols + nrows;
+    CELL streams_cell, dirs_cell;
+    POINT *outlets;
+
+    outlets = (POINT *) G_malloc((out_max) * sizeof(POINT));
+    outlets_num = 0;
+
+    for (r = 0; r < nrows; ++r)
+	for (c = 0; c < ncols; ++c) {
+	    segment_get(streams, &streams_cell, r, c);
+	    if (streams_cell > 0) {
+		if (outlets_num > (out_max - 1)) {
+		    out_max *= 2;
+		    outlets =
+			(POINT *) G_realloc(outlets, out_max * sizeof(POINT));
+		}
+
+		segment_get(dirs, &dirs_cell, r, c);
+		d = abs(dirs_cell);
+		if (NOT_IN_REGION(d))
+		    next_stream = -1;	/* border */
+		else {
+		    segment_get(streams, &next_stream, NR(d), NC(d));
+		    if (next_stream < 1)
+			next_stream = -1;
+		}
+
+		if (d == 0)
+		    next_stream = -1;
+		cur_stream = streams_cell;
+
+		if (cur_stream != next_stream) {	/* is outlet or node! */
+		    outlets[outlets_num].r = r;
+		    outlets[outlets_num].c = c;
+
+		    if (next_stream == -1)
+			outlets[outlets_num].is_outlet = 1;
+		    else
+			outlets[outlets_num].is_outlet = 0;
+
+		    outlets_num++;
+
+
+		}
+	    }			/* end if streams */
+	}
+
+    stat_streams = (STREAM *) G_malloc((outlets_num) * sizeof(STREAM));
+
+    for (i = 0; i < outlets_num; ++i) {
+	stat_streams[i].r = outlets[i].r;
+	stat_streams[i].c = outlets[i].c;
+	stat_streams[i].is_outlet = outlets[i].is_outlet;
+	stat_streams[i].index = i;
+	stat_streams[i].slope = 0.;
+	stat_streams[i].gradient = 0.;
+	stat_streams[i].length = 0.;
+	stat_streams[i].elev_diff = 0.;
+	stat_streams[i].elev_spring = 0.;
+	segment_get(elevation, &(stat_streams[i].elev_outlet), outlets[i].r,
+		    outlets[i].c);
+	segment_get(streams, &(stat_streams[i].order), outlets[i].r,
+		    outlets[i].c);
+	stat_streams[i].basin_area = 0.;
+	stat_streams[i].cell_num = 0;
+    }
+
+    G_free(outlets);
+    return 0;
+}
+
+
+int ram_calculate_streams(CELL **streams, CELL **dirs, FCELL **elevation)
+{
+
+    int i, j, s, d;		/* s - streams index */
+    int done = 1;
+    int r, c;
+    int next_r, next_c;
+    float cur_northing, cur_easting;
+    float next_northing, next_easting;
+    float diff_elev;
+    double cur_length;
+    struct Cell_head window;
+
+    G_get_window(&window);
+    G_begin_distance_calculations();
+
+    for (s = 0; s < outlets_num; ++s) {
+	r = stat_streams[s].r;
+	c = stat_streams[s].c;
+
+	cur_northing = window.north - (r + .5) * window.ns_res;
+	cur_easting = window.west + (c + .5) * window.ew_res;
+	d = (dirs[r][c] == 0) ? 2 : abs(dirs[r][c]);
+
+	next_northing = window.north - (NR(d) + .5) * window.ns_res;
+	next_easting = window.west + (NC(d) + .5) * window.ew_res;
+
+	stat_streams[s].length =
+	    G_distance(next_easting, next_northing, cur_easting,
+		       cur_northing);
+
+	done = 1;
+
+	while (done) {
+	    done = 0;
+	    cur_northing = window.north - (r + .5) * window.ns_res;
+	    cur_easting = window.west + (c + .5) * window.ew_res;
+
+	    stat_streams[s].cell_num++;
+	    stat_streams[s].elev_spring = elevation[r][c];
+
+	    for (i = 1; i < 9; ++i) {
+		if (NOT_IN_REGION(i))
+		    continue;	/* border */
+
+		j = DIAG(i);
+		next_r = NR(i);
+		next_c = NC(i);
+
+		if (streams[next_r][next_c] == stat_streams[s].order &&
+		    dirs[next_r][next_c] == j) {
+
+		    next_northing =
+			window.north - (next_r + .5) * window.ns_res;
+		    next_easting =
+			window.west + (next_c + .5) * window.ew_res;
+		    cur_length =
+			G_distance(next_easting, next_northing, cur_easting,
+				   cur_northing);
+		    diff_elev = elevation[next_r][next_c] - elevation[r][c];
+		    diff_elev = (diff_elev < 0) ? 0. : diff_elev;	/* water cannot flow up */
+
+		    stat_streams[s].length += cur_length;
+		    stat_streams[s].slope += (diff_elev / cur_length);
+
+		    r = next_r;
+		    c = next_c;
+		    done = 1;
+		    break;
+		}		/* end if */
+	    }			/* end for i */
+	}			/* end while */
+    }				/* end for s */
+    return 0;
+}
+
+
+////
+
+
+int seg_calculate_streams(SEGMENT *streams, SEGMENT *dirs,
+			  SEGMENT *elevation)
+{
+
+    int i, j, s, d;		/* s - streams index */
+    int done = 1;
+    int r, c;
+    int next_r, next_c;
+    float cur_northing, cur_easting;
+    float next_northing, next_easting;
+    float diff_elev;
+    double cur_length;
+    CELL streams_cell, dirs_cell;
+    FCELL elevation_cell, elevation_next_cell;
+    struct Cell_head window;
+
+    G_get_window(&window);
+    G_begin_distance_calculations();
+
+    for (s = 0; s < outlets_num; ++s) {
+	r = stat_streams[s].r;
+	c = stat_streams[s].c;
+
+	cur_northing = window.north - (r + .5) * window.ns_res;
+	cur_easting = window.west + (c + .5) * window.ew_res;
+
+	segment_get(dirs, &dirs_cell, r, c);
+	d = (dirs_cell == 0) ? 2 : abs(dirs_cell);
+
+	next_northing = window.north - (NR(d) + .5) * window.ns_res;
+	next_easting = window.west + (NC(d) + .5) * window.ew_res;
+
+	stat_streams[s].length =
+	    G_distance(next_easting, next_northing, cur_easting,
+		       cur_northing);
+
+	done = 1;
+
+	while (done) {
+	    done = 0;
+	    cur_northing = window.north - (r + .5) * window.ns_res;
+	    cur_easting = window.west + (c + .5) * window.ew_res;
+
+	    stat_streams[s].cell_num++;
+	    segment_get(elevation, &(stat_streams[s].elev_spring), r, c);
+
+	    for (i = 1; i < 9; ++i) {
+		if (NOT_IN_REGION(i))
+		    continue;	/* border */
+
+		j = DIAG(i);
+		next_r = NR(i);
+		next_c = NC(i);
+
+		segment_get(streams, &streams_cell, next_r, next_c);
+		segment_get(dirs, &dirs_cell, next_r, next_c);
+
+		if (streams_cell == stat_streams[s].order && dirs_cell == j) {
+
+		    next_northing =
+			window.north - (next_r + .5) * window.ns_res;
+		    next_easting =
+			window.west + (next_c + .5) * window.ew_res;
+		    cur_length =
+			G_distance(next_easting, next_northing, cur_easting,
+				   cur_northing);
+
+		    segment_get(elevation, &elevation_next_cell, next_r,
+				next_c);
+		    segment_get(elevation, &elevation_cell, r, c);
+		    diff_elev = elevation_next_cell - elevation_cell;
+		    diff_elev = (diff_elev < 0) ? 0. : diff_elev;	/* water cannot flow up */
+
+		    stat_streams[s].length += cur_length;
+		    stat_streams[s].slope += (diff_elev / cur_length);
+
+		    r = next_r;
+		    c = next_c;
+		    done = 1;
+		    break;
+		}		/* end if */
+	    }			/* end for i */
+	}			/* end while */
+    }				/* end for s */
+    return 0;
+}
+
+double ram_calculate_basins_area(CELL **dirs, int r, int c)
+{
+    int i, j;
+    int next_r, next_c;
+    double area;
+    POINT n_cell;
+
+    tail = 0;
+    head = -1;
+
+    area = G_area_of_cell_at_row(r);
+
+    while (tail != head) {
+	for (i = 1; i < 9; ++i) {
+
+	    if (NOT_IN_REGION(i))
+		continue;	/* border */
+
+	    j = DIAG(i);
+	    next_r = NR(i);
+	    next_c = NC(i);
+
+	    if (dirs[next_r][next_c] == j) {	/* countributing cell */
+		area += G_area_of_cell_at_row(r);
+		n_cell.r = next_r;
+		n_cell.c = next_c;
+		fifo_insert(n_cell);
+	    }
+	}			/* end for i... */
+
+	n_cell = fifo_return_del();
+	r = n_cell.r;
+	c = n_cell.c;
+    }				/* end while */
+    return area;
+}
+
+
+int ram_calculate_basins(CELL **dirs)
+{
+    int i;
+
+    total_basins = 0.;
+
+    G_begin_cell_area_calculations();
+    fifo_max = 4 * (nrows + ncols);
+    fifo_points = (POINT *) G_malloc((fifo_max + 1) * sizeof(POINT));
+
+    for (i = 0; i < outlets_num; ++i) {
+	stat_streams[i].basin_area =
+	    ram_calculate_basins_area(dirs, stat_streams[i].r,
+				      stat_streams[i].c);
+
+	if (stat_streams[i].is_outlet)
+	    total_basins += stat_streams[i].basin_area;
+    }
+
+    G_free(fifo_points);
+    return 0;
+}
+
+double seg_calculate_basins_area(SEGMENT *dirs, int r, int c)
+{
+    int i, j;
+    int next_r, next_c;
+    double area;
+    CELL dirs_cell;
+    POINT n_cell;
+
+    tail = 0;
+    head = -1;
+
+    area = G_area_of_cell_at_row(r);
+
+    while (tail != head) {
+	for (i = 1; i < 9; ++i) {
+
+	    if (NOT_IN_REGION(i))
+		continue;	/* border */
+
+	    j = DIAG(i);
+	    next_r = NR(i);
+	    next_c = NC(i);
+
+	    segment_get(dirs, &dirs_cell, next_r, next_c);
+
+	    if (dirs_cell == j) {	/* countributing cell */
+		area += G_area_of_cell_at_row(r);
+		n_cell.r = next_r;
+		n_cell.c = next_c;
+		fifo_insert(n_cell);
+	    }
+	}			/* end for i... */
+
+	n_cell = fifo_return_del();
+	r = n_cell.r;
+	c = n_cell.c;
+    }				/* end while */
+    return area;
+}
+
+int seg_calculate_basins(SEGMENT *dirs)
+{
+    int i;
+
+    total_basins = 0.;
+
+    G_begin_cell_area_calculations();
+    fifo_max = 4 * (nrows + ncols);
+    fifo_points = (POINT *) G_malloc((fifo_max + 1) * sizeof(POINT));
+
+    for (i = 0; i < outlets_num; ++i) {
+	stat_streams[i].basin_area =
+	    seg_calculate_basins_area(dirs, stat_streams[i].r,
+				      stat_streams[i].c);
+	if (stat_streams[i].is_outlet)
+	    total_basins += stat_streams[i].basin_area;
+    }
+
+    G_free(fifo_points);
+    return 0;
+}

Added: grass-addons/grass7/grass7/raster/r.stream.stats/stats_print.c
===================================================================
--- grass-addons/grass7/grass7/raster/r.stream.stats/stats_print.c	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.stream.stats/stats_print.c	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,149 @@
+#include "local_proto.h"
+
+int print_stats(int order_max)
+{
+
+    int i;
+
+    fflush(stdout);
+    /* summary statistics */
+    fprintf(stdout, "\n");
+    fprintf(stdout, "Summary:\n");
+    fprintf(stdout,
+	    "Max order | Tot.N.str. | Tot.str.len. | Tot.area. | Dr.dens. | Str.freq. \n");
+    fprintf(stdout,
+	    "  (num)   |    (num)   |     (km)     |   (km2)   | (km/km2) | (num/km2) \n");
+    fprintf(stdout, " %8d | %10d | %12.4f | %9.4f | %8.4f | %7.4f \n",
+	    stats_total.order, stats_total.stream_num,
+	    stats_total.sum_length / 1000, stats_total.sum_area / 1000000,
+	    stats_total.drainage_density * 1000,
+	    stats_total.stream_frequency * 1000000);
+
+    fprintf(stdout, "\n");
+    fprintf(stdout, "Stream ratios based on regresion coefficient:\n");
+    fprintf(stdout, " Bif.rt. | Len.rt. | Area.rt. | Slo.rt. | Grd.rt. \n");
+    fprintf(stdout, " %7.4f | %7.4f | %8.4f | %7.4f | %7.4f\n",
+	    stats_total.reg_bifur_ratio,
+	    stats_total.reg_length_ratio,
+	    stats_total.reg_area_ratio,
+	    stats_total.reg_slope_ratio, stats_total.reg_gradient_ratio);
+    fprintf(stdout, "\n");
+    fprintf(stdout, "Avaraged stream ratios with standard deviations:\n");
+    fprintf(stdout, " Bif.rt. | Len.rt. | Area.rt. | Slo.rt. | Grd.rt. \n");
+    fprintf(stdout, " %7.4f | %7.4f | %8.4f | %7.4f | %7.4f\n",
+	    stats_total.bifur_ratio,
+	    stats_total.length_ratio,
+	    stats_total.area_ratio,
+	    stats_total.slope_ratio, stats_total.gradient_ratio);
+
+    fprintf(stdout, " %7.4f | %7.4f | %8.4f | %7.4f | %7.4f\n",
+	    stats_total.std_bifur_ratio,
+	    stats_total.std_length_ratio,
+	    stats_total.std_area_ratio,
+	    stats_total.std_slope_ratio, stats_total.std_gradient_ratio);
+    fprintf(stdout, "\n");
+
+    /* base parameters */
+    fprintf(stdout,
+	    "Order | Avg.len |  Avg.ar  |  Avg.sl |  Avg.grad. | Avg.el.dif\n");
+    fprintf(stdout,
+	    " num  |   (km)  |  (km2)   |  (m/m)  |    (m/m)   |     (m)   \n");
+    for (i = 1; i <= order_max; ++i) {
+	fprintf(stdout, "%5d | %7.4f | %8.4f | %7.4f | %10.4f | %7.4f\n",
+		ord_stats[i].order,
+		ord_stats[i].avg_length / 1000,
+		ord_stats[i].avg_area / 1000000,
+		ord_stats[i].avg_slope,
+		ord_stats[i].avg_gradient, ord_stats[i].avg_elev_diff);
+    }
+    fprintf(stdout, "\n");
+    /* std dev of base parameters */
+    fprintf(stdout,
+	    "Order | Std.len |  Std.ar  |  Std.sl |  Std.grad. | Std.el.dif\n");
+    fprintf(stdout,
+	    " num  |   (km)  |  (km2)   |  (m/m)  |    (m/m)   |     (m)   \n");
+    for (i = 1; i <= order_max; ++i) {
+	fprintf(stdout, "%5d | %7.4f | %8.4f | %7.4f | %10.4f | %7.4f\n",
+		ord_stats[i].order,
+		ord_stats[i].std_length / 1000,
+		ord_stats[i].std_area / 1000000,
+		ord_stats[i].std_slope,
+		ord_stats[i].std_gradient, ord_stats[i].std_elev_diff);
+    }
+    /* sum statistics of orders */
+    fprintf(stdout, "\n");
+    fprintf(stdout, "Order | N.streams | Tot.len (km) | Tot.area (km2)\n");
+    for (i = 1; i <= order_max; ++i) {
+	fprintf(stdout, "%5d | %9d | %12.4f | %7.4f\n",
+		ord_stats[i].order,
+		ord_stats[i].stream_num,
+		ord_stats[i].sum_length / 1000,
+		ord_stats[i].sum_area / 1000000);
+    }
+    /* order ratios */
+    fprintf(stdout, "\n");
+    fprintf(stdout,
+	    "Order | Bif.rt. | Len.rt. | Area.rt. | Slo.rt. | Grd.rt. | d.dens. | str.freq.\n");
+    for (i = 1; i <= order_max; ++i) {
+	fprintf(stdout,
+		"%5d | %7.4f | %7.4f | %8.4f | %7.4f | %7.4f | %7.4f | %7.4f\n",
+		ord_stats[i].order, ord_stats[i].bifur_ratio,
+		ord_stats[i].length_ratio, ord_stats[i].area_ratio,
+		ord_stats[i].slope_ratio, ord_stats[i].gradient_ratio,
+		ord_stats[i].drainage_density * 1000,
+		ord_stats[i].stream_frequency * 1000000);
+    }
+    fflush(stdout);
+    return 0;
+}
+
+int print_stats_total(void)
+{
+    fflush(stdout);
+    fprintf(stdout, "Catchment's characteristics (based on regresion):  \n");
+    fprintf(stdout, "Max order: %d \n", stats_total.order);
+    fprintf(stdout, "Total number of streams: %d \n", stats_total.stream_num);
+    fprintf(stdout, "Total stream length (km): %2.4f \n",
+	    stats_total.sum_length / 1000);
+    fprintf(stdout, "Total cachment area (km2): %2.4f \n",
+	    stats_total.sum_area / 1000000);
+    fprintf(stdout, "Drainage density: %2.4f\n",
+	    stats_total.drainage_density * 1000);
+    fprintf(stdout, "Stream frequency: %2.4f \n",
+	    stats_total.stream_frequency * 1000000);
+    fprintf(stdout, "Bifurcation ratio: %2.4f \n",
+	    stats_total.reg_bifur_ratio);
+    fprintf(stdout, "Length ratio: %2.4f \n", stats_total.reg_length_ratio);
+    fprintf(stdout, "Area ratio: %2.4f \n", stats_total.reg_area_ratio);
+    fprintf(stdout, "Slope ratio: %2.4f \n", stats_total.reg_slope_ratio);
+    fprintf(stdout, "Gradient ratio: %2.4f \n",
+	    stats_total.reg_gradient_ratio);
+    fflush(stdout);
+    return 0;
+}
+
+int print_stats_orders(int order_max)
+{
+
+    int i;
+
+    fflush(stdout);
+    fprintf(stdout, "Order's summary: \n");
+    fprintf(stdout,
+	    "order,num_of_streams,avg_length,avg_area,avg_slope,avg_grad,avg_elev.diff,sum_length,sum_area\n");
+
+    for (i = 1; i <= order_max; ++i) {
+	fprintf(stdout, "%d,%d,%f,%f,%f,%f,%f,%f,%f\n",
+		ord_stats[i].order,
+		ord_stats[i].stream_num,
+		ord_stats[i].avg_length / 1000,
+		ord_stats[i].avg_area / 1000000,
+		ord_stats[i].avg_slope,
+		ord_stats[i].avg_gradient,
+		ord_stats[i].avg_elev_diff,
+		ord_stats[i].sum_length / 1000,
+		ord_stats[i].sum_area / 1000000);
+    }
+    fflush(stdout);
+    return 0;
+}

Added: grass-addons/grass7/grass7/raster/r.sun.angle/Makefile
===================================================================
--- grass-addons/grass7/grass7/raster/r.sun.angle/Makefile	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.sun.angle/Makefile	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,12 @@
+MODULE_TOPDIR = ../..
+
+PGM = r.sun.angle
+
+LIBES = $(GPROJLIB) $(RASTERLIB) $(GISLIB)
+DEPENDENCIES = $(GPROJDEP) $(RASTERDEP) $(GISDEP)
+
+EXTRA_INC = $(PROJINC)
+
+include $(MODULE_TOPDIR)/include/Make/Module.make
+
+default: cmd

Added: grass-addons/grass7/grass7/raster/r.sun.angle/main.c
===================================================================
--- grass-addons/grass7/grass7/raster/r.sun.angle/main.c	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.sun.angle/main.c	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,521 @@
+
+/****************************************************************************
+ *
+ * MODULE:       r.sun.angle
+ * AUTHOR(S):    Markus Metz
+ * PURPOSE:      Calculates solar azimuth and angle
+ * COPYRIGHT:    (C) 2010 by the GRASS Development Team
+ *
+ *               This program is free software under the GNU General Public
+ *               License (>=v2). Read the file COPYING that comes with GRASS
+ *               for details.
+ *
+ *****************************************************************************/
+
+/* TODO: always use solpos if time is Greenwich standard time */
+
+#define MAIN
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include <grass/gis.h>
+#include <grass/raster.h>
+#include <grass/gprojects.h>
+#include <grass/glocale.h>
+#include "solpos00.h"
+
+void set_solpos_time(struct posdata *, int, int, int, int, int, int);
+void set_solpos_longitude(struct posdata *, double );
+int roundoff(double *);
+
+int main(int argc, char *argv[])
+{
+    struct GModule *module;
+    struct
+    {
+	struct Option *elev, *azimuth, *sunhours, *year,
+	    *month, *day, *hour, *minutes, *seconds;
+	struct Flag *gst_time, *solpos;
+    } parm;
+    struct Cell_head window;
+    FCELL *elevbuf, *azimuthbuf, *sunhourbuf;
+    struct History hist;
+
+    /* projection information of input map */
+    struct Key_Value *in_proj_info, *in_unit_info;
+    struct pj_info iproj;	/* input map proj parameters  */
+    struct pj_info oproj;	/* output map proj parameters  */
+
+    char *elev_name, *azimuth_name, *sunhour_name;
+    int elev_fd, azimuth_fd, sunhour_fd;
+    double ha, ha_cos, s_gamma, s_elevation, s_azimuth;
+    double s_declination, sd_sin, sd_cos;
+    double se_sin, sa_cos;
+    double east, east_ll, north, north_ll;
+    double north_gc, north_gc_sin, north_gc_cos;  /* geocentric latitude */
+    double ba2;
+    int year, month, day, hour, minutes, seconds;
+    int doy;   					/* day of year */
+    int row, col, nrows, ncols;
+    int do_reproj = 0;
+    int lst_time = 1;
+    int use_solpos = 0;
+    struct posdata pd;
+
+    G_gisinit(argv[0]);
+
+    module = G_define_module();
+    G_add_keyword(_("raster"));
+    G_add_keyword(_("solar"));
+    module->label = _("Calculates solar elevation and azimuth.");
+    module->description = _("Solar elevation: the angle between the direction of the geometric center "
+			    "of the sun's apparent disk and the (idealized) horizon. "
+			    "Solar azimuth: the angle from due north in clockwise direction.");
+    
+    parm.elev = G_define_standard_option(G_OPT_R_OUTPUT);
+    parm.elev->key = "elevation";
+    parm.elev->label = _("Output raster map with solar elevation angle");
+    parm.elev->required = NO;
+
+    parm.azimuth = G_define_standard_option(G_OPT_R_OUTPUT);
+    parm.azimuth->key = "azimuth";
+    parm.azimuth->label = _("Output raster map with solar azimuth angle");
+    parm.azimuth->required = NO;
+    
+    parm.sunhours = G_define_standard_option(G_OPT_R_OUTPUT);
+    parm.sunhours->key = "sunhour";
+    parm.sunhours->label = _("Output raster map with sunshine hours");
+    parm.sunhours->description = _("Sunshine hours require solpos and Greenwich standard time");
+    parm.sunhours->required = NO;
+
+    parm.year = G_define_option();
+    parm.year->key = "year";
+    parm.year->type = TYPE_INTEGER;
+    parm.year->required = YES;
+    parm.year->description = _("Year");
+    parm.year->options = "1950-2050";
+    parm.year->guisection = _("Time");
+
+    parm.month = G_define_option();
+    parm.month->key = "month";
+    parm.month->type = TYPE_INTEGER;
+    parm.month->required = NO;
+    parm.month->label = _("Month");
+    parm.month->description = _("If not given, day is interpreted as day of the year");
+    parm.month->options = "0-12";
+    parm.month->guisection = _("Time");
+
+    parm.day = G_define_option();
+    parm.day->key = "day";
+    parm.day->type = TYPE_INTEGER;
+    parm.day->required = YES;
+    parm.day->description = _("Day");
+    parm.day->options = "0-365";
+    parm.day->guisection = _("Time");
+
+    parm.hour = G_define_option();
+    parm.hour->key = "hour";
+    parm.hour->type = TYPE_INTEGER;
+    parm.hour->required = YES;
+    parm.hour->description = _("Hour");
+    parm.hour->options = "0-24";
+    parm.hour->answer = "12";
+    parm.hour->guisection = _("Time");
+
+    parm.minutes = G_define_option();
+    parm.minutes->key = "minute";
+    parm.minutes->type = TYPE_INTEGER;
+    parm.minutes->required = YES;
+    parm.minutes->description = _("Minutes");
+    parm.minutes->options = "0-60";
+    parm.minutes->answer = "0";
+    parm.minutes->guisection = _("Time");
+
+    parm.seconds = G_define_option();
+    parm.seconds->key = "second";
+    parm.seconds->type = TYPE_INTEGER;
+    parm.seconds->required = YES;
+    parm.seconds->description = _("Seconds");
+    parm.seconds->options = "0-60";
+    parm.seconds->answer = "0";
+    parm.seconds->guisection = _("Time");
+
+    parm.gst_time = G_define_flag();
+    parm.gst_time->key = 't';
+    parm.gst_time->description = _("Time is Greenwich standard time, not local sidereal time");
+
+    parm.solpos = G_define_flag();
+    parm.solpos->key = 's';
+    parm.solpos->description = _("Use solpos algorithm of NREL");
+
+    if (G_parser(argc, argv))
+	exit(EXIT_FAILURE);
+
+    G_get_window(&window);
+
+    /* require at least one output */
+    elev_name = parm.elev->answer;
+    azimuth_name = parm.azimuth->answer;
+    sunhour_name = parm.sunhours->answer;
+    if (!elev_name && !azimuth_name && !sunhour_name)
+	G_fatal_error(_("No output requested, exiting."));
+
+    sscanf(parm.year->answer, "%i", &year);
+    if (parm.month->answer)
+	sscanf(parm.month->answer, "%i", &month);
+    else
+	month = -1;
+    sscanf(parm.day->answer, "%i", &day);
+    sscanf(parm.hour->answer, "%i", &hour);
+    sscanf(parm.minutes->answer, "%i", &minutes);
+    sscanf(parm.seconds->answer, "%i", &seconds);
+
+    lst_time = (parm.gst_time->answer == 0);
+    use_solpos = parm.solpos->answer;
+
+    /* init variables */
+    ha = 180;
+    ha_cos = 0;
+    sd_cos = 0;
+    sd_sin = 1;
+    north_gc_cos = 0;
+    north_gc_sin = 1;
+    se_sin = 0;
+
+    if (use_solpos && lst_time) {
+	G_warning(_("NREL solpos algorithm uses Greenwich standard time."));
+	G_warning(_("Time will be interpreted as Greenwich standard time."));
+
+	lst_time = 0;
+    }
+    if (!use_solpos) {
+	if (lst_time)
+	    G_message(_("Time will be interpreted as local sidereal time."));
+	else
+	    G_message(_("Time will be interpreted as Greenwich standard time."));
+	
+	if (sunhour_name)
+	    G_fatal_error(_("Sunshine hours require solpos"));
+    }
+
+    if ((G_projection() != PROJECTION_LL)) {
+	if (window.proj == 0)
+	    G_fatal_error(_("Current projection is x,y (undefined)."));
+
+	do_reproj = 1;
+
+	/* read current projection info */
+	if ((in_proj_info = G_get_projinfo()) == NULL)
+	    G_fatal_error(_("Can't get projection info of current location"));
+
+	if ((in_unit_info = G_get_projunits()) == NULL)
+	    G_fatal_error(_("Can't get projection units of current location"));
+
+	if (pj_get_kv(&iproj, in_proj_info, in_unit_info) < 0)
+	    G_fatal_error(_("Can't get projection key values of current location"));
+
+	G_free_key_value(in_proj_info);
+	G_free_key_value(in_unit_info);
+
+	/*  output projection to lat/long w/ same ellipsoid as input */
+	oproj.zone = 0;
+	oproj.meters = 1.;
+	sprintf(oproj.proj, "ll");
+	if ((oproj.pj = pj_latlong_from_proj(iproj.pj)) == NULL)
+	    G_fatal_error(_("Unable to update lat/long projection parameters"));
+    }
+
+    /* always init pd */
+    S_init(&pd);
+    pd.function = S_GEOM;
+    if (use_solpos) {
+	pd.function = S_ZENETR;
+	if (azimuth_name)
+	    pd.function = S_SOLAZM;
+	if (sunhour_name)
+	    pd.function |= S_SRSS;
+    }
+    if (month == -1)
+	doy = day;
+    else
+	doy = dom2doy2(year, month, day);
+    
+    set_solpos_time(&pd, year, 1, doy, hour, minutes, seconds);
+    set_solpos_longitude(&pd, 0);
+    pd.latitude = 0;
+    S_solpos(&pd);
+
+    if (lst_time) {
+	/* hour angle */
+	/***************************************************************
+	 * The hour angle of a point on the Earth's surface is the angle
+	 * through which the earth would turn to bring the meridian of
+	 * the point directly under the sun. This angular displacement
+	 * represents time (1 hour = 15 degrees).
+	 * The hour angle is negative in the morning, zero at 12:00,
+	 * and positive in the afternoon
+	 ***************************************************************/
+
+	ha = 15.0 * (hour + minutes / 60.0 + seconds / 3600.0) - 180.;
+	G_debug(1, "Solar hour angle, degrees: %.2f", ha);
+	ha *= DEG2RAD;
+	ha_cos = cos(ha);
+	roundoff(&ha_cos);
+    }
+
+    if (!use_solpos) {
+	/* sun declination */
+	/***************************************************************
+	 * The declination of the sun is the angle between
+	 * the rays of the sun and the plane of the Earth's equator.
+	 ***************************************************************/
+
+	s_gamma = (2 * M_PI * (doy - 1)) / 365;
+	G_debug(1, "fractional year in radians: %.2f", s_gamma);
+	/* sun declination for day of year with Fourier series representation
+	 * NOTE: based on 1950, override with solpos */
+	s_declination = (0.006918 - 0.399912 * cos(s_gamma) + 0.070257 * sin(s_gamma) -
+			 0.006758 * cos(2 * s_gamma) + 0.000907 * sin(2 * s_gamma) -
+			 0.002697 * cos(3 * s_gamma) + 0.00148 * sin(3 * s_gamma));
+
+	G_debug(1, "sun declination: %.5f", s_declination * RAD2DEG);
+	G_debug(1, "sun declination (solpos): %.5f", pd.declin);
+
+	if (lst_time) {
+	    north_ll = (window.north + window.south) / 2;
+	    east_ll = (window.east + window.west) / 2;
+	    if (do_reproj) {
+		if (pj_do_proj(&east_ll, &north_ll, &iproj, &oproj) < 0)
+		    G_fatal_error(_("Error in pj_do_proj (projection of input coordinate pair)"));
+	    }
+	    pd.timezone = east_ll / 15.;
+	    pd.time_updated = 1;
+	    set_solpos_longitude(&pd, east_ll);
+	    G_debug(1, "fake timezone: %.2f", pd.timezone);
+	    S_solpos(&pd);
+	    G_debug(1, "Solar hour angle (solpos), degrees: %.2f", pd.hrang);
+	}
+
+	/* always use solpos sun declination */
+	s_declination = pd.declin * DEG2RAD;
+	sd_sin = sin(s_declination);
+	roundoff(&sd_sin);
+	sd_cos = cos(s_declination);
+	roundoff(&sd_cos);
+
+	G_debug(1, "sun declination (solpos): %.5f", s_declination * RAD2DEG);
+
+	if (0 && lst_time) {
+	    pd.timezone = 0;
+	    pd.time_updated = pd.longitude_updated = 1;
+	    S_solpos(&pd);
+	}
+    }
+
+    if (elev_name) {
+	if ((elev_fd = Rast_open_new(elev_name, FCELL_TYPE)) < 0)
+	    G_fatal_error(_("Unable to create raster map <%s>"), elev_name);
+
+	elevbuf = Rast_allocate_f_buf();
+    }
+    else {
+	elevbuf = NULL;
+	elev_fd = -1;
+    }
+
+    if (azimuth_name) {
+	if ((azimuth_fd = Rast_open_new(azimuth_name, FCELL_TYPE)) < 0)
+	    G_fatal_error(_("Unable to create raster map <%s>"), azimuth_name);
+
+	azimuthbuf = Rast_allocate_f_buf();
+    }
+    else {
+	azimuthbuf = NULL;
+	azimuth_fd = -1;
+    }
+
+    if (sunhour_name) {
+	if ((sunhour_fd = Rast_open_new(sunhour_name, FCELL_TYPE)) < 0)
+	    G_fatal_error(_("Unable to create raster map <%s>"), sunhour_name);
+
+	sunhourbuf = Rast_allocate_f_buf();
+    }
+    else {
+	sunhourbuf = NULL;
+	sunhour_fd = -1;
+    }
+
+    if (elev_name && azimuth_name) {
+	G_message(_("Calculating solar elevation and azimuth..."));
+    }
+    else if (elev_name) {
+	G_message(_("Calculating solar elevation..."));
+    }
+    else if (azimuth_name) {
+	G_message(_("Calculating solar azimuth..."));
+    }
+
+    nrows = Rast_window_rows();
+    ncols = Rast_window_cols();
+
+    ba2 = 6356752.3142 / 6378137.0;
+    ba2 = ba2 * ba2;
+
+    for (row = 0; row < nrows; row++) {
+
+	G_percent(row, nrows, 2);
+	
+	/* get cell center northing */
+	north = window.north - (row + 0.5) * window.ns_res;
+	north_ll = north;
+
+	for (col = 0; col < ncols; col++) {
+	    long int retval;
+	    s_elevation = s_azimuth = -1.;
+
+	    /* get cell center easting */
+	    east = window.west + (col + 0.5) * window.ew_res;
+	    east_ll = east;
+
+	    if (do_reproj) {
+		north_ll = north;
+
+		if (pj_do_proj(&east_ll, &north_ll, &iproj, &oproj) < 0)
+		    G_fatal_error(_("Error in pj_do_proj (projection of input coordinate pair)"));
+	    }
+
+	    /* geocentric latitude */
+	    north_gc = atan(ba2 * tan(DEG2RAD * north_ll));
+	    north_gc_sin = sin(north_gc);
+	    roundoff(&north_gc_sin);
+	    north_gc_cos = cos(north_gc);
+	    roundoff(&north_gc_cos);
+
+	    if (!lst_time) {
+		set_solpos_longitude(&pd, east_ll);
+		pd.latitude = north_gc * RAD2DEG;
+		retval = S_solpos(&pd);
+		S_decode(retval, &pd);
+		G_debug(3, "solpos hour angle: %.5f", pd.hrang);
+	    }
+
+	    /* solar elevation angle */
+	    if (!use_solpos) {
+		if (!lst_time) {
+		    ha = pd.hrang;
+		    ha_cos = cos(ha * DEG2RAD);
+		    roundoff(&ha_cos);
+		}
+		se_sin = ha_cos * sd_cos * north_gc_cos + sd_sin * north_gc_sin;
+		roundoff(&se_sin);
+		s_elevation = RAD2DEG * asin(se_sin);
+	    }
+	    else /* use_solpos && !lst_time */
+		s_elevation = pd.elevetr;
+
+	    if (elev_name)
+		elevbuf[col] = s_elevation;
+
+	    if (azimuth_name) {
+		/* solar azimuth angle */
+		if (!use_solpos) {
+		    sa_cos = (se_sin * north_gc_sin - sd_sin) /
+		             (cos(DEG2RAD * s_elevation) * north_gc_cos);
+		    roundoff(&sa_cos);
+		    s_azimuth = RAD2DEG * acos(sa_cos);
+		    
+		    /* morning */
+		    s_azimuth = 180. - RAD2DEG * acos(sa_cos);
+		    if (ha > 0)   /* afternoon */
+			s_azimuth = 360.0 - s_azimuth;
+		}
+		else
+		    s_azimuth = pd.azim;
+
+		azimuthbuf[col] = s_azimuth;
+	    }
+	    
+	    if (sunhour_name) {
+		sunhourbuf[col] = (pd.ssetr - pd.sretr) / 60.;
+		if (sunhourbuf[col] > 24.)
+		    sunhourbuf[col] = 24.;
+		if (sunhourbuf[col] < 0.)
+		    sunhourbuf[col] = 0.;
+	    }
+
+	}
+	if (elev_name)
+	    Rast_put_f_row(elev_fd, elevbuf);
+	if (azimuth_name)
+	    Rast_put_f_row(azimuth_fd, azimuthbuf);
+	if (sunhour_name)
+	    Rast_put_f_row(sunhour_fd, sunhourbuf);
+    }
+    G_percent(1, 1, 2);
+
+    if (elev_name) {
+	Rast_close(elev_fd);
+	/* writing history file */
+	Rast_short_history(elev_name, "raster", &hist);
+	Rast_command_history(&hist);
+	Rast_write_history(elev_name, &hist);
+    }
+    if (azimuth_name) {
+	Rast_close(azimuth_fd);
+	/* writing history file */
+	Rast_short_history(azimuth_name, "raster", &hist);
+	Rast_command_history(&hist);
+	Rast_write_history(azimuth_name, &hist);
+    }
+    if (sunhour_name) {
+	Rast_close(sunhour_fd);
+	/* writing history file */
+	Rast_short_history(sunhour_name, "raster", &hist);
+	Rast_command_history(&hist);
+	Rast_write_history(sunhour_name, &hist);
+    }
+
+    G_done_msg(" ");
+
+    exit(EXIT_SUCCESS);
+}
+
+void set_solpos_time(struct posdata *pdat, int year, int month, int day,
+                    int hour, int minute, int second)
+{
+    pdat->year = year; 
+    pdat->month = month; 
+    pdat->day = day; 
+    pdat->daynum = day; 
+    pdat->hour = hour; 
+    pdat->minute = minute; 
+    pdat->second = second;
+    pdat->timezone = 0;
+
+    pdat->time_updated = 1; 
+    pdat->longitude_updated = 1;
+}
+
+void set_solpos_longitude(struct posdata *pdat, double longitude)
+{
+    pdat->longitude = longitude;
+
+    pdat->longitude_updated = 1;
+}
+
+int roundoff(double *x)
+{
+    /* watch out for the roundoff errors */
+    if (fabs(*x) > 1.0) {
+	if (*x > 0.0)
+	    *x = 1.0;
+	else
+	    *x = -1.0;
+
+	return 1;
+    }
+
+    return 0;
+}

Added: grass-addons/grass7/grass7/raster/r.sun.angle/r.sun.angle.html
===================================================================
--- grass-addons/grass7/grass7/raster/r.sun.angle/r.sun.angle.html	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.sun.angle/r.sun.angle.html	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,42 @@
+<h2>DESCRIPTION</h2>
+
+<em>r.sun.angle</em> calculates sun elevation and sun azimuth angles for
+the given time of day and each grid cell in the current region. 
+Additionally, the photoperiod (sunshine hours) can be calculated.
+
+<p>
+Sun elevation, height, height angle, or solar altitude angle is the
+angle in degrees between the horizon and a line that points from the
+site towards the centre of the sun.
+<p>
+The sun azimuth angle is here defined as the azimuth angle in degrees
+of the sun from due north in a clockwise direction.
+<p>
+The time used here is defined such that 12:00 (high noon) is the time
+when the sun has reached its highest point in the sky at the current site,
+unless the <em>-t</em> flag is used in which case time is interpreted as 
+Greenwich standard time.
+<p>
+If a <em>sunhour</em> output map is specified, the module calculates 
+sunshine hours for the given day. This option requires both Greenwhich 
+standard time (<em>-t</em> flag) and the solpos algorithm of NREL 
+(<em>-s</em> flag).
+
+<h2>EXAMPLES</h2>
+
+Calculate sun's elevation angle map for 2010-10-11 at 14:00h solar time:
+<div class="code"><pre>
+r.sun.angle elevation=sun_elev year=2010 month=10 day=11 hour=14 minute=00
+</pre></div>
+<p>
+
+Calculate photoperiod of day of year 1 (1st January) 2012
+<div class="code"><pre>
+r.sun.angle -s sunhour=photoperiod_doy_001 year=2012 day=1
+</pre></div>
+
+<h2>AUTHOR</h2>
+
+Markus Metz
+
+<p><i>Last changed: $Date: 2012-09-04 13:41:54 +0200 (Tue, 04 Sep 2012) $</i>

Added: grass-addons/grass7/grass7/raster/r.sun.angle/solpos00.c
===================================================================
--- grass-addons/grass7/grass7/raster/r.sun.angle/solpos00.c	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.sun.angle/solpos00.c	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,1040 @@
+
+/*============================================================================
+*    Contains:
+*        S_solpos     (computes solar position and intensity
+*                      from time and place)
+*
+*            INPUTS:     (via posdata struct) year, daynum, hour,
+*                        minute, second, latitude, longitude, timezone,
+*                        intervl
+*            OPTIONAL:   (via posdata struct) month, day, press, temp, tilt,
+*                        aspect, function
+*            OUTPUTS:    EVERY variable in the struct posdata
+*                            (defined in solpos.h)
+*
+*                       NOTE: Certain conditions exist during which some of
+*                       the output variables are undefined or cannot be
+*                       calculated.  In these cases, the variables are
+*                       returned with flag values indicating such.  In other
+*                       cases, the variables may return a realistic, though
+*                       invalid, value. These variables and the flag values
+*                       or invalid conditions are listed below:
+*
+*                       amass     -1.0 at zenetr angles greater than 93.0
+*                                 degrees
+*                       ampress   -1.0 at zenetr angles greater than 93.0
+*                                 degrees
+*                       azim      invalid at zenetr angle 0.0 or latitude
+*                                 +/-90.0 or at night
+*                       elevetr   limited to -9 degrees at night
+*                       etr       0.0 at night
+*                       etrn      0.0 at night
+*                       etrtilt   0.0 when cosinc is less than 0
+*                       prime     invalid at zenetr angles greater than 93.0
+*                                 degrees
+*                       sretr     +/- 2999.0 during periods of 24 hour sunup or
+*                                 sundown
+*                       ssetr     +/- 2999.0 during periods of 24 hour sunup or
+*                                 sundown
+*                       ssha      invalid at the North and South Poles
+*                       unprime   invalid at zenetr angles greater than 93.0
+*                                 degrees
+*                       zenetr    limited to 99.0 degrees at night
+*
+*        S_init       (optional initialization for all input parameters in
+*                      the posdata struct)
+*           INPUTS:     struct posdata*
+*           OUTPUTS:    struct posdata*
+*
+*                     (Note: initializes the required S_solpos INPUTS above
+*                      to out-of-bounds conditions, forcing the user to
+*                      supply the parameters; initializes the OPTIONAL
+*                      S_solpos inputs above to nominal values.)
+*
+*       S_decode      (optional utility for decoding the S_solpos return code)
+*           INPUTS:     long integer S_solpos return value, struct posdata*
+*           OUTPUTS:    text to stderr
+*
+*    Usage:
+*         In calling program, just after other 'includes', insert:
+*
+*              #include "solpos.h"
+*
+*         Function calls:
+*              S_init(struct posdata*)  [optional]
+*              .
+*              .
+*              [set time and location parameters before S_solpos call]
+*              .
+*              .
+*              int retval = S_solpos(struct posdata*)
+*              S_decode(int retval, struct posdata*) [optional]
+*                  (Note: you should always look at the S_solpos return
+*                   value, which contains error codes. S_decode is one option
+*                   for examining these codes.  It can also serve as a
+*                   template for building your own application-specific
+*                   decoder.)
+*
+*    Martin Rymes
+*    National Renewable Energy Laboratory
+*    25 March 1998
+*
+*    27 April 1999 REVISION:  Corrected leap year in S_date.
+*    13 January 2000 REVISION:  SMW converted to structure posdata parameter
+*                               and subdivided into functions.
+*    01 February 2001 REVISION: SMW corrected ecobli calculation
+*                               (changed sign). Error is small (max 0.015 deg
+*                               in calculation of declination angle)
+*    11 April 2001 REVISION:    SMW corrected parenthesis grouping in
+*                               validation() function for pressure and
+*                               shadowband.  As it was, the validation
+*                               routine would have checked for and reported
+*                               high limit errors when the functions had not
+*                               been selected.
+*----------------------------------------------------------------------------*/
+#include <math.h>
+#include <string.h>
+#include <stdio.h>
+#include <grass/gis.h>
+#include <grass/glocale.h>
+#include "solpos00.h"
+
+/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ *
+ * Structures defined for this module
+ *
+ *++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
+struct trigdata			/* used to pass calculated values locally */
+{
+    float cd;			/* cosine of the declination */
+    float ch;			/* cosine of the hour angle */
+    float cl;			/* cosine of the latitude */
+    float sd;			/* sine of the declination */
+    float sl;			/* sine of the latitude */
+};
+
+
+/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ *
+ * Temporary global variables used only in this file:
+ *
+ *++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
+static int month_days[2][13] = { {0, 0, 31, 59, 90, 120, 151,
+				  181, 212, 243, 273, 304, 334},
+{0, 0, 31, 60, 91, 121, 152,
+ 182, 213, 244, 274, 305, 335}
+};
+
+		   /* cumulative number of days prior to beginning of month */
+
+
+/*============================================================================
+*    Local function prototypes
+============================================================================*/
+static long int validate(struct posdata *pdat);
+static void dom2doy(struct posdata *pdat);
+static void doy2dom(struct posdata *pdat);
+static void geometry(struct posdata *pdat);
+static void zen_no_ref(struct posdata *pdat, struct trigdata *tdat);
+static void ssha(struct posdata *pdat, struct trigdata *tdat);
+static void sbcf(struct posdata *pdat, struct trigdata *tdat);
+static void tst(struct posdata *pdat);
+static void srss(struct posdata *pdat);
+static void sazm(struct posdata *pdat, struct trigdata *tdat);
+static void refrac(struct posdata *pdat);
+static void amass(struct posdata *pdat);
+static void prime(struct posdata *pdat);
+static void etr(struct posdata *pdat);
+static void tilt(struct posdata *pdat);
+static void localtrig(struct posdata *pdat, struct trigdata *tdat);
+
+/*============================================================================
+*    Long integer function S_solpos, adapted from the VAX solar libraries
+*
+*    This function calculates the apparent solar position and the
+*    intensity of the sun (theoretical maximum solar energy) from
+*    time and place on Earth.
+*
+*    Requires (from the struct posdata parameter):
+*        Date and time:
+*            year
+*            daynum   (requirement depends on the S_DOY switch)
+*            month    (requirement depends on the S_DOY switch)
+*            day      (requirement depends on the S_DOY switch)
+*            hour
+*            minute
+*            second
+*            interval  DEFAULT 0
+*        Location:
+*            latitude
+*            longitude
+*        Location/time adjuster:
+*            timezone
+*        Atmospheric pressure and temperature:
+*            press     DEFAULT 1013.0 mb
+*            temp      DEFAULT 10.0 degrees C
+*        Tilt of flat surface that receives solar energy:
+*            aspect    DEFAULT 180 (South)
+*            tilt      DEFAULT 0 (Horizontal)
+*        Function Switch (codes defined in solpos.h)
+*            function  DEFAULT S_ALL
+*
+*    Returns (via the struct posdata parameter):
+*        everything defined in the struct posdata in solpos.h.
+*----------------------------------------------------------------------------*/
+long S_solpos(struct posdata *pdat)
+{
+    long int retval;
+
+    struct trigdata trigdat, *tdat;
+
+    tdat = &trigdat;		/* point to the structure */
+
+    /* initialize the trig structure */
+    tdat->sd = -999.0;		/* flag to force calculation of trig data */
+    tdat->cd = 1.0;
+    tdat->ch = 1.0;		/* set the rest of these to something safe */
+    tdat->cl = 1.0;
+    tdat->sl = 1.0;
+
+    if ((retval = validate(pdat)) != 0)	/* validate the inputs */
+	return retval;
+
+
+    if (pdat->function & L_DOY)
+	doy2dom(pdat);		/* convert input doy to month-day */
+    else
+	dom2doy(pdat);		/* convert input month-day to doy */
+
+    if (pdat->function & L_GEOM)
+	geometry(pdat);		/* do basic geometry calculations */
+
+    if (pdat->function & L_ZENETR)	/* etr at non-refracted zenith angle */
+	zen_no_ref(pdat, tdat);
+
+    if (pdat->function & L_SSHA)	/* Sunset hour calculation */
+	ssha(pdat, tdat);
+
+    if (pdat->function & L_SBCF)	/* Shadowband correction factor */
+	sbcf(pdat, tdat);
+
+    if (pdat->function & L_TST)	/* true solar time */
+	tst(pdat);
+
+    if (pdat->function & L_SRSS)	/* sunrise/sunset calculations */
+	srss(pdat);
+
+    if (pdat->function & L_SOLAZM)	/* solar azimuth calculations */
+	sazm(pdat, tdat);
+
+    if (pdat->function & L_REFRAC)	/* atmospheric refraction calculations */
+	refrac(pdat);
+
+    if (pdat->function & L_AMASS)	/* airmass calculations */
+	amass(pdat);
+
+    if (pdat->function & L_PRIME)	/* kt-prime/unprime calculations */
+	prime(pdat);
+
+    if (pdat->function & L_ETR)	/* ETR and ETRN (refracted) */
+	etr(pdat);
+
+    if (pdat->function & L_TILT)	/* tilt calculations */
+	tilt(pdat);
+
+    return 0;
+}
+
+
+/*============================================================================
+*    Void function S_init
+*
+*    This function initiates all of the input parameters in the struct
+*    posdata passed to S_solpos().  Initialization is either to nominal
+*    values or to out of range values, which forces the calling program to
+*    specify parameters.
+*
+*    NOTE: This function is optional if you initialize ALL input parameters
+*          in your calling code.  Note that the required parameters of date
+*          and location are deliberately initialized out of bounds to force
+*          the user to enter real-world values.
+*
+*    Requires: Pointer to a posdata structure, members of which are
+*           initialized.
+*
+*    Returns: Void
+*----------------------------------------------------------------------------*/
+void S_init(struct posdata *pdat)
+{
+    pdat->day = -99;		/* Day of month (May 27 = 27, etc.) */
+    pdat->daynum = -999;	/* Day number (day of year; Feb 1 = 32 ) */
+    pdat->hour = -99;		/* Hour of day, 0 - 23 */
+    pdat->minute = -99;		/* Minute of hour, 0 - 59 */
+    pdat->month = -99;		/* Month number (Jan = 1, Feb = 2, etc.) */
+    pdat->second = -99;		/* Second of minute, 0 - 59 */
+    pdat->year = -99;		/* 4-digit year */
+    pdat->interval = 0;		/* instantaneous measurement interval */
+    pdat->aspect = 180.0;	/* Azimuth of panel surface (direction it
+				   faces) N=0, E=90, S=180, W=270 */
+    pdat->latitude = -99.0;	/* Latitude, degrees north (south negative) */
+    pdat->longitude = -999.0;	/* Longitude, degrees east (west negative) */
+    pdat->press = 1013.0;	/* Surface pressure, millibars */
+    pdat->solcon = 1367.0;	/* Solar constant, 1367 W/sq m */
+    pdat->temp = 15.0;		/* Ambient dry-bulb temperature, degrees C */
+    pdat->tilt = 0.0;		/* Degrees tilt from horizontal of panel */
+    pdat->timezone = -99.0;	/* Time zone, east (west negative). */
+    pdat->sbwid = 7.6;		/* Eppley shadow band width */
+    pdat->sbrad = 31.7;		/* Eppley shadow band radius */
+    pdat->sbsky = 0.04;		/* Drummond factor for partly cloudy skies */
+    pdat->function = S_ALL;	/* compute all parameters */
+
+    pdat->time_updated = 0;
+    pdat->longitude_updated = 0;
+}
+
+
+/*============================================================================
+*    Local long int function validate
+*
+*    Validates the input parameters
+*----------------------------------------------------------------------------*/
+static long int validate(struct posdata *pdat)
+{
+
+    long int retval = 0;	/* start with no errors */
+
+    /* No absurd dates, please. */
+    if (pdat->function & L_GEOM) {
+	if ((pdat->year < 1950) || (pdat->year > 2050))	/* limits of algoritm */
+	    retval |= (1L << S_YEAR_ERROR);
+	if (!(pdat->function & S_DOY) &&
+	    ((pdat->month < 1) || (pdat->month > 12)))
+	    retval |= (1L << S_MONTH_ERROR);
+	if (!(pdat->function & S_DOY) &&
+	    ((pdat->day < 1) || (pdat->day > 31)))
+	    retval |= (1L << S_DAY_ERROR);
+	if ((pdat->function & S_DOY) &&
+	    ((pdat->daynum < 1) || (pdat->daynum > 366)))
+	    retval |= (1L << S_DOY_ERROR);
+
+	/* No absurd times, please. */
+	if ((pdat->hour < 0) || (pdat->hour > 24))
+	    retval |= (1L << S_HOUR_ERROR);
+	if ((pdat->minute < 0) || (pdat->minute > 59))
+	    retval |= (1L << S_MINUTE_ERROR);
+	if ((pdat->second < 0) || (pdat->second > 59))
+	    retval |= (1L << S_SECOND_ERROR);
+	if ((pdat->hour == 24) && (pdat->minute > 0))	/* no more than 24 hrs */
+	    retval |= ((1L << S_HOUR_ERROR) | (1L << S_MINUTE_ERROR));
+	if ((pdat->hour == 24) && (pdat->second > 0))	/* no more than 24 hrs */
+	    retval |= ((1L << S_HOUR_ERROR) | (1L << S_SECOND_ERROR));
+	if (fabs(pdat->timezone) > 12.0)
+	    retval |= (1L << S_TZONE_ERROR);
+	if ((pdat->interval < 0) || (pdat->interval > 28800))
+	    retval |= (1L << S_INTRVL_ERROR);
+
+	/* No absurd locations, please. */
+	if (fabs(pdat->longitude) > 180.0)
+	    retval |= (1L << S_LON_ERROR);
+	if (fabs(pdat->latitude) > 90.0)
+	    retval |= (1L << S_LAT_ERROR);
+    }
+
+    /* No silly temperatures or pressures, please. */
+    if ((pdat->function & L_REFRAC) && (fabs(pdat->temp) > 100.0))
+	retval |= (1L << S_TEMP_ERROR);
+    if ((pdat->function & L_REFRAC) &&
+	((pdat->press < 0.0) || (pdat->press > 2000.0)))
+	retval |= (1L << S_PRESS_ERROR);
+
+    /* No out of bounds tilts, please */
+    if ((pdat->function & L_TILT) && (fabs(pdat->tilt) > 180.0))
+	retval |= (1L << S_TILT_ERROR);
+    if ((pdat->function & L_TILT) && (fabs(pdat->aspect) > 360.0))
+	retval |= (1L << S_ASPECT_ERROR);
+
+    /* No oddball shadowbands, please */
+    if ((pdat->function & L_SBCF) &&
+	((pdat->sbwid < 1.0) || (pdat->sbwid > 100.0)))
+	retval |= (1L << S_SBWID_ERROR);
+    if ((pdat->function & L_SBCF) &&
+	((pdat->sbrad < 1.0) || (pdat->sbrad > 100.0)))
+	retval |= (1L << S_SBRAD_ERROR);
+    if ((pdat->function & L_SBCF) && (fabs(pdat->sbsky) > 1.0))
+	retval |= (1L << S_SBSKY_ERROR);
+
+    return retval;
+}
+
+
+/*============================================================================
+*    Local Void function dom2doy
+*
+*    Converts day-of-month to day-of-year
+*
+*    Requires (from struct posdata parameter):
+*            year
+*            month
+*            day
+*
+*    Returns (via the struct posdata parameter):
+*            year
+*            daynum
+*----------------------------------------------------------------------------*/
+static void dom2doy(struct posdata *pdat)
+{
+    pdat->daynum = pdat->day + month_days[0][pdat->month];
+
+    /* (adjust for leap year) */
+    if (((pdat->year % 4) == 0) &&
+	(((pdat->year % 100) != 0) || ((pdat->year % 400) == 0)) &&
+	(pdat->month > 2))
+	pdat->daynum += 1;
+}
+
+
+int dom2doy2(int year, int month, int day)
+{
+    int doy = day + month_days[0][month];
+
+    /* (adjust for leap year) */
+    if (((year % 4) == 0) &&
+	(((year % 100) != 0) || ((year % 400) == 0)) &&
+	(month > 2))
+	doy += 1;
+
+    return doy;
+}
+
+/*============================================================================
+*    Local void function doy2dom
+*
+*    This function computes the month/day from the day number.
+*
+*    Requires (from struct posdata parameter):
+*        Year and day number:
+*            year
+*            daynum
+*
+*    Returns (via the struct posdata parameter):
+*            year
+*            month
+*            day
+*----------------------------------------------------------------------------*/
+static void doy2dom(struct posdata *pdat)
+{
+    int imon;			/* Month (month_days) array counter */
+    int leap;			/* leap year switch */
+
+    /* Set the leap year switch */
+    if (((pdat->year % 4) == 0) &&
+	(((pdat->year % 100) != 0) || ((pdat->year % 400) == 0)))
+	leap = 1;
+    else
+	leap = 0;
+
+    /* Find the month */
+    imon = 12;
+    while (pdat->daynum <= month_days[leap][imon])
+	--imon;
+
+    /* Set the month and day of month */
+    pdat->month = imon;
+    pdat->day = pdat->daynum - month_days[leap][imon];
+}
+
+
+/*============================================================================
+*    Local Void function geometry
+*
+*    Does the underlying geometry for a given time and location
+*----------------------------------------------------------------------------*/
+static void geometry(struct posdata *pdat)
+{
+    float bottom;		/* denominator (bottom) of the fraction */
+    float c2;			/* cosine of d2 */
+    float cd;			/* cosine of the day angle or delination */
+    float d2;			/* pdat->dayang times two */
+    float delta;		/* difference between current year and 1949 */
+    float s2;			/* sine of d2 */
+    float sd;			/* sine of the day angle */
+    float top;			/* numerator (top) of the fraction */
+    int leap;			/* leap year counter */
+
+    /** time-dependent variables **/
+    if (pdat->time_updated) {
+	/* Day angle */
+	/*  Iqbal, M.  1983.  An Introduction to Solar Radiation.
+	   Academic Press, NY., page 3 */
+	pdat->dayang = 360.0 * (pdat->daynum - 1) / 365.0;
+
+	/* Earth radius vector * solar constant = solar energy */
+	/*  Spencer, J. W.  1971.  Fourier series representation of the
+	   position of the sun.  Search 2 (5), page 172 */
+	sd = sin(DEG2RAD * pdat->dayang);
+	cd = cos(DEG2RAD * pdat->dayang);
+	d2 = 2.0 * pdat->dayang;
+	c2 = cos(DEG2RAD * d2);
+	s2 = sin(DEG2RAD * d2);
+
+	pdat->erv = 1.000110 + 0.034221 * cd + 0.001280 * sd;
+	pdat->erv += 0.000719 * c2 + 0.000077 * s2;
+
+	/* Universal Coordinated (Greenwich standard) time */
+	/*  Michalsky, J.  1988.  The Astronomical Almanac's algorithm for
+	   approximate solar position (1950-2050).  Solar Energy 40 (3),
+	   pp. 227-235. */
+	pdat->utime =
+	    pdat->hour * 3600.0 +
+	    pdat->minute * 60.0 + pdat->second - (float)pdat->interval / 2.0;
+	pdat->utime = pdat->utime / 3600.0 - pdat->timezone;
+
+	/* Julian Day minus 2,400,000 days (to eliminate roundoff errors) */
+	/*  Michalsky, J.  1988.  The Astronomical Almanac's algorithm for
+	   approximate solar position (1950-2050).  Solar Energy 40 (3),
+	   pp. 227-235. */
+
+	/* No adjustment for century non-leap years since this function is
+	   bounded by 1950 - 2050 */
+	delta = pdat->year - 1949;
+	leap = (int)(delta / 4.0);
+	pdat->julday =
+	    32916.5 + delta * 365.0 + leap + pdat->daynum + pdat->utime / 24.0;
+
+	/* Time used in the calculation of ecliptic coordinates */
+	/* Noon 1 JAN 2000 = 2,400,000 + 51,545 days Julian Date */
+	/*  Michalsky, J.  1988.  The Astronomical Almanac's algorithm for
+	   approximate solar position (1950-2050).  Solar Energy 40 (3),
+	   pp. 227-235. */
+	pdat->ectime = pdat->julday - 51545.0;
+
+	/* Mean longitude */
+	/*  Michalsky, J.  1988.  The Astronomical Almanac's algorithm for
+	   approximate solar position (1950-2050).  Solar Energy 40 (3),
+	   pp. 227-235. */
+	pdat->mnlong = 280.460 + 0.9856474 * pdat->ectime;
+
+	/* (dump the multiples of 360, so the answer is between 0 and 360) */
+	pdat->mnlong -= 360.0 * (int)(pdat->mnlong / 360.0);
+	if (pdat->mnlong < 0.0)
+	    pdat->mnlong += 360.0;
+
+	/* Mean anomaly */
+	/*  Michalsky, J.  1988.  The Astronomical Almanac's algorithm for
+	   approximate solar position (1950-2050).  Solar Energy 40 (3),
+	   pp. 227-235. */
+	pdat->mnanom = 357.528 + 0.9856003 * pdat->ectime;
+
+	/* (dump the multiples of 360, so the answer is between 0 and 360) */
+	pdat->mnanom -= 360.0 * (int)(pdat->mnanom / 360.0);
+	if (pdat->mnanom < 0.0)
+	    pdat->mnanom += 360.0;
+
+	/* Ecliptic longitude */
+	/*  Michalsky, J.  1988.  The Astronomical Almanac's algorithm for
+	   approximate solar position (1950-2050).  Solar Energy 40 (3),
+	   pp. 227-235. */
+	pdat->eclong = pdat->mnlong + 1.915 * sin(pdat->mnanom * DEG2RAD) +
+	    0.020 * sin(2.0 * pdat->mnanom * DEG2RAD);
+
+	/* (dump the multiples of 360, so the answer is between 0 and 360) */
+	pdat->eclong -= 360.0 * (int)(pdat->eclong / 360.0);
+	if (pdat->eclong < 0.0)
+	    pdat->eclong += 360.0;
+
+	/* Obliquity of the ecliptic */
+	/*  Michalsky, J.  1988.  The Astronomical Almanac's algorithm for
+	   approximate solar position (1950-2050).  Solar Energy 40 (3),
+	   pp. 227-235. */
+
+	/* 02 Feb 2001 SMW corrected sign in the following line */
+	/*  pdat->ecobli = 23.439 + 4.0e-07 * pdat->ectime;     */
+	/* more precisely: */
+	/*  pdat->ecobli = 23.43929 - 3.56237e-07 * pdat->ectime;     */
+	pdat->ecobli = 23.439 - 4.0e-07 * pdat->ectime;
+	G_debug(1, "axial tilt (solpos): %.5f", pdat->ecobli);
+
+	if (pdat->ectime != 0) {
+	    /* convert ectime from days to years */
+	    double ectime = pdat->ectime / 36525.0;
+	    double ectime2 = ectime * ectime;
+	    double ectime3 = ectime2 * ectime;
+
+	    /* recommended by the International Astronomical Union in 2000: */
+	    /* accurate for the year 2000 +- 5000 years
+	     * result is in arc seconds */
+	    pdat->ecobli = 84381.448 - 46.84024 * ectime - 5.9e-5 * ectime2 + 1.813e-3 * ectime3;
+	    /* convert to degrees */
+	    pdat->ecobli /= 3600.0;
+
+	    G_debug(1, "axial tilt (IAU 2000): %.5f", pdat->ecobli);
+	}
+	else
+	    pdat->ecobli = 23.43929;
+
+	/* Declination */
+	/*  Michalsky, J.  1988.  The Astronomical Almanac's algorithm for
+	   approximate solar position (1950-2050).  Solar Energy 40 (3),
+	   pp. 227-235. */
+	pdat->declin = RAD2DEG * asin(sin(pdat->ecobli * DEG2RAD) *
+				      sin(pdat->eclong * DEG2RAD));
+
+	/* Right ascension */
+	/*  Michalsky, J.  1988.  The Astronomical Almanac's algorithm for
+	   approximate solar position (1950-2050).  Solar Energy 40 (3),
+	   pp. 227-235. */
+	top = cos(DEG2RAD * pdat->ecobli) * sin(DEG2RAD * pdat->eclong);
+	bottom = cos(DEG2RAD * pdat->eclong);
+
+	pdat->rascen = RAD2DEG * atan2(top, bottom);
+
+	/* (make it a positive angle) */
+	if (pdat->rascen < 0.0)
+	    pdat->rascen += 360.0;
+
+	/* Greenwich mean sidereal time */
+	/*  Michalsky, J.  1988.  The Astronomical Almanac's algorithm for
+	   approximate solar position (1950-2050).  Solar Energy 40 (3),
+	   pp. 227-235. */
+	pdat->gmst = 6.697375 + 0.0657098242 * pdat->ectime + pdat->utime;
+
+	/* (dump the multiples of 24, so the answer is between 0 and 24) */
+	pdat->gmst -= 24.0 * (int)(pdat->gmst / 24.0);
+	if (pdat->gmst < 0.0)
+	    pdat->gmst += 24.0;
+
+	pdat->time_updated = 0;
+    }
+    
+    /** longitude-dependent variables **/
+    if (pdat->longitude_updated) {
+	/* Local mean sidereal time */
+	/*  Michalsky, J.  1988.  The Astronomical Almanac's algorithm for
+	   approximate solar position (1950-2050).  Solar Energy 40 (3),
+	   pp. 227-235. */
+	pdat->lmst = pdat->gmst * 15.0 + pdat->longitude;
+
+	/* (dump the multiples of 360, so the answer is between 0 and 360) */
+	pdat->lmst -= 360.0 * (int)(pdat->lmst / 360.0);
+	if (pdat->lmst < 0.)
+	    pdat->lmst += 360.0;
+
+	/* Hour angle */
+	/*  Michalsky, J.  1988.  The Astronomical Almanac's algorithm for
+	   approximate solar position (1950-2050).  Solar Energy 40 (3),
+	   pp. 227-235. */
+	pdat->hrang = pdat->lmst - pdat->rascen;
+
+	/* (force it between -180 and 180 degrees) */
+	if (pdat->hrang < -180.0)
+	    pdat->hrang += 360.0;
+	else if (pdat->hrang > 180.0)
+	    pdat->hrang -= 360.0;
+
+	pdat->longitude_updated = 0;
+    }
+}
+
+
+/*============================================================================
+*    Local Void function zen_no_ref
+*
+*    ETR solar zenith angle
+*       Iqbal, M.  1983.  An Introduction to Solar Radiation.
+*            Academic Press, NY., page 15
+*----------------------------------------------------------------------------*/
+static void zen_no_ref(struct posdata *pdat, struct trigdata *tdat)
+{
+    float cz;			/* cosine of the solar zenith angle */
+
+    localtrig(pdat, tdat);
+    cz = tdat->sd * tdat->sl + tdat->cd * tdat->cl * tdat->ch;
+
+    /* (watch out for the roundoff errors) */
+    if (fabs(cz) > 1.0) {
+	if (cz >= 0.0)
+	    cz = 1.0;
+	else
+	    cz = -1.0;
+    }
+
+    pdat->zenetr = acos(cz) * RAD2DEG;
+
+    /* (limit the degrees below the horizon to 9 [+90 -> 99]) */
+    if (pdat->zenetr > 99.0)
+	pdat->zenetr = 99.0;
+
+    pdat->elevetr = 90.0 - pdat->zenetr;
+}
+
+
+/*============================================================================
+*    Local Void function ssha
+*
+*    Sunset hour angle, degrees
+*       Iqbal, M.  1983.  An Introduction to Solar Radiation.
+*            Academic Press, NY., page 16
+*----------------------------------------------------------------------------*/
+static void ssha(struct posdata *pdat, struct trigdata *tdat)
+{
+    float cssha;		/* cosine of the sunset hour angle */
+    float cdcl;			/* ( cd * cl ) */
+
+    localtrig(pdat, tdat);
+    cdcl = tdat->cd * tdat->cl;
+
+    if (fabs(cdcl) >= 0.001) {
+	cssha = -tdat->sl * tdat->sd / cdcl;
+
+	/* This keeps the cosine from blowing on roundoff */
+	if (cssha < -1.0)
+	    pdat->ssha = 180.0;
+	else if (cssha > 1.0)
+	    pdat->ssha = 0.0;
+	else
+	    pdat->ssha = RAD2DEG * acos(cssha);
+    }
+    else if (((pdat->declin >= 0.0) && (pdat->latitude > 0.0)) ||
+	     ((pdat->declin < 0.0) && (pdat->latitude < 0.0)))
+	pdat->ssha = 180.0;
+    else
+	pdat->ssha = 0.0;
+}
+
+
+/*============================================================================
+*    Local Void function sbcf
+*
+*    Shadowband correction factor
+*       Drummond, A. J.  1956.  A contribution to absolute pyrheliometry.
+*            Q. J. R. Meteorol. Soc. 82, pp. 481-493
+*----------------------------------------------------------------------------*/
+static void sbcf(struct posdata *pdat, struct trigdata *tdat)
+{
+    float p, t1, t2;		/* used to compute sbcf */
+
+    localtrig(pdat, tdat);
+    p = 0.6366198 * pdat->sbwid / pdat->sbrad * pow(tdat->cd, 3);
+    t1 = tdat->sl * tdat->sd * pdat->ssha * DEG2RAD;
+    t2 = tdat->cl * tdat->cd * sin(pdat->ssha * DEG2RAD);
+    pdat->sbcf = pdat->sbsky + 1.0 / (1.0 - p * (t1 + t2));
+
+}
+
+
+/*============================================================================
+*    Local Void function tst
+*
+*    TST -> True Solar Time = local standard time + TSTfix, time
+*      in minutes from midnight.
+*        Iqbal, M.  1983.  An Introduction to Solar Radiation.
+*            Academic Press, NY., page 13
+*----------------------------------------------------------------------------*/
+static void tst(struct posdata *pdat)
+{
+    pdat->tst = (180.0 + pdat->hrang) * 4.0;
+    pdat->tstfix = pdat->tst - (float)pdat->hour * 60.0 - pdat->minute - (float)pdat->second / 60.0 + (float)pdat->interval / 120.0;	/* add back half of the interval */
+
+    /* bound tstfix to this day */
+    while (pdat->tstfix > 720.0)
+	pdat->tstfix -= 1440.0;
+    while (pdat->tstfix < -720.0)
+	pdat->tstfix += 1440.0;
+
+    pdat->eqntim =
+	pdat->tstfix + 60.0 * pdat->timezone - 4.0 * pdat->longitude;
+
+}
+
+
+/*============================================================================
+*    Local Void function srss
+*
+*    Sunrise and sunset times (minutes from midnight)
+*----------------------------------------------------------------------------*/
+static void srss(struct posdata *pdat)
+{
+    if (pdat->ssha <= 1.0) {
+	pdat->sretr = 2999.0;
+	pdat->ssetr = -2999.0;
+    }
+    else if (pdat->ssha >= 179.0) {
+	pdat->sretr = -2999.0;
+	pdat->ssetr = 2999.0;
+    }
+    else {
+	pdat->sretr = 720.0 - 4.0 * pdat->ssha - pdat->tstfix;
+	pdat->ssetr = 720.0 + 4.0 * pdat->ssha - pdat->tstfix;
+    }
+}
+
+
+/*============================================================================
+*    Local Void function sazm
+*
+*    Solar azimuth angle
+*       Iqbal, M.  1983.  An Introduction to Solar Radiation.
+*            Academic Press, NY., page 15
+*----------------------------------------------------------------------------*/
+static void sazm(struct posdata *pdat, struct trigdata *tdat)
+{
+    float ca;			/* cosine of the solar azimuth angle */
+    float ce;			/* cosine of the solar elevation */
+    float cecl;			/* ( ce * cl ) */
+    float se;			/* sine of the solar elevation */
+
+    localtrig(pdat, tdat);
+    ce = cos(DEG2RAD * pdat->elevetr);
+    se = sin(DEG2RAD * pdat->elevetr);
+
+    pdat->azim = 180.0;
+    cecl = ce * tdat->cl;
+    if (fabs(cecl) >= 0.001) {
+	ca = (se * tdat->sl - tdat->sd) / cecl;
+	if (ca > 1.0)
+	    ca = 1.0;
+	else if (ca < -1.0)
+	    ca = -1.0;
+
+	pdat->azim = 180.0 - acos(ca) * RAD2DEG;
+	if (pdat->hrang > 0)
+	    pdat->azim = 360.0 - pdat->azim;
+    }
+}
+
+
+/*============================================================================
+*    Local Int function refrac
+*
+*    Refraction correction, degrees
+*        Zimmerman, John C.  1981.  Sun-pointing programs and their
+*            accuracy.
+*            SAND81-0761, Experimental Systems Operation Division 4721,
+*            Sandia National Laboratories, Albuquerque, NM.
+*----------------------------------------------------------------------------*/
+static void refrac(struct posdata *pdat)
+{
+    float prestemp;		/* temporary pressure/temperature correction */
+    float refcor;		/* temporary refraction correction */
+    float tanelev;		/* tangent of the solar elevation angle */
+
+    /* If the sun is near zenith, the algorithm bombs; refraction near 0 */
+    if (pdat->elevetr > 85.0)
+	refcor = 0.0;
+
+    /* Otherwise, we have refraction */
+    else {
+	tanelev = tan(DEG2RAD * pdat->elevetr);
+	if (pdat->elevetr >= 5.0)
+	    refcor = 58.1 / tanelev -
+		0.07 / (pow(tanelev, 3)) + 0.000086 / (pow(tanelev, 5));
+	else if (pdat->elevetr >= -0.575)
+	    refcor = 1735.0 +
+		pdat->elevetr * (-518.2 + pdat->elevetr * (103.4 +
+							   pdat->elevetr *
+							   (-12.79 +
+							    pdat->elevetr *
+							    0.711)));
+	else
+	    refcor = -20.774 / tanelev;
+
+	prestemp = (pdat->press * 283.0) / (1013.0 * (273.0 + pdat->temp));
+	refcor *= prestemp / 3600.0;
+    }
+
+    /* Refracted solar elevation angle */
+    pdat->elevref = pdat->elevetr + refcor;
+
+    /* (limit the degrees below the horizon to 9) */
+    if (pdat->elevref < -9.0)
+	pdat->elevref = -9.0;
+
+    /* Refracted solar zenith angle */
+    pdat->zenref = 90.0 - pdat->elevref;
+    pdat->coszen = cos(DEG2RAD * pdat->zenref);
+}
+
+
+/*============================================================================
+*    Local Void function  amass
+*
+*    Airmass
+*       Kasten, F. and Young, A.  1989.  Revised optical air mass
+*            tables and approximation formula.  Applied Optics 28 (22),
+*            pp. 4735-4738
+*----------------------------------------------------------------------------*/
+static void amass(struct posdata *pdat)
+{
+    if (pdat->zenref > 93.0) {
+	pdat->amass = -1.0;
+	pdat->ampress = -1.0;
+    }
+    else {
+	pdat->amass =
+	    1.0 / (cos(DEG2RAD * pdat->zenref) + 0.50572 *
+		   pow((96.07995 - pdat->zenref), -1.6364));
+
+	pdat->ampress = pdat->amass * pdat->press / 1013.0;
+    }
+}
+
+
+/*============================================================================
+*    Local Void function prime
+*
+*    Prime and Unprime
+*    Prime  converts Kt to normalized Kt', etc.
+*       Unprime deconverts Kt' to Kt, etc.
+*            Perez, R., P. Ineichen, Seals, R., & Zelenka, A.  1990.  Making
+*            full use of the clearness index for parameterizing hourly
+*            insolation conditions. Solar Energy 45 (2), pp. 111-114
+*----------------------------------------------------------------------------*/
+static void prime(struct posdata *pdat)
+{
+    pdat->unprime = 1.031 * exp(-1.4 / (0.9 + 9.4 / pdat->amass)) + 0.1;
+    pdat->prime = 1.0 / pdat->unprime;
+}
+
+
+/*============================================================================
+*    Local Void function etr
+*
+*    Extraterrestrial (top-of-atmosphere) solar irradiance
+*----------------------------------------------------------------------------*/
+static void etr(struct posdata *pdat)
+{
+    if (pdat->coszen > 0.0) {
+	pdat->etrn = pdat->solcon * pdat->erv;
+	pdat->etr = pdat->etrn * pdat->coszen;
+    }
+    else {
+	pdat->etrn = 0.0;
+	pdat->etr = 0.0;
+    }
+}
+
+
+/*============================================================================
+*    Local Void function localtrig
+*
+*    Does trig on internal variable used by several functions
+*----------------------------------------------------------------------------*/
+static void localtrig(struct posdata *pdat, struct trigdata *tdat)
+{
+    /* define masks to prevent calculation of uninitialized variables */
+#define SD_MASK ( L_ZENETR | L_SSHA | S_SBCF | S_SOLAZM )
+#define SL_MASK ( L_ZENETR | L_SSHA | S_SBCF | S_SOLAZM )
+#define CL_MASK ( L_ZENETR | L_SSHA | S_SBCF | S_SOLAZM )
+#define CD_MASK ( L_ZENETR | L_SSHA | S_SBCF )
+#define CH_MASK ( L_ZENETR )
+
+    if (tdat->sd < -900.0) {	/* sd was initialized -999 as flag */
+	tdat->sd = 1.0;		/* reflag as having completed calculations */
+	if (pdat->function | CD_MASK)
+	    tdat->cd = cos(DEG2RAD * pdat->declin);
+	if (pdat->function | CH_MASK)
+	    tdat->ch = cos(DEG2RAD * pdat->hrang);
+	if (pdat->function | CL_MASK)
+	    tdat->cl = cos(DEG2RAD * pdat->latitude);
+	if (pdat->function | SD_MASK)
+	    tdat->sd = sin(DEG2RAD * pdat->declin);
+	if (pdat->function | SL_MASK)
+	    tdat->sl = sin(DEG2RAD * pdat->latitude);
+    }
+}
+
+
+/*============================================================================
+*    Local Void function tilt
+*
+*    ETR on a tilted surface
+*----------------------------------------------------------------------------*/
+static void tilt(struct posdata *pdat)
+{
+    float ca;			/* cosine of the solar azimuth angle */
+    float cp;			/* cosine of the panel aspect */
+    float ct;			/* cosine of the panel tilt */
+    float sa;			/* sine of the solar azimuth angle */
+    float sp;			/* sine of the panel aspect */
+    float st;			/* sine of the panel tilt */
+    float sz;			/* sine of the refraction corrected solar zenith angle */
+
+
+    /* Cosine of the angle between the sun and a tipped flat surface,
+       useful for calculating solar energy on tilted surfaces */
+    ca = cos(DEG2RAD * pdat->azim);
+    cp = cos(DEG2RAD * pdat->aspect);
+    ct = cos(DEG2RAD * pdat->tilt);
+    sa = sin(DEG2RAD * pdat->azim);
+    sp = sin(DEG2RAD * pdat->aspect);
+    st = sin(DEG2RAD * pdat->tilt);
+    sz = sin(DEG2RAD * pdat->zenref);
+    pdat->cosinc = pdat->coszen * ct + sz * st * (ca * cp + sa * sp);
+
+    if (pdat->cosinc > 0.0)
+	pdat->etrtilt = pdat->etrn * pdat->cosinc;
+    else
+	pdat->etrtilt = 0.0;
+
+}
+
+
+/*============================================================================
+*    Void function S_decode
+*
+*    This function decodes the error codes from S_solpos return value
+*
+*    Requires the long integer return value from S_solpos
+*
+*    Returns descriptive text to stderr
+*----------------------------------------------------------------------------*/
+void S_decode(long code, struct posdata *pdat)
+{
+    if (code & (1L << S_YEAR_ERROR))
+	G_warning(_("S_decode ==> Please fix the year: %d [1950-2050]"),
+		  pdat->year);
+    if (code & (1L << S_MONTH_ERROR))
+	G_warning(_("S_decode ==> Please fix the month: %d"), pdat->month);
+    if (code & (1L << S_DAY_ERROR))
+	G_warning(_("S_decode ==> Please fix the day-of-month: %d"),
+		  pdat->day);
+    if (code & (1L << S_DOY_ERROR))
+	G_warning(_("S_decode ==> Please fix the day-of-year: %d"),
+		  pdat->daynum);
+    if (code & (1L << S_HOUR_ERROR))
+	G_warning(_("S_decode ==> Please fix the hour: %d"), pdat->hour);
+    if (code & (1L << S_MINUTE_ERROR))
+	G_warning(_("S_decode ==> Please fix the minute: %d"), pdat->minute);
+    if (code & (1L << S_SECOND_ERROR))
+	G_warning(_("S_decode ==> Please fix the second: %d"), pdat->second);
+    if (code & (1L << S_TZONE_ERROR))
+	G_warning(_("S_decode ==> Please fix the time zone: %f"),
+		  pdat->timezone);
+    if (code & (1L << S_INTRVL_ERROR))
+	G_warning(_("S_decode ==> Please fix the interval: %d"),
+		  pdat->interval);
+    if (code & (1L << S_LAT_ERROR))
+	G_warning(_("S_decode ==> Please fix the latitude: %f"),
+		  pdat->latitude);
+    if (code & (1L << S_LON_ERROR))
+	G_warning(_("S_decode ==> Please fix the longitude: %f"),
+		  pdat->longitude);
+    if (code & (1L << S_TEMP_ERROR))
+	G_warning(_("S_decode ==> Please fix the temperature: %f"),
+		  pdat->temp);
+    if (code & (1L << S_PRESS_ERROR))
+	G_warning(_("S_decode ==> Please fix the pressure: %f"), pdat->press);
+    if (code & (1L << S_TILT_ERROR))
+	G_warning(_("S_decode ==> Please fix the tilt: %f"), pdat->tilt);
+    if (code & (1L << S_ASPECT_ERROR))
+	G_warning(_("S_decode ==> Please fix the aspect: %f"), pdat->aspect);
+    if (code & (1L << S_SBWID_ERROR))
+	G_warning(_("S_decode ==> Please fix the shadowband width: %f"),
+		  pdat->sbwid);
+    if (code & (1L << S_SBRAD_ERROR))
+	G_warning(_("S_decode ==> Please fix the shadowband radius: %f"),
+		  pdat->sbrad);
+    if (code & (1L << S_SBSKY_ERROR))
+	G_warning(_("S_decode ==> Please fix the shadowband sky factor: %f"),
+		  pdat->sbsky);
+}

Added: grass-addons/grass7/grass7/raster/r.sun.angle/solpos00.h
===================================================================
--- grass-addons/grass7/grass7/raster/r.sun.angle/solpos00.h	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.sun.angle/solpos00.h	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,376 @@
+
+#define RAD2DEG 57.295779513	/* converts from radians to degrees */
+#define DEG2RAD 0.0174532925	/* converts from degrees to radians */
+
+int dom2doy2(int year, int month, int day);
+
+ /*============================================================================
+*
+*    NAME:  solpos.h
+*
+*    Contains:
+*        S_solpos     (computes the solar position and intensity
+*                      from time and place)
+*            INPUTS:     (from posdata)
+*                          year, month, day, hour, minute, second,
+*                          latitude, longitude, timezone, interval
+*            OPTIONAL:   (from posdata; defaults from S_init function)
+*                            press   DEFAULT 1013.0 (standard pressure)
+*                            temp    DEFAULT   10.0 (standard temperature)
+*                            tilt    DEFAULT    0.0 (horizontal panel)
+*                            aspect  DEFAULT  180.0 (South-facing panel)
+*                            sbwid   DEFAULT    7.6 (shadowband width)
+*                            sbrad   DEFAULT   31.7 (shadowband radius)
+*                            sbsky   DEFAULT   0.04 (shadowband sky factor)
+*
+*            OUTPUTS:    (posdata) daynum, amass, ampress, azim, cosinc,
+*                        elevref, etr, etrn, etrtilt, prime,
+*                        sbcf, sretr, ssetr, unprime, zenref
+*
+*            RETURNS:   Long int status code (defined in solpos.h)
+*
+*    Usage:
+*         In calling program, along with other 'includes', insert:
+*
+*              #include "solpos.h"
+*
+*    Martin Rymes
+*    National Renewable Energy Laboratory
+*    25 March 1998
+*
+*----------------------------------------------------------------------------*/
+
+/*============================================================================
+*
+*     Define the function codes
+*
+*----------------------------------------------------------------------------*/
+#define L_DOY    0x0001
+#define L_GEOM   0x0002
+#define L_ZENETR 0x0004
+#define L_SSHA   0x0008
+#define L_SBCF   0x0010
+#define L_TST    0x0020
+#define L_SRSS   0x0040
+#define L_SOLAZM 0x0080
+#define L_REFRAC 0x0100
+#define L_AMASS  0x0200
+#define L_PRIME  0x0400
+#define L_TILT   0x0800
+#define L_ETR    0x1000
+#define L_ALL    0xFFFF
+
+/*============================================================================
+*
+*     Define the bit-wise masks for each function
+*
+*----------------------------------------------------------------------------*/
+#define S_DOY    ( L_DOY                          )
+#define S_GEOM   ( L_GEOM   | S_DOY               )
+#define S_ZENETR ( L_ZENETR | S_GEOM              )
+#define S_SSHA   ( L_SSHA   | S_GEOM              )
+#define S_SBCF   ( L_SBCF   | S_SSHA              )
+#define S_TST    ( L_TST    | S_GEOM              )
+#define S_SRSS   ( L_SRSS   | S_SSHA   | S_TST    )
+#define S_SOLAZM ( L_SOLAZM | S_ZENETR            )
+#define S_REFRAC ( L_REFRAC | S_ZENETR            )
+#define S_AMASS  ( L_AMASS  | S_REFRAC            )
+#define S_PRIME  ( L_PRIME  | S_AMASS             )
+#define S_TILT   ( L_TILT   | S_SOLAZM | S_REFRAC )
+#define S_ETR    ( L_ETR    | S_REFRAC            )
+#define S_ALL    ( L_ALL                          )
+
+
+/*============================================================================
+*
+*     Enumerate the error codes
+*     (Bit positions are from least significant to most significant)
+*
+*----------------------------------------------------------------------------*/
+/*          Code          Bit       Parameter            Range
+   ===============     ===  ===================  =============   */
+enum
+{ S_YEAR_ERROR,			/*  0   year                  1950 -  2050   */
+    S_MONTH_ERROR,		/*  1   month                    1 -    12   */
+    S_DAY_ERROR,		/*  2   day-of-month             1 -    31   */
+    S_DOY_ERROR,		/*  3   day-of-year              1 -   366   */
+    S_HOUR_ERROR,		/*  4   hour                     0 -    24   */
+    S_MINUTE_ERROR,		/*  5   minute                   0 -    59   */
+    S_SECOND_ERROR,		/*  6   second                   0 -    59   */
+    S_TZONE_ERROR,		/*  7   time zone              -12 -    12   */
+    S_INTRVL_ERROR,		/*  8   interval (seconds)       0 - 28800   */
+    S_LAT_ERROR,		/*  9   latitude               -90 -    90   */
+    S_LON_ERROR,		/* 10   longitude             -180 -   180   */
+    S_TEMP_ERROR,		/* 11   temperature (deg. C)  -100 -   100   */
+    S_PRESS_ERROR,		/* 12   pressure (millibars)     0 -  2000   */
+    S_TILT_ERROR,		/* 13   tilt                   -90 -    90   */
+    S_ASPECT_ERROR,		/* 14   aspect                -360 -   360   */
+    S_SBWID_ERROR,		/* 15   shadow band width (cm)   1 -   100   */
+    S_SBRAD_ERROR,		/* 16   shadow band radius (cm)  1 -   100   */
+    S_SBSKY_ERROR
+};				/* 17   shadow band sky factor  -1 -     1   */
+
+struct posdata
+{
+
+  /***** ALPHABETICAL LIST OF COMMON VARIABLES *****/
+    /* Each comment begins with a 1-column letter code:
+       I:  INPUT variable
+       O:  OUTPUT variable
+       T:  TRANSITIONAL variable used in the algorithm,
+       of interest only to the solar radiation
+       modelers, and available to you because you
+       may be one of them.
+
+       The FUNCTION column indicates which sub-function
+       within solpos must be switched on using the
+       "function" parameter to calculate the desired
+       output variable.  All function codes are
+       defined in the solpos.h file.  The default
+       S_ALL switch calculates all output variables.
+       Multiple functions may be or'd to create a
+       composite function switch.  For example,
+       (S_TST | S_SBCF). Specifying only the functions
+       for required output variables may allow solpos
+       to execute more quickly.
+
+       The S_DOY mask works as a toggle between the
+       input date represented as a day number (daynum)
+       or as month and day.  To set the switch (to
+       use daynum input), the function is or'd; to
+       clear the switch (to use month and day input),
+       the function is inverted and and'd.
+
+       For example:
+       pdat->function |= S_DOY (sets daynum input)
+       pdat->function &= ~S_DOY (sets month and day input)
+
+       Whichever date form is used, S_solpos will
+       calculate and return the variables(s) of the
+       other form.  See the soltest.c program for
+       other examples. */
+
+    /* VARIABLE        I/O  Function    Description */
+    /* -------------  ----  ----------  --------------------------------------- */
+
+    int day;			/* I/O: S_DOY      Day of month (May 27 = 27, etc.)
+				   solpos will CALCULATE this by default,
+				   or will optionally require it as input
+				   depending on the setting of the S_DOY
+				   function switch. */
+    int daynum;			/* I/O: S_DOY      Day number (day of year; Feb 1 = 32 )
+				   solpos REQUIRES this by default, but
+				   will optionally calculate it from
+				   month and day depending on the setting
+				   of the S_DOY function switch. */
+    int function;		/* I:              Switch to choose functions for desired
+				   output. */
+    int hour;			/* I:              Hour of day, 0 - 23, DEFAULT = 12 */
+    int interval;		/* I:              Interval of a measurement period in
+				   seconds.  Forces solpos to use the
+				   time and date from the interval
+				   midpoint. The INPUT time (hour,
+				   minute, and second) is assumed to
+				   be the END of the measurement
+				   interval. */
+    int minute;			/* I:              Minute of hour, 0 - 59, DEFAULT = 0 */
+    int month;			/* I/O: S_DOY      Month number (Jan = 1, Feb = 2, etc.)
+				   solpos will CALCULATE this by default,
+				   or will optionally require it as input
+				   depending on the setting of the S_DOY
+				   function switch. */
+    int second;			/* I:              Second of minute, 0 - 59, DEFAULT = 0 */
+    int year;			/* I:              4-digit year (2-digit year is NOT
+				   allowed */
+
+    int time_updated;           /* recalculate time-dependent variables */
+    int longitude_updated;      /* recalculate longitude-dependent variables */
+
+  /***** FLOATS *****/
+
+    float amass;		/* O:  S_AMASS    Relative optical airmass */
+    float ampress;		/* O:  S_AMASS    Pressure-corrected airmass */
+    float aspect;		/* I:             Azimuth of panel surface (direction it
+				   faces) N=0, E=90, S=180, W=270,
+				   DEFAULT = 180 */
+    float azim;			/* O:  S_SOLAZM   Solar azimuth angle:  N=0, E=90, S=180,
+				   W=270 */
+    float cosinc;		/* O:  S_TILT     Cosine of solar incidence angle on
+				   panel */
+    float coszen;		/* O:  S_REFRAC   Cosine of refraction corrected solar
+				   zenith angle */
+    float dayang;		/* T:  S_GEOM     Day angle (daynum*360/year-length)
+				   degrees */
+    float declin;		/* T:  S_GEOM     Declination--zenith angle of solar noon
+				   at equator, degrees NORTH */
+    float eclong;		/* T:  S_GEOM     Ecliptic longitude, degrees */
+    float ecobli;		/* T:  S_GEOM     Obliquity of ecliptic */
+    float ectime;		/* T:  S_GEOM     Time of ecliptic calculations */
+    float elevetr;		/* O:  S_ZENETR   Solar elevation, no atmospheric
+				   correction (= ETR) */
+    float elevref;		/* O:  S_REFRAC   Solar elevation angle,
+				   deg. from horizon, refracted */
+    float eqntim;		/* T:  S_TST      Equation of time (TST - LMT), minutes */
+    float erv;			/* T:  S_GEOM     Earth radius vector
+				   (multiplied to solar constant) */
+    float etr;			/* O:  S_ETR      Extraterrestrial (top-of-atmosphere)
+				   W/sq m global horizontal solar
+				   irradiance */
+    float etrn;			/* O:  S_ETR      Extraterrestrial (top-of-atmosphere)
+				   W/sq m direct normal solar
+				   irradiance */
+    float etrtilt;		/* O:  S_TILT     Extraterrestrial (top-of-atmosphere)
+				   W/sq m global irradiance on a tilted
+				   surface */
+    float gmst;			/* T:  S_GEOM     Greenwich mean sidereal time, hours */
+    float hrang;		/* T:  S_GEOM     Hour angle--hour of sun from solar noon,
+				   degrees WEST */
+    float julday;		/* T:  S_GEOM     Julian Day of 1 JAN 2000 minus
+				   2,400,000 days (in order to regain
+				   single precision) */
+    float latitude;		/* I:             Latitude, degrees north (south negative) */
+    float longitude;		/* I:             Longitude, degrees east (west negative) */
+    float lmst;			/* T:  S_GEOM     Local mean sidereal time, degrees */
+    float mnanom;		/* T:  S_GEOM     Mean anomaly, degrees */
+    float mnlong;		/* T:  S_GEOM     Mean longitude, degrees */
+    float rascen;		/* T:  S_GEOM     Right ascension, degrees */
+    float press;		/* I:             Surface pressure, millibars, used for
+				   refraction correction and ampress */
+    float prime;		/* O:  S_PRIME    Factor that normalizes Kt, Kn, etc. */
+    float sbcf;			/* O:  S_SBCF     Shadow-band correction factor */
+    float sbwid;		/* I:             Shadow-band width (cm) */
+    float sbrad;		/* I:             Shadow-band radius (cm) */
+    float sbsky;		/* I:             Shadow-band sky factor */
+    float solcon;		/* I:             Solar constant (NREL uses 1367 W/sq m) */
+    float ssha;			/* T:  S_SRHA     Sunset(/rise) hour angle, degrees */
+    float sretr;		/* O:  S_SRSS     Sunrise time, minutes from midnight,
+				   local, WITHOUT refraction */
+    float ssetr;		/* O:  S_SRSS     Sunset time, minutes from midnight,
+				   local, WITHOUT refraction */
+    float temp;			/* I:             Ambient dry-bulb temperature, degrees C,
+				   used for refraction correction */
+    float tilt;			/* I:             Degrees tilt from horizontal of panel */
+    float timezone;		/* I:             Time zone, east (west negative).
+				   USA:  Mountain = -7, Central = -6, etc. */
+    float tst;			/* T:  S_TST      True solar time, minutes from midnight */
+    float tstfix;		/* T:  S_TST      True solar time - local standard time */
+    float unprime;		/* O:  S_PRIME    Factor that denormalizes Kt', Kn', etc. */
+    float utime;		/* T:  S_GEOM     Universal (Greenwich) standard time */
+    float zenetr;		/* T:  S_ZENETR   Solar zenith angle, no atmospheric
+				   correction (= ETR) */
+    float zenref;		/* O:  S_REFRAC   Solar zenith angle, deg. from zenith,
+				   refracted */
+};
+
+/* For users that wish to access individual functions, the following table
+   lists all output and transition variables, the L_ mask for the function
+   that calculates them, and all the input variables required by that function.
+   The function variable is set to the L_ mask, which will force S_solpos to
+   only call the required function.  L_ masks may be ORed as desired.
+
+   VARIABLE      Mask       Required Variables
+   ---------  ----------  ---------------------------------------
+   amass      L_AMASS    zenref, press
+   ampress    L_AMASS    zenref, press
+   azim       L_SOLAZM   elevetr, declin, latitude, hrang
+   cosinc     L_TILT     azim, aspect, tilt, zenref, coszen,etrn
+   coszen     L_REFRAC   elevetr, press, temp
+   dayang     L_GEOM     All date, time, and location inputs
+   declin     L_GEOM     All date, time, and location inputs
+   eclong     L_GEOM     All date, time, and location inputs
+   ecobli     L_GEOM     All date, time, and location inputs
+   ectime     L_GEOM     All date, time, and location inputs
+   elevetr    L_ZENETR   declin, latitude, hrang
+   elevref    L_REFRAC   elevetr, press, temp
+   eqntim     L_TST      hrang, hour, minute, second, interval
+   erv        L_GEOM     All date, time, and location inputs
+   etr        L_ETR      coszen, solcon, erv
+   etrn       L_ETR      coszen, solcon, erv
+   etrtilt    L_TILT     azim, aspect, tilt, zenref, coszen, etrn
+   gmst       L_GEOM     All date, time, and location inputs
+   hrang      L_GEOM     All date, time, and location inputs
+   julday     L_GEOM     All date, time, and location inputs
+   lmst       L_GEOM     All date, time, and location inputs
+   mnanom     L_GEOM     All date, time, and location inputs
+   mnlong     L_GEOM     All date, time, and location inputs
+   rascen     L_GEOM     All date, time, and location inputs
+   prime      L_PRIME    amass
+   sbcf       L_SBCF     latitude, declin, ssha, sbwid, sbrad, sbsky
+   ssha       L_SRHA     latitude, declin
+   sretr      L_SRSS     ssha, tstfix
+   ssetr      L_SRSS     ssha, tstfix
+   tst        L_TST      hrang, hour, minute, second, interval
+   tstfix     L_TST      hrang, hour, minute, second, interval
+   unprime    L_PRIME    amass
+   utime      L_GEOM     All date, time, and location inputs
+   zenetr     L_ZENETR   declination, latitude, hrang
+   zenref     L_REFRAC   elevetr, press, temp
+
+ */
+
+/*============================================================================
+*    Long int function S_solpos, adapted from the NREL VAX solar libraries
+*
+*    This function calculates the apparent solar position and intensity
+*    (theoretical maximum solar energy) based on the date, time, and
+*    location on Earth. (DEFAULT values are from the optional S_posinit
+*    function.)
+*
+*    Requires:
+*        Date and time:
+*            year
+*            month  (optional without daynum)
+*            day    (optional without daynum)
+*            daynum
+*            hour
+*            minute
+*            second
+*        Location:
+*            latitude
+*            longitude
+*        Location/time adjuster:
+*            timezone
+*        Atmospheric pressure and temperature:
+*            press     DEFAULT 1013.0 mb
+*            temp      DEFAULT 10.0 degrees C
+*        Tilt of flat surface that receives solar energy:
+*            aspect    DEFAULT 180 (South)
+*            tilt      DEFAULT 0 (Horizontal)
+*        Shadow band parameters:
+*            sbwid     DEFAULT 7.6 cm
+*            sbrad     DEFAULT 31.7 cm
+*            sbsky     DEFAULT 0.04
+*        Functionality
+*            function  DEFAULT S_ALL (all output parameters computed)
+*
+*    Returns:
+*        everything defined at the top of this listing.
+*----------------------------------------------------------------------------*/
+long S_solpos(struct posdata *pdat);
+
+/*============================================================================
+*    Void function S_init
+*
+*    This function initiates all of the input functions to S_Solpos().
+*    NOTE: This function is optional if you initialize all input parameters
+*          in your calling code.
+*
+*    Requires: Pointer to a posdata structure, members of which are
+*           initialized.
+*
+*    Returns: Void
+*
+*----------------------------------------------------------------------------*/
+void S_init(struct posdata *pdat);
+
+
+/*============================================================================
+*    Void function S_decode
+*
+*    This function decodes the error codes from S_solpos return value
+*
+*    INPUTS: Long integer S_solpos return value, struct posdata*
+*
+*    OUTPUTS: Descriptive text of errors to stderr
+*----------------------------------------------------------------------------*/
+void S_decode(long code, struct posdata *pdat);

Added: grass-addons/grass7/grass7/raster/r.threshold/Makefile
===================================================================
--- grass-addons/grass7/grass7/raster/r.threshold/Makefile	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.threshold/Makefile	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,7 @@
+MODULE_TOPDIR = ../..
+
+PGM = r.threshold
+
+include $(MODULE_TOPDIR)/include/Make/Script.make
+
+default: script

Added: grass-addons/grass7/grass7/raster/r.threshold/r.threshold.html
===================================================================
--- grass-addons/grass7/grass7/raster/r.threshold/r.threshold.html	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.threshold/r.threshold.html	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,31 @@
+<h2>DESCRIPTION</h2>
+
+<em>r.threshold</em> finds optimal threshold for stream extraction. 
+
+<h2>NOTES</h2>
+
+The module finds a first tentative value of upslope area to be used as input to
+extract the river network using <em>r.stream.extract</em> or <em>r.watershed</em>.
+Real streams depend on many factors, such as rainfall, infiltration rate,
+geology, climate etc. i.e. the same topography in different parts of
+the world yields different real stream networks. This approach provides
+a best guess about what makes sense when looking only at the DEM.
+
+<h2>EXAMPLE</h2>
+
+<div class="code"><pre>
+r.threshold acc=accumulation_map
+</pre></div>
+
+<h2>SEE ALSO</h2>
+
+<em>
+<a href="r.stream.extract.html">r.stream.extract</a>,
+<a href="r.watershed.html">r.watershed</a>
+</em>
+
+<h2>AUTHOR</h2>
+<p>Margherita Di Leo (dileomargherita AT gmail DOT com)
+
+<p>
+<i>Last changed: $Date: 2012-04-10 20:51:23 +0200 (Tue, 10 Apr 2012) $</i>

Added: grass-addons/grass7/grass7/raster/r.threshold/r.threshold.py
===================================================================
--- grass-addons/grass7/grass7/raster/r.threshold/r.threshold.py	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.threshold/r.threshold.py	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,70 @@
+#!/usr/bin/env python
+
+################################################################################
+#
+# MODULE:       r.threshold.py
+#
+# AUTHOR(S):    Margherita Di Leo <dileomargherita at gmail.com>
+#               
+# PURPOSE:      Find optimal threshold for stream extraction
+#
+# COPYRIGHT:    (c) 2011 by Margherita Di Leo and the GRASS Development Team
+#               
+#               This program is free software under the GNU General
+#               Public License (>=v2). Read the file COPYING that
+#               comes with GRASS for details.
+#
+################################################################################
+
+#%module
+#% description: Find optimal threshold for stream extraction
+#% keywords: raster
+#% keywords: hydrology
+#%end
+#%option
+#% key: acc
+#% type: string
+#% gisprompt: old, raster, raster
+#% key_desc: acc
+#% description: Name of accumulation raster map 
+#% required: yes
+#%end
+
+import os, sys
+import math
+import numpy as np
+
+import grass.script as grass
+
+def main():
+    stats = grass.read_command('r.stats', input = options['acc'], fs = 'space', nv = '*', nsteps = '1000', flags = 'Anc').split('\n')[:-1]
+    
+    mappatella = np.zeros((len(stats),3),float)
+    
+    # mappatella is a matrix, in the first column the value of upslope area is stored, 
+    # in the second the number of cells, in the third the distance from origin is calculated
+    
+    for i in range(len(stats)):
+        mappatella[i,0],  mappatella[i,1] = map(float, stats[i].split(' '))
+        # calculating distance from origin of each point; origin of the plot is in low left point 
+        mappatella[i,2] = math.sqrt((mappatella[i,0]**2) + (mappatella[i,1]**2))
+    
+    area = mappatella[:,0]
+    num_cells = mappatella[:,1]
+    distance = mappatella[:,2]
+    
+    index = np.where(distance==min(distance))
+    th = area[index]
+    
+    if th < 0:
+        grass.warning("Flow accumulation contains negative values")
+    else:
+        grass.message("Suggested threshold is %d" % th )
+    
+    grass.message("Done!")
+    
+    return 0
+
+if __name__ == "__main__":
+    options, flags = grass.parser()
+    sys.exit(main())

Added: grass-addons/grass7/grass7/raster/r.vol.dem/Makefile
===================================================================
--- grass-addons/grass7/grass7/raster/r.vol.dem/Makefile	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.vol.dem/Makefile	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,10 @@
+MODULE_TOPDIR = ../..
+
+PGM = r.vol.dem
+
+LIBES = $(RASTERLIB) $(GISLIB)
+DEPENDENCIES = $(RASTERDEP) $(GISDEP)
+
+include $(MODULE_TOPDIR)/include/Make/Module.make
+
+default: cmd

Added: grass-addons/grass7/grass7/raster/r.vol.dem/chull.c
===================================================================
--- grass-addons/grass7/grass7/raster/r.vol.dem/chull.c	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.vol.dem/chull.c	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,1283 @@
+/*
+   This code is described in "Computational Geometry in C" (Second Edition),
+   Chapter 4.  It is not written to be comprehensible without the 
+   explanation in that book.
+
+   Input: 3n integer coordinates for the points.
+   Output: the 3D convex hull, in postscript with embedded comments
+   showing the vertices and faces.
+
+   Compile: gcc -o chull chull.c
+
+   Written by Joseph O'Rourke, with contributions by 
+   Kristy Anderson, John Kutcher, Catherine Schevon, Susan Weller.
+   Last modified: March 1998
+   Questions to orourke at cs.smith.edu.
+   --------------------------------------------------------------------
+   This code is Copyright 1998 by Joseph O'Rourke.  It may be freely 
+   redistributed in its entirety provided that this copyright notice is 
+   not removed.
+   --------------------------------------------------------------------
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+
+#include <grass/gis.h>
+
+#include "globals.h"
+
+/*Define Boolean type */
+typedef enum
+{ BFALSE, BTRUE } bool;
+
+/* Define vertex indices. */
+#define X   0
+#define Y   1
+#define Z   2
+
+/* Define structures for vertices, edges and faces */
+typedef struct tVertexStructure tsVertex;
+typedef tsVertex *tVertex;
+
+typedef struct tEdgeStructure tsEdge;
+typedef tsEdge *tEdge;
+
+typedef struct tFaceStructure tsFace;
+typedef tsFace *tFace;
+
+struct tVertexStructure
+{
+    long int v[3];
+    int vnum;
+    tEdge duplicate;		/* pointer to incident cone edge (or NULL) */
+    bool onhull;		/* T iff point on hull. */
+    bool mark;			/* T iff point already processed. */
+    tVertex next, prev;
+};
+
+struct tEdgeStructure
+{
+    tFace adjface[2];
+    tVertex endpts[2];
+    tFace newface;		/* pointer to incident cone face. */
+    bool delete;		/* T iff edge should be delete. */
+    tEdge next, prev;
+};
+
+struct tFaceStructure
+{
+    tEdge edge[3];
+    tVertex vertex[3];
+    bool visible;		/* T iff face visible from new point. */
+    tFace next, prev;
+};
+
+/* Define flags */
+#define ONHULL   	BTRUE
+#define REMOVED  	BTRUE
+#define VISIBLE  	BTRUE
+#define PROCESSED	BTRUE
+#define SAFE		2000000000	/* Range of safe coord values. */
+
+/* Global variable definitions */
+tVertex vertices = NULL;
+tEdge edges = NULL;
+tFace faces = NULL;
+bool debug = BFALSE;
+bool check = BFALSE;
+
+/* Function declarations */
+tVertex MakeNullVertex(void);
+void ReadVertices(long int *px, long int *py, long int *pz, int num_points);
+void Print(void);
+void Dump(FILE * tmpfile);
+void SubVec(long int a[3], long int b[3], long int c[3]);
+int DoubleTriangle(void);
+void ConstructHull(void);
+bool AddOne(tVertex p);
+int VolumeSign(tFace f, tVertex p);
+int Volumei(tFace f, tVertex p);
+tFace MakeConeFace(tEdge e, tVertex p);
+void MakeCcw(tFace f, tEdge e, tVertex p);
+tEdge MakeNullEdge(void);
+tFace MakeNullFace(void);
+tFace MakeFace(tVertex v0, tVertex v1, tVertex v2, tFace f);
+void CleanUp(void);
+void CleanEdges(void);
+void CleanFaces(void);
+void CleanVertices(void);
+bool Collinear(tVertex a, tVertex b, tVertex c);
+void CheckEuler(long int V, long int E, long int F);
+void PrintPoint(tVertex p);
+void Checks(void);
+void Consistency(void);
+void Convexity(void);
+void PrintOut(tVertex v);
+void PrintVertices(void);
+void PrintEdges(void);
+void PrintFaces(void);
+
+#include "macros.h"
+
+
+/*
+
+   Release all memory allocated for edges, faces and vertices
+
+ */
+void freeMem(void)
+{
+    tEdge e;			/* Primary index into edge list. */
+    tFace f;			/* Primary pointer into face list. */
+    tVertex v;
+    tEdge te;			/* Temporary edge pointer. */
+    tFace tf;			/* Temporary face pointer. */
+    tVertex tv;			/* Temporary vertex pointer. */
+
+    if (DEBUG) {
+	fprintf(stdout, "FREE MEM:\n");
+	fflush(stdout);
+    }
+
+    if (DEBUG) {
+	fprintf(stdout, "  EDGES:\n");
+	fflush(stdout);
+    }
+    e = edges;
+    do {
+	te = e;
+	e = e->next;
+	DELETE(edges, te);
+    } while (e != edges);
+
+    if (DEBUG) {
+	fprintf(stdout, "  FACES:\n");
+	fflush(stdout);
+    }
+    f = faces;
+    do {
+	tf = f;
+	f = f->next;
+	DELETE(faces, tf);
+    } while (f != faces);
+
+    if (DEBUG) {
+	fprintf(stdout, "  VERTICES:\n");
+	fflush(stdout);
+    }
+    v = vertices;
+    do {
+	tv = v;
+	v = v->next;
+	DELETE(vertices, tv);
+    } while (v != vertices);
+
+    FREE(te);
+    FREE(tf);
+    FREE(tv);
+
+    DELETE(edges, e);
+    DELETE(faces, f);
+    DELETE(vertices, v);
+
+    FREE(edges);
+    FREE(faces);
+    FREE(vertices);
+
+    if (DEBUG) {
+	fprintf(stdout, "MEM FREE'D!\n");
+	fflush(stdout);
+    }
+
+}
+
+
+/*-------------------------------------------------------------------*/
+int make3DHull(long int *px, long int *py, long int *pz, int num_points,
+	       FILE * tmpfile)
+{
+    int error;
+
+    check = BFALSE;
+    debug = BFALSE;
+
+    if (DEBUG > 1)
+	check = BTRUE;
+    if (DEBUG > 2)
+	debug = BTRUE;
+
+    ReadVertices(px, py, pz, num_points);
+
+    error = DoubleTriangle();
+    if (error < 0) {
+	G_warning("All points of this layer are in the same voxel plane.\n");
+	freeMem();
+	return (error);
+    }
+
+    ConstructHull();
+
+    Dump(tmpfile);
+
+    freeMem();
+
+    return (0);
+}
+
+/*---------------------------------------------------------------------
+MakeNullVertex: Makes a vertex, nulls out fields.
+---------------------------------------------------------------------*/
+tVertex MakeNullVertex(void)
+{
+    tVertex v;
+
+    NEW(v, tsVertex);
+    v->duplicate = NULL;
+    v->onhull = !ONHULL;
+    v->mark = !PROCESSED;
+    ADD(vertices, v);
+
+    return v;
+}
+
+/*---------------------------------------------------------------------
+ReadVertices: Reads in the vertices, and links them into a circular
+list with MakeNullVertex.  There is no need for the # of vertices to be
+the first line: the function looks for EOF instead.  Sets the global
+variable vertices via the ADD macro.
+---------------------------------------------------------------------*/
+void ReadVertices(long int *px, long int *py, long int *pz, int num_points)
+{
+    tVertex v;
+    int vnum = 0;
+    int i;
+
+    for (i = 0; i < num_points; i++) {
+	v = MakeNullVertex();
+	v->v[X] = px[i];
+	v->v[Y] = py[i];
+	v->v[Z] = pz[i];
+	v->vnum = vnum++;
+	if ((abs(px[i]) > SAFE) || (abs(py[i]) > SAFE) || (abs(pz[i]) > SAFE)) {
+	    printf
+		("Coordinate of vertex below might be too large: run with -c flag\n");
+	    PrintPoint(v);
+	}
+    }
+}
+
+/*---------------------------------------------------------------------
+Dump: Dumps out the vertices and the faces to a file.  
+Uses the vnum indices  corresponding to the order in which the vertices 
+were input.
+Output is in GRASS ASCII file format.
+---------------------------------------------------------------------*/
+void Dump(FILE * tmpfile)
+{
+    /* Pointers to vertices, edges, faces. */
+    tVertex v;
+    tEdge e;
+    tFace f;
+    double dx, dy, dz;
+    long int a[3], b[3];	/* used to compute normal vector */
+
+    /* Counters for Euler's formula. */
+    long int V = 0, E = 0, F = 0;
+
+    /* Note: lowercase==pointer, uppercase==counter. */
+    long int cat;
+
+    f = faces;
+    do {
+	++F;
+	f = f->next;
+    } while (f != faces);
+
+    /* GRASS 6 map header */
+    fprintf(tmpfile, "ORGANIZATION: \n");
+    fprintf(tmpfile, "DIGIT DATE: \n");
+    fprintf(tmpfile, "DIGIT NAME: \n");
+    fprintf(tmpfile, "MAP NAME: \n");
+    fprintf(tmpfile, "MAP DATE: \n");
+    fprintf(tmpfile, "MAP SCALE: 10000\n");
+    fprintf(tmpfile, "OTHER INFO: %li faces.\n", F);
+    fprintf(tmpfile, "ZONE: 0\n");
+    fprintf(tmpfile, "MAP THRESH: 0.5\n");
+    fprintf(tmpfile, "VERTI:\n");
+
+    cat = 1;
+
+    /* putting all faces into one object does not produce nice output in NVIZ !
+       If we decided to dump all layers into a single file, we would also need
+       a cat for each object to be passed from the main program.   
+     */
+
+    /*
+       printf("F  %li 1\n", F*4);
+       do {                          
+       dx = ((double) ( f->vertex[0]->v[X] ) / (1000));
+       dy = ((double) ( f->vertex[0]->v[Y] ) / (1000));
+       dz = ((double) ( f->vertex[0]->v[Z] ) / (1000));
+       printf(" %.3f %.3f %.3f\n", dx, dy, dz);
+       dx = ((double) ( f->vertex[1]->v[X] ) / (1000));
+       dy = ((double) ( f->vertex[1]->v[Y] ) / (1000));
+       dz = ((double) ( f->vertex[1]->v[Z] ) / (1000));
+       printf(" %.3f %.3f %.3f\n", dx, dy, dz);
+       dx = ((double) ( f->vertex[2]->v[X] ) / (1000));
+       dy = ((double) ( f->vertex[2]->v[Y] ) / (1000));
+       dz = ((double) ( f->vertex[2]->v[Z] ) / (1000));
+       printf(" %.3f %.3f %.3f\n", dx, dy, dz);
+       dx = ((double) ( f->vertex[0]->v[X] ) / (1000));
+       dy = ((double) ( f->vertex[0]->v[Y] ) / (1000));
+       dz = ((double) ( f->vertex[0]->v[Z] ) / (1000));
+       printf(" %.3f %.3f %.3f\n", dx, dy, dz);      
+       f = f->next;
+       } while ( f != faces );
+       printf(" %li 1\n", cat);
+     */
+
+    do {
+	fprintf(tmpfile, "F  4 1\n");
+	dx = ((double)(f->vertex[0]->v[X]) / (PRECISION));
+	dy = ((double)(f->vertex[0]->v[Y]) / (PRECISION));
+	dz = ((double)(f->vertex[0]->v[Z]) / (PRECISION));
+	fprintf(tmpfile, " %.3f %.3f %.3f\n", dx, dy, dz);
+	dx = ((double)(f->vertex[1]->v[X]) / (PRECISION));
+	dy = ((double)(f->vertex[1]->v[Y]) / (PRECISION));
+	dz = ((double)(f->vertex[1]->v[Z]) / (PRECISION));
+	fprintf(tmpfile, " %.3f %.3f %.3f\n", dx, dy, dz);
+	dx = ((double)(f->vertex[2]->v[X]) / (PRECISION));
+	dy = ((double)(f->vertex[2]->v[Y]) / (PRECISION));
+	dz = ((double)(f->vertex[2]->v[Z]) / (PRECISION));
+	fprintf(tmpfile, " %.3f %.3f %.3f\n", dx, dy, dz);
+	dx = ((double)(f->vertex[0]->v[X]) / (PRECISION));
+	dy = ((double)(f->vertex[0]->v[Y]) / (PRECISION));
+	dz = ((double)(f->vertex[0]->v[Z]) / (PRECISION));
+	fprintf(tmpfile, " %.3f %.3f %.3f\n", dx, dy, dz);
+	fprintf(tmpfile, " %li 1\n", cat);
+	cat++;
+	f = f->next;
+    } while (f != faces);
+
+    if (DEBUG > 0) {
+	fprintf(stdout, "3D Convex hull check (Euler):\n");
+	check = BTRUE;
+	CheckEuler(V, E, F);
+    }
+
+
+
+}
+
+
+
+/*---------------------------------------------------------------------
+Print: Prints out the vertices and the faces.  Uses the vnum indices 
+corresponding to the order in which the vertices were input.
+Output is in PostScript format.
+---------------------------------------------------------------------*/
+void Print(void)
+{
+    /* Pointers to vertices, edges, faces. */
+    tVertex v;
+    tEdge e;
+    tFace f;
+    long int xmin, ymin, xmax, ymax;
+    long int a[3], b[3];	/* used to compute normal vector */
+
+    /* Counters for Euler's formula. */
+    long int V = 0, E = 0, F = 0;
+
+    /* Note: lowercase==pointer, uppercase==counter. */
+
+   /*-- find X min & max --*/
+    v = vertices;
+    xmin = xmax = v->v[X];
+    do {
+	if (v->v[X] > xmax)
+	    xmax = v->v[X];
+	else if (v->v[X] < xmin)
+	    xmin = v->v[X];
+	v = v->next;
+    } while (v != vertices);
+
+   /*-- find Y min & max --*/
+    v = vertices;
+    ymin = ymax = v->v[Y];
+    do {
+	if (v->v[Y] > ymax)
+	    ymax = v->v[Y];
+	else if (v->v[Y] < ymin)
+	    ymin = v->v[Y];
+	v = v->next;
+    } while (v != vertices);
+
+    /* PostScript header */
+    printf("%%!PS\n");
+    printf("%%%%BoundingBox: %li %li %li %li\n", xmin, ymin, xmax, ymax);
+    printf(".00 .00 setlinewidth\n");
+    printf("%li %li translate\n", -xmin + 72, -ymin + 72);
+    /* The +72 shifts the figure one inch from the lower left corner */
+
+    /* Vertices. */
+    v = vertices;
+    do {
+	if (v->mark)
+	    V++;
+	v = v->next;
+    } while (v != vertices);
+    printf("\n%%%% Vertices:\tV = %li\n", V);
+    printf("%%%% index:\tx\ty\tz\n");
+    do {
+	printf("%%%% %5d:\t%li\t%li\t%li\n",
+	       v->vnum, v->v[X], v->v[Y], v->v[Z]);
+	v = v->next;
+    } while (v != vertices);
+
+    /* Faces. */
+    /* visible faces are printed as PS output */
+    f = faces;
+    do {
+	++F;
+	f = f->next;
+    } while (f != faces);
+    printf("\n%%%% Faces:\tF = %li\n", F);
+    printf("%%%% Visible faces only: \n");
+    do {
+	/* Print face only if it is visible: if normal vector >= 0 */
+	SubVec(f->vertex[1]->v, f->vertex[0]->v, a);
+	SubVec(f->vertex[2]->v, f->vertex[1]->v, b);
+	if ((a[0] * b[1] - a[1] * b[0]) >= 0) {
+	    printf("%%%% vnums:  %d  %d  %d\n",
+		   f->vertex[0]->vnum,
+		   f->vertex[1]->vnum, f->vertex[2]->vnum);
+	    printf("newpath\n");
+	    printf("%li\t%li\tmoveto\n",
+		   f->vertex[0]->v[X], f->vertex[0]->v[Y]);
+	    printf("%li\t%li\tlineto\n",
+		   f->vertex[1]->v[X], f->vertex[1]->v[Y]);
+	    printf("%li\t%li\tlineto\n",
+		   f->vertex[2]->v[X], f->vertex[2]->v[Y]);
+	    printf("closepath stroke\n\n");
+	}
+	f = f->next;
+    } while (f != faces);
+
+    /* prints a list of all faces */
+    printf("%%%% List of all faces: \n");
+    printf("%%%%\tv0\tv1\tv2\t(vertex indices)\n");
+    do {
+	printf("%%%%\t%d\t%d\t%d\n",
+	       f->vertex[0]->vnum, f->vertex[1]->vnum, f->vertex[2]->vnum);
+	f = f->next;
+    } while (f != faces);
+
+    /* Edges. */
+    e = edges;
+    do {
+	E++;
+	e = e->next;
+    } while (e != edges);
+    printf("\n%%%% Edges:\tE = %li\n", E);
+    /* Edges not printed out (but easily added). */
+
+    printf("\nshowpage\n\n");
+
+    if (DEBUG > 0) {
+	fprintf(stdout, "3D Convex hull check (Euler):\n");
+	check = BTRUE;
+	CheckEuler(V, E, F);
+    }
+
+}
+
+/*---------------------------------------------------------------------
+SubVec:  Computes a - b and puts it into c.
+---------------------------------------------------------------------*/
+void SubVec(long int a[3], long int b[3], long int c[3])
+{
+    long int i;
+
+    for (i = 0; i < 2; i++)
+	c[i] = a[i] - b[i];
+
+}
+
+/*---------------------------------------------------------------------
+ DoubleTriangle builds the initial double triangle.  It first finds 3 
+ noncollinear points and makes two faces out of them, in opposite order.
+ It then finds a fourth point that is not coplanar with that face.  The  
+ vertices are stored in the face structure in counterclockwise order so 
+ that the volume between the face and the point is negative. Lastly, the
+ 3 newfaces to the fourth point are constructed and the data structures
+ are cleaned up. 
+---------------------------------------------------------------------*/
+
+/* RETURN:      0 if OK */
+/*              -1 if all points collinear */
+/*              -2 if all points coplanar */
+
+int DoubleTriangle(void)
+{
+    tVertex v0, v1, v2, v3, t;
+    tFace f0, f1 = NULL;
+    tEdge e0, e1, e2, s;
+    long int vol;
+
+    /* Find 3 noncollinear points. */
+    v0 = vertices;
+    while (Collinear(v0, v0->next, v0->next->next)) {
+	if ((v0 = v0->next) == vertices) {
+	    if (debug) {
+		printf("DoubleTriangle:  All points are collinear!\n");
+	    }
+	    return (-1);
+	}
+    }
+    v1 = v0->next;
+    v2 = v1->next;
+
+    /* Mark the vertices as processed. */
+    v0->mark = PROCESSED;
+    v1->mark = PROCESSED;
+    v2->mark = PROCESSED;
+
+    /* Create the two "twin" faces. */
+    f0 = MakeFace(v0, v1, v2, f1);
+    f1 = MakeFace(v2, v1, v0, f0);
+
+    /* Link adjacent face fields. */
+    f0->edge[0]->adjface[1] = f1;
+    f0->edge[1]->adjface[1] = f1;
+    f0->edge[2]->adjface[1] = f1;
+    f1->edge[0]->adjface[1] = f0;
+    f1->edge[1]->adjface[1] = f0;
+    f1->edge[2]->adjface[1] = f0;
+
+    /* Find a fourth, noncoplanar point to form tetrahedron. */
+    v3 = v2->next;
+    vol = VolumeSign(f0, v3);
+    while (!vol) {
+	if ((v3 = v3->next) == v0) {
+	    if (debug) {
+		printf("DoubleTriangle:  All points are coplanar!\n");
+	    }
+	    return (-2);
+	}
+	vol = VolumeSign(f0, v3);
+    }
+
+    /* Insure that v3 will be the first added. */
+    vertices = v3;
+    if (debug) {
+	fprintf(stderr,
+		"DoubleTriangle: finished. Head repositioned at v3.\n");
+	PrintOut(vertices);
+    }
+
+
+    return (0);
+}
+
+
+/*---------------------------------------------------------------------
+ConstructHull adds the vertices to the hull one at a time.  The hull
+vertices are those in the list marked as onhull.
+---------------------------------------------------------------------*/
+void ConstructHull(void)
+{
+    tVertex v, vnext;
+    long int vol;
+    bool changed;		/* T if addition changes hull; not used. */
+    int i;
+    int numVertices;
+
+    if (VERBOSE) {
+	fprintf(stdout, "  Constructing 3D hull: \n");
+    }
+
+
+    v = vertices;
+    i = 0;
+    do {
+	vnext = v->next;
+	v = vnext;
+	i++;
+    } while (v != vertices);
+    numVertices = i;
+
+    v = vertices;
+    i = 0;
+    do {
+	vnext = v->next;
+	if (!v->mark) {
+	    v->mark = PROCESSED;
+	    changed = AddOne(v);
+	    CleanUp();
+
+	    if (check) {
+		fprintf(stderr, "ConstructHull: After Add of %d & Cleanup:\n",
+			v->vnum);
+		Checks();
+	    }
+	    if (debug)
+		PrintOut(v);
+	}
+	v = vnext;
+	i++;
+	if (VERBOSE) {
+	    G_percent(i, numVertices, 1);
+	}
+    } while (v != vertices);
+
+    fflush(stdout);
+
+}
+
+/*---------------------------------------------------------------------
+AddOne is passed a vertex.  It first determines all faces visible from 
+that point.  If none are visible then the point is marked as not 
+onhull.  Next is a loop over edges.  If both faces adjacent to an edge
+are visible, then the edge is marked for deletion.  If just one of the
+adjacent faces is visible then a new face is constructed.
+---------------------------------------------------------------------*/
+bool AddOne(tVertex p)
+{
+    tFace f;
+    tEdge e, temp;
+    long int vol;
+    bool vis = BFALSE;
+
+    if (debug) {
+	fprintf(stderr, "AddOne: starting to add v%d.\n", p->vnum);
+	PrintOut(vertices);
+    }
+
+    /* Mark faces visible from p. */
+    f = faces;
+    do {
+	vol = VolumeSign(f, p);
+	if (debug)
+	    fprintf(stderr,
+		    "faddr: %6x   paddr: %6x   Vol = %li\n", (unsigned int)f,
+		    (unsigned int)p, vol);
+	if (vol < 0) {
+	    f->visible = VISIBLE;
+	    vis = BTRUE;
+	}
+	f = f->next;
+    } while (f != faces);
+
+    /* If no faces are visible from p, then p is inside the hull. */
+    if (!vis) {
+	p->onhull = !ONHULL;
+	return BFALSE;
+    }
+
+    /* Mark edges in interior of visible region for deletion.
+       Erect a newface based on each border edge. */
+    e = edges;
+    do {
+	temp = e->next;
+	if (e->adjface[0]->visible && e->adjface[1]->visible)
+	    /* e interior: mark for deletion. */
+	    e->delete = REMOVED;
+	else if (e->adjface[0]->visible || e->adjface[1]->visible)
+	    /* e border: make a new face. */
+	    e->newface = MakeConeFace(e, p);
+	e = temp;
+    } while (e != edges);
+    return BTRUE;
+}
+
+/*---------------------------------------------------------------------
+VolumeSign returns the sign of the volume of the tetrahedron determined by f
+and p.  VolumeSign is +1 iff p is on the negative side of f,
+where the positive side is determined by the rh-rule.  So the volume 
+is positive if the ccw normal to f points outside the tetrahedron.
+The final fewer-multiplications form is due to Bob Williamson.
+---------------------------------------------------------------------*/
+int VolumeSign(tFace f, tVertex p)
+{
+    double vol;
+    long int voli;
+    double ax, ay, az, bx, by, bz, cx, cy, cz;
+
+    ax = f->vertex[0]->v[X] - p->v[X];
+    ay = f->vertex[0]->v[Y] - p->v[Y];
+    az = f->vertex[0]->v[Z] - p->v[Z];
+    bx = f->vertex[1]->v[X] - p->v[X];
+    by = f->vertex[1]->v[Y] - p->v[Y];
+    bz = f->vertex[1]->v[Z] - p->v[Z];
+    cx = f->vertex[2]->v[X] - p->v[X];
+    cy = f->vertex[2]->v[Y] - p->v[Y];
+    cz = f->vertex[2]->v[Z] - p->v[Z];
+
+    vol = ax * (by * cz - bz * cy)
+	+ ay * (bz * cx - bx * cz)
+	+ az * (bx * cy - by * cx);
+
+    if (debug)
+	fprintf(stderr,
+		"Face=%6x; Vertex=%d: vol(int) = %li, vol(double) = %.f\n",
+		(unsigned int)f, p->vnum, voli, vol);
+
+    /* The volume should be an integer. */
+    if (vol > 0.5)
+	return 1;
+    else if (vol < -0.5)
+	return -1;
+    else
+	return 0;
+}
+
+/*---------------------------------------------------------------------*/
+int Volumei(tFace f, tVertex p)
+{
+    double vol;
+    long int voli;
+    double ax, ay, az, bx, by, bz, cx, cy, cz, dx, dy, dz;
+
+    ax = f->vertex[0]->v[X] - p->v[X];
+    ay = f->vertex[0]->v[Y] - p->v[Y];
+    az = f->vertex[0]->v[Z] - p->v[Z];
+    bx = f->vertex[1]->v[X] - p->v[X];
+    by = f->vertex[1]->v[Y] - p->v[Y];
+    bz = f->vertex[1]->v[Z] - p->v[Z];
+    cx = f->vertex[2]->v[X] - p->v[X];
+    cy = f->vertex[2]->v[Y] - p->v[Y];
+    cz = f->vertex[2]->v[Z] - p->v[Z];
+
+    vol = (ax * (by * cz - bz * cy)
+	   + ay * (bz * cx - bx * cz)
+	   + az * (bx * cy - by * cx));
+
+    if (debug)
+	fprintf(stderr,
+		"Face=%6x; Vertex=%d: vol(int) = %li, vol(double) = %.f\n",
+		(unsigned int)f, p->vnum, voli, vol);
+
+    /* The volume should be an integer. */
+    if (vol > 0.5)
+	return 1;
+    else if (vol < -0.5)
+	return -1;
+    else
+	return 0;
+}
+
+
+/*-------------------------------------------------------------------*/
+void PrintPoint(tVertex p)
+{
+    int i;
+
+    for (i = 0; i < 3; i++)
+	printf("\t%li", p->v[i]);
+    putchar('\n');
+}
+
+/*---------------------------------------------------------------------
+MakeConeFace makes a new face and two new edges between the 
+edge and the point that are passed to it. It returns a pointer to
+the new face.
+---------------------------------------------------------------------*/
+tFace MakeConeFace(tEdge e, tVertex p)
+{
+    tEdge new_edge[2];
+    tFace new_face;
+    int i, j;
+
+    /* Make two new edges (if don't already exist). */
+    for (i = 0; i < 2; ++i)
+	/* If the edge exists, copy it into new_edge. */
+	if (!(new_edge[i] = e->endpts[i]->duplicate)) {
+	    /* Otherwise (duplicate is NULL), MakeNullEdge. */
+	    new_edge[i] = MakeNullEdge();
+	    new_edge[i]->endpts[0] = e->endpts[i];
+	    new_edge[i]->endpts[1] = p;
+	    e->endpts[i]->duplicate = new_edge[i];
+	}
+
+    /* Make the new face. */
+    new_face = MakeNullFace();
+    new_face->edge[0] = e;
+    new_face->edge[1] = new_edge[0];
+    new_face->edge[2] = new_edge[1];
+    MakeCcw(new_face, e, p);
+
+    /* Set the adjacent face pointers. */
+    for (i = 0; i < 2; ++i)
+	for (j = 0; j < 2; ++j)
+	    /* Only one NULL link should be set to new_face. */
+	    if (!new_edge[i]->adjface[j]) {
+		new_edge[i]->adjface[j] = new_face;
+		break;
+	    }
+
+    return new_face;
+}
+
+/*---------------------------------------------------------------------
+MakeCcw puts the vertices in the face structure in counterclock wise 
+order.  We want to store the vertices in the same 
+order as in the visible face.  The third vertex is always p.
+---------------------------------------------------------------------*/
+void MakeCcw(tFace f, tEdge e, tVertex p)
+{
+    tFace fv;			/* The visible face adjacent to e */
+    int i;			/* Index of e->endpoint[0] in fv. */
+    tEdge s;			/* Temporary, for swapping */
+
+    if (e->adjface[0]->visible)
+	fv = e->adjface[0];
+    else
+	fv = e->adjface[1];
+
+    /* Set vertex[0] & [1] of f to have the same orientation
+       as do the corresponding vertices of fv. */
+    for (i = 0; fv->vertex[i] != e->endpts[0]; ++i) ;
+    /* Orient f the same as fv. */
+    if (fv->vertex[(i + 1) % 3] != e->endpts[1]) {
+	f->vertex[0] = e->endpts[1];
+	f->vertex[1] = e->endpts[0];
+    }
+    else {
+	f->vertex[0] = e->endpts[0];
+	f->vertex[1] = e->endpts[1];
+	SWAP(s, f->edge[1], f->edge[2]);
+    }
+    /* This swap is tricky. e is edge[0]. edge[1] is based on endpt[0],
+       edge[2] on endpt[1].  So if e is oriented "forwards," we
+       need to move edge[1] to follow [0], because it precedes. */
+
+    f->vertex[2] = p;
+}
+
+/*---------------------------------------------------------------------
+MakeNullEdge creates a new cell and initializes all pointers to NULL
+and sets all flags to off.  It returns a pointer to the empty cell.
+---------------------------------------------------------------------*/
+tEdge MakeNullEdge(void)
+{
+    tEdge e;
+
+    NEW(e, tsEdge);
+    e->adjface[0] = e->adjface[1] = e->newface = NULL;
+    e->endpts[0] = e->endpts[1] = NULL;
+    e->delete = !REMOVED;
+    ADD(edges, e);
+    return e;
+}
+
+/*--------------------------------------------------------------------
+MakeNullFace creates a new face structure and initializes all of its
+flags to NULL and sets all the flags to off.  It returns a pointer
+to the empty cell.
+---------------------------------------------------------------------*/
+tFace MakeNullFace(void)
+{
+    tFace f;
+    int i;
+
+    NEW(f, tsFace);
+    for (i = 0; i < 3; ++i) {
+	f->edge[i] = NULL;
+	f->vertex[i] = NULL;
+    }
+    f->visible = !VISIBLE;
+    ADD(faces, f);
+    return f;
+}
+
+/*---------------------------------------------------------------------
+MakeFace creates a new face structure from three vertices (in ccw
+order).  It returns a pointer to the face.
+---------------------------------------------------------------------*/
+tFace MakeFace(tVertex v0, tVertex v1, tVertex v2, tFace fold)
+{
+    tFace f;
+    tEdge e0, e1, e2;
+
+    /* Create edges of the initial triangle. */
+    if (!fold) {
+	e0 = MakeNullEdge();
+	e1 = MakeNullEdge();
+	e2 = MakeNullEdge();
+    }
+    else {			/* Copy from fold, in reverse order. */
+	e0 = fold->edge[2];
+	e1 = fold->edge[1];
+	e2 = fold->edge[0];
+    }
+    e0->endpts[0] = v0;
+    e0->endpts[1] = v1;
+    e1->endpts[0] = v1;
+    e1->endpts[1] = v2;
+    e2->endpts[0] = v2;
+    e2->endpts[1] = v0;
+
+    /* Create face for triangle. */
+    f = MakeNullFace();
+    f->edge[0] = e0;
+    f->edge[1] = e1;
+    f->edge[2] = e2;
+    f->vertex[0] = v0;
+    f->vertex[1] = v1;
+    f->vertex[2] = v2;
+
+    /* Link edges to face. */
+    e0->adjface[0] = e1->adjface[0] = e2->adjface[0] = f;
+
+    return f;
+}
+
+/*---------------------------------------------------------------------
+CleanUp goes through each data structure list and clears all
+flags and NULLs out some pointers.  The order of processing
+(edges, faces, vertices) is important.
+---------------------------------------------------------------------*/
+void CleanUp(void)
+{
+    CleanEdges();
+    CleanFaces();
+    CleanVertices();
+}
+
+/*---------------------------------------------------------------------
+CleanEdges runs through the edge list and cleans up the structure.
+If there is a newface then it will put that face in place of the 
+visible face and NULL out newface. It also deletes so marked edges.
+---------------------------------------------------------------------*/
+void CleanEdges(void)
+{
+    tEdge e;			/* Primary index into edge list. */
+    tEdge t;			/* Temporary edge pointer. */
+
+    /* Integrate the newface's into the data structure. */
+    /* Check every edge. */
+    e = edges;
+    do {
+	if (e->newface) {
+	    if (e->adjface[0]->visible)
+		e->adjface[0] = e->newface;
+	    else
+		e->adjface[1] = e->newface;
+	    e->newface = NULL;
+	}
+	e = e->next;
+    } while (e != edges);
+
+    /* Delete any edges marked for deletion. */
+    while (edges && edges->delete) {
+	e = edges;
+	DELETE(edges, e);
+    }
+    e = edges->next;
+    do {
+	if (e->delete) {
+	    t = e;
+	    e = e->next;
+	    DELETE(edges, t);
+	}
+	else
+	    e = e->next;
+    } while (e != edges);
+}
+
+/*---------------------------------------------------------------------
+CleanFaces runs through the face list and deletes any face marked visible.
+---------------------------------------------------------------------*/
+void CleanFaces(void)
+{
+    tFace f;			/* Primary pointer into face list. */
+    tFace t;			/* Temporary pointer, for deleting. */
+
+
+    while (faces && faces->visible) {
+	f = faces;
+	DELETE(faces, f);
+    }
+    f = faces->next;
+    do {
+	if (f->visible) {
+	    t = f;
+	    f = f->next;
+	    DELETE(faces, t);
+	}
+	else
+	    f = f->next;
+    } while (f != faces);
+}
+
+/*---------------------------------------------------------------------
+CleanVertices runs through the vertex list and deletes the 
+vertices that are marked as processed but are not incident to any 
+undeleted edges. 
+---------------------------------------------------------------------*/
+void CleanVertices(void)
+{
+    tEdge e;
+    tVertex v, t;
+
+    /* Mark all vertices incident to some undeleted edge as on the hull. */
+    e = edges;
+    do {
+	e->endpts[0]->onhull = e->endpts[1]->onhull = ONHULL;
+	e = e->next;
+    } while (e != edges);
+
+    /* Delete all vertices that have been processed but
+       are not on the hull. */
+    while (vertices && vertices->mark && !vertices->onhull) {
+	v = vertices;
+	DELETE(vertices, v);
+    }
+    v = vertices->next;
+    do {
+	if (v->mark && !v->onhull) {
+	    t = v;
+	    v = v->next;
+	    DELETE(vertices, t)
+	}
+	else
+	    v = v->next;
+    } while (v != vertices);
+
+    /* Reset flags. */
+    v = vertices;
+    do {
+	v->duplicate = NULL;
+	v->onhull = !ONHULL;
+	v = v->next;
+    } while (v != vertices);
+}
+
+/*---------------------------------------------------------------------
+Collinear checks to see if the three points given are collinear,
+by checking to see if each element of the cross product is zero.
+---------------------------------------------------------------------*/
+bool Collinear(tVertex a, tVertex b, tVertex c)
+{
+    return
+	(c->v[Z] - a->v[Z]) * (b->v[Y] - a->v[Y]) -
+	(b->v[Z] - a->v[Z]) * (c->v[Y] - a->v[Y]) == 0
+	&& (b->v[Z] - a->v[Z]) * (c->v[X] - a->v[X]) -
+	(b->v[X] - a->v[X]) * (c->v[Z] - a->v[Z]) == 0
+	&& (b->v[X] - a->v[X]) * (c->v[Y] - a->v[Y]) -
+	(b->v[Y] - a->v[Y]) * (c->v[X] - a->v[X]) == 0;
+}
+
+/*---------------------------------------------------------------------
+Consistency runs through the edge list and checks that all
+adjacent faces have their endpoints in opposite order.  This verifies
+that the vertices are in counterclockwise order.
+---------------------------------------------------------------------*/
+void Consistency(void)
+{
+    register tEdge e;
+    register int i, j;
+
+    e = edges;
+
+    do {
+	/* find index of endpoint[0] in adjacent face[0] */
+	for (i = 0; e->adjface[0]->vertex[i] != e->endpts[0]; ++i) ;
+
+	/* find index of endpoint[0] in adjacent face[1] */
+	for (j = 0; e->adjface[1]->vertex[j] != e->endpts[0]; ++j) ;
+
+	/* check if the endpoints occur in opposite order */
+	if (!(e->adjface[0]->vertex[(i + 1) % 3] ==
+	      e->adjface[1]->vertex[(j + 2) % 3] ||
+	      e->adjface[0]->vertex[(i + 2) % 3] ==
+	      e->adjface[1]->vertex[(j + 1) % 3]))
+	    break;
+	e = e->next;
+
+    } while (e != edges);
+
+    if (e != edges)
+	fprintf(stderr, "Checks: edges are NOT consistent.\n");
+    else
+	fprintf(stderr, "Checks: edges consistent.\n");
+
+}
+
+/*---------------------------------------------------------------------
+Convexity checks that the volume between every face and every
+point is negative.  This shows that each point is inside every face
+and therefore the hull is convex.
+---------------------------------------------------------------------*/
+void Convexity(void)
+{
+    register tFace f;
+    register tVertex v;
+    long int vol;
+
+    f = faces;
+
+    do {
+	v = vertices;
+	do {
+	    if (v->mark) {
+		vol = VolumeSign(f, v);
+		if (vol < 0)
+		    break;
+	    }
+	    v = v->next;
+	} while (v != vertices);
+
+	f = f->next;
+
+    } while (f != faces);
+
+    if (f != faces)
+	fprintf(stderr, "Checks: NOT convex.\n");
+    else if (check)
+	fprintf(stderr, "Checks: convex.\n");
+}
+
+/*---------------------------------------------------------------------
+CheckEuler checks Euler's relation, as well as its implications when
+all faces are known to be triangles.  Only prints positive information
+when debug is true, but always prints negative information.
+---------------------------------------------------------------------*/
+void CheckEuler(long int V, long int E, long int F)
+{
+    if (check)
+	fprintf(stderr, "Checks: V, E, F = %li %li %li:\t", V, E, F);
+
+    if ((V - E + F) != 2)
+	fprintf(stderr, "Checks: V-E+F != 2\n");
+    else if (check)
+	fprintf(stderr, "V-E+F = 2\t");
+
+
+    if (F != (2 * V - 4))
+	fprintf(stderr, "Checks: F=%li != 2V-4=%li; V=%li\n",
+		F, 2 * V - 4, V);
+    else if (check)
+	fprintf(stderr, "F = 2V-4\t");
+
+    if ((2 * E) != (3 * F))
+	fprintf(stderr, "Checks: 2E=%li != 3F=%li; E=%li, F=%li\n",
+		2 * E, 3 * F, E, F);
+    else if (check)
+	fprintf(stderr, "2E = 3F\n");
+}
+
+/*-------------------------------------------------------------------*/
+void Checks(void)
+{
+    tVertex v;
+    tEdge e;
+    tFace f;
+    long int V = 0, E = 0, F = 0;
+
+    Consistency();
+    Convexity();
+    if (v = vertices)
+	do {
+	    if (v->mark)
+		V++;
+	    v = v->next;
+	} while (v != vertices);
+    if (e = edges)
+	do {
+	    E++;
+	    e = e->next;
+	} while (e != edges);
+    if (f = faces)
+	do {
+	    F++;
+	    f = f->next;
+	} while (f != faces);
+    CheckEuler(V, E, F);
+}
+
+
+/*===================================================================
+These functions are used whenever the debug flag is set.
+They print out the entire contents of each data structure.  
+Printing is to standard error.  To grab the output in a file in the csh, 
+use this:
+	chull < i.file >&! o.file
+=====================================================================*/
+
+/*-------------------------------------------------------------------*/
+void PrintOut(tVertex v)
+{
+    fprintf(stderr, "\nHead vertex %d = %6x :\n", v->vnum, (unsigned int)v);
+    PrintVertices();
+    PrintEdges();
+    PrintFaces();
+}
+
+/*-------------------------------------------------------------------*/
+void PrintVertices(void)
+{
+    tVertex temp;
+
+    temp = vertices;
+    fprintf(stderr, "Vertex List\n");
+    if (vertices)
+	do {
+	    fprintf(stderr, "  addr %6x\t", (unsigned int)vertices);
+	    fprintf(stderr, "  vnum %4d", vertices->vnum);
+	    fprintf(stderr, "   (%6li,%6li,%6li)", vertices->v[X],
+		    vertices->v[Y], vertices->v[Z]);
+	    fprintf(stderr, "   active:%3d", vertices->onhull);
+	    fprintf(stderr, "   dup:%5x", (unsigned int)vertices->duplicate);
+	    fprintf(stderr, "   mark:%2d\n", vertices->mark);
+	    vertices = vertices->next;
+	} while (vertices != temp);
+
+}
+
+/*-------------------------------------------------------------------*/
+void PrintEdges(void)
+{
+    tEdge temp;
+    int i;
+
+    temp = edges;
+    fprintf(stderr, "Edge List\n");
+    if (edges)
+	do {
+	    fprintf(stderr, "  addr: %6x\t", (unsigned int)edges);
+	    fprintf(stderr, "adj: ");
+	    for (i = 0; i < 2; ++i)
+		fprintf(stderr, "%6x", (unsigned int)edges->adjface[i]);
+	    fprintf(stderr, "  endpts:");
+	    for (i = 0; i < 2; ++i)
+		fprintf(stderr, "%4d", edges->endpts[i]->vnum);
+	    fprintf(stderr, "  del:%3d\n", edges->delete);
+	    edges = edges->next;
+	} while (edges != temp);
+
+}
+
+/*-------------------------------------------------------------------*/
+void PrintFaces(void)
+{
+    int i;
+    tFace temp;
+
+    temp = faces;
+    fprintf(stderr, "Face List\n");
+    if (faces)
+	do {
+	    fprintf(stderr, "  addr: %6x\t", (unsigned int)faces);
+	    fprintf(stderr, "  edges:");
+	    for (i = 0; i < 3; ++i)
+		fprintf(stderr, "%6x", (unsigned int)faces->edge[i]);
+	    fprintf(stderr, "  vert:");
+	    for (i = 0; i < 3; ++i)
+		fprintf(stderr, "%4d", faces->vertex[i]->vnum);
+	    fprintf(stderr, "  vis: %d\n", faces->visible);
+	    faces = faces->next;
+	} while (faces != temp);
+
+}

Added: grass-addons/grass7/grass7/raster/r.vol.dem/chull.h
===================================================================
--- grass-addons/grass7/grass7/raster/r.vol.dem/chull.h	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.vol.dem/chull.h	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,2 @@
+int make3DHull(long int *X, long int *Y, long int *Z, int num_points,
+	       FILE * tmpfile);

Added: grass-addons/grass7/grass7/raster/r.vol.dem/globals.h
===================================================================
--- grass-addons/grass7/grass7/raster/r.vol.dem/globals.h	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.vol.dem/globals.h	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,40 @@
+#ifndef GLOBAL_H
+#define GLOBAL_H
+
+#define PROGVERSION 0.55
+#define PROGNAME "r.vol.dem"
+
+/* if DEBUG > 1 we will dump even more details */
+#define DEBUG 0
+
+/* NULL valued cells */
+#define NULLVALUE -1
+/* masked cells */
+#define MASKVALUE -2
+/* unset cells */
+#define UNSET -3
+
+/* value to represent NULL in VTK files */
+#define DNULLVALUE -99999.99
+
+#define TMPFILE "voxeltmp.tmp"
+
+#ifdef MAIN
+/* number of decimal places with which coordinates are stored */
+double PRECISION;
+
+/* verbose output includes progress display */
+int VERBOSE;
+
+/* number of DEMs in the input */
+int NSLICES;
+
+#else
+
+extern double PRECISION;
+extern int VERBOSE;
+extern int NSLICES;
+
+#endif /* MAIN */
+
+#endif /* GLOBAL_H */

Added: grass-addons/grass7/grass7/raster/r.vol.dem/macros.h
===================================================================
--- grass-addons/grass7/grass7/raster/r.vol.dem/macros.h	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.vol.dem/macros.h	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,39 @@
+
+/*====================================================================
+    macros.h
+ 
+ 	macros used to access data structures and perform quick tests.
+
+  ====================================================================*/
+
+/* general-purpose macros */
+#define SWAP(t,x,y)	{ t = x; x = y; y = t; }
+
+#define NEW(p,type)	if ((p=(type *) malloc (sizeof(type))) == NULL) {\
+				printf ("Out of Memory!\n");\
+				exit(0);\
+			}
+
+#define FREE(p)		if (p) { free ((char *) p); p = NULL; }
+
+
+#define ADD( head, p )  if ( head )  { \
+				p->next = head; \
+				p->prev = head->prev; \
+				head->prev = p; \
+				p->prev->next = p; \
+			} \
+			else { \
+				head = p; \
+				head->next = head->prev = p; \
+			}
+
+#define DELETE( head, p ) if ( head )  { \
+				if ( head == head->next ) \
+					head = NULL;  \
+				else if ( p == head ) \
+					head = head->next; \
+				p->next->prev = p->prev;  \
+				p->prev->next = p->next;  \
+				FREE( p ); \
+			}

Added: grass-addons/grass7/grass7/raster/r.vol.dem/main.c
===================================================================
--- grass-addons/grass7/grass7/raster/r.vol.dem/main.c	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.vol.dem/main.c	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,1423 @@
+/* r.vol.dem */
+/* Purpose: Interpolate a voxel model from a series of DEMs by flood filling the voxel space in between. */
+
+
+/* TODO: 
+
+   BUG: output_ascii_points (): when option -f is given, the v.in.ascii module aborts with an error message!
+   strangely, if you copy and paste the line from the tmpfile, which is exactly the same syntax,
+   it works! (???)
+
+   - fix warnings and license issues for chull.c (provide complete copy of the original sources)
+
+   - tempfiles
+   this program leaves lots of them around right now ...
+
+   - cell counts: AVOID counting cells twice for layers that have the same label!
+
+   - USER MAN PAGE:
+
+   filling up or down does not make a difference in volume, unless -f option is also given!
+   BUT: it makes a difference in the labeling of layers: 
+   When filling down, the bottom DEM
+   is interpreted as the last boundary of a layer and is thus assigned an individual label
+   When fillin up, the top DEM
+   is interpreted as the last boundary of a layer and is thus assigned an individual label
+   Where this is undesirable, boundaries can be dissolved by giving them identical labels using the labels= option!
+
+   Visible differences in Paraview are due to rounding effects in the software. Displaying points in NVIZ will show you
+   that both data sets are the same [check if this ist true: same number of points in both cases?]
+
+   Vector hulls are currently very rough approximations with lots of shortcomings
+
+   Layers are numbered from bottom to top : 0 .. n
+
+   DEMs have to be given from bottom to top as well. Order matters!
+
+   - LICENSE ISSUES with convex hull 3D code !(?): include at least a full version of original chull.c and add some comments!
+   - also replace warinng messages (e.g. all points colinear) with own versions.
+
+   - make clean and get rid of compiler warnings
+
+   in a first pass, that can also be disabled by the user
+   - check for overlaps 
+
+   in a second pass, to be optionally enabled by user:
+   - create a 0/1 mask file for each DEM to mask
+   out interpolation for edges that are not straight
+
+   - fuzzy layer boundaries (!)
+
+   - in mode -f revert interpolation direction once at the end to make sure everything gets filled (?)!
+   - maybe as a separate option -r if it will be good for anything
+
+   - standard options for voxels (data type ...)
+
+   - automatically adjust 3D region to fit full DEM data (x,y,z)
+
+   - output a map that shows areas with topologic problems. User can overlay all DEMs and this map and query for problems. 
+   Map will contain highest ID of the DEM(s) 
+   that caused a problem here. After clearing all problems, user might have to generate another map with errors from lower ID DEMs ...
+   [DONE BUT UNTESTED]
+
+   - DNULLVALUE needs to be adjustable, also many other vars in globals.h: PRECISION, TMPFILE, ...
+
+   - EXPORTS: switch all export functions away from ASCII bridge:
+   3D vector hulls output:
+   - export 3D vector hulls into one GRASS bin file and create proper attribute table
+   - 3D vector hulls don't overlap nicely, because the points are in the voxel centers.
+   all hull points have to be extruded half a voxel size into normal direction!
+   - layers with all points on one voxel plane do not get turned into a hull currently!
+   - RRR:GGG:BBB color option for each layer    
+   voxel output:
+   - add history information
+   - a category number for each DEM (3d raster cats?)
+   - RRR:GGG:BBB color option for each layer
+
+   - surface smoothing for VTK file output
+   smoothing surfaces for VTK-output with top= and bottom= options (r3.out.vtk) smoothes all surfaces by degrees!       
+
+   - more progress indicators in export functions!  [lots done but test what it looks like]
+
+   - implement quite operation: most messages don't respect VERBOSE! [lots done, but needs testing]
+
+   - v.in.ascii now takes --o for overwrite. Since when?
+
+ */
+
+#define MAIN
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+
+#include <string.h>
+#include <math.h>
+#include <time.h>
+
+#include <grass/gis.h>
+#include <grass/raster3d.h>
+#include <grass/glocale.h>
+
+#include "chull.h"
+
+#include "globals.h"
+
+/* ================================================================================
+
+   GLOBAL DECLARATIONS
+
+   =================================================================================== */
+
+
+/* by making this global, all func's will have access to module options and flags */
+struct
+{
+    struct Option *maps;	/* raster DEM(s) to work on */
+    struct Option *output;	/* output rast3d map */
+    struct Option *values;	/* specify the value that each layer represents */
+    struct Option *colors;	/* RRR:GGG:BBB triplets for each layer */
+    struct Option *error;	/* raster map to represent topology errors in input DEMs */
+    struct Option *algorithm;	/* choose interpolation algorithm */
+}
+parm;
+struct
+{
+    struct Flag *countcells;	/* calculate 3D cell stats for each layer */
+    struct Flag *fillnull;	/* fill NULL areas in input DEMs from above or below */
+    struct Flag *hull;		/* export a 3D hull polygon for every layer */
+    struct Flag *grasspts;	/* produce a GRASS points vector file */
+    struct Flag *points;	/* produce VTK point data instead of cells */
+    struct Flag *quiet;		/* no status display on screen */
+    struct Flag *skip;		/* start interpolation even if topology errors were detected */
+    struct Flag *vtk;		/* generate a VTK file */
+    struct Flag *zadjust;	/* adjust z range of current region to fit DEM data */
+}
+flag;
+
+
+
+/* ================================================================================
+
+   UTILITY FUNCTIONS
+
+   =================================================================================== */
+
+/* returns 1 if the integer is a DEM ID, not a MASKED or NULL value or UNSET,
+   0 otherwise */
+int isValue(int val)
+{
+    if (val == UNSET) {
+	return (0);
+    }
+    if (val == NULLVALUE) {
+	return (0);
+    }
+    if (val == MASKVALUE) {
+	return (0);
+    }
+    return (1);
+}
+
+int isUnset(int val)
+{
+    if (val == UNSET) {
+	return (1);
+    }
+    return (0);
+}
+
+int isMask(int val)
+{
+    if (val == MASKVALUE) {
+	return (1);
+    }
+    return (0);
+}
+
+int isNull(int val)
+{
+    if (val == NULLVALUE) {
+	return (1);
+    }
+    return (0);
+}
+
+
+/* returns 1 if the string contains a valid RRR:GGG:BBB color triplet,
+   0 otherwise 
+
+   IF the string is valid, the R, G and B levels (0-255) will be
+   stored at the int pointers (NULL otherwise)   
+ */
+
+int isRGB(char *triplet, unsigned short int *R, unsigned short int *G,
+	  unsigned short int *B)
+{
+    R = NULL;
+    G = NULL;
+    B = NULL;
+    return (0);
+}
+
+
+/* ================================================================================
+
+   Z-RANGE AND TOPOLOGY CHECKING
+
+   =================================================================================== */
+
+
+/* checks if a DEM value intersects a voxel at a given depth */
+/* depth goes from 0 (bottom voxel) to slices-1 (top voxel) */
+/* returns 1 if DEM intersects, 0 if not */
+
+/* if a DEM intersects the top surface of a voxel, that counts as */
+/* a cut, the bottom does not. */
+int cut(DCELL val, int depth, struct Cell_head window)
+{
+    if (DEBUG > 2) {
+	fprintf(stdout, "CUT: %.3f at depth %i", (double)val, depth);
+    }
+    if ((val > (window.bottom + depth * window.tb_res)) &&
+	(val < (window.bottom + (depth + 1) * window.tb_res))) {
+	if (DEBUG > 2) {
+	    fprintf(stdout, " = YES\n");
+	}
+	return (1);
+    }
+    if (val == window.bottom + (depth + 1) * window.tb_res) {
+	if (DEBUG > 1) {
+	    fprintf(stdout, " = YES\n");
+	}
+	return (1);
+    }
+    if (DEBUG > 2) {
+	fprintf(stdout, " = NO\n");
+    }
+    return (0);
+}
+
+
+/* Adjust the ACTIVE region's Z range so that it will be big enough for the
+   highest and lowest point in the input DEMs.
+   This setting will stay in effect even after r.vol.dem exits!
+ */
+void adjust_zrange(void)
+{
+    fprintf(stderr, "DEBUG: Adjustment of Z range not implemented yet.\n");
+    return;
+}
+
+
+/* check if DEMs are within z-range of current 3d region */
+void check_zrange(int *fd, DCELL ** dcell, int nfiles)
+{
+
+    struct Cell_head window;
+
+    int i;
+    int row, col, nrows, ncols;
+
+    double top, bottom;
+    int topDEM, bottomDEM;
+
+    nrows = Rast_window_rows();
+    ncols = Rast_window_cols();
+
+    G_get_window(&window);
+
+    if (flag.zadjust->answer) {
+	adjust_zrange();
+	fprintf(stderr, "DEBUG: Insert a return() statement here.\n");
+    }
+
+    if (VERBOSE)
+	fprintf(stdout, " Z-range checking, pass 1: \n");
+
+    /* get maximum and minimum elevation from all DEMs */
+    row = 0;
+    Rast_get_d_row(fd[0], dcell[0], row);
+    top = dcell[0][0];
+    topDEM = 0;
+    for (i = 0; i < nfiles; i++) {
+	for (row = 0; row < nrows; row++) {
+	    Rast_get_d_row(fd[i], dcell[i], row);
+	    for (col = 0; col < ncols; col++) {
+		if (dcell[i][col] > top) {
+		    top = dcell[i][col];
+		    topDEM = i;
+		}
+	    }
+	}
+
+	G_percent(i, (nfiles - 1), 1);
+    }
+    fflush(stdout);
+    if (DEBUG)
+	fprintf(stdout, "TOP = %.2f in %s\n", top,
+		parm.maps->answers[topDEM]);
+
+    if (VERBOSE)
+	fprintf(stdout, " z-range-checking, pass 2: \n");
+
+    row = 0;
+    Rast_get_d_row(fd[0], dcell[0], row);
+    bottom = dcell[0][0];
+    bottomDEM = 0;
+    for (i = 0; i < nfiles; i++) {
+	for (row = 0; row < nrows; row++) {
+	    Rast_get_d_row(fd[i], dcell[i], row);
+	    for (col = 0; col < ncols; col++) {
+		if (dcell[i][col] < bottom) {
+		    bottom = dcell[i][col];
+		    bottomDEM = i;
+		}
+	    }
+	}
+	G_percent(i, (nfiles - 1), 1);
+    }
+    fflush(stdout);
+    if (DEBUG)
+	fprintf(stdout, "BOTTOM = %.2f in %s\n", bottom,
+		parm.maps->answers[bottomDEM]);
+
+    if (top > window.top) {
+	G_fatal_error(_("Highest DEM value (%.3f in %s) outside extent of current 3d region (top=%.3f) "),
+		      top, parm.maps->answers[topDEM], window.top);
+    }
+
+    if (bottom < window.bottom) {
+	G_fatal_error(_("Lowest DEM value (%.3f in %s) outside extent of current 3d region (bottom=%.3f) "),
+		      bottom, parm.maps->answers[bottomDEM], window.bottom);
+    }
+
+    return;
+}
+
+
+void check_topologies(int *fd, DCELL ** dcell, int nfiles)
+{
+
+    int i, j;
+    struct Cell_head window;
+    int row, col, nrows, ncols;
+    int nerrors;
+
+    CELL **c_error = NULL;
+    int f_error = 0;
+
+    if (VERBOSE)
+	fprintf(stdout, " Checking DEM topologies: \n");
+
+    nerrors = 0;
+
+    Rast_get_window(&window);
+    nrows = Rast_window_rows();
+    ncols = Rast_window_cols();
+
+    /* does the user want a topology error map? */
+    /* if so, we need to alloc mem and create a new CELL map */
+    if (parm.error->answer != NULL) {
+
+	/* KILL ME */
+	fprintf(stderr,
+		"DEBUG: Topology error mapping is an untested feature.\n");
+	/* KILL ME */
+
+	c_error = (CELL **) G_malloc(nrows * sizeof(CELL *));
+	for (row = 0; row < nrows; row++) {
+	    c_error[row] = Rast_allocate_c_buf();
+	}
+	f_error = Rast_open_new(parm.error->answer, CELL_TYPE);
+	if (f_error < 0) {
+	    G_fatal_error
+		("Could not create new CELL raster map for mapping topology errors.");
+	}
+	/* initialise error map */
+	for (row = 0; row < nrows; row++) {
+	    Rast_set_c_null_value(&c_error[row][0], ncols);
+	}
+    }
+
+    for (row = 0; row < nrows; row++) {
+	for (i = 0; i < nfiles; i++) {
+	    Rast_get_d_row(fd[i], dcell[i], row);
+	}
+	for (col = 0; col < ncols; col++) {
+	    for (i = 0; i < nfiles; i++) {
+		/* check for undershoots from DEMs above */
+		for (j = i + 1; j < nfiles; j++) {
+		    if (dcell[j][col] <= dcell[i][col]) {
+			/* UNDERSHOOT */
+
+			G_warning(_("Z value in %s undershoots Z value in %s at cells %i,%i, \ncoordinates: E=%f, N=%f.\n"),
+				  parm.maps->answers[j],
+				  parm.maps->answers[i], col, row,
+				  Rast_col_to_easting((double)col, &window),
+				  Rast_row_to_northing((double)row, &window)
+			    );
+			nerrors++;
+			if (parm.error->answer != NULL) {
+			    c_error[row][col] = j;
+			}
+		    }
+		}
+		/* check for overshoots from DEMs below */
+		for (j = i - 1; j >= 0; j--) {
+		    if (dcell[j][col] >= dcell[i][col]) {
+			/* OVERSHOOT! */
+			G_warning(_("Z value in %s overshoots Z value in %s at cells %i,%i, \ncoordinates: E=%f, N=%f.\n"),
+				  parm.maps->answers[j],
+				  parm.maps->answers[i], col, row,
+				  Rast_col_to_easting((double)col, &window),
+				  Rast_row_to_northing((double)row, &window)
+			    );
+
+			nerrors++;
+			if (parm.error->answer != NULL) {
+			    c_error[row][col] = j;
+			}
+		    }
+		}
+	    }
+	}
+
+	if (VERBOSE)
+	    G_percent(row, (nrows - 1), 2);
+    }
+    fflush(stdout);
+    if (parm.error->answer != NULL) {
+	for (row = 0; row < nrows; row++) {
+	    Rast_put_c_row(f_error, c_error[row]);
+	}
+	Rast_close(f_error);
+    }
+    if (nerrors > 0) {
+	G_fatal_error(_("Found %i errors in DEM topology! Aborting."),
+		      nerrors);
+    }
+
+    return;
+}
+
+
+
+/* ================================================================================
+
+   CORE INTERPOLATION ROUTINES
+
+   =================================================================================== */
+
+
+void interpolate_up(int *flist, DCELL ** dcell, int col, int nfiles)
+{
+
+    struct Cell_head window;
+    int fillval;
+    double level;
+    double stopat;
+    int i, j, k;
+    int DEMAbove;
+    int highestDEMValue;
+
+    Rast_get_window(&window);
+
+    /* DEMs must be provided in this order: bottom,...,top ... */
+    for (i = 0; i < NSLICES; i++) {
+	/* ... the interpolated column, however, has its lowest value */
+	/* at the bottom (last element of array), so that order needs to be switched! */
+	flist[(NSLICES - 1) - i] = NULLVALUE;	/* NULLVALUE = no DEM cuts at this point */
+	for (j = 0; j < nfiles; j++) {
+	    if (!Rast_is_d_null_value(&dcell[j][col])) {	/* SKIP NULL VALUED CELLS */
+		if (cut(dcell[j][col], i, window)) {
+		    flist[(NSLICES - 1) - i] = j;
+		}
+	    }
+	}
+    }
+
+    /* interpolate one column by 'flood filling' DEM values up from the bottom */
+    fillval = flist[0];
+
+    /* first we need to know where to stop the interpolation ! */
+
+    /* find the highest DEM that has a data value at this point! */
+    highestDEMValue = -1;
+    i = (nfiles - 1);
+    while ((i >= 0) && (highestDEMValue == -1)) {
+	if (!Rast_is_d_null_value(&dcell[i][col])) {
+	    highestDEMValue = i;
+	}
+	i--;
+    }
+    i++;
+
+    if (highestDEMValue == -1) {
+	/* there is no DEM with any data at this point ! */
+	stopat = window.bottom - 1;	/* this will prevent any interpolation from happening here ! */
+    }
+    else {
+	/* we found a DEM with a value ... */
+	if (highestDEMValue == (nfiles - 1)) {
+	    /* ... and it is the top one, so we just set this as interpolation stop */
+	    stopat = dcell[(nfiles - 1)][col];
+	}
+	else {
+	    /* ... but it is not the top one, so we need to decide what to do */
+	    if (flag.fillnull->answer) {
+		/* this flag forces us to keep filling (all the way up to the top of the current 3D region) */
+		stopat = window.top;
+	    }
+	    else {
+		/* we will only fill up to the highest DEM with a value */
+		/* but we make sure to fill up at least one slice ! */
+		stopat =
+		    dcell[highestDEMValue][col] + (window.tb_res +
+						   (window.tb_res * 0.5));
+	    }
+	}
+    }
+
+    if (DEBUG > 1) {
+	fprintf(stderr, "  STOPAT = %.2f\n", stopat);
+    }
+
+    for (i = (NSLICES - 1); i >= 0; i--) {
+	if (isValue(flist[i])) {
+	    /* check, if there is another DEM cutting point above this slice */
+	    /* if not, only keep filling, if flag -f has been set ! */
+	    if (flag.fillnull->answer) {
+		fillval = flist[i];
+	    }
+	    else {
+		DEMAbove = 0;
+		for (k = i; k >= 0; k--) {
+		    if (isValue(flist[k])) {
+			DEMAbove = 1;
+		    }
+		}
+		if (DEMAbove) {
+		    fillval = flist[i];
+		}
+	    }
+	}
+	else {
+	    /* check if we are still below top level */
+	    level = window.bottom + (((NSLICES - 1) - i) * window.tb_res);
+	    if (level < stopat) {
+		flist[i] = fillval;
+	    }
+	    else {
+		flist[i] = NULLVALUE;
+	    }
+	}
+    }
+
+    return;
+
+}
+
+
+void interpolate_down(int *flist, DCELL ** dcell, int col, int nfiles)
+{
+
+    struct Cell_head window;
+    int fillval;
+    double level;
+    double stopat = 0.0;
+    int i, j, k;
+    int DEMBelow;
+    int lowestDEMValue;
+
+    Rast_get_window(&window);
+
+    /* DEMs must be provided in this order: bottom,...,top ... */
+    for (i = 0; i < NSLICES; i++) {
+	/* ... the interpolated column, however, has its lowest value */
+	/* at the bottom, so that order needs to be switched! */
+	flist[(NSLICES - 1) - i] = NULLVALUE;	/* NULLVALUE = no DEM cuts at this point */
+	for (j = 0; j < nfiles; j++) {
+	    if (!Rast_is_d_null_value(&dcell[j][col])) {	/* SKIP NULL VALUED CELLS */
+		if (cut(dcell[j][col], i, window)) {
+		    flist[(NSLICES - 1) - i] = j;
+		}
+	    }
+	}
+    }
+
+    /* interpolate one column by 'flood filling' DEM values down from the top */
+    fillval = flist[0];
+
+    /* first we need to know where to stop the interpolation ! */
+
+    /* find the lowest DEM that has a data value at this point! */
+    lowestDEMValue = -1;
+    i = 0;
+    while ((i < nfiles) && (lowestDEMValue == -1)) {
+	if (!Rast_is_d_null_value(&dcell[i][col])) {
+	    lowestDEMValue = i;
+	}
+	i++;
+    }
+    i--;
+
+    if (lowestDEMValue == -1) {
+	/* there is no DEM with any data at this point ! */
+	stopat = window.top + 1;	/* this will prevent any interpolation from happening here ! */
+    }
+    else {
+	/* we found a DEM with a value ... */
+	if (lowestDEMValue == 0) {
+	    /* ... and it is the bottom one, so we just set this as interpolation stop */
+	    stopat = dcell[0][col];
+	}
+	else {
+	    /* ... but it is not the bottom one, so we need to decide what to do */
+	    if (flag.fillnull->answer) {
+		/* this flag forces us to keep filling (all the way down to the bottom of the current 3D region) */
+		stopat = window.bottom;
+	    }
+	    else {
+		/* we will only fill down to the lowest DEM with a value */
+		/* but we make sure to fill down at least one slice ! */
+		stopat =
+		    dcell[lowestDEMValue][col] - (window.tb_res +
+						  (window.tb_res * 0.5));
+	    }
+	}
+    }
+
+    if (DEBUG > 1) {
+	fprintf(stderr, "  STOPAT = %.2f\n", stopat);
+    }
+
+    for (i = 1; i < NSLICES; i++) {
+	if (isValue(flist[i])) {
+	    /* check, if there is another DEM cutting point below this slice */
+	    /* if not, only keep filling, if flag -f has been set ! */
+	    if (flag.fillnull->answer) {
+		fillval = flist[i];
+	    }
+	    else {
+		DEMBelow = 0;
+		for (k = i; k <= NSLICES; k++) {
+		    if (isValue(flist[k])) {
+			DEMBelow = 1;
+		    }
+		}
+		if (DEMBelow) {
+		    fillval = flist[i];
+		}
+	    }
+	}
+	else {
+	    /* check if we are still above bottom level */
+	    level = window.bottom + (((NSLICES - 1) - i) * window.tb_res);
+	    if (level >= stopat) {
+		flist[i] = fillval;
+	    }
+	    else {
+		flist[i] = NULLVALUE;
+	    }
+	}
+    }
+
+    return;
+}
+
+
+void interpolate(int *fd, DCELL ** dcell, int nfiles, int nvalues,
+		 double ***ascii)
+{
+
+    struct Cell_head window;
+
+    int *flist;
+
+    int i;
+    int row, col, nrows, ncols;
+
+    Rast_get_window(&window);
+
+    nrows = Rast_window_rows();
+    ncols = Rast_window_cols();
+
+    flist = G_malloc(sizeof(int) * NSLICES);
+
+    if (VERBOSE)
+	fprintf(stdout, "\nInterpolating: \n");
+
+    for (row = 0; row < nrows; row++) {
+	/* read one row from all layers */
+	for (i = 0; i < nfiles; i++) {
+	    Rast_get_d_row(fd[i], dcell[i], row);
+	}
+	for (col = 0; col < ncols; col++) {
+
+	    if (!strcmp(parm.algorithm->answer, "up")) {
+		interpolate_up(flist, dcell, col, nfiles);
+	    }
+	    if (!strcmp(parm.algorithm->answer, "down")) {
+		interpolate_down(flist, dcell, col, nfiles);
+	    }
+
+	    for (i = 1; i < NSLICES; i++) {
+		if (isValue(flist[i])) {
+		    if (nvalues == 0) {
+			/* either enumerate layers from 0 .. n */
+			ascii[i][row][col] = (double)(flist[i]);
+		    }
+		    else {
+			/* OR write user-provided values for layers? */
+			ascii[i][row][col] =
+			    atof(parm.values->answers[flist[i]]);
+		    }
+		}
+		else {
+		    /* write a NULL valued voxel */
+		    ascii[i][row][col] = DNULLVALUE;
+		}
+	    }
+	    if (DEBUG > 1) {
+		fprintf(stdout, "col %i (", col);
+		for (i = 0; i < NSLICES; i++) {
+		    if (isValue(flist[i])) {
+			fprintf(stdout, "%i ", flist[i]);
+		    }
+		    if (isNull(flist[i])) {
+			fprintf(stdout, "N ");
+		    }
+		    if (isMask(flist[i])) {
+			fprintf(stdout, "M ");
+		    }
+		}
+		fprintf(stdout, ")\n");
+	    }
+	}
+
+	if (VERBOSE) {
+	    G_percent(row, nrows - 1, 2);
+	}
+	if (DEBUG > 1)
+	    fprintf(stdout, "row=%i\n", row);
+    }
+    fprintf(stdout, "\n");
+    fflush(stdout);
+}
+
+
+/* ================================================================================
+
+   DATA OUTPUT AND EXPORT
+
+   =================================================================================== */
+
+void count_3d_cells(double ***ascii, int nfiles, int nvalues)
+{
+    struct Cell_head window;
+    int a, i, j, k;
+    unsigned long int sum;
+    int nrows, ncols;
+
+    Rast_get_window(&window);
+    nrows = Rast_window_rows();
+    ncols = Rast_window_cols();
+
+    fprintf(stdout, "\nCell counts: \n");
+
+    for (a = 0; a < nfiles; a++) {
+	sum = 0;
+	for (i = 0; i < NSLICES; i++) {
+	    for (j = 0; j < nrows; j++) {
+		for (k = 0; k < ncols; k++) {
+		    if (nvalues == 0) {
+			if (a == (int)ascii[i][j][k]) {
+			    sum++;
+			}
+		    }
+		    else {
+			if (atof(parm.values->answers[a]) == ascii[i][j][k]) {
+			    sum++;
+			}
+		    }
+		}
+	    }
+	}
+	if (nvalues == 0) {
+	    fprintf(stdout, "  Layer %i has %li 3D cells\n", a, sum);
+	}
+	else {
+	    fprintf(stdout, "  Layer %i (label=%f) has %li 3D cells\n", a,
+		    atof(parm.values->answers[a]), sum);
+	}
+    }
+}
+
+
+void output_ascii(double ***ascii)
+{
+
+    struct Cell_head window;
+    int i, j, k;
+    int nrows, ncols;
+    FILE *tmpfile;
+
+
+    Rast_get_window(&window);
+    nrows = Rast_window_rows();
+    ncols = Rast_window_cols();
+
+    /* open a tmp file for writing ascii output data */
+    tmpfile = fopen(TMPFILE, "w+");
+    if (tmpfile == NULL) {
+	G_fatal_error(_("Could not create temporary file for writing ASCII output (%s)"),
+		      TMPFILE);
+    }
+    /* write output to ASCII file */
+    fprintf(tmpfile, "north: %f\n", window.north);
+    fprintf(tmpfile, "south: %f\n", window.south);
+    fprintf(tmpfile, "east: %f\n", window.east);
+    fprintf(tmpfile, "west: %f\n", window.west);
+    fprintf(tmpfile, "top: %f\n", window.top);
+    fprintf(tmpfile, "bottom: %f\n", window.bottom);
+    fprintf(tmpfile, "rows: %i\n", nrows);
+    fprintf(tmpfile, "cols: %i\n", ncols);
+    fprintf(tmpfile, "levels:%i\n", NSLICES);
+    for (i = 0; i < NSLICES; i++) {
+	for (j = 0; j < nrows; j++) {
+	    for (k = 0; k < ncols; k++) {
+		/* below is the correct data order for Paraview and GRASS rast3d ASCII files ! */
+		fprintf(tmpfile, "%f ",
+			ascii[(NSLICES - 1) - i][(nrows - 1) - j][k]);
+	    }
+	    fprintf(tmpfile, "\n");
+	}
+    }
+    fclose(tmpfile);
+}
+
+
+void output_ascii_points(double ***ascii)
+{
+
+    struct Cell_head window;
+    int i, j, k;
+    int nrows, ncols;
+    FILE *tmpfile;
+    char tmp[2048];
+    double x, y, z, w;
+    int error;
+
+
+    Rast_get_window(&window);
+    nrows = Rast_window_rows();
+    ncols = Rast_window_cols();
+
+    /* open a tmp file for writing ascii output data */
+    sprintf(tmp, "%s.points.txt", parm.output->answer);
+    tmpfile = fopen(tmp, "w+");
+    if (tmpfile == NULL) {
+	G_fatal_error(_("Could not create temporary file for writing ASCII output (%s)"),
+		      tmp);
+    }
+
+    fprintf(tmpfile, "# Simple 3D vector points file.\n");
+    fprintf(tmpfile, "# This file was created by %s version %.2f \n",
+	    PROGNAME, PROGVERSION);
+    fprintf(tmpfile, "# Tab delimited point data: x, y, z, value. \n");
+    fprintf(tmpfile, "# Import into GRASS GIS using this command:\n");
+    fprintf(tmpfile,
+	    "#   v.in.ascii in=%s.points.txt out=%s -z x=1 y=2 z=3 cat=0 columns='x double, y double, z double, w double' fs=tab\n",
+	    parm.output->answer, parm.output->answer);
+
+    /* write output to ASCII file */
+    for (i = 0; i < NSLICES; i++) {
+	for (j = 0; j < nrows; j++) {
+	    for (k = 0; k < ncols; k++) {
+		/* coordinates for points will be centers of 3D raster cells ! */
+		/* only produce points at non-NULL locations ! */
+		w = ascii[i][(nrows - 1) - j][k];
+		if (w != DNULLVALUE) {
+		    x = window.west + (window.ew_res * k) +
+			(window.ew_res * 0.5);
+		    y = window.south + (window.ns_res * j) +
+			(window.ns_res * 0.5);
+		    z = window.top - (window.tb_res * i) -
+			(window.tb_res * 0.5);
+		    fprintf(tmpfile, "%.6f\t%.6f\t%.6f\t%.6f\n", x, y, z, w);
+		}
+	    }
+	}
+    }
+
+    if (VERBOSE) {
+	fprintf(stdout, "\nRunning v.in.ascii to create 3D points map: \n");
+    }
+
+    /* TODO: KILL THIS AND REPLACE WITH NEAT --o OPTION CHECK */
+    /* remove output map, if exists */
+    sprintf(tmp, "g.remove vect=%s", parm.output->answer);
+    error = system(tmp);
+    if (error != EXIT_SUCCESS) {
+	G_fatal_error("Error running command: %s", tmp);
+    }
+
+    /* call v.in.ascii to make GRASS native vector map */
+    sprintf(tmp,
+	    "v.in.ascii in=%s.points.txt out=%s -z x=1 y=2 z=3 cat=0 columns='x double, y double, z double, w double' fs=tab\n",
+	    parm.output->answer, parm.output->answer);
+
+    error = system(tmp);
+    if (error != EXIT_SUCCESS) {
+	G_fatal_error("Error running command: %s", tmp);
+    }
+
+    if (VERBOSE)
+	fprintf(stdout, " DONE \n");
+
+    fclose(tmpfile);
+}
+
+
+void output_ascii_hulls(double ***ascii, int nvalues, int nfiles)
+{
+
+    struct Cell_head window;
+    int i, j, k, l;
+    double label;
+    int num_points;
+    int nrows, ncols;
+    FILE *tmpfile;
+    char tmp[2048];
+    double w;
+    long int *px;
+    long int *py;
+    long int *pz;
+    int curPoint;
+
+    int error;
+
+    Rast_get_window(&window);
+    nrows = Rast_window_rows();
+    ncols = Rast_window_cols();
+
+
+    /* MAIN LOOP START */
+    /* do this vor every layer, i.e. all 3D cells with the same label */
+    for (l = 0; l < nfiles; l++) {
+
+	/* open tmp file for writing ascii output data */
+	sprintf(tmp, "%s.hull.%i.txt", parm.output->answer, l);
+	tmpfile = fopen(tmp, "w+");
+	if (tmpfile == NULL) {
+	    G_fatal_error(_("Could not create temporary file for writing ASCII output (%s)"),
+			  tmp);
+	}
+
+	if (nvalues == 0) {
+	    /* either enumerate layers from 0 .. (nfiles-1) */
+	    label = (double)l;
+	}
+	else {
+	    /* OR use user-provided values for layers? */
+	    label = atof(parm.values->answers[l]);
+	}
+
+	num_points = 0;
+	/* create arrays large enough to store all points of the current layer */
+	for (i = 0; i < NSLICES; i++) {
+	    for (j = 0; j < nrows; j++) {
+		for (k = 0; k < ncols; k++) {
+		    w = ascii[i][j][k];
+		    if (w == label) {
+			num_points++;
+		    }
+		}
+	    }
+	}
+
+	if (DEBUG) {
+	    fprintf(stderr, "EXPORT HULLS: %i points with label %.6f\n",
+		    num_points, label);
+	}
+
+	px = (long int *)malloc(num_points * sizeof(long int));
+	py = (long int *)malloc(num_points * sizeof(long int));
+	pz = (long int *)malloc(num_points * sizeof(long int));
+
+	/* pick points with current label from ASCII array */
+
+	curPoint = 0;
+	for (i = 0; i < NSLICES; i++) {
+	    for (j = 0; j < nrows; j++) {
+		for (k = 0; k < ncols; k++) {
+		    /* coordinates for points will be centers of 3D raster cells ! */
+		    /* only produce points at non-NULL locations ! */
+		    /* we have to store them as int values for performance reasons, so we will multiply by PRECISION */
+		    /* PRECISION = 1000 = 10^3 = 3 decimal places precision! */
+		    w = ascii[i][(nrows - 1) - j][k];
+		    if (w == label) {
+			px[curPoint] =
+			    ((long int)window.west + (window.ew_res * k)
+			     + (window.ew_res * 0.5)) * (PRECISION);
+			py[curPoint] =
+			    ((long int)window.south + (window.ns_res * j)
+			     + (window.ns_res * 0.5)) * (PRECISION);
+			pz[curPoint] =
+			    ((long int)window.top - (window.tb_res * i)
+			     - (window.tb_res * 0.5)) * (PRECISION);
+			curPoint++;
+		    }
+		}
+	    }
+	}
+
+	if (VERBOSE) {
+	    fprintf(stdout, "\nExporting 3D convex hull for layer %i: \n", l);
+	}
+	/* make 3D hull */
+	error = make3DHull(px, py, pz, num_points, tmpfile);
+
+	if (error < 0) {
+
+	    fprintf(stdout,
+		    "DEBUG: Simple planar hulls not implemented yet.\n");
+	    fprintf(stdout, "DEBUG: This layer will not be exported.\n");
+
+	    /* all points in the same voxel plane. Let's output a very simple hull with 8 vertices */
+
+	    /* ONCE THIS IS IMPLEMENTED: call v.in.ascii for these hulls, too! */
+
+	    if (l == 0) {
+		/* this is the bottom DEM: we will extend it half a slice (tbres) down */
+		fprintf(tmpfile,
+			"DEBUG: Simple planar hulls not implemented yet.\n");
+		fprintf(tmpfile, "DEBUG: This layer was not exported.\n");
+	    }
+	    else {
+		if (l == (nfiles - 1)) {
+		    /* this is the top DEM: we will extend it half a slice (tbres) up */
+		    fprintf(tmpfile,
+			    "DEBUG: Simple planar hulls not implemented yet.\n");
+		    fprintf(stdout, "DEBUG: This layer was not exported.\n");
+		}
+		else {
+		    /* this DEM is somewhare in between, its vector representation will be planar! */
+		    fprintf(tmpfile,
+			    "DEBUG: Simple planar hulls not implemented yet.\n");
+		    fprintf(stdout, "DEBUG: This layer was not exported.\n");
+		}
+	    }
+	}
+
+	/* free memory for points */
+	free(px);
+	free(py);
+	free(pz);
+
+	fclose(tmpfile);
+
+	/* call v.in.ascii to create a native GRASS vector map */
+	/* DEBUG: remove once planar hulls are implemented */
+	if (error > -1) {
+	    if (VERBOSE) {
+		fprintf(stdout,
+			"\nRunning v.in.ascii to create 3D points map: \n");
+	    }
+	    sprintf(tmp,
+		    "v.in.ascii -z in=%s.hull.%i.txt out=%s_hull_%i form=standard",
+		    parm.output->answer, l, parm.output->answer, l);
+
+	    error = system(tmp);
+	    if (error != EXIT_SUCCESS) {
+		G_fatal_error("Error running command: %s", tmp);
+	    }
+
+	    if (VERBOSE)
+		fprintf(stdout, " DONE \n");
+	}
+    }
+    /* MAIN LOOP END */
+}
+
+
+
+void output_vtk()
+{
+
+    char sys[2048];
+    int error;
+
+    if (flag.vtk->answer) {
+
+	/* write a VTK file for visualisation in paraview etc. */
+	if (VERBOSE)
+	    fprintf(stdout, "\nCreating VTK file (%s.vtk): \n",
+		    parm.output->answer);
+
+	if (flag.points->answer) {
+	    sprintf(sys, "r3.out.vtk -p in=%s out=%s.vtk null=%f dp=3",
+		    parm.output->answer, parm.output->answer, DNULLVALUE);
+
+	}
+	else {
+	    sprintf(sys, "r3.out.vtk in=%s out=%s.vtk null=%f dp=3",
+		    parm.output->answer, parm.output->answer, DNULLVALUE);
+	}
+	if (DEBUG > 0) {
+	    fprintf(stdout, "%s\n", sys);
+	}
+	error = system(sys);
+	if (error != 0) {
+	    G_fatal_error("Error running command: %s", sys);
+	}
+
+    }
+}
+
+
+/* ================================================================================
+
+   MAIN
+
+   =================================================================================== */
+
+
+int main(int argc, char *argv[])
+{
+    struct GModule *module;
+
+    struct Cell_head window;
+
+    int i, j, k;
+    int nrows, ncols;
+
+    int *fd;
+    int nfiles, nvalues, ncolors;
+    double dslices;
+    char *name, *mapset;
+    DCELL **dcell;
+
+    double ***ascii;		/* 3D array that holds values to print into ASCII file */
+
+    unsigned short int *R;
+    unsigned short int *G;
+    unsigned short int *B;
+
+    char sys[2048];
+
+    module = G_define_module();
+    G_add_keyword(_("raster"));
+    G_add_keyword(_("volume"));
+    G_add_keyword(_("conversion"));
+    module->description =
+	"Creates a 3D raster model (voxels) from a series of raster DEMs";
+
+    /* DEFINE OPTIONS AND FLAGS */
+    /* input raster map */
+    parm.maps = G_define_standard_option(G_OPT_R_MAPS);
+    parm.maps->key = "input";
+    parm.maps->description =
+	"Input DEMs (at least 2) in raster format. Bottom DEM first";
+    parm.maps->multiple = YES;
+
+    /* Output map name */
+    parm.output = G_define_standard_option(G_OPT_R3_OUTPUT);
+
+    /* optional: specify a value for each layer */
+    parm.values = G_define_option();
+    parm.values->key = "labels";
+    parm.values->type = TYPE_DOUBLE;
+    parm.values->required = NO;
+    parm.values->description = "List of label values, one for each 3D layer";
+
+    /* optional: specify an RRR:GGG:BBB color triplet for each layer */
+    parm.colors = G_define_option();
+    parm.colors->key = "colors";
+    parm.colors->type = TYPE_STRING;
+    parm.colors->required = NO;
+    parm.colors->description =
+	"List of RRR:GGG:BBB color triplets, one for each layer";
+
+    /* optional: Raster map to represent topology errors in input DEMs */
+    parm.error = G_define_standard_option(G_OPT_R_OUTPUT);
+    parm.error->key = "errormap";
+    parm.error->required = NO;
+    parm.error->description =
+	"Raster map to represent topology errors in input DEMs";
+
+    /* algorithm to use for flood filling */
+    parm.algorithm = G_define_option();
+    parm.algorithm->key = "algorithm";
+    parm.algorithm->type = TYPE_STRING;
+    parm.algorithm->required = NO;
+    parm.algorithm->options = "up,down";
+    parm.algorithm->answer = "up";
+    parm.algorithm->description = "3D flood fill algorithm to use";
+
+    /* 3D cell stats? */
+    flag.countcells = G_define_flag();
+    flag.countcells->key = 'c';
+    flag.countcells->description = "Calculate 3D cell counts for each layer.";
+
+    /* VTK point data output ? */
+    flag.fillnull = G_define_flag();
+    flag.fillnull->key = 'f';
+    flag.fillnull->description = "Fill through NULL value areas in DEMs";
+
+    /* export a 3D hull polygon for every layer ? */
+
+/** Suffers from severe memory leak! MN 4/2012
+    flag.hull = G_define_flag();
+    flag.hull->key = 'h';
+    flag.hull->description = "Export convex hull polygons for layers";
+**/
+
+    /* GRASS ASCII vector point data output ? */
+    flag.grasspts = G_define_flag();
+    flag.grasspts->key = 'g';
+    flag.grasspts->description = "Export voxel model as vector points";
+
+    /* VTK point data output ? */
+    flag.points = G_define_flag();
+    flag.points->key = 'p';
+    flag.points->description = "Export VTK point data instead of cell data";
+
+    /* quiet operation? */
+    flag.quiet = G_define_flag();
+    flag.quiet->key = 'q';
+    flag.quiet->description = "Disable on-screen progress display";
+
+    /* skip DEM topology checks? */
+    flag.skip = G_define_flag();
+    flag.skip->key = 's';
+    flag.skip->description = "Skip topology error checking";
+
+    /* generate a VTK file? */
+    flag.vtk = G_define_flag();
+    flag.vtk->key = 'v';
+    flag.vtk->description =
+	"Generate a .vtk file for visualisation with e.g. paraview";
+
+    /* adjust Z-region settings to fit DEM values? */
+    flag.zadjust = G_define_flag();
+    flag.zadjust->key = 'z';
+    flag.zadjust->description = "Fit active region's Z range to input DEMs";
+
+    int error;
+
+
+    /* INIT GLOBAL VARIABLES */
+    VERBOSE = 1;
+    NSLICES = 0;
+    PRECISION = 1000;
+
+    /* setup some basic GIS stuff */
+    G_gisinit(argv[0]);
+    if (G_parser(argc, argv))
+	exit(EXIT_FAILURE);
+
+    if (flag.quiet->answer) {
+	VERBOSE = 0;
+    }
+
+    Rast_get_window(&window);
+    nrows = Rast_window_rows();
+    ncols = Rast_window_cols();
+
+    /*                                                      */
+    /*      STEP 1: VALIDATE input data and topology        */
+    /*                                                      */
+
+    fprintf(stdout, "Validating data: \n");
+
+    /* check if input DEMs are available */
+    /* allocate all necessary handles */
+    for (nfiles = 0; parm.maps->answers[nfiles]; nfiles++) ;
+
+    if (DEBUG)
+	fprintf(stdout, "nfiles = %i\n", nfiles);
+
+    fd = (int *)G_malloc(nfiles * sizeof(int));
+    dcell = (DCELL **) G_malloc(nfiles * sizeof(DCELL *));
+
+    if (nfiles < 2) {
+	G_fatal_error("Need at least two raster maps!");
+    }
+
+    for (i = 0; i < nfiles; i++) {
+	dcell[i] = Rast_allocate_d_buf();
+	name = parm.maps->answers[i];
+	mapset = G_find_raster2(name, "");
+	if (!mapset)
+	    G_fatal_error(_("%s - raster map not found"), name);
+	fd[i] = Rast_open_old(name, mapset);
+	if (fd[i] < 0)
+	    G_fatal_error(_("%s - can't open raster map"), name);
+    }
+
+    nvalues = 0;
+    ncolors = 0;
+    /* if values and/or colors have been specified for the model: check these parameters */
+    if (parm.values->answers != NULL)
+	for (nvalues = 0; parm.values->answers[nvalues]; nvalues++) ;
+    if (nvalues > 0) {
+	if (nvalues != nfiles) {
+	    G_fatal_error(_("Number of values (%i) does not match number of DEMs (%i)!"),
+			  nvalues, nfiles);
+	}
+    }
+    if (parm.colors->answers != NULL) {
+	for (ncolors = 0; parm.colors->answers[ncolors]; ncolors++) ;
+	/* KILL ME */
+	fprintf(stdout, "DEBUG: custom RGB colouring not implemented yet.\n");
+	/* KILL ME */
+    }
+    if (ncolors > 0) {
+	R = G_malloc(ncolors * sizeof(unsigned short int));
+	G = G_malloc(ncolors * sizeof(unsigned short int));
+	B = G_malloc(ncolors * sizeof(unsigned short int));
+	if (ncolors != nfiles) {
+	    G_fatal_error(_("Number of RGB triplets (%i) does not match number of DEMs (%i)!"),
+			  ncolors, nfiles);
+	}
+	for (i = 0; i < ncolors; i++) {
+	    if (!isRGB(parm.colors->answers[i], &R[i], &G[i], &B[i])) {
+		G_fatal_error(_("%s is not a valid RRR:GGG:BBB code!"),
+			      parm.colors->answers[i]);
+	    }
+	}
+    }
+
+    check_zrange(fd, dcell, nfiles);
+
+    if (!flag.skip->answer) {
+	check_topologies(fd, dcell, nfiles);
+    }
+
+    /* let's see how many slices we will make */
+    dslices = ((window.top - window.bottom) / window.tb_res);
+    NSLICES = (int)rint(dslices);
+    if (NSLICES < 1) {
+	G_fatal_error
+	    ("This would produce < 1 slice. Adjust active 3d region resolution.");
+    }
+    if (DEBUG) {
+	fprintf(stdout, "%i DEMS, NSLICES = %i (%f)\n", nfiles, NSLICES,
+		dslices);
+	fflush(stdout);
+    }
+
+
+    /*                                                      */
+    /*      STEP 2: INTERPOLATE volume from DEMs            */
+    /*                                                      */
+
+    /* allocate array for storing voxel data and initialise it with DNULLVALUE */
+    ascii = (double ***)G_malloc(NSLICES * sizeof(double **));
+    for (i = 0; i < NSLICES; i++) {
+	ascii[i] = (double **)G_malloc(nrows * sizeof(double *));
+	for (j = 0; j < nrows; j++) {
+	    ascii[i][j] = G_malloc(ncols * sizeof(double));
+	    for (k = 0; k < ncols; k++) {
+		ascii[i][j][k] = DNULLVALUE;
+	    }
+	}
+    }
+    interpolate(fd, dcell, nfiles, nvalues, ascii);
+
+
+    /*                                                      */
+    /*      STEP 3: OUTPUT volume data                      */
+    /*                                                      */
+
+    /* TEMP SECTION */
+    /* this will only stay in here temporarily until this
+       program will be able to write voxel maps directly !!! */
+    output_ascii(ascii);
+    /* now call r3.in.ascii to write a voxel model for us */
+
+    if (VERBOSE)
+	fprintf(stdout, "Running r3.in.ascii to create voxel model: \n");
+
+    sprintf(sys, "r3.in.ascii in=%s out=%s nv=%f", TMPFILE,
+	    parm.output->answer, DNULLVALUE);
+    if (DEBUG > 0) {
+	fprintf(stdout, "%s\n", sys);
+    }
+    error = system(sys);
+    if (error != EXIT_SUCCESS) {
+	G_fatal_error("Error running command: %s", sys);
+    }
+    if (VERBOSE)
+	fprintf(stdout, " DONE \n");
+
+    /* END (TEMP SECTION) */
+
+
+    /* VTK output */
+    if (flag.vtk->answer) {
+	output_vtk();
+    }
+
+    /* ASCII vector points output */
+    if (flag.grasspts->answer) {
+	output_ascii_points(ascii);
+    }
+
+    /* ASCII convex hulls ouput */
+    if (flag.hull->answer) {
+	output_ascii_hulls(ascii, nvalues, nfiles);
+    }
+
+    /* show cell count stats? */
+    if (flag.countcells->answer) {
+	count_3d_cells(ascii, nfiles, nvalues);
+    }
+
+    fprintf(stdout, "\nJOB DONE.\n");
+    fflush(stdout);
+
+    return (EXIT_SUCCESS);
+}

Added: grass-addons/grass7/grass7/raster/r.vol.dem/r.vol.dem.html
===================================================================
--- grass-addons/grass7/grass7/raster/r.vol.dem/r.vol.dem.html	                        (rev 0)
+++ grass-addons/grass7/grass7/raster/r.vol.dem/r.vol.dem.html	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,136 @@
+<h2>DESCRIPTION</h2>
+
+<em>r.vol.dem</em> interpolates a voxel model from a series of DEMs by
+flood filling the voxel space in between.
+
+The module is able to calculate voxel maps between at least two DEMs.
+The algorithm is based on a so-called "Flood-filling" algorithm. Since
+a date, label or category number of an e.g., archaeological stratum
+represents always the value for the entire stratum it would be more
+suitable to fill the entire 3D unit with this single value.
+<p>
+The input bottom and top DEMs represent each the bottom and top border
+for the "voxeled" stratum, in this case the implicit structure. Before
+running the <em>r.vol.dem</em> module, one needs to adjust the
+three-dimensional extent of the 3D interpolation which works as an
+analytical mask in the GRASS GIS module <em>g.region</em>. This
+procedure adjusts additionally the voxel's size which influences the
+3D resolution of the entire stratum. Furthermore, it is possible to
+adjust the height and width of the voxel in order to obtain a cube or
+cuboid voxel shape. In general, the smaller the voxel's size the higher
+the resolution, the more precise 3D units. 
+
+<h2>NOTES</h2>
+
+The input data for the 3D interpolation which requires at least two
+raster DEMs. They have to be entered in a certain rank, with the lowest,
+according to elevation, DEM first. 
+<p>
+The list of label values is one for each 3D layer (labels=value): Since
+one can enter an infinite number of DEMs it is possible adjust certain
+labels for each 3D layer. If they are not specified, labelling starts
+with layer 0. The numbers are given always upwards disregarding the
+algorithm direction.
+<p>
+The <em>errormap</em> raster map is to represent topology errors in input
+DEMs. This option does not yet create a real map but gives the coordinates
+where intersections of DEMs occur.
+<p>
+The <em>algorithm</em> parameter is used to select the 3D flood fill
+algorithm to use. The user can chose between an up or down filling
+direction. The default adjustment is the upwards algorithm. The results
+can become very different according to the shape and extension of the DEMs.
+<p>
+The <em>-c</em> flag calculates 3D cell counts for each layer: This option 
+counts the number of voxels for each 3D layer label. Unfortunately, this
+count is not stored in the <em>r3.info</em> information. Thus, if one
+needs this information afterwards, one has to repeat the whole calculation. 
+<p>
+The <em>-f</em> flag fills through NULL value areas in DEMs: Null value
+areas are areas which lie outside a 3D layer defined by two successive DEMs
+in the input command. In the case, where a 3D layer is limited not only
+from one unit surface, e.g. on top, this flag allows a further 3D
+interpolation until the next DEM or the region's margin.
+
+<center>
+<img src="r_vol_dem_layerdown.jpg" border=1><br>
+Layer down NULL filling behaviour of <em>r.vol.dem</em>
+</center>
+<p>
+<center>
+<img src="r_vol_dem_layerup.jpg" border=1><br>
+Layer up NULL filling behaviour of <em>r.vol.dem</em>
+</center>
+
+<!-- Suffers from severe memory leak! MN 4/2012
+<p>
+The <em>-h</em> flag export convex hull for polygon layers: This option
+creates a 3D polygon out of the voxel model. This means, at first it will
+be generated a voxel model. Afterwards, this will be converted into a
+vector-file. However, the flag does not yet work properly.
+-->
+
+<p>
+The <em>-g</em> flag exports voxel model as vector points: This option
+creates a vector point for each interpolated voxel. This became necessary
+because of the lack of suitable representation in the visualisation module
+nivz in GRASS GIS 6. Nevertheless, the points can be represented virtually
+as cubes in nviz which gives an idea of the voxel layer. Unfortunately,
+there is still an error in the module using this flag (state 01.06.2006)
+that can be corrected by the following procedure:
+The module <em>r.vol.dem</em> creates a temporary txt-file in the HOME
+directory. Opening this file one will find a line which starts with 
+"# v.in.ascii". This line needs to be copied without the #-sign and
+executed in the GRASS bash shell. 
+<p>
+The <em>-p</em> flag exports VTK point data instead of cell data: This
+option reflects the fact that the visualisation program ParaView which
+treats cell data and point data differently in comparison to the program
+GRASS GIS. Hence, if one wants to visualise GRASS voxel in ParaView, this
+flag is recommended. The VTK floating point precision is 1/1000 of the
+current GRASS location's map unit.
+<p>
+The <em>-q</em> flag disables on-screen progress display:
+This option does not yet work. 
+<p>
+The <em>-s</em> flag skips topology error checking:
+The module checks the input DEMs for intersection before running the
+algorithm. If such an unwanted intersection is found, the algorithm creates
+an errormap (see <em>errormap</em> option) and stops the entire 3D
+interpolation process. Using this flag one can skip this precaution. 
+<p>
+The <em>-v</em> flag generates a vtk-file for visualisation with e.g.
+ParaView: Since the GRASS visualisation module nviz is unable to show
+voxel as (semitransparent) cubes, the Open Source visualisation
+program ParaView is now commonly used for the visualisation of GRASS GIS
+maps and especially for 3D visualisations. Hence, the output GRASS GIS 
+files have to be converted into a ParaView readable format.
+<p>
+The <em>-z</em> flag fits active region's z range to input DEMs:
+This option does not yet work.
+
+<h2>EXAMPLE</h2>
+
+<div class = "code"><pre>
+tbd
+</pre></div>
+
+<h2>SEE ALSO</h2>
+
+<em>
+<a href="g.region.html">g.region</a>,
+<a href="r.to.rast3.html">r.to.rast3</a>,
+<a href="r.to.rast3elev.html">r.to.rast3elev</a>
+</em>
+
+<p>
+<a href="http://undine-lieberwirth.info/?page_id=8">Screenhot gallery</a>
+
+<h2> AUTHOR</h2>
+
+Software: Benjamin Ducke
+<p>
+Documentation: Undine Lieberwirth
+
+<p>
+<i>Last changed: $Date: 2012-05-26 14:39:10 +0200 (Sat, 26 May 2012) $</i>

Added: grass-addons/grass7/grass7/raster/r.vol.dem/r_vol_dem_layerdown.jpg
===================================================================
(Binary files differ)


Property changes on: grass-addons/grass7/grass7/raster/r.vol.dem/r_vol_dem_layerdown.jpg
___________________________________________________________________
Added: svn:mime-type
   + application/octet-stream

Added: grass-addons/grass7/grass7/raster/r.vol.dem/r_vol_dem_layerup.jpg
===================================================================
(Binary files differ)


Property changes on: grass-addons/grass7/grass7/raster/r.vol.dem/r_vol_dem_layerup.jpg
___________________________________________________________________
Added: svn:mime-type
   + application/octet-stream

Added: grass-addons/grass7/grass7/raster.txt
===================================================================
--- grass-addons/grass7/grass7/raster.txt	                        (rev 0)
+++ grass-addons/grass7/grass7/raster.txt	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,7 @@
+Content-Type: text/x-zim-wiki
+Wiki-Format: zim 0.4
+Creation-Date: 2012-10-15T20:04:25+02:00
+
+====== raster0 ======
+Created Monday 15 October 2012
+

Added: grass-addons/grass7/grass7.txt
===================================================================
--- grass-addons/grass7/grass7.txt	                        (rev 0)
+++ grass-addons/grass7/grass7.txt	2012-10-15 18:25:43 UTC (rev 53410)
@@ -0,0 +1,7 @@
+Content-Type: text/x-zim-wiki
+Wiki-Format: zim 0.4
+Creation-Date: 2012-10-15T20:03:42+02:00
+
+====== grass70 ======
+Created Monday 15 October 2012
+



More information about the grass-commit mailing list